Docker Compose Tutorial: Deploy 10 Services in One File
Master Docker Compose by deploying a complete homelab stack. Learn to configure multiple services, networks, volumes, and environment variables in a single compose file.
Posted by
Related reading
Private Cloud vs Public Cloud: When to Self-Host and When Not To
Understand when self-hosting makes sense and when public cloud is better. A practical guide to choosing between private cloud homelab and AWS/GCP/Azure services.
Homelab Documentation: Wiki.js vs BookStack for Self-Hosted Wikis
Document your homelab setup with self-hosted wikis. Compare Wiki.js and BookStack for creating searchable documentation of your infrastructure and procedures.
Docker Security Scanning: Trivy and Dockle for Safe Containers
Scan your Docker images for vulnerabilities before deploying. Learn to use Trivy and Dockle to secure your self-hosted homelab container infrastructure.

The Power of Docker Compose
Docker Compose transforms complex multi-container deployments into a single YAML file. Instead of running multiple docker commands, you define your entire infrastructure as code and deploy it with one command.
In this tutorial, we'll build a complete homelab stack with 10 services that work together seamlessly.
Complete Homelab Stack
This Docker Compose file includes: Traefik (reverse proxy), Portainer, Nextcloud, Jellyfin, Vaultwarden, Pi-hole, Uptime Kuma, Heimdall, Watchtower, and Wireguard.
version: "3.8"
networks:
homelab:
driver: bridge
services:
# Reverse Proxy
traefik:
image: traefik:latest
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik:/etc/traefik
networks:
- homelab
# Container Management
portainer:
image: portainer/portainer-ce:latest
container_name: portainer
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
networks:
- homelab
# Cloud Storage
nextcloud:
image: nextcloud:latest
container_name: nextcloud
restart: unless-stopped
volumes:
- nextcloud_data:/var/www/html
environment:
- MYSQL_HOST=nextcloud-db
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=${DB_PASSWORD}
networks:
- homelab
# Media Server
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
volumes:
- jellyfin_config:/config
- ./media:/media
networks:
- homelab
# Password Manager
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
volumes:
- vaultwarden_data:/data
environment:
- WEBSOCKET_ENABLED=true
networks:
- homelabEnvironment Variables
Create a .env file for sensitive configuration:
# .env file DB_PASSWORD=your_secure_database_password DOMAIN=homelab.local [email protected] TIMEZONE=America/New_York
Essential Commands
# Start all services docker compose up -d # View logs docker compose logs -f # Stop all services docker compose down # Update all images docker compose pull && docker compose up -d # Restart single service docker compose restart jellyfin
Best Practices
- Always use named volumes for persistent data
- Keep secrets in .env files (never commit them)
- Use a dedicated network for inter-service communication
- Set restart policies for automatic recovery
- Pin image versions in production
