mirror of
https://github.com/basnijholt/compose-farm.git
synced 2026-02-10 17:12:06 +00:00
386 lines
8.8 KiB
Markdown
386 lines
8.8 KiB
Markdown
---
|
|
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
|
|
```
|