A comprehensive on-premises homelab running Docker Swarm on Proxmox VE.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Proxmox VE On-Premises β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Managers: β
β βββββββββββββββββ βββββββββββββββββ βββββββββββββββββ β
β β dkr-srv-1 β β dkr-srv-2 β β dkr-srv-3 β β
β β (Manager) βββββΊβ (Manager) βββββΊβ (Manager) β β
β β 10.0.30.21 β β 10.0.30.22 β β 10.0.30.23 β β
β βββββββββββββββββ βββββββββββββββββ βββββββββββββββββ β
β β
β Workers: β
β βββββββββββββββββ βββββββββββββββββ βββββββββββββββββ β
β β dkr-wrkr-1 β β dkr-wrkr-2 β β dkr-wrkr-3 β β
β β (Worker) β β (Worker) β β (Worker) β β
β β 10.0.30.31 β β 10.0.30.32 β β 10.0.30.33 β β
β βββββββββββββββββ βββββββββββββββββ βββββββββββββββββ β
β β
β Docker Swarm Cluster β
β (3 Managers + 3 Workers) β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Shared Storage β β
β β CephFS (/mnt/cephfs) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Component | Technology |
|---|---|
| Virtualization | Proxmox VE |
| Container Orchestration | Docker Swarm |
| Shared Storage | CephFS |
| Configuration Management | Ansible |
| Infrastructure as Code | Terraform |
| Secrets Management | Doppler |
| Task Runner | Taskfile |
| DNS Management | Cloudflare |
| Reverse Proxy | Traefik |
project-dockerlab/
βββ ansible/ # Configuration management
β βββ group_vars/ # Variable definitions
β βββ inventory/ # Host inventory
β βββ roles/ # Ansible roles
β β βββ fresh_install/ # Base OS config, users, SSH, packages
β β βββ docker_swarm/ # Docker Swarm initialization
β β βββ portainer/ # Portainer deployment
β β βββ geerlingguy.docker/ # External role: Docker installation
β β βββ geerlingguy.pip/ # External role: pip/Python dependencies
β βββ *.yml # Playbooks
βββ terraform_infra/ # Core infrastructure (Proxmox, Hetzner, networks)
βββ terraform_apps/ # App-level IaC (DNS, Portainer stacks)
βββ docker/ # Swarm stacks and app configs
β βββ traefik/ # Traefik reverse proxy stack
β βββ socket-proxy/ # Docker socket proxy stack
β βββ homepage/ # Homepage dashboard stack
β βββ beszel/ # Beszel monitoring stack
β βββ backup/ # Restic backup stack
β βββ cloudflared/ # Cloudflare tunnel stack
β βββ ... # Other stacks
βββ docs/ # Detailed documentation
β βββ ansible.md # Ansible documentation
β βββ terraform.md # Terraform documentation
β βββ doppler.md # Doppler documentation
β βββ taskfile.md # Taskfile documentation
βββ archive/ # Deprecated/backup files
βββ taskfile/ # Task definitions
βββ Taskfile.yml # Main task runner config
- Doppler CLI - Secrets management
- Task - Task runner
- Terraform - Infrastructure provisioning
- Ansible - Configuration management
- SSH access to Proxmox and target nodes
# Login to Doppler
doppler login
# Setup project
doppler setup
# Select: project-dockerlab / dev# Initialize Terraform
task tf:init
# Install Ansible dependencies
task ansible:init# Preview infrastructure changes
task tf:plan
# Apply infrastructure
task tf:apply# Preview configuration changes
task ansible:site:plan
# Apply full configuration
task ansible:site:apply# Deploy app stacks via Terraform (Portainer)
task tfa:apply
# Or deploy individual stacks manually
cd docker/traefik
docker stack deploy -c traefik-stack.yml traefik| Node | IP Address | Role | Purpose |
|---|---|---|---|
| dkr-srv-1 | 10.0.30.21 | Manager | Swarm management, core services |
| dkr-srv-2 | 10.0.30.22 | Manager | Swarm management, core services |
| dkr-srv-3 | 10.0.30.23 | Manager | Swarm management, core services |
| dkr-wrkr-1 | 10.0.30.31 | Worker | Application workloads |
| dkr-wrkr-2 | 10.0.30.32 | Worker | Application workloads |
| dkr-wrkr-3 | 10.0.30.33 | Worker | Application workloads |
- VLAN 30: Docker/Container network (10.0.30.0/24)
- VLAN 40: Proxmox management (10.0.40.0/24)
# List all available tasks
task --list-all
# Terraform
task tf:plan # Preview infrastructure changes
task tf:apply # Apply infrastructure
task tf:destroy # Destroy all infrastructure
# Ansible
task ansible:site:apply # Full site deployment
task ansible:preflight:apply # System updates
task ansible:docker:apply # Docker installation only
task ansible:tailscale:apply # Tailscale setup onlyDetailed documentation for each component:
| Document | Description |
|---|---|
| Ansible | Playbooks, roles, and configuration |
| Terraform | Infrastructure provisioning |
| Doppler | Secrets management |
| Taskfile | Task runner commands |
| Cloudflare Tunnel Setup | Secure remote access without opening external ports |
| Dockpeek Setup | Simple Docker container explorer |
| Glance Setup | Self-hosted dashboard |
| Monitoring Setup | Docker Swarm monitoring solution |
| Traefik Setup | Traefik Ingress Controller |
-
Access Proxmox Community Scripts
-
Run the Script
- Open Proxmox Shell
- Copy and execute the community script
-
Convert to Template
- Right-click VM β "Convert to Template"
- Template ID: 9008 (used in Terraform)
-
Template Naming
- Recommended:
debian13-docker-template
- Recommended:
All secrets are managed through Doppler. See Doppler Documentation for setup details.
Swarm stacks are in the docker/ directory:
A simple Traefik whoami service for testing Swarm deployments:
cd docker/traefik
docker stack deploy -c whoami-stack.yml whoamiSecure remote access without opening external ports. See Cloudflare Tunnel Setup for details.
A simple Docker container explorer. See Dockpeek Setup for details.
A self-hosted dashboard that puts all your feeds in one place. See Glance Setup for details.
A complete monitoring solution for Docker Swarm. See Monitoring Setup for details.
Traefik Ingress Controller. See Traefik Setup for details.
Ghost is a powerful open-source blogging and publishing platform. See Ghost Setup for details.
Automated backup solution using Restic with support for Backblaze B2, AWS S3, or SFTP storage. See Backup Setup for details.
Features:
- Pre-backup database dumps (MySQL, Postgres)
- Incremental, deduplicated, encrypted backups
- Automatic retention (7 daily, 4 weekly, 3 monthly)
- Discord notifications
A minimal, self-hosted wiki with Markdown and Git version control.
Required Doppler Secrets: None (first registered user becomes admin)
A collaborative bookmark manager that preserves webpages. Deployed on worker nodes.
URL: https://links.yourdomain.com
Required Doppler Secrets:
| Secret | Description |
|---|---|
LINKWARDEN_POSTGRES_PASSWORD |
PostgreSQL password for database |
LINKWARDEN_NEXTAUTH_SECRET |
Secret for session encryption (generate with openssl rand -base64 32) |
LINKWARDEN_MEILI_KEY |
Meilisearch master key for search (generate with openssl rand -base64 32) |
Open-source media server. Deployed on worker nodes with access to shared media library.
URL: https://jelly.yourdomain.com
Required Doppler Secrets: None (first user becomes admin)
Media server running on QNAP NAS, routed through Traefik on the primary swarm.
Required Doppler Secrets:
| Secret | Description |
|---|---|
PLEX_CLAIM |
Claim token from https://plex.tv/claim (expires in 4 minutes) |
Metrics and logs collector for Grafana Cloud. Runs globally on all swarm nodes.
Required Doppler Secrets:
| Secret | Description | Where to find |
|---|---|---|
GRAFANA_CLOUD_PROMETHEUS_URL |
Remote write URL (e.g., https://prometheus-prod-xx-xxx.grafana.net/api/prom/push) |
Grafana Cloud β Connections β Hosted Prometheus β Details |
GRAFANA_CLOUD_PROMETHEUS_USERNAME |
Numeric username/ID | Same page as above |
GRAFANA_CLOUD_LOKI_URL |
Loki push URL (e.g., https://logs-prod-xxx.grafana.net/loki/api/v1/push) |
Grafana Cloud β Connections β Hosted Logs β Details |
GRAFANA_CLOUD_LOKI_USERNAME |
Numeric username/ID | Same page as above |
GRAFANA_CLOUD_API_KEY |
API key with MetricsPublisher and LogsPublisher permissions |
Grafana Cloud β Administration β API Keys β Add API Key |
How to get Grafana Cloud credentials:
- Go to grafana.com β Sign in
- Navigate to My Account β Your Grafana Cloud stack
- Click Connections β Hosted Prometheus β Copy the Remote Write URL and Username
- Click Connections β Hosted Logs β Copy the Push URL and Username
- Go to Administration β API Keys β Add API Key
- Name:
alloy-homelab - Role:
MetricsPublisher(create another forLogsPublisheror use Admin)
- Name:
- Add all values to Doppler
| Secret | Purpose |
|---|---|
PROXMOX_AUTH_TOKEN |
Proxmox VE API |
CLOUDFLARE_API_TOKEN |
Cloudflare DNS |
GHOST_DB_PASSWORD |
MySQL password for Ghost database user |
GHOST_DB_ROOT_PASSWORD |
MySQL root password for Ghost database |
GHOST_MAIL_TRANSPORT |
Mail transport (e.g., SMTP) - optional |
GHOST_MAIL_HOST |
SMTP host - optional |
GHOST_MAIL_PORT |
SMTP port - optional |
GHOST_MAIL_USER |
SMTP username - optional |
GHOST_MAIL_PASSWORD |
SMTP password - optional |
GHOST_MAIL_FROM |
From address for emails - optional |
PLEX_CLAIM |
Plex claim token (get from https://plex.tv/claim) |
GRAFANA_CLOUD_PROMETHEUS_URL |
Grafana Cloud Prometheus remote write URL |
GRAFANA_CLOUD_PROMETHEUS_USERNAME |
Grafana Cloud Prometheus username |
GRAFANA_CLOUD_LOKI_URL |
Grafana Cloud Loki push URL |
GRAFANA_CLOUD_LOKI_USERNAME |
Grafana Cloud Loki username |
GRAFANA_CLOUD_API_KEY |
Grafana Cloud API key |
BESZEL_AGENT_KEY |
Beszel agent key (get from Beszel hub UI) |
LINKWARDEN_POSTGRES_PASSWORD |
PostgreSQL password for Linkwarden |
LINKWARDEN_NEXTAUTH_SECRET |
NextAuth session secret for Linkwarden |
LINKWARDEN_MEILI_KEY |
Meilisearch master key for Linkwarden |
graph LR
A[Terraform] -->|Provision VMs| B[Ansible Preflight]
B -->|System Updates| C[Base Config]
C -->|Hostname, Packages| D[Tailscale]
D -->|Mesh Network| E[Docker]
E -->|Install Docker| F[Swarm]
F -->|Form Cluster| G[Deploy Apps]
For those who want to loosely couple the deployment stages without a full CI/CD server, we've added automated pipeline options:
- One-command deployment:
task deployruns the full Terraform β Ansible β Terraform pipeline sequentially - Enhanced scripting:
./scripts/deploy.shprovides detailed logging and error handling - Event-driven options: Webhook receiver for external triggering
See Deployment Pipeline Plan for detailed implementation options and comparisons.
# Test connectivity
ansible -i ansible/inventory/hosts all -m ping# Check Tailscale status on a node
tailscale status
tailscale ip -4# Check swarm status
docker node ls
docker service lsThis project is for personal homelab use.