Managing a small fleet of 6-10 containers across 2-3 hosts represents a "Goldilocks" zone in system administration: too complex for manual ad-hoc commands, but small enough that heavy orchestrators like Kubernetes introduce more problems (overhead, complexity, resource drain) than they solve.
This guide outlines a tiered approach to Docker administration, prioritizing simplicity, data integrity, and a "clean" production environment.
For users who want zero "middleman" overhead and full control over every configuration byte, the combination of SSH and Docker Compose remains the gold standard.
docker run directly. Keep every service in a docker-compose.yml file stored in a private Git repository./opt/stacks/app-name/)..env files sibling to your compose files.You can manage remote hosts without logging in by using the Docker Context feature:
# Register a remote host
docker context create remote-host --docker "host=ssh://user@host-ip"
# Switch to it
docker context use remote-host
# Run commands as if local
docker compose up -d
If you prefer a "Heroku-like" experience where SSL, domain routing, and deployments are handled automatically, several open-source tools have matured to solve this specifically for small networks.
Coolify is arguably the most advanced self-hosted PaaS. It manages your servers, handles Git-push-to-deploy, and automates database backups.
Created by the developer of Uptime Kuma, Dockge provides a beautiful, reactive UI for managing your Compose stacks. Unlike Portainer, it doesn't try to abstract Docker; it just helps you manage the .yaml files.
An older, extremely stable PaaS that uses Docker Swarm under the hood for "one-click" apps and automatic Nginx/SSL setup.
When moving beyond a single host, you must solve for Networking and Storage.
For 2-3 hosts, Docker Swarm is significantly easier than Kubernetes. It is built into Docker and uses an "overlay network" that allows containers on Host A to talk to Host B as if they were local.
docker swarm init on Host A, docker swarm join on Host B/C.Regardless of the tool you choose, these three rules prevent "screwing things up":
Containers are ephemeral; volumes are not.
/var/lib/docker/volumes/ (or your bind mounts) and your .env/docker-compose.yml files daily. Push encrypted copies to an offsite S3 bucket (Backblaze B2 or MinIO).Use Watchtower to keep your images fresh.
:version-tag (e.g., postgres:15) instead of :latest to ensure a minor update doesn't break your database schema unexpectedly.By default, Docker logs can grow indefinitely. Limit them in your /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
| Goal | Recommended Stack |
|---|---|
| Max Control / Zero Bloat | SSH + Git + Docker Contexts |
| Easy Web Management | Dockge + Nginx Proxy Manager |
| Full Private Cloud (GitOps) | Coolify |
| High Stability / Multi-Host | Docker Swarm + CapRover |