--- icon: lucide/globe --- # Traefik Integration Compose Farm can generate Traefik file-provider configuration for routing traffic across multiple hosts. ## The Problem When you run Traefik on one host but stacks on others, Traefik's docker provider can't see remote containers. The file provider bridges this gap. ``` Internet │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Host: nuc │ │ │ │ ┌─────────┐ │ │ │ Traefik │◄─── Docker provider sees local containers │ │ │ │ │ │ │ │◄─── File provider sees remote stacks │ │ └────┬────┘ (from compose-farm.yml) │ │ │ │ └───────┼─────────────────────────────────────────────────────┘ │ ├────────────────────┐ │ │ ▼ ▼ ┌───────────────┐ ┌───────────────┐ │ Host: hp │ │ Host: nas │ │ │ │ │ │ plex:32400 │ │ jellyfin:8096 │ └───────────────┘ └───────────────┘ ``` ## How It Works 1. Your compose files have standard Traefik labels 2. Compose Farm reads labels and generates file-provider config 3. Traefik watches the generated file 4. Traffic routes to remote stacks via host IP + published port ## Setup ### Step 1: Configure Traefik File Provider Add directory watching to your Traefik config: ```yaml # traefik.yml or docker-compose.yml command providers: file: directory: /opt/traefik/dynamic.d watch: true ``` Or via command line: ```yaml services: traefik: command: - --providers.file.directory=/dynamic.d - --providers.file.watch=true volumes: - /opt/traefik/dynamic.d:/dynamic.d:ro ``` ### Step 2: Add Traefik Labels to Services Your compose files use standard Traefik labels: ```yaml # /opt/compose/plex/docker-compose.yml services: plex: image: lscr.io/linuxserver/plex ports: - "32400:32400" # IMPORTANT: Must publish port! labels: - traefik.enable=true - traefik.http.routers.plex.rule=Host(`plex.example.com`) - traefik.http.routers.plex.entrypoints=websecure - traefik.http.routers.plex.tls.certresolver=letsencrypt - traefik.http.services.plex.loadbalancer.server.port=32400 ``` **Important:** Services must publish ports for cross-host routing. Traefik connects via `host_ip:published_port`. ### Step 3: Generate File Provider Config ```bash cf traefik-file --all -o /opt/traefik/dynamic.d/compose-farm.yml ``` This generates: ```yaml # /opt/traefik/dynamic.d/compose-farm.yml http: routers: plex: rule: Host(`plex.example.com`) entryPoints: - websecure tls: certResolver: letsencrypt service: plex services: plex: loadBalancer: servers: - url: http://192.168.1.11:32400 ``` ## Auto-Regeneration Configure automatic regeneration in `compose-farm.yaml`: ```yaml compose_dir: /opt/compose traefik_file: /opt/traefik/dynamic.d/compose-farm.yml traefik_stack: traefik hosts: nuc: address: 192.168.1.10 hp: address: 192.168.1.11 stacks: traefik: nuc # Traefik runs here plex: hp # Routed via file-provider grafana: hp ``` With `traefik_file` set, these commands auto-regenerate the config: - `cf up` - `cf down` - `cf restart` - `cf update` - `cf apply` ### traefik_stack Option When set, stacks on the **same host as Traefik** are skipped in file-provider output. Traefik's docker provider handles them directly. ```yaml traefik_stack: traefik # traefik runs on nuc stacks: traefik: nuc # NOT in file-provider (docker provider) portainer: nuc # NOT in file-provider (docker provider) plex: hp # IN file-provider (cross-host) ``` ## Label Syntax ### Routers ```yaml labels: # Basic router - traefik.http.routers.myapp.rule=Host(`app.example.com`) - traefik.http.routers.myapp.entrypoints=websecure # With TLS - traefik.http.routers.myapp.tls=true - traefik.http.routers.myapp.tls.certresolver=letsencrypt # With middleware - traefik.http.routers.myapp.middlewares=auth@file ``` ### Services ```yaml labels: # Load balancer port - traefik.http.services.myapp.loadbalancer.server.port=8080 # Health check - traefik.http.services.myapp.loadbalancer.healthcheck.path=/health ``` ### Middlewares Middlewares should be defined in a separate file (not generated by Compose Farm): ```yaml # /opt/traefik/dynamic.d/middlewares.yml http: middlewares: auth: basicAuth: users: - "user:$apr1$..." ``` Reference in labels: ```yaml labels: - traefik.http.routers.myapp.middlewares=auth@file ``` ## Variable Substitution Labels can use environment variables: ```yaml labels: - traefik.http.routers.myapp.rule=Host(`${DOMAIN}`) ``` Compose Farm resolves variables from: 1. Stack's `.env` file 2. Current environment ```bash # /opt/compose/myapp/.env DOMAIN=app.example.com ``` ## Port Resolution Compose Farm determines the target URL from published ports: ```yaml ports: - "8080:80" # Uses 8080 - "192.168.1.11:8080:80" # Uses 8080 on specific IP ``` If no suitable port is found, a warning is shown. ## Complete Example ### compose-farm.yaml ```yaml compose_dir: /opt/compose traefik_file: /opt/traefik/dynamic.d/compose-farm.yml traefik_stack: traefik hosts: nuc: address: 192.168.1.10 hp: address: 192.168.1.11 nas: address: 192.168.1.100 stacks: traefik: nuc plex: hp jellyfin: nas grafana: nuc nextcloud: nuc ``` ### /opt/compose/plex/docker-compose.yml ```yaml services: plex: image: lscr.io/linuxserver/plex container_name: plex ports: - "32400:32400" labels: - traefik.enable=true - traefik.http.routers.plex.rule=Host(`plex.example.com`) - traefik.http.routers.plex.entrypoints=websecure - traefik.http.routers.plex.tls.certresolver=letsencrypt - traefik.http.services.plex.loadbalancer.server.port=32400 # ... other config ``` ### Generated compose-farm.yml ```yaml http: routers: plex: rule: Host(`plex.example.com`) entryPoints: - websecure tls: certResolver: letsencrypt service: plex jellyfin: rule: Host(`jellyfin.example.com`) entryPoints: - websecure tls: certResolver: letsencrypt service: jellyfin services: plex: loadBalancer: servers: - url: http://192.168.1.11:32400 jellyfin: loadBalancer: servers: - url: http://192.168.1.100:8096 ``` Note: `grafana` and `nextcloud` are NOT in the file because they're on the same host as Traefik (`nuc`). ## Combining with Existing Config If you have existing Traefik dynamic config: ```bash # Move existing config to directory mkdir -p /opt/traefik/dynamic.d mv /opt/traefik/dynamic.yml /opt/traefik/dynamic.d/manual.yml # Generate Compose Farm config cf traefik-file --all -o /opt/traefik/dynamic.d/compose-farm.yml # Update Traefik to watch directory # --providers.file.directory=/dynamic.d ``` Traefik merges all YAML files in the directory. ## Troubleshooting ### Stack Not Accessible 1. **Check port is published:** ```yaml ports: - "8080:80" # Must be published, not just exposed ``` 2. **Check label syntax:** ```bash cf check mystack ``` 3. **Verify generated config:** ```bash cf traefik-file mystack ``` 4. **Check Traefik logs:** ```bash docker logs traefik ``` ### Config Not Regenerating 1. **Verify traefik_file is set:** ```bash cf config show | grep traefik ``` 2. **Check file permissions:** ```bash ls -la /opt/traefik/dynamic.d/ ``` 3. **Manually regenerate:** ```bash cf traefik-file --all -o /opt/traefik/dynamic.d/compose-farm.yml ``` ### Variable Not Resolved 1. **Check .env file exists:** ```bash cat /opt/compose/myservice/.env ``` 2. **Test variable resolution:** ```bash cd /opt/compose/myservice docker compose config ```