How Docker Changed the Self-Hosting Landscape
How Docker Changed the Self-Hosting Landscape
Before Docker, self-hosting meant dependency hell, configuration nightmares, and "it works on my machine." Docker turned one-week projects into one-minute deploys.
Before and After
Installing Mattermost (2015 vs 2026)
2015 (Manual Installation):
- Install Go runtime
- Install PostgreSQL
- Configure database users and permissions
- Download Mattermost binary
- Create system user
- Configure Mattermost (config.json — 200+ settings)
- Set up Nginx reverse proxy
- Configure SSL certificates (manually with Let's Encrypt)
- Create systemd service
- Configure logrotate
- Set up backup cron jobs
Time: 4-8 hours. Error-prone. Different on every Linux distro.
2026 (Docker):
services:
mattermost:
image: mattermost/mattermost-team-edition:latest
environment:
MM_SQLSETTINGS_DRIVERNAME: postgres
MM_SQLSETTINGS_DATASOURCE: postgres://mm:password@db:5432/mattermost
ports: ["8065:8065"]
db:
image: postgres:16
environment:
POSTGRES_USER: mm
POSTGRES_PASSWORD: password
POSTGRES_DB: mattermost
volumes: ["db_data:/var/lib/postgresql/data"]
volumes:
db_data:
docker compose up -d
Time: 5 minutes. Works identically on any machine.
The 5 Ways Docker Changed Everything
1. Eliminated Dependency Hell
The old problem:
App A needs Python 3.8
App B needs Python 3.11
Both need different versions of libssl
PostgreSQL 14 conflicts with PostGIS on Ubuntu 22.04
Docker's solution: Each app runs in isolation with its own dependencies. No conflicts, ever.
Container A: Python 3.8, libssl 1.1
Container B: Python 3.11, libssl 3.0
Container C: PostgreSQL 16, PostGIS 3.4
They don't see each other. They can't conflict.
2. Made Deploys Reproducible
Before Docker:
- "It works on my machine" was a meme for a reason
- Development, staging, and production environments differed
- Setup instructions were outdated within months
After Docker:
docker compose upworks the same everywhere- The Docker image IS the deployment artifact
- If it works locally, it works on the server
3. Simplified Updates
Before:
# Hope the new version doesn't break your config
sudo apt update && sudo apt upgrade
# Fix broken dependencies
# Manually migrate database schema
# Restart services in the right order
# Roll back if something breaks (good luck)
After:
docker compose pull # Download new images
docker compose up -d # Restart with new versions
# Something broke?
docker compose down
# Change image tag back to previous version
docker compose up -d # Instant rollback
4. Enabled One-Command Tools
Docker images let projects ship ready-to-run software:
| Tool | Docker Command | What You Get |
|---|---|---|
| Uptime Kuma | docker run -p 3001:3001 louislam/uptime-kuma | Full monitoring dashboard |
| Vaultwarden | docker run -p 8080:80 vaultwarden/server | Password manager |
| Plausible | docker compose up (3 containers) | Privacy-first analytics |
| PocketBase | Single binary (no Docker needed!) | Full backend |
5. Created the Self-Hosting Ecosystem
Docker standardized how software is packaged and deployed, which enabled:
- Docker Hub: 100K+ official images, searchable, versionable
- Coolify/Dokku: PaaS tools built on Docker
- Portainer: GUI for managing containers
- Watchtower: Automatic container updates
- Awesome-selfhosted: Community curated list of self-hostable tools
Docker Compose: The Self-Hoster's Best Friend
Docker Compose lets you define multi-container applications in a single file:
Example: Full Monitoring Stack
services:
grafana:
image: grafana/grafana:latest
ports: ["3000:3000"]
volumes: ["grafana_data:/var/lib/grafana"]
prometheus:
image: prom/prometheus:latest
ports: ["9090:9090"]
volumes: ["./prometheus.yml:/etc/prometheus/prometheus.yml"]
node-exporter:
image: prom/node-exporter:latest
pid: host
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
volumes:
grafana_data:
Three services. One file. One command. Full observability stack.
The Docker Compose Pattern
Every self-hosted tool follows the same pattern:
services:
app: # The application
image: company/tool:latest # Official image
environment: # Configuration via env vars
DATABASE_URL: postgres://...
ports: ["8080:8080"] # Exposed port
depends_on: [db] # Start order
db: # Database
image: postgres:16 # Standard database image
volumes: ["data:/var/lib/postgresql/data"] # Persistent storage
volumes:
data: # Named volume for data persistence
Once you understand this pattern, you can deploy anything.
What Docker Didn't Solve
Still Requires Some Knowledge
| Task | Docker Helps? | What You Still Need |
|---|---|---|
| Initial server setup | Partial | SSH, firewall, basic Linux |
| Networking | Partial | DNS, reverse proxy concepts |
| SSL certificates | No | Caddy/Traefik/Nginx config |
| Backups | No | Backup scripts, offsite storage |
| Monitoring | No | Separate monitoring setup |
| Security | Partial | Firewall rules, update policies |
Docker's Overhead
| Concern | Reality |
|---|---|
| RAM usage | Each container adds 10-50 MB overhead |
| Disk usage | Images can be 100-500 MB each |
| Complexity | Docker itself needs updating and monitoring |
| Networking | Docker networking can be confusing |
| Storage | Volume management requires attention |
The Tools Built on Docker
Docker's standardization enabled an ecosystem of management tools:
| Tool | What It Does | Why It Matters |
|---|---|---|
| Coolify | Full PaaS (deploy, monitor, SSL) | Makes Docker invisible |
| Portainer | Docker GUI (manage containers, images, volumes) | Visual management |
| Watchtower | Auto-update containers | Hands-off maintenance |
| Traefik | Reverse proxy + auto-SSL | Dynamic routing for containers |
| Caddy | Reverse proxy + auto-SSL | Simpler config than Traefik |
| Duplicati | Backup Docker volumes | Automated backups |
The Impact on Open Source
Docker changed how open source projects think about distribution:
Before Docker:
- Ship source code
- Write installation guides for 5+ Linux distros
- Users compile from source or use package managers
- "Installation" section of README = 2 pages
After Docker:
- Ship a Docker image
- One installation guide works everywhere
- Users
docker pulland run - "Installation" section = 3 lines
This lowered the barrier for:
- Users — Anyone can run complex software
- Developers — Ship once, works everywhere
- Projects — Focus on features, not installation support
The Bottom Line
Docker didn't just change self-hosting — it made it possible for non-sysadmins. The combination of:
- Docker images → Standardized packaging
- Docker Compose → Declarative multi-service deployments
- Docker Hub → Centralized distribution
- PaaS tools (Coolify) → GUI on top of Docker
...turned self-hosting from a specialized skill into something any developer can do in an afternoon.
Find Docker-ready open source tools at OSSAlt.