First-Time Setup & Deployment (Docker Compose)
This page walks you through deploying the application using Docker Compose on a fresh host. You’ve already pulled the image (see previous page).
Prerequisites
- Docker Engine / CLI 28.1.1 (or compatible)
- Docker Compose plugin v2.x
- Image already pulled from
synaccess.azurecr.io
- A deployment folder (example path used below:
/opt/syn-cloud
)
Check your versions:
docker --version
docker compose version
1) Create the deployment folder
sudo mkdir -p /opt/syn-cloud/{certs}
cd /opt/syn-cloud
- Put any TLS/CA files you need under
./certs/
(host) — they’ll appear in the container at/certs/...
..
2) Create the files
Create docker-compose.yml
in /opt/syn-cloud
:
version: "3.9"
services:
syn-cloud:
# Default to 'latest' unless TAG is set in .env
image: synaccess.azurecr.io/syn-cloud:${TAG:-latest}
container_name: syn-cloud
env_file:
- .env
# Uncomment/leave as-is to make TLS material or other read-only assets
# available inside the container. For example, mount database CA certificates
# or HTTPS cert/key pairs and reference the in-container paths from your .env
# (e.g., TLS_CERT=/certs/fullchain.pem).
volumes:
- ./certs:/certs:ro
# Publishes the app on the same port configured in .env.
# When PORT=443 and CONNECTION_SECURITY=tls the container will terminate TLS.
ports:
- "${PORT:-80}:${PORT:-80}"
restart: unless-stopped
# Always check for a newer image on 'up' (useful when tracking 'latest')
# pull_policy: always
Create .env
next to it (copy/paste then edit values):
# These values are consumed by docker-compose.yml and the application at runtime.
# -----------------------------------------------------------------------------
# Database connectivity
# -----------------------------------------------------------------------------
# Full PostgreSQL connection URI. Include credentials and database name.
# Example for managed Postgres: postgres://user:password@host:5432/database
DB_CONNECTION_STRING=postgres://username:password@database-host:5432/database-name
# Connection pool sizing. Keep small for low-resource deployments.
DB_MIN_CONNECTIONS=2
DB_MAX_CONNECTIONS=40
# TLS options (optional). Set DB_SSL_MODE to one of: disable, prefer, require, verify-ca, verify-full.
# When supplying certificate paths, mount them via docker-compose (see volumes example) and
# point these variables at the in-container path (e.g. /certs/root.crt). You can also
# inline PEM content by escaping newlines with \\n
DB_SSL_MODE=
DB_SSL_ROOT_CERT=
DB_SSL_CERT=
DB_SSL_KEY=
# Set to false ONLY when you must skip certificate validation (not recommended).
DB_SSL_REJECT_UNAUTHORIZED=
# -----------------------------------------------------------------------------
# Application runtime
# -----------------------------------------------------------------------------
# The public hostname for the deployment (used when generating links/emails).
HOST=localhost
# Listening port inside the container AND host mapping. Ensure docker-compose ports section matches.
# Common values: 80 for HTTP, 443 when running TLS directly, 3000 for alternate ports.
PORT=80
# Bind address used by the web server; :: listens on all IPv4/IPv6 addresses.
BIND_HOST=0.0.0.0
# Optional override for the externally reachable URL. Leave blank to auto-generate from HOST/PORT/CONNECTION_SECURITY.
HOST_URL=
# Choose none or tls. When tls is selected, provide TLS_CERT and TLS_KEY.
CONNECTION_SECURITY=none
# When true AND running TLS, the app will redirect HTTP (80) to HTTPS (443) inside the container.
FORWARD_PORT_80_TO_443=false
# TLS certificate and key can be either inline PEM (escape newlines with \\n) or filesystem paths mounted into the container.
TLS_CERT=
TLS_KEY=
# Comma-separated list or wildcard for allowed CORS origins. Use * for testing only.
CORS_ORIGIN=
# -----------------------------------------------------------------------------
# Image pinning (optional)
# -----------------------------------------------------------------------------
# Leave TAG unset to track 'latest'. To pin/revert to a specific version, set TAG here.
# TAG=2025.10.02
Tip: Keep a backup before edits:
cp .env .env.backup.$(date +%Y%m%d-%H%M%S)
3) Login (one-time per host)
docker login synaccess.azurecr.io -u <TOKEN_USER> -p '<TOKEN_PASSWORD>'
Expected output: Login Succeeded
.
4) Start the application
docker compose up -d
Compose will create (or recreate) the container and start it with the variables from .env
.
5) Verify
docker compose ps
docker compose logs --tail=200 syn-cloud
curl -I http://127.0.0.1:${PORT:-80} || true
- You should see
Up
indocker compose ps
. - Adjust the port if you changed
PORT
in.env
.
6) Initial in-app setup (first login)
After the container is running and you can reach the URL, complete these one-time steps inside Syn Cloud.
-
Open your Syn Cloud URL Visit
https://<your-hostname>
(orhttp://<your-hostname>:<port>
if not using TLS). -
Go to Deployment Settings On first boot, the app should direct users to /deployment-settings.
-
Create the Super Admin account
- Username (or email)
- Email address
- Strong password
- Save
This Super Admin account is the primary administrator. Its email/username and password are used later when pairing PDUs to your cloud.
-
Configure SMTP (email)
- SMTP host/port (587 STARTTLS or 465 SMTPS)
- Username / password (service account recommended)
- Encryption (STARTTLS or SSL/TLS)
- Save and Send test email
SMTP enables email verification, password resets, and user invitations. Without SMTP, users won’t be able to complete email-based flows.
-
Confirm deployment details On Deployment Settings, verify the displayed Deployment URL and environment details match your
.env
(for exampleHOST
,PORT
, and TLS settings).
When finished, continue with pairing PDUs and inviting users.
7) Database Connectivity Schemes
The app reads DB settings from .env
and supports three common patterns:
Scenario | How to configure in .env | When to use |
---|---|---|
Username + password | DB_CONNECTION_STRING=postgres://username:password@db-host:5432/database (leave TLS vars blank, or set DB_SSL_MODE=prefer to negotiate TLS if supported). | Simplest configuration for trusted/internal networks. |
Server-authenticated TLS | DB_CONNECTION_STRING as above; set DB_SSL_MODE=verify-ca or verify-full ; point DB_SSL_ROOT_CERT at the mounted CA (e.g., /certs/root.crt ). | When the DB requires TLS and you only need to validate the server certificate. |
Mutual TLS (client certs) | Same as above plus set DB_SSL_CERT and DB_SSL_KEY to mounted paths (e.g., /certs/client.crt , /certs/client.key ). | Managed services or hardened deployments that require client certificates. |
Mounting certificates: Place your CA/client certificates under
./certs/
(host). The compose file maps./certs:/certs:ro
, so reference them in.env
as/certs/<file>
.
8) Applying Migrations
- The backend runs migrations automatically on first startup.
- Ensure your DB user has privileges to CREATE, ALTER, and INSERT.
- Watch
docker compose logs --tail=200 syn-cloud
for migration output on first boot.
9) Configure HTTPS Termination
Choose one of the following:
-
Terminate TLS inside the app
- Set
CONNECTION_SECURITY=tls
andPORT=443
in.env
. - Put
fullchain.pem
andprivkey.pem
under./certs/
. - Set in
.env
:TLS_CERT=/certs/fullchain.pem
TLS_KEY=/certs/privkey.pem
- (Optional)
FORWARD_PORT_80_TO_443=true
to redirect HTTP→HTTPS within the container.
- Set
-
Terminate TLS at a reverse proxy (nginx, Caddy, Traefik, etc.)
- Leave
CONNECTION_SECURITY=none
, keepPORT=80
. - Point your proxy at the container’s HTTP listener.
- Manage certificates in the proxy; the app container does not need the private key.
- Leave
-
Hybrid / Load balancer offload
- Present certificates at the LB and forward HTTP to the container (
CONNECTION_SECURITY=none
). - Ensure LB forwards
X-Forwarded-Proto
so the app generates correct HTTPS links.
- Present certificates at the LB and forward HTTP to the container (
When certificates change, restart to apply:
docker compose up -d
(or--force-recreate
).
10) Edit configuration later
- Edit
.env
and re-apply:
docker compose up -d
# If changes don’t apply, force recreation:
docker compose up -d --force-recreate
- Pin or roll back to a specific image tag by setting
TAG
in.env
, then:
docker compose pull
docker compose up -d
11) Troubleshooting
-
401 Unauthorized during pull → Re-run the login:
docker login synaccess.azurecr.io -u <TOKEN_USER> -p '<TOKEN_PASSWORD>'
-
DNS/network error
nslookup synaccess.azurecr.io curl -I https://synaccess.azurecr.io/v2/ || true
-
Database connection errors on first boot Verify
DB_CONNECTION_STRING
and any TLS variables. Confirm mounted cert paths (/certs/...
) exist.
12 What persists between restarts
- Any mapped paths in
volumes:
(e.g.,./certs
,./logs
) persist on the host. - If you add a DB service in your compose later, its data can live in
./pgdata
.
Do not commit
.env
to version control. Keep credentials safe.
Updated 12 days ago