Deploying with Docker
Two ways to run the image: Docker Compose (recommended, includes HTTPS) or a plain docker run. Read Deploying dpndncY first if you have not.
#Docker Compose with HTTPS
The repository's docker-compose.yml runs the platform plus Caddy, which obtains and renews certificates automatically.
#What you need
- Docker Engine with the Compose v2 plugin (
docker compose versionworks). - Two DNS names pointing at the machine, for example
dpndncy.example.com(console) andapi.dpndncy.example.com(API). - Ports 80 and 443 reachable from the internet, so Let's Encrypt can validate the names. On a private network, see "Internal certificates" below.
#Steps
# 1. Get the deployment files (or use the dpndncy-deploy.tar.gz you were given)
mkdir dpndncy && cd dpndncy
curl -fsSL https://dpndncy.com/downloads/dpndncy-deploy.tar.gz | tar xz
# 2. Configure
cp .env.example .env
$EDITOR .env # DOMAIN, API_DOMAIN, ACME_EMAIL, APP_SECRET, SUPERADMIN_EMAIL, SUPERADMIN_PASSWORD
# 3. Start
docker compose up -d
docker compose logs -f dpndncY # wait for "dpndncY SCA Engine running"Generate APP_SECRET with openssl rand -hex 32. Open https://<DOMAIN> and sign in with SUPERADMIN_EMAIL. Then follow "Setting up a new workplace" in Deploying dpndncY.
Compose reads .env for itself and passes it to the container. The environment section of the compose file derives CORS_ORIGIN, APP_URL, NEXT_PUBLIC_APP_ORIGIN and PUBLIC_API_URL from DOMAIN and API_DOMAIN, so you do not set those.
#Internal certificates
With no public DNS (for example dpndncy.corp.local), use Caddy's own certificate authority. In .env set:
CADDYFILE=./Caddyfile.internalBrowsers and CI runners must trust that authority once. Its root certificate is in the caddy-data volume at /data/caddy/pki/authorities/local/root.crt:
docker compose cp caddy:/data/caddy/pki/authorities/local/root.crt ./dpndncy-root.crtTo use a certificate from your own CA instead, mount it into the caddy service and add tls /certs/tls.crt /certs/tls.key to both site blocks of the Caddyfile.
#Another reverse proxy
Any proxy works if it sends the console hostname to dpndncY:3000 and the API hostname to dpndncY:3001, keeps X-Forwarded-For and X-Forwarded-Proto, and allows long requests (scans and uploads run for minutes; use read and send timeouts of 600 seconds and a body limit of at least MAX_ZIP_UPLOAD_MB, default 200 MB). Keep TRUST_PROXY=true. deploy/nginx/dpndncy.conf is an nginx example.
#Updating
docker compose pull
docker compose up -dPin DPNDNCY_IMAGE to a version (for example ghcr.io/dpndncy-sca/platform:2.9.0) so an update happens when you choose. Take a backup first (Running dpndncY); a new version can migrate the database. docker compose --profile auto-update up -d adds Watchtower, which updates unattended. Most production installs do not want that.
#Everything that lives where
| Thing | Where |
|---|---|
| Database, secrets, licences, caches | volume dpndncy-data, mounted at /app/data |
| Certificates | volumes caddy-data, caddy-config |
| Logs | docker compose logs, JSON lines, rotated at 10 MB x 5 files |
#Plain docker run (evaluation)
For a quick look on one machine, without HTTPS. Pick a hostname or address you will browse to; the three origin variables must match it exactly:
docker run -d --name dpndncy --restart unless-stopped \
-p 8080:3000 -p 8081:3001 \
-v dpndncy-data:/app/data \
-e APP_SECRET=$(openssl rand -hex 32) \
-e ENABLE_BOOTSTRAP_SUPERADMIN=true \
-e [email protected] \
-e SUPERADMIN_PASSWORD='choose-a-long-password' \
-e CORS_ORIGIN=http://localhost:8080 \
-e NEXT_PUBLIC_APP_ORIGIN=http://localhost:8080 \
-e APP_URL=http://localhost:8080 \
-e PUBLIC_API_URL=http://localhost:8081 \
-e COOKIE_SECURE=false \
ghcr.io/dpndncy-sca/platform:stableConsole at http://localhost:8080, API at http://localhost:8081.
- The volume must be mounted at
/app/data. Anywhere else, and the database is lost when the container is removed. COOKIE_SECURE=falseis needed only because this runs over plain HTTP. With HTTPS leave it at its default,true.- Without
CORS_ORIGINthe backend exits at start-up in production mode.
#Troubleshooting
| Symptom | Cause and fix |
|---|---|
Container restarts at once, log says CORS_ORIGIN missing in production |
Set CORS_ORIGIN (Compose does this from DOMAIN) |
Container restarts, log says APP_SECRET env var missing in production |
Set APP_SECRET |
| Sign-in page loads but sign-in says the request could not be verified | The address in the browser does not match CORS_ORIGIN / NEXT_PUBLIC_APP_ORIGIN. Use the same scheme, host and port |
| Sign-in works but you are signed out on the next click | COOKIE_SECURE=true over plain HTTP. Use HTTPS or set it to false for evaluation |
| Certificates are not issued | DNS for both names does not point here yet, or ports 80/443 are blocked. docker compose logs caddy |
| CLI or pipeline gets 404 from the console address | Use the API address, not the console. See Scanning from CI/CD pipelines |
| Everyone is signed out after a restart | Expected. Browser sessions end whenever the server restarts. API tokens keep working. If they stop working too, the signing key was rotated with the emergency option, or the data volume was replaced |