Running Docker Compose in Production Behind a Reverse Proxy
Take a docker-compose.yml from the laptop to a hardened production host with TLS, restart policies, and rate limiting behind Caddy or Nginx.
Netbay Developer Relations
Netbay Engineering
On this page
Docker Compose is the fastest way to get a multi-service app running, but the version that lives in a docker-compose.yml next to your README is not production-ready. Login instead of asking "is it working on my laptop", the job becomes: is it working when the host reboots, the port is scanned, and users hammer the front door. The difference is a reverse proxy, sane restart rules, and a read-only, non-root runtime.
This guide walks a Compose stack that sits behind a reverse proxy with automatic TLS and gets it ready to serve real traffic from a Netbay VPS.
Compose as a Production Unit
Compose is not just a dev tool. With docker compose up -d, restart: unless-stopped, healthchecks, and logging limits, the same file can serve a small app for years. The key discipline is to keep secrets out of the file and to make each service resilient.
Start with a hardened base:
version: "3.9"
services:
web:
image: myapp:1.4.2
restart: unless-stopped
read_only: true
tmpfs:
- /tmp
security_opt:
- no-new-privileges:true
environment:
- DB_HOST=db
- DB_NAME=app
depends_on:
db:
condition: service_healthy
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
db:
image: postgres:16-alpine
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 10s
timeout: 4s
retries: 5
volumes:
- dbdata:/var/lib/postgresql/dataWhy a Reverse Proxy Belongs In Front
Publishing ports directly on the host is fine for a lab, but in production you want one TLS-terminating front door. A reverse proxy centralizes certificates, request limits, and access logs. It also means your app containers can listen on an internal network only, shrinking the attack surface.
Caddy is the least configuration-heavy choice because it obtains and renews certificates automatically:
app.example.net {
reverse_proxy web:8080
encode gzip
log {
output stdout
format json
}
@slow path /api/*
header @slow Cache-Control "no-store"
}The diagram shows where each piece sits in the trust boundary.
Run Caddy itself as a service with its own restart rule, bind it to the public port, and let it proxy to the internal Compose network. Nginx works identically from an architecture standpoint but you manage certificates yourself, usually with certbot.
Networking, Secrets, and Backups
Give services a private user-defined network so nothing is reachable from outside except the proxy. Store secrets in environment files with tight permissions or Docker secrets, and back up the database volume with a scheduled job.
docker network create frontend
docker compose up -d
docker exec -t $(docker compose ps -q db) pg_dump -U app app | gzip > /backups/app-$(date +%F).sql.gzPractical Checklist Before Go-Live
- Every container is pinned to a specific image tag, never
:lateston a timer. restart: unless-stoppedis set on every long-running service.- Only the proxy publishes a port to the host; everything else is internal.
- Log rotation caps disk use so a chatty app cannot fill the disk.
- A healthcheck exists for stateful services so
depends_onactually waits.
Takeaway
Compose plus a reverse proxy covers a large share of real production workloads with far less machinery than a full cluster. Put this stack on a single Netbay instance, ship the file to the host, and you have a deployable service in minutes — netbayhosts.in provisions the server in under 60 seconds so you can get to the good part.
Keep reading
Follow along on a real VPS
Deploy Linux in under 60 seconds
These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.
Deploy an instance