Skip to Content

Production Guide: Deploy Authelia with Docker Compose and Traefik ForwardAuth on Ubuntu

Protect internal apps with centralized SSO, policy-based access control, and production-grade hardening.

Meta description: Deploy Authelia on Ubuntu with Docker Compose and Traefik ForwardAuth, including secure config, SSO setup, verification, and troubleshooting.

If your team runs multiple internal web tools, authentication sprawl eventually becomes an operational risk: inconsistent MFA policies, duplicate user stores, and emergency changes that are hard to audit. This guide implements a production-ready pattern using Authelia as centralized access control with Traefik ForwardAuth in front of your applications. You get one policy layer, consistent sign-in flows, and a clearer incident response path.

Real-world use case: a platform team hosts Grafana, internal admin panels, runbooks, CI utilities, and lightweight business tools. Each app has different auth quality and update cadence. Rather than trust app-by-app security settings, the team introduces a stable identity gateway and enforces access rules by domain and user group.

Architecture and flow overview

  • Traefik receives HTTPS traffic and routes by hostname.
  • Protected routes call Authelia ForwardAuth before upstream app handling.
  • Authelia evaluates session state, 2FA requirements, and rule matching.
  • If allowed, Traefik forwards request to app with identity headers.
  • If denied, user is redirected to Authelia sign-in portal.

This model decouples application logic from identity enforcement. Your app teams move faster because auth policy changes happen in one place, and your security team gains predictability across the whole self-hosted estate.

Prerequisites

  • Ubuntu 22.04+ server with static IP
  • DNS records for auth.example.com and protected app domains
  • Network policy allowing inbound ports 80/443
  • Ownership for identity policy lifecycle, 2FA rollouts, and break-glass access
  • Secure storage for generated secrets and encrypted off-host backups

Before go-live, define who approves policy changes, who can execute emergency bypass, and how each access change is reviewed after incidents. Operations clarity prevents outage chaos later.

sudo apt update && sudo apt -y upgrade
sudo apt -y install ca-certificates curl gnupg lsb-release jq ufw
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
sudo apt update && sudo apt -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin

If the copy button does not work in your browser, manually copy from the code block above.

mkdir -p ~/authelia-prod/{authelia,traefik,dynamic,secrets,backups}
cd ~/authelia-prod
openssl rand -base64 48 > secrets/session_secret.txt
openssl rand -base64 48 > secrets/storage_encryption_key.txt
chmod 600 secrets/*.txt

If the copy button does not work in your browser, manually copy from the code block above.

Step-by-step deployment

1) Build the baseline stack

Deploy Traefik and Authelia in one Compose project. Keep Docker socket read-only and avoid exposing internal control ports externally.

version: "3.9"
services:
  traefik:
    image: traefik:v3.0
    container_name: traefik
    restart: unless-stopped
    ports: ["80:80", "443:443"]
    command:
      - --providers.docker=true
      - --providers.file.directory=/dynamic
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - [email protected]
      - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./dynamic:/dynamic
      - ./traefik:/letsencrypt

  authelia:
    image: authelia/authelia:latest
    container_name: authelia
    restart: unless-stopped
    volumes:
      - ./authelia:/config
      - ./secrets:/secrets:ro
    labels:
      - traefik.enable=true
      - traefik.http.routers.authelia.rule=Host(`auth.example.com`)
      - traefik.http.routers.authelia.entrypoints=websecure
      - traefik.http.routers.authelia.tls.certresolver=le
      - traefik.http.services.authelia.loadbalancer.server.port=9091

If the copy button does not work in your browser, manually copy from the code block above.

2) Configure Authelia policies and storage

Start with default deny. Explicitly define who can access what and require two-factor where the risk justifies it. This protects you from accidental exposure when a new app route is introduced.

theme: auto
default_2fa_method: totp
log: { level: info }
server: { address: tcp://0.0.0.0:9091 }
authentication_backend:
  file: { path: /config/users_database.yml }
access_control:
  default_policy: deny
  rules:
    - domain: "*.example.com"
      policy: two_factor
session:
  secret: "{{ secret "/secrets/session_secret.txt" }}"
  cookies:
    - name: authelia_session
      domain: example.com
      authelia_url: https://auth.example.com
storage:
  encryption_key: "{{ secret "/secrets/storage_encryption_key.txt" }}"
  local: { path: /config/db.sqlite3 }
notifier:
  filesystem: { filename: /config/notification.txt }

If the copy button does not work in your browser, manually copy from the code block above.

3) Configure ForwardAuth middleware

Define middleware once and reuse across app routers. This gives consistent behavior and simpler auditing.

http:
  middlewares:
    authelia-forwardauth:
      forwardAuth:
        address: http://authelia:9091/api/authz/forward-auth
        trustForwardHeader: true
        authResponseHeaders: [Remote-User, Remote-Groups, Remote-Email, Remote-Name]

If the copy button does not work in your browser, manually copy from the code block above.

4) Attach middleware to applications

Apply middleware labels to each protected service. Pilot with one low-risk app first, then expand to operationally critical systems.

services:
  whoami:
    image: traefik/whoami
    labels:
      - traefik.enable=true
      - traefik.http.routers.whoami.rule=Host(`app.example.com`)
      - traefik.http.routers.whoami.entrypoints=websecure
      - traefik.http.routers.whoami.tls.certresolver=le
      - traefik.http.routers.whoami.middlewares=authelia-forwardauth@file

If the copy button does not work in your browser, manually copy from the code block above.

5) Bring up stack and bootstrap users

Start containers, check logs, create initial user credentials, and verify sign-in flows before broad rollout.

cd ~/authelia-prod
docker compose up -d
docker compose logs -f --tail=100 authelia

docker exec -it authelia authelia crypto hash generate argon2 --password 'ChangeMeNow!'
# add hash to users_database.yml and reload container

If the copy button does not work in your browser, manually copy from the code block above.

Configuration and secret-handling best practices

Most long-term failures are not installation issuesβ€”they are process failures: unmanaged policy growth, stale secrets, and undocumented emergency actions. Treat this deployment like platform code.

  • Version-control all Authelia/Traefik configs with peer review.
  • Store generated secrets outside repository and rotate on a fixed cadence.
  • Separate high-privilege domains from standard internal apps.
  • Require MFA for admin routes before expanding to general dashboards.
  • Publish an access governance matrix that maps groups to domains.

For enterprise environments, map policy tiers (critical, standard, low-risk) to explicit controls: MFA strictness, session duration, and device trust behavior. This prevents one-size-fits-none policy drift.

Also define incident playbooks for identity outages: how to confirm scope, how to apply temporary emergency policy, how to revert safely, and how to run postmortem hardening. Teams that rehearse this recover faster and with fewer risky shortcuts.

Verification checklist

  • Unauthenticated users are redirected to Authelia portal
  • Authenticated users with matching policy reach protected apps
  • Users outside required groups receive deny response
  • TLS certificates are valid and auto-renew
  • Restart test passes without manual repair
  • Audit-relevant logs are retained centrally
curl -I https://app.example.com
curl -s https://auth.example.com/api/health | jq
# Optional check for routers if dashboard/API is enabled:
# curl -s http://127.0.0.1:8080/api/http/routers | jq

If the copy button does not work in your browser, manually copy from the code block above.

Operational hardening and day-2 runbook

Production-readiness depends on day-2 controls, not just initial setup. Add a lightweight weekly routine: verify certificate expiry windows, check failed auth trends, review policy changes, and validate backup artifacts. Security tooling without operational rhythm degrades quickly.

Establish objective SLO-style indicators for identity gateway health: median auth response latency, successful login ratio, and policy-deny ratio by domain. Sudden shifts in these metrics usually reveal upstream DNS, proxy routing, or session-store regressions before users escalate tickets.

For change management, introduce phased rollouts:

  • Phase 1: One non-critical app with a pilot team.
  • Phase 2: Shared engineering tools and dashboards.
  • Phase 3: Administrative and operational control planes.

At each phase, capture rollback conditions in plain language. Example: if login failure rate exceeds 3% for 10 minutes, revert last policy commit and restore known-good middleware config.

Run quarterly recovery drills: restore config backup to a staging node, rehydrate users, and verify that protected routes enforce expected policy. A backup that cannot be restored under time pressure is not a backup strategy.

Common issues and fixes

Redirect loops between app and auth portal

Usually cookie domain mismatch or wrong authelia_url. Ensure hostnames, scheme, and session domain are consistent.

401 responses for valid users

Check rule ordering. Broad deny rules above specific allow rules will block legitimate traffic.

Identity headers missing upstream

Confirm authResponseHeaders and ensure intermediate proxies are not stripping headers.

ACME certificate issuance failure

Validate port 80 reachability and DNS propagation. Temporary DNS mismatch often breaks initial issuance.

Frequent session invalidation

Session secrets changed or clock skew on host nodes. Keep secrets stable and NTP healthy.

Maintenance automation examples:

0 2 * * * /usr/bin/docker compose -f /home/ubuntu/authelia-prod/docker-compose.yml pull && /usr/bin/docker compose -f /home/ubuntu/authelia-prod/docker-compose.yml up -d
15 2 * * 0 /usr/bin/docker image prune -af --filter "until=168h"
30 2 * * * /usr/bin/tar -czf /home/ubuntu/authelia-prod/backups/authelia-config-$(date +\%F-\%H\%M).tar.gz /home/ubuntu/authelia-prod/authelia /home/ubuntu/authelia-prod/dynamic

If the copy button does not work in your browser, manually copy from the code block above.

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo apt -y install fail2ban

If the copy button does not work in your browser, manually copy from the code block above.

FAQ

Can I use Authelia without Traefik?

Yes. It supports multiple reverse proxies. This guide selects Traefik for clean ForwardAuth integration in containerized stacks.

Do I need LDAP immediately?

No. File users are fine for small teams. Migrate to LDAP/IdP when user lifecycle management becomes operationally expensive.

Should default policy be deny or one_factor?

For production, default deny is safer. Explicit allows reduce accidental exposure and improve auditability.

What should I protect first?

Start with admin systems, observability, and deployment control planes. Expand after validation.

How do I roll policy updates safely?

Use staged rollout, clear rollback triggers, and peer-reviewed config changes with runbook references.

Which logs are essential during incidents?

Correlate Traefik access logs, Authelia decision logs, and application logs to isolate routing vs auth vs app failures quickly.

Related guides

Talk to us

Need help implementing a hardened authentication layer across your self-hosted stack? We can help with policy architecture, staged rollout, and production operations.

Contact Us

Deploy MinIO on Kubernetes with Helm: Production-Ready S3-Compatible Object Storage
A practical guide to running highly available MinIO on Kubernetes with secure secrets, ingress TLS, and operational safeguards.