Files
stack/docs/1-getting-started/4-docker-deployment/traefik.md
Jason Woltje 12abdfe81d feat(#93): implement agent spawn via federation
Implements FED-010: Agent Spawn via Federation feature that enables
spawning and managing Claude agents on remote federated Mosaic Stack
instances via COMMAND message type.

Features:
- Federation agent command types (spawn, status, kill)
- FederationAgentService for handling agent operations
- Integration with orchestrator's agent spawner/lifecycle services
- API endpoints for spawning, querying status, and killing agents
- Full command routing through federation COMMAND infrastructure
- Comprehensive test coverage (12/12 tests passing)

Architecture:
- Hub → Spoke: Spawn agents on remote instances
- Command flow: FederationController → FederationAgentService →
  CommandService → Remote Orchestrator
- Response handling: Remote orchestrator returns agent status/results
- Security: Connection validation, signature verification

Files created:
- apps/api/src/federation/types/federation-agent.types.ts
- apps/api/src/federation/federation-agent.service.ts
- apps/api/src/federation/federation-agent.service.spec.ts

Files modified:
- apps/api/src/federation/command.service.ts (agent command routing)
- apps/api/src/federation/federation.controller.ts (agent endpoints)
- apps/api/src/federation/federation.module.ts (service registration)
- apps/orchestrator/src/api/agents/agents.controller.ts (status endpoint)
- apps/orchestrator/src/api/agents/agents.module.ts (lifecycle integration)

Testing:
- 12/12 tests passing for FederationAgentService
- All command service tests passing
- TypeScript compilation successful
- Linting passed

Refs #93

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-03 14:37:06 -06:00

13 KiB

Traefik Reverse Proxy Integration

Mosaic Stack supports flexible Traefik integration with three deployment modes:

  1. Bundled Mode: Self-contained Traefik instance
  2. Upstream Mode: Connect to external Traefik
  3. None Mode: Direct port exposure (no reverse proxy)

Quick Start

# 1. Copy bundled configuration
cp .env.traefik-bundled.example .env

# 2. Update passwords and secrets in .env
# Edit POSTGRES_PASSWORD, AUTHENTIK_SECRET_KEY, JWT_SECRET, etc.

# 3. Start with bundled Traefik profile
docker compose --profile traefik-bundled up -d

# 4. Access services
# - Web: https://mosaic.local
# - API: https://api.mosaic.local
# - Auth: https://auth.mosaic.local
# - Traefik Dashboard: http://localhost:8080

Upstream Mode (For Existing Traefik Instances)

# 1. Ensure external Traefik network exists
docker network create traefik-public

# 2. Copy upstream configuration
cp .env.traefik-upstream.example .env

# 3. Update .env with your domains and secrets

# 4. Create override file for network attachment
cp docker-compose.override.yml.example docker-compose.override.yml

# 5. Edit docker-compose.override.yml and uncomment upstream network section

# 6. Start services
docker compose up -d

None Mode (Direct Port Access)

# 1. Use default .env.example
cp .env.example .env

# 2. Ensure TRAEFIK_MODE=none (default)

# 3. Start services
docker compose up -d

# 4. Access services on standard ports
# - Web: http://localhost:3000
# - API: http://localhost:3001
# - Auth: http://localhost:9000

Configuration Reference

Environment Variables

Variable Default Description
TRAEFIK_MODE none Traefik mode: bundled, upstream, or none
TRAEFIK_ENABLE false Enable Traefik labels on services
MOSAIC_API_DOMAIN api.mosaic.local Domain for API service
MOSAIC_WEB_DOMAIN mosaic.local Domain for Web service
MOSAIC_AUTH_DOMAIN auth.mosaic.local Domain for Authentik service
TRAEFIK_NETWORK traefik-public External Traefik network (upstream mode)
TRAEFIK_TLS_ENABLED true Enable TLS/HTTPS
TRAEFIK_ACME_EMAIL - Email for Let's Encrypt (production)
TRAEFIK_CERTRESOLVER - Cert resolver name (e.g., letsencrypt)
TRAEFIK_DASHBOARD_ENABLED true Enable Traefik dashboard (bundled mode)
TRAEFIK_DASHBOARD_PORT 8080 Dashboard port (bundled mode)
TRAEFIK_ENTRYPOINT websecure Traefik entrypoint (web or websecure)
TRAEFIK_DOCKER_NETWORK mosaic-public Docker network for Traefik routing

Docker Compose Profiles

Profile Description
traefik-bundled Activates bundled Traefik service
authentik Enables Authentik SSO services
ollama Enables Ollama AI service
full Enables all optional services

Deployment Scenarios

Local Development with Self-Signed Certificates

# .env configuration
TRAEFIK_MODE=bundled
TRAEFIK_ENABLE=true
TRAEFIK_TLS_ENABLED=true
TRAEFIK_ACME_EMAIL=  # Empty for self-signed
MOSAIC_API_DOMAIN=api.mosaic.local
MOSAIC_WEB_DOMAIN=mosaic.local
MOSAIC_AUTH_DOMAIN=auth.mosaic.local

# Start services
docker compose --profile traefik-bundled up -d

# Add to /etc/hosts
echo "127.0.0.1 mosaic.local api.mosaic.local auth.mosaic.local" | sudo tee -a /etc/hosts

Browser will show certificate warnings (expected for self-signed certs).

Production with Let's Encrypt

# .env configuration
TRAEFIK_MODE=bundled
TRAEFIK_ENABLE=true
TRAEFIK_TLS_ENABLED=true
TRAEFIK_ACME_EMAIL=admin@example.com
TRAEFIK_CERTRESOLVER=letsencrypt
MOSAIC_API_DOMAIN=api.example.com
MOSAIC_WEB_DOMAIN=example.com
MOSAIC_AUTH_DOMAIN=auth.example.com

Prerequisites:

  1. DNS records pointing to your server
  2. Ports 80 and 443 accessible from internet
  3. Uncomment ACME configuration in docker/traefik/traefik.yml
# docker/traefik/traefik.yml
certificatesResolvers:
  letsencrypt:
    acme:
      email: "${TRAEFIK_ACME_EMAIL}"
      storage: "/letsencrypt/acme.json"
      httpChallenge:
        entryPoint: web

Connecting to Existing Traefik (web1.corp.uscllc.local)

For the shared development environment at ~/src/traefik:

# 1. Verify external Traefik is running
docker ps | grep traefik

# 2. Verify external network exists
docker network ls | grep traefik-public

# 3. Configure .env
TRAEFIK_MODE=upstream
TRAEFIK_ENABLE=true
TRAEFIK_NETWORK=traefik-public
TRAEFIK_DOCKER_NETWORK=traefik-public
MOSAIC_API_DOMAIN=mosaic-api.uscllc.com
MOSAIC_WEB_DOMAIN=mosaic.uscllc.com
MOSAIC_AUTH_DOMAIN=mosaic-auth.uscllc.com

# 4. Create docker-compose.override.yml
cp docker-compose.override.yml.example docker-compose.override.yml

# 5. Edit docker-compose.override.yml - uncomment network section
# networks:
#   traefik-public:
#     external: true
#     name: traefik-public

# 6. Add services to external network
# api:
#   networks:
#     - traefik-public
# web:
#   networks:
#     - traefik-public
# authentik-server:
#   networks:
#     - traefik-public

# 7. Start services
docker compose up -d

Services will be auto-discovered by the external Traefik instance.

Advanced Configuration

Custom Middleware

Add authentication or rate limiting via Traefik middleware:

# docker-compose.override.yml
services:
  traefik:
    labels:
      # Define basic auth middleware
      - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xyz..."
      # Define rate limit middleware
      - "traefik.http.middlewares.ratelimit.ratelimit.average=100"
      - "traefik.http.middlewares.ratelimit.ratelimit.burst=50"

  api:
    labels:
      # Apply middleware to API router
      - "traefik.http.routers.mosaic-api.middlewares=auth@docker,ratelimit@docker"

Generate basic auth password:

echo $(htpasswd -nb admin your-password) | sed -e s/\\$/\\$\\$/g

Custom TLS Certificates

To use custom certificates instead of Let's Encrypt:

# docker/traefik/dynamic/tls.yml
tls:
  certificates:
    - certFile: /certs/domain.crt
      keyFile: /certs/domain.key

Mount certificate directory:

# docker-compose.override.yml
services:
  traefik:
    volumes:
      - ./certs:/certs:ro

Multiple Domains

Route multiple domains to different services:

# .env
MOSAIC_WEB_DOMAIN=mosaic.local,app.mosaic.local,www.mosaic.local
# Traefik will match all domains

Or use override for complex routing:

# docker-compose.override.yml
services:
  web:
    labels:
      - "traefik.http.routers.mosaic-web.rule=Host(`mosaic.local`) || Host(`app.mosaic.local`)"
      - "traefik.http.routers.mosaic-web-www.rule=Host(`www.mosaic.local`)"
      - "traefik.http.routers.mosaic-web-www.middlewares=redirect-www"
      - "traefik.http.middlewares.redirect-www.redirectregex.regex=^https://www.mosaic.local/(.*)"
      - "traefik.http.middlewares.redirect-www.redirectregex.replacement=https://mosaic.local/$${1}"

Troubleshooting

Services Not Accessible via Domain

Check Traefik is running:

docker ps | grep traefik

Check Traefik dashboard:

# Bundled mode
open http://localhost:8080

# Check registered routers
curl http://localhost:8080/api/http/routers | jq

Verify labels are applied:

docker inspect mosaic-api | jq '.Config.Labels'

Check DNS/hosts file:

# Local development
cat /etc/hosts | grep mosaic

Certificate Errors

Self-signed certificates (development):

  • Browser warnings are expected
  • Add exception in browser or import CA certificate

Let's Encrypt failures:

# Check Traefik logs
docker logs mosaic-traefik

# Verify ACME email is set
docker exec mosaic-traefik cat /etc/traefik/traefik.yml

# Check certificate storage
docker exec mosaic-traefik ls -la /letsencrypt/

Upstream Mode Not Connecting

Verify external network exists:

docker network ls | grep traefik-public

Create network if missing:

docker network create traefik-public

Check service network attachment:

docker inspect mosaic-api | jq '.NetworkSettings.Networks'

Verify external Traefik can see services:

# From external Traefik container
docker exec <external-traefik-container> traefik healthcheck

Port Conflicts

Bundled mode port conflicts:

# Check what's using ports
sudo lsof -i :80
sudo lsof -i :443
sudo lsof -i :8080

# Change ports in .env
TRAEFIK_HTTP_PORT=8000
TRAEFIK_HTTPS_PORT=8443
TRAEFIK_DASHBOARD_PORT=8081

Dashboard Not Accessible

Check dashboard is enabled:

# In .env
TRAEFIK_DASHBOARD_ENABLED=true

Verify Traefik configuration:

docker exec mosaic-traefik cat /etc/traefik/traefik.yml | grep -A5 "api:"

Access dashboard:

# Default
http://localhost:8080/dashboard/

# Custom port
http://localhost:${TRAEFIK_DASHBOARD_PORT}/dashboard/

Security Considerations

Production Checklist

  • Use Let's Encrypt or valid SSL certificates
  • Disable Traefik dashboard or protect with authentication
  • Enable HTTP to HTTPS redirect
  • Configure rate limiting middleware
  • Use strong passwords for all services
  • Restrict Traefik dashboard to internal network
  • Enable Traefik access logs for audit trail
  • Regularly update Traefik image version

Securing the Dashboard

Option 1: Disable in production

TRAEFIK_DASHBOARD_ENABLED=false

Option 2: Add basic authentication

# docker-compose.override.yml
services:
  traefik:
    command:
      - "--configFile=/etc/traefik/traefik.yml"
      - "--api.dashboard=true"
    labels:
      - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.middlewares=auth"
      - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xyz..."

Option 3: IP whitelist

# docker-compose.override.yml
services:
  traefik:
    labels:
      - "traefik.http.middlewares.ipwhitelist.ipwhitelist.sourcerange=127.0.0.1/32,10.0.0.0/8"
      - "traefik.http.routers.dashboard.middlewares=ipwhitelist"

Performance Tuning

Connection Limits

# docker/traefik/traefik.yml
entryPoints:
  web:
    address: ":80"
    transport:
      respondingTimeouts:
        readTimeout: 60
        writeTimeout: 60
        idleTimeout: 180
  websecure:
    address: ":443"
    transport:
      respondingTimeouts:
        readTimeout: 60
        writeTimeout: 60
        idleTimeout: 180

Rate Limiting

# docker-compose.override.yml
services:
  traefik:
    labels:
      - "traefik.http.middlewares.ratelimit.ratelimit.average=100"
      - "traefik.http.middlewares.ratelimit.ratelimit.burst=200"
      - "traefik.http.middlewares.ratelimit.ratelimit.period=1s"

Testing

Integration tests are available to verify Traefik configuration:

# Run all Traefik tests
./tests/integration/docker/traefik.test.sh all

# Test specific mode
./tests/integration/docker/traefik.test.sh bundled
./tests/integration/docker/traefik.test.sh upstream
./tests/integration/docker/traefik.test.sh none

See tests/integration/docker/README.md for details.

Migration Guide

From None Mode to Bundled Mode

# 1. Stop existing services
docker compose down

# 2. Backup current .env
cp .env .env.backup

# 3. Switch to bundled configuration
cp .env.traefik-bundled.example .env

# 4. Transfer existing secrets from .env.backup to .env

# 5. Start with Traefik profile
docker compose --profile traefik-bundled up -d

# 6. Update application URLs if needed
# Old: http://localhost:3000
# New: https://mosaic.local

From Bundled Mode to Upstream Mode

# 1. Ensure external Traefik is running
docker network create traefik-public

# 2. Update .env
TRAEFIK_MODE=upstream
TRAEFIK_NETWORK=traefik-public

# 3. Create override file
cp docker-compose.override.yml.example docker-compose.override.yml

# 4. Edit override file to uncomment network section

# 5. Restart without bundled profile
docker compose down
docker compose up -d

Additional Resources