> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/TecharoHq/Anubis/llms.txt
> Use this file to discover all available pages before exploring further.

# Traefik Deployment

> Deploy Anubis behind Traefik reverse proxy

Traefik is a modern HTTP reverse proxy with automatic service discovery. This guide shows how to deploy Anubis with Traefik using Docker labels or Kubernetes.

## Deployment Architecture

Traefik uses Anubis as a ForwardAuth middleware:

```mermaid theme={null}
flowchart LR
    user[User]
    traefik[Traefik]
    anubis[Anubis]
    target[Backend]
    
    user -->|:443 HTTPS| traefik
    traefik -.->|:8080 auth check| anubis
    anubis -.->|200/redirect| traefik
    traefik -->|:80 validated| target
```

## Docker Compose Configuration

Here's a complete working example with Traefik v3.3:

**compose.yml:**

```yaml theme={null}
services:
  traefik:
    image: traefik:v3.3
    ports:
      - 80:80
      - 443:443
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./letsencrypt:/letsencrypt
      - ./traefik.yml:/traefik.yml:ro
    networks:
      - traefik
    labels:
      - traefik.enable=true
      - traefik.docker.network=traefik
      
      # Define Anubis ForwardAuth middleware
      - traefik.http.middlewares.anubis.forwardauth.address=http://anubis:8080/.within.website/x/cmd/anubis/api/check
      
      # Redirect HTTP to HTTPS
      - traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
      - traefik.http.routers.web.rule=PathPrefix(`/`)
      - traefik.http.routers.web.entrypoints=web
      - traefik.http.routers.web.middlewares=redirect-to-https
      - traefik.http.routers.web.tls=false

  anubis:
    image: ghcr.io/techarohq/anubis:main
    environment:
      # Listen for Traefik
      BIND: ":8080"
      # Empty target - Anubis only validates, doesn't proxy
      TARGET: " "
      # Allowed redirect domains
      REDIRECT_DOMAINS: "example.com,anubis.example.com"
      # Public URL for Anubis
      PUBLIC_URL: "https://anubis.example.com"
      # Cookie domain
      COOKIE_DOMAIN: "example.com"
    networks:
      - traefik
    labels:
      - traefik.enable=true
      - traefik.docker.network=traefik
      - traefik.http.routers.anubis.rule=Host(`anubis.example.com`)
      - traefik.http.routers.anubis.entrypoints=websecure
      - traefik.http.services.anubis.loadbalancer.server.port=8080
      - traefik.http.routers.anubis.service=anubis
      - traefik.http.routers.anubis.tls.certresolver=le

  # Protected by Anubis
  target:
    image: traefik/whoami:latest
    networks:
      - traefik
    labels:
      - traefik.enable=true
      - traefik.docker.network=traefik
      - traefik.http.routers.target.rule=Host(`example.com`)
      - traefik.http.routers.target.entrypoints=websecure
      - traefik.http.services.target.loadbalancer.server.port=80
      - traefik.http.routers.target.service=target
      - traefik.http.routers.target.tls.certresolver=le
      # Use Anubis middleware
      - traefik.http.routers.target.middlewares=anubis@docker

  # Not protected by Anubis
  target2:
    image: traefik/whoami:latest
    networks:
      - traefik
    labels:
      - traefik.enable=true
      - traefik.docker.network=traefik
      - traefik.http.routers.target2.rule=Host(`another.example.com`)
      - traefik.http.routers.target2.entrypoints=websecure
      - traefik.http.services.target2.loadbalancer.server.port=80
      - traefik.http.routers.target2.service=target2
      - traefik.http.routers.target2.tls.certresolver=le
      # No middleware - not protected

networks:
  traefik:
    name: traefik
```

**traefik.yml:**

```yaml theme={null}
api:
  insecure: false  # Don't enable in production

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"

certificatesResolvers:
  le:
    acme:
      tlsChallenge: {}
      email: "admin@example.com"
      storage: "/letsencrypt/acme.json"

providers:
  docker: {}
```

## How It Works

1. **User requests `https://example.com`**
2. **Traefik checks middleware** - ForwardAuth sends request to `http://anubis:8080/.within.website/x/cmd/anubis/api/check`
3. **Anubis validates**:
   * If validated: Returns 200, Traefik forwards to backend
   * If not validated: Returns 401 with redirect to challenge page
4. **User completes challenge** at `https://anubis.example.com`
5. **Anubis redirects back** to `https://example.com`
6. **Request succeeds** - cookie is set, future requests pass validation

## ForwardAuth Middleware

The key configuration is the ForwardAuth middleware:

```yaml theme={null}
traefik.http.middlewares.anubis.forwardauth.address=http://anubis:8080/.within.website/x/cmd/anubis/api/check
```

This tells Traefik to send an auth check to Anubis before forwarding to the backend.

### Additional ForwardAuth Options

```yaml theme={null}
labels:
  # Basic ForwardAuth
  - traefik.http.middlewares.anubis.forwardauth.address=http://anubis:8080/.within.website/x/cmd/anubis/api/check
  
  # Trust forwarded headers
  - traefik.http.middlewares.anubis.forwardauth.trustForwardHeader=true
  
  # Forward auth headers to backend
  - traefik.http.middlewares.anubis.forwardauth.authResponseHeaders=X-Anubis-Verified,X-Real-IP
```

## Multiple Protected Services

Protect different services with the same Anubis instance:

```yaml theme={null}
services:
  app1:
    image: app1:latest
    labels:
      - traefik.http.routers.app1.rule=Host(`app1.example.com`)
      - traefik.http.routers.app1.middlewares=anubis@docker
      - traefik.http.routers.app1.tls.certresolver=le

  app2:
    image: app2:latest
    labels:
      - traefik.http.routers.app2.rule=Host(`app2.example.com`)
      - traefik.http.routers.app2.middlewares=anubis@docker
      - traefik.http.routers.app2.tls.certresolver=le
```

Update Anubis environment:

```yaml theme={null}
anubis:
  environment:
    REDIRECT_DOMAINS: "app1.example.com,app2.example.com,anubis.example.com"
    COOKIE_DOMAIN: "example.com"
```

## Path-Based Protection

Protect only specific paths:

```yaml theme={null}
labels:
  # Protect /admin paths only
  - traefik.http.routers.app-admin.rule=Host(`example.com`) && PathPrefix(`/admin`)
  - traefik.http.routers.app-admin.middlewares=anubis@docker
  
  # Public paths (no middleware)
  - traefik.http.routers.app-public.rule=Host(`example.com`) && PathPrefix(`/`)
  - traefik.http.routers.app-public.priority=1
```

Note: Higher priority rules are evaluated first.

## Kubernetes Deployment

For Kubernetes with Traefik ingress controller, see the [Kubernetes deployment guide](./kubernetes).

Quick example using Ingress:

```yaml theme={null}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: protected-app
  annotations:
    traefik.ingress.kubernetes.io/router.middlewares: default-anubis@kubernetescrd
spec:
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app
                port:
                  number: 80
```

## Custom Middleware Chain

Combine Anubis with other Traefik middlewares:

```yaml theme={null}
labels:
  # Define middleware chain
  - traefik.http.middlewares.secure-chain.chain.middlewares=rate-limit,anubis,compression
  
  # Rate limiting
  - traefik.http.middlewares.rate-limit.ratelimit.average=100
  - traefik.http.middlewares.rate-limit.ratelimit.burst=50
  
  # Compression
  - traefik.http.middlewares.compression.compress=true
  
  # Apply to router
  - traefik.http.routers.app.middlewares=secure-chain
```

Middleware execution order: rate-limit → anubis → compression

## Health Checks

Configure Traefik to health check Anubis:

```yaml theme={null}
labels:
  - traefik.http.services.anubis.loadbalancer.healthcheck.path=/healthz
  - traefik.http.services.anubis.loadbalancer.healthcheck.port=9090
  - traefik.http.services.anubis.loadbalancer.healthcheck.interval=10s
```

## Load Balancing Multiple Anubis Instances

```yaml theme={null}
services:
  anubis1:
    image: ghcr.io/techarohq/anubis:main
    environment:
      BIND: ":8080"
      ED25519_PRIVATE_KEY_HEX_FILE: "/secrets/anubis-key.txt"
    volumes:
      - ./secrets:/secrets:ro

  anubis2:
    image: ghcr.io/techarohq/anubis:main
    environment:
      BIND: ":8080"
      ED25519_PRIVATE_KEY_HEX_FILE: "/secrets/anubis-key.txt"
    volumes:
      - ./secrets:/secrets:ro

  traefik:
    labels:
      - traefik.http.middlewares.anubis.forwardauth.address=http://anubis/.within.website/x/cmd/anubis/api/check
      - traefik.http.services.anubis.loadbalancer.servers[0].url=http://anubis1:8080
      - traefik.http.services.anubis.loadbalancer.servers[1].url=http://anubis2:8080
```

All instances must use the same signing key for JWT validation.

## Troubleshooting

### Redirect Loops

Check:

1. `REDIRECT_DOMAINS` includes all your domains
2. `PUBLIC_URL` matches Anubis router hostname
3. `COOKIE_DOMAIN` is set correctly

### 502 Bad Gateway on Auth Request

Verify:

1. Anubis is running: `docker ps`
2. Network connectivity: `docker exec traefik wget -O- http://anubis:8080/.within.website/x/cmd/anubis/api/check`
3. Check Traefik logs: `docker logs traefik`

### Certificates Not Working

Ensure:

1. DNS points to your server
2. Ports 80 and 443 are accessible
3. Email is configured in traefik.yml
4. Check Let's Encrypt rate limits

### ForwardAuth Not Triggering

Verify:

1. Middleware is attached to router: `middlewares=anubis@docker`
2. Middleware name matches: `traefik.http.middlewares.anubis.forwardauth.address=...`
3. Check Traefik dashboard for middleware configuration

## Testing

Test the ForwardAuth flow:

```bash theme={null}
# Without valid cookie - should return 401
curl -v http://anubis:8080/.within.website/x/cmd/anubis/api/check

# Check Traefik routing
curl -v https://example.com

# View Traefik logs
docker logs -f traefik
```

## Resources

* [Traefik Documentation](https://doc.traefik.io/traefik/)
* [ForwardAuth Middleware](https://doc.traefik.io/traefik/middlewares/http/forwardauth/)
* [Docker Provider](https://doc.traefik.io/traefik/providers/docker/)
