Running Docker and Docker Compose in Production on a VPS: The 2026 Checklist

Docker Compose is the fastest way to go from "it works on my laptop" to "it runs on a server". It is also easy to deploy in a way that works on day one and breaks quietly on day thirty: a full disk, a container that never restarted, a database port open to the internet. This checklist covers the production basics for running Docker and Compose on a single VPS, the setup most small teams and SaaS projects actually use.
1. Choose the right VPS
Containers do not need special hardware, but they make it very easy to run many services on one machine. Size for the sum of your containers at peak, not the average. For a typical web app with a database, cache and background worker, 4 vCPU and 8 GB RAM is a comfortable starting point. Prefer NVMe storage, because image layers, logs and databases all write to disk. A Linux VPS with full root access works well; a Cloud VPS with dedicated vCPU and RAM is the better fit if builds and databases run on the same machine.
2. Install Docker the supported way
Install Docker Engine and the Compose plugin from Docker's official repository rather than an old distribution package, so you get current security fixes. Then add your deploy user to the docker group, and remember that this group is effectively root access: only trusted users belong there.
3. Write a Compose file that survives reboots
services:
app:
image: ghcr.io/yourorg/app:1.4.2
restart: unless-stopped
env_file: .env
depends_on:
db:
condition: service_healthy
ports:
- "127.0.0.1:3000:3000"
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
retries: 5
volumes:
- db_data:/var/lib/postgresql/data
secrets:
- db_password
volumes:
db_data:
secrets:
db_password:
file: ./secrets/db_password.txtThe details that matter:
restart: unless-stoppedbrings services back after a crash or reboot.Pinned image tags such as
1.4.2instead oflatest, so a redeploy never surprises you with a new version.Health checks with
depends_on: condition: service_healthy, so the app waits for the database.Named volumes for anything that must persist. Container filesystems are disposable.
Log rotation, because the default logging driver keeps growing until the disk is full.
4. Do not publish ports you do not need
This is the most common production mistake. Docker writes its own firewall rules, and a published port such as 5432:5432 can be reachable from the internet even if UFW appears to block it. Publish only what a reverse proxy needs, bind it to 127.0.0.1, and let databases and caches talk over the internal Compose network without any published port at all.
5. Put a reverse proxy in front
Run Caddy, Nginx or Traefik as the only service listening on ports 80 and 443. It terminates TLS, renews certificates and routes traffic to your containers. This also gives you one place to add rate limiting, compression and security headers.
6. Keep secrets out of images and Git
Use an .env file that is not committed to version control, or Compose secrets for passwords and API keys. Never bake credentials into an image; anyone who can pull the image can read them.
7. Back up volumes, not containers
Containers can be recreated from images in seconds. What you cannot recreate is the data in your volumes. Back up databases with their native tools, for example pg_dump or mysqldump, rather than copying live data files, and store copies off the server. On IM HOST Cloud VPS, an automatic backup of the whole server runs every 72 hours at no extra cost, which is a useful safety net alongside your own database dumps.
8. Plan for disk usage
Old images, stopped containers and build cache accumulate. Schedule a regular docker system prune with care, after making sure it will not remove anything you rely on, and monitor free space with an alert well before 90 percent.
9. Update deliberately
Patch the host OS regularly and reboot when the kernel updates.
Rebuild your images to pick up base-image security fixes.
Deploy new versions by changing the tag, running
docker compose pullanddocker compose up -d, and keep the previous tag ready for rollback.
10. Monitor what users feel
A running container is not the same as a working app. Add an external uptime check on a real endpoint, alert on container restarts, and keep an eye on response times. Simple tools are enough; what matters is that someone gets notified.
Where to run it
IM HOST Linux VPS and Cloud VPS plans come with full root access, NVMe storage, a dedicated IPv4 address and support from engineers 24/7, in the US, UK, Poland, Germany and Egypt. Compare Linux VPS and Cloud VPS plans to pick the right size for your stack.
More from our blog
Discover more practical guides and product insights from the IM Host team.
View all articles