*Last updated: November 2026 — error strings vary slightly by Compose v2 / Engine version.*
You deployed a self-host stack (Caddy + app) and something fails at up, healthcheck, HTTPS, or after reboot. Skip theory — match your symptom in the tables.
docker compose ps — Exit / Restarting?
docker compose logs --tail=200 SERVICE
ss -tlnp | grep -E ':80|:443|:5432|:2283' — who owns ports?
df -h and free -h — disk / RAM
docker compose config — interpolated YAML valid?
Symptom
Cause
Fix
`Bind for 0.0.0.0:80 failed: port is already allocated`
Another process/container already uses host 80
`sudo ss -tlnp \
grep :80` — stop nginx/apache/old Caddy; only one proxy publishes 80/443
`Bind for 0.0.0.0:443 failed`
Same for 443
Same as above; check leftover `docker` publish and host `caddy`/`nginx`
App works on `http://VPS_IP:8080` but not via domain
You published app ports and skipped proxy, or DNS wrong
Prefer proxy-only publish; set DNS A/AAAA; use `https://hostname` in app env
`curl localhost` works, public IP fails
Cloud firewall / ufw / security group closed
Open TCP 80/443 (and SSH); `sudo ufw status`
Conflict between two compose projects both mapping `80:80`
Two proxies
One shared proxy network; other stacks join external network without publishing 80/443
Publishing `127.0.0.1:9443:9443` then can’t open remotely
Bind is localhost-only (intentional)
Use SSH tunnel or bind to VPN IP — don’t switch to `0.0.0.0` without auth
Symptom
Cause
Fix
`Permission denied` writing to bind mount
Container user ≠ host directory owner
`ls -ln` the dir; `chown` to documented UID/GID (e.g. Paperless `USERMAP_UID`/`GID`) or match image user
Paperless consume folder ignores new files
UID mismatch / wrong mount path / inotify limits
Align USERMAP_*; confirm mount is the consume dir; check `fs.inotify.max_user_watches` on busy hosts
Postgres / Immich DB won’t start after copy
Data dir owned by wrong UID; incomplete copy
Stop stack; copy with `rsync -a`; fix ownership to postgres image UID (often 999 or 70 — check image); never mix major PG versions in same data dir
`Read-only file system` in container
`:ro` mount or read-only rootfs
Remove erroneous `:ro` from writable data paths
Named volume empty after “migration”
You recreated project name / volume name
`docker volume ls`; compose prefixes volumes with project name — use external volumes or consistent `-p` project name
Lost data after `docker compose down -v`
`-v` deletes named volumes
Never use `-v` on production unless intentional; backups first
SQLite `database is locked` (Vaultwarden etc.)
Two writers / storage on NFS with bad locking
One container writer; keep DB on local SSD; avoid NFS for SQLite
Symptom
Cause
Fix
Container `Restarting` / `Exit 137`
OOM killer (137 often = SIGKILL)
`dmesg \
grep -i oom`; raise RAM or lower app load (disable Immich ML; smaller models); set sane `deploy.resources` only if you understand throttling
Host freezes under Immich / Jellyfin
RAM + CPU thrash
Specs table: Immich wants multi-GB RAM; transcoding needs headroom
Healthcheck fails, app actually fine
Wrong URL/port in healthcheck; app slow to listen
Increase `start_period`; fix path/port; see Engine version for `start_interval` support
`start_interval` rejected by Compose/Engine
Feature needs newer Docker Engine
Upgrade Engine/Compose or remove `start_interval` from healthcheck
Depends_on “healthy” never becomes true
Dependency healthcheck broken
Fix dependency healthcheck first; temporary `depends_on` without condition for debug
Symptom
Cause
Fix
`no matching manifest for linux/arm64`
Image not multi-arch; VPS is ARM
Pick ARM-capable tag/image or use amd64 VPS
App broke after recreate
`:latest` moved
Pin versions (`image: repo:1.2.3`); upgrade deliberately
`pull access denied` / rate limit
Auth or Hub anonymous limits
`docker login`; mirror; pin and avoid frantic pulls
Compose warns about obsolete `version:` key
Compose spec v2 ignores top-level `version`
Remove `version:` line — harmless warning
Symptom
Cause
Fix
`$` in password / Argon2 hash truncated
Compose interpolates `$VARS`
Escape as `$$` in compose, or pass via env_file without putting `$...` in YAML strings incorrectly
Vaultwarden admin token invalid
Hash altered by interpolation or wrong quoting
Generate token inside docs’ method; escape `$`; recreate with correct `ADMIN_TOKEN`
Variable empty in container
`.env` not next to compose file; wrong `env_file:` path
Put `.env` in project dir; run compose from that dir; `docker compose config` to inspect
Boolean/string confusion (`"false"` vs false)
App-specific parsing
Follow app docs; many accept string env only
Symptom
Cause
Fix
Proxy can’t resolve `service-name`
Different compose projects / networks
Attach apps to same user-defined network; use external network
502/503 from Caddy/Traefik
Upstream down, wrong port, or still starting
Check upstream `compose logs`; match internal listen port (Vaultwarden 80, Paperless 8000, Immich server 2283 — confirm your tag)
Infinite redirect
App forced HTTPS while proxy also redirects; wrong `DOMAIN`
Set public URL to exact external `https://host`; don’t double-terminate oddly
WebSockets fail (some apps)
Proxy missing headers / timeouts
Caddy `reverse_proxy` usually OK; raise timeouts for large uploads (Immich)
Works on HTTP IP, HTTPS cert fails
ACME challenge failing
See **Caddy certificate failures** page (DNS/ufw/IPv6)
Symptom
Cause
Fix
`no space left on device`
Images, logs, bind data filled disk
`df -h`; `docker system df`; prune unused images; rotate logs; enlarge disk
Container logs huge
Default json-file unlimited
Add log options (`max-size`, `max-file`) on services
Can’t pull after prune
You pruned needed images
`compose pull` again; don’t prune volumes blindly
docker compose ps -a
docker compose logs --tail=200 SERVICE
docker compose config
docker inspect CONTAINER --format '{{.State.Status}} {{.State.OOMKilled}} {{.State.ExitCode}}'
ss -tlnp | grep -E ':80|:443'
df -h
free -h
dmesg -T | tail -50
docker compose ps shows healthy / running, not restart loop
OOMKilled is false in docker inspect
Only proxy owns 80/443
App URL env matches public HTTPS hostname
Backup still runs on the correct volume path
Caddy certificate failures (DNS, ufw, IPv6)
Caddy vs Traefik
Coolify vs Portainer vs Compose