Bot 42d31e38e4
ci/woodpecker/push/deploy Pipeline was successful
ci/woodpecker/cron/renovate Pipeline was successful
git stack: switch provision-secrets to Pattern B .env rewrite (test phase) + add git to bootstrap-tier guard
Context: git hosts the source of truth for every other stack's compose
files, so in a disaster-recovery scenario it must be restorable from a
flat git.yaml + git.env backup alone, with zero dependency on a running
Swarm's Docker secret store (native Docker secrets can't be resolved
until Swarm already exists, which is the circular dependency git.yaml
would otherwise create). Path 2 (documented decision): Pattern B for
git specifically, same mechanism the ai stack already uses.

provision-secrets / git) case:
  - Previously created native Docker secrets (git_db_password,
    git_runner_token, git_mcp_access_token) via create-secrets.sh —
    leftover from an earlier, abandoned Pattern C attempt.
  - Now rewrites only the secret-bearing lines (GITEA__database__PASSWD,
    GITEA_RUNNER_REGISTRATION_TOKEN, GITEA_MCP_ACCESS_TOKEN) via
    grep -v + printf, mirroring the ai) case exactly. Also strips the
    legacy GITEA_ACCESS_TOKEN key name so the test file converges on the
    git.env.example-documented key.
  - TEST PHASE: target is git.env.pipelinetest, NOT git.env. The real
    git.env is never opened for writing by this step. First run seeds
    the test file from the real git.env (to carry over all non-secret
    lines), then only the 3 secret lines are refreshed on every push.
  - Real cutover (pointing git.yaml/stack-deploy at the generated file,
    then retiring git.env.pipelinetest) is a deliberate follow-up step
    after manually diffing the rendered output.

deploy / bootstrap-tier guard:
  - Added git to the traefik|woodpecker|postgresql|secrets guard list.
    git.yaml changes now sync to the host but require a manual
    `stack-deploy.sh git` run, same as the other foundational stacks —
    prevents an auto-deploy of a bad git.yaml change from taking down
    Gitea before a human can look at it (Gitea itself is what every
    other pipeline needs to trigger a fix).
2026-09-02 00:02:36 -07:00
2026-08-26 21:36:48 -07:00
2026-07-18 22:05:01 -07:00
2026-07-05 21:42:27 -07:00

Homelab Infrastructure Repository - Docker Swarm Compose Files

This Gitea repository contains Docker Swarm compose files for all services running in the homelab.

For operational scripts (backup hooks, prune watchdog, network configuration), see the separate homelab-scripts repository.


📁 Directory Structure

├── traefik.yaml               # Reverse proxy & load balancer
├── auth.yaml                  # Authentik authentication
├── postgresql.yaml            # PostgreSQL database
├── maintenance.yaml           # Cronicle scheduler, Uptime Kuma
├── ... (other service stacks)
└── README.md                  # This file

🚀 Quick Start

Deploy a Stack

# SSH into a Docker LXC (docker-1, docker-2, or docker-3)
ssh root@docker-1

# Clone this repo locally
cd /volume1/docker
git clone https://git.bryanmail.net/admin/compose-files.git repo
cd repo

# Deploy a stack
docker stack deploy -c traefik.yaml traefik
docker stack deploy -c auth.yaml auth
docker stack deploy -c postgresql.yaml postgresql

Update a Stack

# Pull latest changes
git pull origin main

# Re-deploy (applies changes)
docker stack deploy -c traefik.yaml traefik

# View status
docker stack ps traefik
docker service ls

Remove a Stack

docker stack rm traefik

📋 Available Stacks

Stack File Purpose
Traefik traefik.yaml Reverse proxy, load balancer, TLS termination
Authentik auth.yaml Authentication & authorization
PostgreSQL postgresql.yaml Database backend
Maintenance maintenance.yaml Cronicle jobs, Uptime Kuma monitoring
... ... (Add more as you create them)

🛠️ Common Tasks

Deploy a New Service

  1. Create compose file in this repo: myservice.yaml
  2. Test locally (on single host):
    docker-compose -f myservice.yaml up -d
    
  3. Convert to Swarm format (remove container_name, use services: for Swarm)
  4. Deploy to Swarm:
    docker stack deploy -c myservice.yaml myservice
    
  5. Commit & push:
    git add myservice.yaml
    git commit -m "Add myservice stack"
    git push origin main
    

Check Service Status

# List all services
docker service ls

# Get details about a service
docker service inspect traefik_reverse-proxy

# View service logs
docker service logs -f traefik_reverse-proxy

# Check tasks (containers)
docker service ps traefik_reverse-proxy

Monitor Disk Space

df -h /volume1/docker-root

# Docker prune watchdog handles auto-cleanup (see homelab-scripts repo)

🔐 Secrets Management

DO NOT commit secrets, passwords, or API keys to this repo.

Use one of these approaches:

services:
  myapp:
    secrets:
      - db_password

secrets:
  db_password:
    external: true

Create the secret:

echo "mysecretpassword" | docker secret create db_password -

Option 2: Environment Files (Not tracked by git)

# Create .env (add to .gitignore)
echo "DB_PASSWORD=mysecretpassword" > .env

# Use in compose
env_file: .env

📚 Architecture

Swarm Cluster

nuck7-1 (Hypervisor)        nuck7-2 (Hypervisor)        nuck7-3 (Hypervisor)
├─ docker-1 (LXC 4031)      ├─ docker-2 (LXC 4032)      ├─ docker-3 (LXC 4033)
│  └─ Swarm Manager         │  └─ Swarm Leader          │  └─ Swarm Manager
└─ ...                      └─ ...                      └─ ...

Storage

  • CephFS mounted at /volume1/docker/ (shared across all nodes)
  • Compose files: /volume1/docker/compose-files/
  • Service data: Named volumes or /volume1/docker/ mounts

Networking

  • VIP: 192.168.4.30 (Keepalived)
  • Docker hosts: 192.168.4.31-33
  • Traefik: Reverse proxy with Let's Encrypt TLS
  • Domain: bryanmail.net

  • homelab-scripts - Operational scripts (backup hooks, monitoring, network config)
  • Proxmox MCP Setup - Documented in notes
  • Architecture Decision Records (ADRs) - Documented in notes

🐛 Troubleshooting

Stack won't deploy

# Check syntax
docker-compose config -f myservice.yaml

# Check node availability
docker node ls

# Check disk space
df -h /volume1/docker-root

Service keeps crashing

# View logs
docker service logs -f myservice_name

# Inspect container
docker ps -a | grep myservice

Network issues

# List networks
docker network ls --filter driver=overlay

# Test connectivity
docker run --rm --network traefik_backend alpine ping traefik_reverse-proxy

📞 Contributing

When adding new services:

  1. Use Swarm-compatible YAML (no container_name)
  2. Document requirements in compose file comments
  3. Test on non-production first
  4. Add notes about volumes, secrets, networking
  5. Update this README with stack description

📝 Git Workflow

# Before starting work
git pull origin main

# Create feature branch for new service
git checkout -b feature/new-service

# Make changes and commit
git add .
git commit -m "Add new-service stack"

# Push
git push origin feature/new-service

Version Control Best Practices

  • Keep compose files in sync with deployed state
  • Pin image versions (avoid latest tag)
  • Document breaking changes in commit messages
  • Use meaningful commit messages for audit trail
S
Description
Docker Swarm compose files for homelab services
Readme
877 KiB
Languages
Shell 77.6%
Python 22.4%