Skip to content

feat: add Traefik as alternative reverse proxy (--profile traefik)#1224

Open
lraphael wants to merge 1 commit intocoleam00:devfrom
lraphael:feat/traefik-reverse-proxy
Open

feat: add Traefik as alternative reverse proxy (--profile traefik)#1224
lraphael wants to merge 1 commit intocoleam00:devfrom
lraphael:feat/traefik-reverse-proxy

Conversation

@lraphael
Copy link
Copy Markdown
Contributor

@lraphael lraphael commented Apr 14, 2026

Motivation

Caddy is a great default for simple setups, but many self-hosters and teams already run Traefik as their central reverse proxy — it's the most widely used cloud-native reverse proxy in the Docker/Kubernetes ecosystem (30k+ GitHub stars, default in tools like Portainer, Rancher, and most Docker Compose template collections).

Adding Traefik as an option means users don't have to run two reverse proxies or maintain custom Traefik-to-Caddy forwarding rules. It also brings:

  • Docker-native routing — services declare their own routes via labels, no separate config file to keep in sync
  • Broad ecosystem fit — drops into existing Traefik stacks (shared dashboards, centralized cert management, middleware chains)
  • Zero-downtime reloads — label changes are picked up automatically without container restarts

This PR is purely additive — the existing --profile cloud (Caddy) is completely unchanged. No breaking changes.

Summary

  • Add Traefik v3 as an alternative reverse proxy via new --profile traefik
  • Add traefik.yml (static config: entrypoints, Let's Encrypt ACME, Docker provider)
  • Add traefik-dynamic.yml (middlewares: security headers, compression, basic auth, form auth)
  • Add Traefik labels to app and auth-service containers in docker-compose.yml
  • Update auth-service/server.js /verify endpoint to use absolute redirects via X-Forwarded-Host/X-Forwarded-Proto — required for Traefik compatibility, still works with Caddy
  • Document Traefik-specific env vars (ACME_EMAIL, TRAEFIK_BASIC_AUTH) in .env.example

Usage

# Caddy (unchanged — same as before)
docker compose --profile cloud up -d

# Traefik (new)
docker compose --profile traefik up -d

# With PostgreSQL
docker compose --profile with-db --profile traefik up -d

# With form auth
docker compose --profile traefik --profile auth up -d

Traefik requires DOMAIN and ACME_EMAIL set in .env.

Auth support

Both authentication options work with both proxies:

Auth method Caddy Traefik
Basic auth CADDY_BASIC_AUTH in .env TRAEFIK_BASIC_AUTH + middleware in traefik-dynamic.yml
Form auth (--profile auth) forward_auth in Caddyfile forwardAuth middleware + labels

Test plan

  • docker compose config validates for all 8 profile combinations
  • Traefik starts and obtains Let's Encrypt certificate
  • HTTPS proxying to app works (200 on /api/health)
  • Traefik basic auth — 401 without credentials, 200 with correct credentials
  • Traefik form auth — full flow: 302 → login page → POST → cookie → 200
  • Caddy still works unchanged with --profile cloud
  • Caddy form auth still works with modified auth-service/server.js
  • SSE streaming works (flushInterval: -1)
  • Security headers present (X-Content-Type-Options, X-Frame-Options, HSTS)

Summary by CodeRabbit

  • New Features

    • Added Traefik as an alternative reverse-proxy deployment option alongside Caddy.
    • Integrated automatic SSL/TLS certificate provisioning via Let's Encrypt for cloud deployments.
    • Added security headers and response compression middleware for Traefik deployments.
  • Bug Fixes

    • Improved authentication service redirect handling to use absolute URLs with proper protocol and hostname detection.
  • Documentation

    • Updated cloud deployment guidance to clarify Caddy vs. Traefik configuration options and requirements.

Add Traefik v3 as an alternative to Caddy for HTTPS reverse proxying.
The existing --profile cloud (Caddy) remains unchanged — Traefik is
purely additive via --profile traefik.

- Add traefik.yml (static config) and traefik-dynamic.yml (middlewares)
- Add traefik service to docker-compose.yml with separate profile
- Add Traefik labels to app and auth-service containers
- Update auth-service /verify to use absolute redirects (X-Forwarded-Host)
  so it works behind both Caddy and Traefik
- Document Traefik-specific env vars (ACME_EMAIL, TRAEFIK_BASIC_AUTH)
  in .env.example

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 14, 2026

📝 Walkthrough

Walkthrough

This pull request introduces Traefik as an alternative reverse proxy option for cloud deployments alongside the existing Caddy setup. It adds static and dynamic Traefik configuration files, Docker Compose service definitions with routing labels, updates environment documentation, and modifies the auth-service redirect logic to use absolute URLs with protocol and host headers.

Changes

Cohort / File(s) Summary
Configuration Guidance
.env.example
Updated cloud deployment instructions to support both Caddy (--profile cloud) and Traefik (--profile traefik) reverse proxies, with new Traefik-specific environment variables (ACME_EMAIL, TRAEFIK_BASIC_AUTH) and clarified form-auth behavior across both proxies.
Auth Service Logic
auth-service/server.js
Modified /verify endpoint redirect to construct absolute Location URLs using x-forwarded-proto and x-forwarded-host headers (instead of relative paths), supporting both Caddy forward_auth and Traefik forwardAuth invocations.
Docker Deployment Configuration
docker-compose.yml
Added new traefik service (image traefik:v3, profiles-gated, ports 80/443, config mounts, Docker socket access, certificate volume) and Traefik routing labels for both app (router archon, host-based rule, HTTPS/TLS, middlewares, backend port mapping) and auth-service (router auth-login, /login and /logout path routing). Introduced traefik_letsencrypt volume. Clarified Caddy/Traefik mutual exclusivity.
Traefik Static & Dynamic Configuration
traefik.yml, traefik-dynamic.yml
Created new static config (traefik.yml) with dashboard disabled, entry points (web/websecure with HTTP-to-HTTPS redirect), ACME/Let's Encrypt certificate resolver, Docker provider, and logging. Created new dynamic config (traefik-dynamic.yml) defining security-headers and compress middlewares, plus commented-out form-auth and basic-auth middleware options.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Traefik
    participant AuthService
    participant AppService

    Client->>Traefik: HTTP/HTTPS request (Host: domain)
    alt Authentication Required (Form-Auth)
        Traefik->>AuthService: forwardAuth to /verify
        AuthService-->>Traefik: Unauthenticated? Redirect to login
        Traefik-->>Client: 302 to login page
        Client->>AuthService: POST login credentials
        AuthService-->>Client: Set auth cookie
    end
    
    Client->>Traefik: Authenticated request
    Traefik->>AppService: Route to backend (port 3000)
    AppService-->>Traefik: Response
    Traefik-->>Client: Response + security headers
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A reverse proxy tale unfolds,
Traefik joins where Caddy holds,
Certificates dance, redirects gleam,
Headers secure the Docker dream,
Two paths now merge, both standing tall,
Auth-service routes them, one and all. 🚀

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is missing several required template sections including: UX Journey (Before/After flows), Architecture Diagram (Before/After module maps), Change Metadata (Risk, Size, Scope, Module labels), Validation Evidence (test command results), Security Impact analysis, Compatibility/Migration details, Human Verification specifics, and Side Effects/Blast Radius assessment. Complete the missing template sections: add UX Journey diagrams, Architecture diagrams with module connections, required labels (Risk/Size/Scope/Module), validation test results, security risk assessment, compatibility details, human verification notes, and side effects/rollback plan details.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add Traefik as alternative reverse proxy (--profile traefik)' clearly and specifically summarizes the main change—adding Traefik support via a new Docker Compose profile.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
traefik-dynamic.yml (1)

7-14: Good security header configuration.

The security headers follow best practices:

  • HSTS with 1-year max-age and includeSubDomains
  • X-Frame-Options: DENY prevents clickjacking
  • Server header cleared to reduce information disclosure

Optional enhancement: Consider adding preload to the HSTS header if you plan to submit the domain to the HSTS preload list:

Strict-Transport-Security: "max-age=31536000; includeSubDomains; preload"

This is only recommended after confirming HTTPS works correctly across all subdomains.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@traefik-dynamic.yml` around lines 7 - 14, The Strict-Transport-Security
header under the security-headers -> headers -> customResponseHeaders currently
uses "max-age=31536000; includeSubDomains"; if you plan to enroll the site in
the HSTS preload list, update the Strict-Transport-Security value to include ";
preload" (e.g., append preload to the existing directive) in the configuration
for security-headers so the header becomes max-age=31536000; includeSubDomains;
preload; confirm HTTPS works across all subdomains before making this change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@traefik-dynamic.yml`:
- Around line 7-14: The Strict-Transport-Security header under the
security-headers -> headers -> customResponseHeaders currently uses
"max-age=31536000; includeSubDomains"; if you plan to enroll the site in the
HSTS preload list, update the Strict-Transport-Security value to include ";
preload" (e.g., append preload to the existing directive) in the configuration
for security-headers so the header becomes max-age=31536000; includeSubDomains;
preload; confirm HTTPS works across all subdomains before making this change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 77dc5fe8-5f51-4752-aea2-42733bad6c79

📥 Commits

Reviewing files that changed from the base of the PR and between 73d9240 and d4dcd3a.

📒 Files selected for processing (5)
  • .env.example
  • auth-service/server.js
  • docker-compose.yml
  • traefik-dynamic.yml
  • traefik.yml

@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented Apr 17, 2026

Related to #1174 — overlapping area or partial fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants