İçindekiler
- 1 Why Docker Compose on a VPS Works So Well for Small SaaS Apps
- 2 What “Production-Ready” Means for Docker Compose on a VPS
- 3 Choosing and Preparing the VPS for Docker Compose
- 4 Designing the Docker Compose Architecture
- 5 Reverse Proxy and SSL Termination with Docker Compose
- 6 Backups for Docker Compose on a VPS: Strategy and Implementation
- 7 Operational Practices: Deployments, Updates and Monitoring
- 8 Security Considerations for Docker Compose SaaS Architectures
- 9 Putting It All Together: A Practical Architecture Blueprint
- 10 Conclusion: Start Simple, Make It Boring, Then Scale
Why Docker Compose on a VPS Works So Well for Small SaaS Apps
If you are building a small SaaS or API product, a single VPS with Docker Compose is often the sweet spot between simplicity, cost and reliability. You get isolation between services, reproducible deployments, easy scaling in small steps, and a clean way to manage dependencies – without jumping straight into the complexity and overhead of full Kubernetes.
But to run Docker Compose in real production, you need more than a docker-compose.yml that works on your laptop. You need a clear architecture for your reverse proxy, SSL termination, persistent storage, backups, monitoring and security. Otherwise, the first certificate expiry, disk fill-up or broken deployment will quickly turn into an outage.
In this guide we will walk through a practical, production-ready VPS architecture for small SaaS apps using Docker Compose. We will focus on three pillars that matter most in real projects: a robust reverse proxy layer, automated SSL certificates and a backup strategy you can actually restore from. As the dchost.com team, we will also share patterns we see working well across customer stacks and our own internal projects.
What “Production-Ready” Means for Docker Compose on a VPS
Running Docker locally and running it on a public-facing VPS are very different stories. For a small SaaS, we consider a Docker Compose stack “production-ready” when it covers at least these areas:
- Network and routing: one or more domains/subdomains routed through a reverse proxy container
- HTTPS everywhere: automated issuance and renewal of SSL certificates
- Persistent storage: no critical data lost when a container is recreated
- Backups and restores: regular, off-site backups that you have tested at least once
- Security baseline: hardened VPS, reasonable isolation between services, secrets handled properly
- Operational flow: a repeatable way to deploy updates and roll back if needed
Everything in this article is built around those goals. If you want a gentle introduction to containers on a single server before going deeper, you can also read our step‑by‑step guide on running isolated Docker containers on a VPS.
Choosing and Preparing the VPS for Docker Compose
For small SaaS apps, a single VPS is usually the best starting point. At dchost.com we see many early‑stage products run comfortably on a mid‑range plan and then scale up or out later.
How to size the VPS
The exact sizing depends on your stack (PHP, Node.js, Go, Python, etc.) and database load, but some practical starting points for a Docker Compose SaaS are:
- vCPU: 2–4 vCPUs for a typical web + API + background workers
- RAM: 4–8 GB for app, database and cache on the same node
- Disk: NVMe‑based storage with enough headroom for database growth and file uploads
- Network: generous monthly bandwidth; small SaaS apps rarely hit CPU limits before network and database
If you want a more systematic way to think about CPU and RAM for different workloads, we covered this in detail in our guide on capacity planning vCPU, RAM and IOPS for web applications.
Linux distribution and base hardening
Pick a well‑supported, LTS‑style distribution such as Ubuntu, Debian or AlmaLinux – all work perfectly with Docker. If you are comparing options, our article on Ubuntu vs Debian vs AlmaLinux for VPS hosting walks through the trade‑offs.
Before touching Docker, bring the VPS into a reasonable security baseline:
- Update packages, enable unattended security upgrades
- Create a non‑root user and disable direct root SSH access
- Configure a firewall (ufw, firewalld or nftables) to allow only SSH and HTTP/HTTPS
- Install Fail2ban to mitigate brute‑force attacks
We maintain a detailed VPS security hardening checklist that you can adapt directly to your Docker hosts.
Installing Docker and structuring the filesystem
Once the base VPS is ready:
- Install the official Docker Engine and Docker Compose plugin from the distribution’s repository or Docker’s repository
- Create a dedicated system user or group to own your application directories (for example, /opt/saas)
- Plan directories for persistent data, such as /var/lib/docker/volumes (managed by Docker) and extra bind‑mount paths like /srv/saas-uploads
- Reserve a separate directory for backups, such as /var/backups/saas
Having a clear structure from day one makes backups and restores dramatically easier.
Designing the Docker Compose Architecture
A robust production stack for a small SaaS on a single VPS usually contains these core services:
- Reverse proxy: Nginx or Traefik handling HTTP/HTTPS, ACME/Let’s Encrypt, redirects and basic security headers
- Application service: your main web/API container(s)
- Database: PostgreSQL or MariaDB/MySQL, running in a container or directly on the host
- Cache/queue: Redis for sessions, cache and background jobs
- Workers: background job consumers, cron workers, schedulers
- Backup sidecar: a container responsible for periodic dumps and pushing them to off‑site storage
Networks and isolation strategy
Compose lets you define multiple networks. A clean pattern for production is:
- public network: only the reverse proxy is attached here, exposing ports 80/443 on the host
- internal network: app, database, redis and workers communicate on this network; nothing else is exposed
In docker-compose.yml, this means defining both networks and attaching services appropriately. The database and Redis containers never publish ports directly on the host. Only the reverse proxy binds to the public IP.
Persistent volumes and data layout
In production you should be able to destroy and recreate any application container without losing data. The usual persistent data in a SaaS are:
- Database files
- Uploaded files (images, documents, exports, etc.)
- Configuration and secrets (.env files, encryption keys, etc.)
- Logs (if you keep them for compliance or debugging)
With Docker Compose you can mix named volumes and host bind mounts:
- Use named volumes for stateful services like the database and Redis
- Use bind mounts for uploads, so they are stored in a normal directory like /srv/saas-uploads that you can back up or move independently
- Keep your .env files and secrets outside the project Git repository and mount them as needed; our guide on managing .env files and secrets safely on a VPS goes deeper into this
Reverse Proxy and SSL Termination with Docker Compose
The reverse proxy is the front door of your SaaS: it terminates TLS, routes to the right container and often enforces basic security policies. With Docker Compose, two battle‑tested approaches are:
- Nginx as a reverse proxy with static configuration files
- Traefik as a dynamic reverse proxy configured by Docker labels
We have covered Nginx and Traefik based production patterns in a WordPress context in our article on containerizing WordPress on one VPS with Traefik or Nginx. The same ideas translate directly to small SaaS apps.
When to choose Nginx
Nginx is a great fit if:
- You have only a handful of domains/subdomains
- You prefer explicit configuration files over labels
- You want fine‑grained control of caching, compression and advanced directives
In this model, the Nginx container mounts a directory with configuration files such as /etc/nginx/conf.d/saas.conf. Each server block proxies to upstream services on the internal Docker network. For SSL, you can either:
- Use a containerized ACME client that writes certificates to a shared volume mounted into Nginx
- Or use a host‑level ACME client (like acme.sh) and bind‑mount /etc/letsencrypt into the Nginx container
If you want to go deeper into ACME challenge types and automation tools, our article on ACME challenges (HTTP‑01, DNS‑01, TLS‑ALPN‑01) is a good companion read.
When to choose Traefik
Traefik shines when:
- You have many subdomains or customer‑specific domains
- You want Traefik to automatically discover services and routes from Docker labels
- You want built‑in Let’s Encrypt integration, HTTP to HTTPS redirects and simple rate limiting
Your docker-compose.yml would define a traefik service with:
- Access to the Docker socket (read‑only)
- A persistent volume for ACME certificates
- Entrypoints for HTTP/HTTPS
- Labels to configure dashboard access and global middlewares
Each app container then declares labels describing its routers, services and TLS configuration. Traefik picks these up dynamically and starts routing instantly – which is very convenient when you add new tenants or features.
Handling SaaS domain patterns
Small SaaS apps typically use one of these domain patterns:
- Single domain: app.example.com or example.com
- Subdomain per tenant: tenant1.example.com, tenant2.example.com
- Custom domains (BYOD): customer‑owned domains like portal.customer.com pointing to your SaaS
Single‑domain and subdomain patterns are straightforward: you control DNS, so you can point A/AAAA records to your VPS and let Nginx or Traefik handle Let’s Encrypt via HTTP‑01.
Custom domains are trickier. Tenants point their DNS to your IP or CNAME, and you must automatically request SSL certificates for each domain. This is where a DNS‑01 based ACME setup or a reverse proxy with advanced certificate management pays off. We wrote an in‑depth guide on this topic for SaaS builders: bring your own domain and get auto‑SSL in multi‑tenant SaaS. The architectural ideas there map directly onto a Docker Compose‑based stack.
Backups for Docker Compose on a VPS: Strategy and Implementation
Backups are the part of architecture nobody enjoys until the first time they save a project. In a Docker Compose environment, you must think in terms of data, configuration and automation.
What to back up
At minimum, your backup set should include:
- Database content (logical dumps or physical snapshots)
- Uploaded files and any persistent media
- Configuration files (.env, docker-compose.yml, Nginx/Traefik config, custom scripts)
- Optional: logs needed for compliance or audits
Within Docker, this usually maps to:
- Named volumes for the database and possibly Redis (if you care about data durability across restarts)
- Bind‑mounted directories for uploads under /srv or /var/www
- Application repository checked out under /opt/saas
On‑server vs off‑site backups
We strongly recommend a layered approach:
- On‑server backups: fast local copies and dumps for quick restores after minor issues
- Off‑site backups: encrypted copies to object storage or another server in case the VPS is lost, compromised or fails badly
A good pattern is to use a dedicated backup container or cronjob that:
- Runs mysqldump or pg_dump inside a short‑lived database client container
- Archives relevant volumes and directories (uploads, configs) into compressed tar files
- Pushes these archives to an S3‑compatible object storage bucket using tools like restic or rclone
We have a detailed, practical guide on this pattern in our article about automating off‑site backups to object storage with rclone, restic and cron. Although the examples there use cPanel and generic VPS setups, the same tools integrate very nicely with Docker volumes and bind mounts.
Backup frequency and retention
Your backup schedule should follow your business requirements (RPO/RTO) more than technical preferences. As a starting point for small SaaS apps:
- Databases: at least every 4 hours for active apps, plus nightly full dumps
- Uploads: nightly sync to off‑site storage, with versioning enabled on the destination
- Configs and compose files: stored in Git + daily off‑site snapshot
For retention, many teams start with something like:
- 7 daily backups
- 4 weekly backups
- 3–6 monthly backups
We discuss RPO/RTO and retention policies in more depth in our guide on designing a backup strategy for SaaS applications.
Don’t forget restore tests
A backup you have never restored from is a backup you cannot fully trust. At least once per quarter, run a simple drill:
- Provision a temporary VPS or use a separate Docker network on the same host
- Restore the latest database dump into a fresh container
- Restore uploads and configs into a cloned environment
- Bring up the stack and verify that core flows (sign‑up, login, key reports) work
Document this as a short runbook so that anyone on your team can execute it calmly when you actually need it.
Operational Practices: Deployments, Updates and Monitoring
Once the architecture is in place, daily operations become the main source of risk. The goal is to make deployments and updates boring.
Deploying application changes
With Docker Compose, a simple deployment flow can be:
- Build new images in CI and push them to a registry
- On the VPS, pull new images: docker compose pull
- Apply the update with docker compose up -d
To minimize downtime, make sure your app supports graceful shutdown and your reverse proxy keeps connections healthy during container restarts. For more advanced setups, you can run blue‑green style deployments with two separate Compose projects and let Nginx or Traefik switch traffic between them, similar to the strategy we describe for PHP applications in our blue‑green deployment guide.
Keeping the host and containers updated
Remember that your attack surface includes both the host OS and the container images:
- Enable automatic security updates on the host and schedule a monthly reboot window
- Regularly rebuild images from up‑to‑date base images and redeploy
- Remove unused images, containers and volumes to keep the system clean
Monitoring and alerts
Even the best architecture needs visibility. At minimum, you should monitor:
- CPU, RAM, disk and network usage on the VPS
- Container health, restarts and logs
- Public HTTP endpoints for uptime and SSL expiry
A lightweight but effective stack combines host‑level metrics (via Node Exporter), a time‑series database and a dashboard/alerting tool. We show one practical path in our guide on VPS monitoring and alerts with Prometheus, Grafana and Uptime Kuma. Uptime Kuma or similar tools can run comfortably in Docker Compose, right next to your SaaS stack, or on a separate monitoring VPS.
Security Considerations for Docker Compose SaaS Architectures
Docker Compose does not magically make things secure or insecure; it simply changes where you express boundaries. A few security principles go a long way:
- Least privilege containers: avoid running containers as root unless strictly necessary; use non‑root users and read‑only file systems where possible
- Minimal image surface: base your services on slim images (Alpine, distroless, etc.) and remove unused tools from images
- Isolate secrets: keep secrets in dedicated .env files or Docker secrets, never in Git, and restrict file permissions on the host
- Network isolation: rely on internal Docker networks and a host firewall so that only the reverse proxy is exposed to the internet
- Access control: use SSH keys instead of passwords, and consider hardware keys or 2FA for critical accounts
Treat your Docker host like any other production server: logins should be audited, sudo access limited, and configuration changes tracked. Our broader guide on securing a VPS server against real‑world threats is a good checklist to review after you set up Compose.
Putting It All Together: A Practical Architecture Blueprint
Let’s summarize a practical, production‑oriented architecture for a small SaaS on a single VPS using Docker Compose:
- VPS: 2–4 vCPUs, 4–8 GB RAM, NVMe storage, hardened following best practices
- Networks: one public network for the reverse proxy; one or more internal networks for app, DB and cache
- Reverse proxy: Nginx or Traefik container terminating TLS and routing to app containers
- Application: one or multiple app containers (for example, Node.js, Laravel, Django), plus background worker containers
- Database: PostgreSQL or MariaDB in a container with a persistent volume, or on the host if you prefer
- Cache/queue: Redis with a persistent volume if you need durability
- Backups: dump scripts and off‑site sync run from a dedicated backup container or cronjobs, tested regularly
- Monitoring: resource metrics, uptime checks and SSL expiry alerts, ideally from a separate monitoring setup
This architecture is simple enough for a small team to understand and operate, but solid enough to serve paying customers. As your SaaS grows, you can scale vertically (bigger VPS), then split out the database or cache to separate servers, and eventually move to multi‑VPS or cluster architectures – without throwing away your containerization work.
Conclusion: Start Simple, Make It Boring, Then Scale
A single VPS running Docker Compose is often exactly what a small SaaS needs: predictable costs, clear boundaries between services and a straightforward operational model. The key is to treat it like a real production environment from day one: put a proper reverse proxy in front, automate SSL, isolate internal services, and design backups you can confidently restore from.
Once these foundations are in place, deployments become routine, SSL renewals happen in the background, backups roll up to off‑site storage automatically, and you can focus on your product instead of firefighting infrastructure issues. When the time comes to scale beyond a single VPS, you can reuse the same Docker images, reverse proxy patterns and backup tooling in multi‑server or clustered setups.
At dchost.com, we design our VPS, dedicated and colocation offerings with exactly these scenarios in mind. If you are planning a new SaaS stack or want to refactor an existing one into Docker Compose on a VPS, you can use this architecture as a starting blueprint and adapt it to your language, framework and growth plans – and our team is here to help you fine‑tune it for your real‑world workloads.
