Skip to Content

Production Guide: Deploy Authentik with Docker Compose + Traefik + PostgreSQL on Ubuntu

Build a production-grade Authentik SSO platform with secure secrets, resilient routing, verification checks, and practical recovery workflows.

Identity sprawl becomes a production incident the moment teams start shipping across multiple environments. A fast-growing SaaS team can easily end up with separate local accounts for internal dashboards, CI tools, observability, and customer portals, each with inconsistent MFA and no central policy. This guide shows a production-ready way to deploy Authentik using Docker Compose, Traefik, and PostgreSQL on Ubuntu so you can standardize SSO and reduce account risk without introducing fragile infrastructure.

The implementation below is intentionally operations-focused: dedicated network boundaries, secrets management patterns that survive handoff between engineers, deterministic startup checks, and practical rollback notes. If you need a secure identity layer for internal and customer-facing apps, this pattern gives you a maintainable baseline you can adapt for staging and production.

Instead of optimizing for a fast demo, this walkthrough optimizes for reliability over months of normal team change: new engineers, policy updates, app onboarding bursts, and emergency access scenarios. The design keeps internet exposure minimal, isolates data services, and embeds verification checkpoints so you can detect drift before it becomes outage risk.

Architecture and flow overview

The deployment uses four logical components. Traefik terminates TLS and routes requests to the Authentik server and worker services. Authentik stores runtime and configuration state in PostgreSQL. Redis is used for queue/cache workloads recommended for production responsiveness. Docker Compose coordinates service lifecycle, health checks, and restart behavior.

  • Edge: Traefik entrypoints (:80 and :443) with Let’s Encrypt certificates.
  • App: Authentik server + worker containers on an internal Docker network.
  • Data: PostgreSQL 16 with persistent volume and tuned defaults.
  • Cache/queue: Redis with append-only persistence enabled.

Request flow: user hits auth.example.com → Traefik handles TLS and forwards to Authentik server → Authentik validates session and policy using PostgreSQL/Redis → callback returns to protected upstream app. Keep database and Redis private to the Docker network; only Traefik should be internet-facing.

For production teams, this architecture balances simplicity and operational control: Compose remains understandable, while Traefik labels and health checks provide enough structure for repeatable operations. Add external monitoring for container health and TLS expiry so routine maintenance never depends on manual dashboard checks.

Prerequisites

  • Ubuntu 22.04/24.04 host with at least 2 vCPU, 4 GB RAM (8 GB preferred for busy SSO).
  • Domain with DNS A/AAAA record pointed to your server, e.g. auth.example.com.
  • Docker Engine + Docker Compose plugin installed.
  • Ports 80 and 443 reachable from the internet.
  • Email SMTP credentials for enrollment, reset, and policy notifications.
  • A password manager to generate/store long random secrets.
  • Basic familiarity with OIDC/SAML terminology and reverse proxy concepts.

Before deployment, confirm your DNS TTL is not excessively high (e.g., 24h) so fixes to records propagate quickly during setup. Also ensure the server clock is synced with NTP because certificate issuance and token validation are both time-sensitive.

Step-by-step deployment

1) Prepare host and folders

Create a dedicated project directory so backups and access controls are straightforward.

sudo mkdir -p /opt/authentik/{compose,secrets,data/postgres,data/redis,data/traefik}
sudo chown -R $USER:$USER /opt/authentik
cd /opt/authentik/compose

Manual copy fallback: if the copy button does not work in your browser, select the code block and copy it manually.

2) Create secrets files

Use strong, unique values. Never commit these to Git.

openssl rand -base64 48 > /opt/authentik/secrets/pg_password.txt
openssl rand -base64 48 > /opt/authentik/secrets/redis_password.txt
openssl rand -base64 64 > /opt/authentik/secrets/authentik_secret_key.txt
chmod 600 /opt/authentik/secrets/*.txt

Manual copy fallback: if the copy button does not work in your browser, select the code block and copy it manually.

3) Write environment file

cat > /opt/authentik/compose/.env <<'EOF'
AUTHENTIK_HOST=auth.example.com
AUTHENTIK_POSTGRES_DB=authentik
AUTHENTIK_POSTGRES_USER=authentik
AUTHENTIK_POSTGRES_HOST=postgres
AUTHENTIK_POSTGRES_PORT=5432
AUTHENTIK_REDIS_HOST=redis
AUTHENTIK_REDIS_PORT=6379
SMTP_HOST=smtp.mailprovider.com
SMTP_PORT=587
[email protected]
[email protected]
EOF

Manual copy fallback: if the copy button does not work in your browser, select the code block and copy it manually.

4) Create docker-compose.yml

cat > /opt/authentik/compose/docker-compose.yml <<'EOF'
services:
  traefik:
    image: traefik:v3.0
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - [email protected]
      - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.le.acme.httpchallenge=true
      - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ../data/traefik:/letsencrypt
    restart: unless-stopped

  postgres:
    image: postgres:16
    environment:
      POSTGRES_DB: ${AUTHENTIK_POSTGRES_DB}
      POSTGRES_USER: ${AUTHENTIK_POSTGRES_USER}
      POSTGRES_PASSWORD_FILE: /run/secrets/pg_password
    volumes:
      - ../data/postgres:/var/lib/postgresql/data
    secrets:
      - pg_password
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${AUTHENTIK_POSTGRES_USER} -d ${AUTHENTIK_POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 10
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    command: ["sh","-c","redis-server --appendonly yes --requirepass "$$(cat /run/secrets/redis_password)""]
    volumes:
      - ../data/redis:/data
    secrets:
      - redis_password
    restart: unless-stopped

  authentik-server:
    image: ghcr.io/goauthentik/server:2026.2
    env_file: .env
    environment:
      AUTHENTIK_SECRET_KEY_FILE: /run/secrets/authentik_secret_key
      AUTHENTIK_POSTGRESQL__PASSWORD_FILE: /run/secrets/pg_password
      AUTHENTIK_REDIS__PASSWORD_FILE: /run/secrets/redis_password
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    secrets:
      - pg_password
      - redis_password
      - authentik_secret_key
    labels:
      - traefik.enable=true
      - traefik.http.routers.authentik.rule=Host(`${AUTHENTIK_HOST}`)
      - traefik.http.routers.authentik.entrypoints=websecure
      - traefik.http.routers.authentik.tls.certresolver=le
      - traefik.http.services.authentik.loadbalancer.server.port=9000
    restart: unless-stopped

  authentik-worker:
    image: ghcr.io/goauthentik/server:2026.2
    command: worker
    env_file: .env
    environment:
      AUTHENTIK_SECRET_KEY_FILE: /run/secrets/authentik_secret_key
      AUTHENTIK_POSTGRESQL__PASSWORD_FILE: /run/secrets/pg_password
      AUTHENTIK_REDIS__PASSWORD_FILE: /run/secrets/redis_password
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    secrets:
      - pg_password
      - redis_password
      - authentik_secret_key
    restart: unless-stopped

secrets:
  pg_password:
    file: ../secrets/pg_password.txt
  redis_password:
    file: ../secrets/redis_password.txt
  authentik_secret_key:
    file: ../secrets/authentik_secret_key.txt
EOF

Manual copy fallback: if the copy button does not work in your browser, select the code block and copy it manually.

5) Launch stack and initialize

cd /opt/authentik/compose
docker compose pull
docker compose up -d
# bootstrap user if first install
docker compose run --rm authentik-server ak create_admin_group
docker compose run --rm authentik-server ak create_superuser

Manual copy fallback: if the copy button does not work in your browser, select the code block and copy it manually.

6) Lock down host firewall and baseline hardening

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

# verify container security options during review
docker info | grep -E "Security Options|Live Restore Enabled"

Manual copy fallback: if the copy button does not work in your browser, select the code block and copy it manually.

After first login, immediately enforce MFA for admin roles, disable open self-registration if not required, and add session idle/absolute timeout policies. Production readiness depends more on policy defaults than on initial install success.

For team operations, create two Authentik groups early: platform-admin and app-owner. Keep flow editing permissions in platform-admin only, while app-owner can manage provider/application assignments. This prevents accidental auth-flow edits during routine app onboarding.

Configuration and secrets handling best practices

Store all credentials in file-based secrets and keep your .env limited to non-sensitive routing or endpoint values. For rotations, replace secret files and restart only affected services. Keep a runbook documenting who can rotate what and how quickly you can recover if a secret is exposed.

  • Use distinct Postgres and Redis credentials per environment.
  • Set strict role boundaries: operators can deploy, security admins can edit authentication flows.
  • Enable SMTP early; password reset is a safety net during incident response.
  • Back up /opt/authentik/data/postgres and /opt/authentik/secrets separately with encryption.
  • Use short-lived admin sessions and require re-authentication for sensitive actions.

If your environment requires compliance controls, log administrative changes and export audits regularly to your SIEM. Authentication systems are high-value targets; retaining reliable logs materially improves incident timelines and post-incident corrective actions.

# quick encrypted backup example
sudo tar -czf - /opt/authentik/data/postgres /opt/authentik/secrets   | age -r age1yourpublickeyhere > /var/backups/authentik-$(date +%F).tar.gz.age

Manual copy fallback: if the copy button does not work in your browser, select the code block and copy it manually.

Verification checklist

Validate the deployment before onboarding production apps:

  • Traefik certificates issued and renewed successfully.
  • Authentik server and worker are healthy for 10+ minutes after restart.
  • Admin MFA enforced and emergency break-glass account stored securely.
  • Test OIDC login flow with a non-admin pilot application.
  • Backup and restore drill completed in a staging environment.
  • Email reset flow tested from a non-privileged account.
docker compose ps
docker compose logs --tail=100 authentik-server
docker compose logs --tail=100 authentik-worker
curl -I https://auth.example.com/-/health/live/
curl -I https://auth.example.com/-/health/ready/

Manual copy fallback: if the copy button does not work in your browser, select the code block and copy it manually.

A practical acceptance gate is to onboard one internal app, one engineering tool, and one staging customer-facing app. If all three login paths pass with expected group claims and MFA behavior, your baseline is typically strong enough for broader migration planning.

Common issues and fixes

Traefik route returns 404

Usually caused by hostname mismatch in labels or DNS drift. Confirm AUTHENTIK_HOST and DNS records are aligned, then restart Traefik and server containers.

Login page loads but callback fails

Most often a redirect URI mismatch in your downstream app’s OIDC client config. Verify exact scheme/host/path and avoid wildcard redirect settings in production.

Worker queue backlog grows

Check Redis memory and worker logs. If queues spike during enrollment campaigns, scale worker replicas and tune retention for non-critical events.

SMTP tests fail silently

Common with wrong TLS mode (STARTTLS vs implicit TLS). Validate provider settings and run a synthetic reset-email test every week.

Database connection resets after reboot

Check storage mount ordering and compose dependency timing; ensure persistent volumes are healthy before app containers initialize.

Unexpected MFA prompts for service accounts

Review policy bindings and flow stages. Service integrations should use dedicated non-interactive mechanisms where supported instead of human MFA flows.

FAQ

Can I run Authentik and apps on the same server?

Yes, for small environments. Use separate networks, strict firewall rules, and monitor resource contention before adding critical workloads.

Do I need Redis in production?

It is strongly recommended. Redis improves queue/cache behavior and helps maintain responsive policy and flow processing under load.

How often should I rotate secrets?

At least quarterly for admin and database credentials, and immediately after staff role changes or suspected exposure events.

What is the safest way to onboard the first application?

Start with an internal low-risk app, enforce MFA from day one, and validate role mapping before moving customer-facing services.

How do I handle zero-downtime upgrades?

Stage upgrades in a clone environment, snapshot PostgreSQL, then roll forward with controlled maintenance windows and rollback checkpoints.

Should local passwords remain enabled?

Keep one break-glass path for emergency access, but disable broad local sign-up/password usage once federated login is stable.

Can I use external managed PostgreSQL?

Yes. It can reduce operational risk if latency is low and you enforce network allowlists, TLS, and backup ownership guarantees.

What backup frequency is realistic for a small team?

Nightly full backups plus hourly WAL/archive strategy is a common starting point; tune frequency to your recovery point objective.

Related internal guides

Talk to us

If you want this implemented with hardened defaults, observability, and tested recovery playbooks, our team can help.

Contact Us

Production Guide: Deploy NetBird with Docker Compose + Nginx on Ubuntu
Run a self-hosted WireGuard mesh control plane with secure onboarding, TLS, and production-grade operational guardrails.