Files
compose-farm/examples/README.md
Bas Nijholt 51f74eab42 examples: Add CoreDNS for *.local domain resolution (#155)
* examples: Add CoreDNS for *.local domain resolution

Adds a CoreDNS example that resolves *.local to the Traefik host,
making the .local routes in all examples work out of the box.

Also removes the redundant Multi-Container Stacks section from
README since paperless-ngx already demonstrates this pattern.

* examples: Add coredns .env file
2026-01-07 12:29:53 +01:00

4.6 KiB

Compose Farm Examples

Real-world examples demonstrating compose-farm patterns for multi-host Docker deployments.

Stacks

Stack Type Demonstrates
traefik Infrastructure Reverse proxy, Let's Encrypt, file-provider
coredns Infrastructure Wildcard DNS for *.local domains
mealie Single container Traefik labels, resource limits, environment vars
uptime-kuma Single container Docker socket, user mapping, custom DNS
paperless-ngx Multi-container Redis + PostgreSQL + App stack
autokuma Multi-host Demonstrates all keyword (runs on every host)

Key Patterns

External Network

All stacks connect to a shared external network for inter-service communication:

networks:
  mynetwork:
    external: true

Create it on each host with consistent settings:

compose-farm init-network --network mynetwork --subnet 172.20.0.0/16

Traefik Labels (Dual Routes)

Stacks expose two routes for different access patterns:

  1. HTTPS route (websecure entrypoint): For your custom domain with Let's Encrypt TLS
  2. HTTP route (web entrypoint): For .local domains on your LAN (no TLS needed)

This pattern allows accessing stacks via:

  • https://mealie.example.com - from anywhere, with TLS
  • http://mealie.local - from your local network, no TLS overhead
labels:
  # HTTPS route for custom domain (e.g., mealie.example.com)
  - traefik.enable=true
  - traefik.http.routers.myapp.rule=Host(`myapp.${DOMAIN}`)
  - traefik.http.routers.myapp.entrypoints=websecure
  - traefik.http.services.myapp.loadbalancer.server.port=8080
  # HTTP route for .local domain (e.g., myapp.local)
  - traefik.http.routers.myapp-local.rule=Host(`myapp.local`)
  - traefik.http.routers.myapp-local.entrypoints=web

Note: .local domains require local DNS to resolve to your Traefik host. The coredns example provides this - edit Corefile to set your Traefik IP.

Environment Variables

Each stack has a .env file for secrets and domain configuration. Edit these files to set your domain and credentials:

# Example: set your domain
echo "DOMAIN=example.com" > mealie/.env

Variables like ${DOMAIN} are substituted at runtime by Docker Compose.

NFS Volume Mounts

All data is stored on shared NFS storage at /mnt/data/:

volumes:
  - /mnt/data/myapp:/app/data

This allows stacks to migrate between hosts without data loss.

Multi-Host Stacks

Stacks that need to run on every host (e.g., monitoring agents):

# In compose-farm.yaml
stacks:
  autokuma: all  # Runs on every configured host

AutoKuma Labels (Optional)

The autokuma example demonstrates compose-farm's multi-host feature - running the same stack on all hosts using the all keyword. AutoKuma itself is not part of compose-farm; it's just a good example because it needs to run on every host to monitor local Docker containers.

AutoKuma automatically creates Uptime Kuma monitors from Docker labels:

labels:
  - kuma.myapp.http.name=My App
  - kuma.myapp.http.url=https://myapp.${DOMAIN}

Quick Start

cd examples

# 1. Create the shared network on all hosts
compose-farm init-network

# 2. Start infrastructure (reverse proxy + DNS)
compose-farm up traefik coredns

# 3. Start other stacks
compose-farm up mealie uptime-kuma

# 4. Check status
compose-farm ps

# 5. Generate Traefik file-provider config for cross-host routing
compose-farm traefik-file --all

# 6. View logs
compose-farm logs mealie

# 7. Stop everything
compose-farm down --all

Configuration

The compose-farm.yaml shows a multi-host setup:

  • primary (192.168.1.10): Runs Traefik and heavy stacks
  • secondary (192.168.1.11): Runs lighter stacks
  • autokuma: Runs on ALL hosts to monitor local containers

When Traefik runs on primary and a stack runs on secondary, compose-farm automatically generates file-provider config so Traefik can route to it.

Traefik File-Provider

When stacks run on different hosts than Traefik, use traefik-file to generate routing config:

# Generate config for all stacks
compose-farm traefik-file --all -o traefik/dynamic.d/compose-farm.yml

# Or configure auto-generation in compose-farm.yaml:
traefik_file: /opt/stacks/traefik/dynamic.d/compose-farm.yml
traefik_stack: traefik

With traefik_file configured, compose-farm automatically regenerates the config after up, down, and update commands.