Skip to content
appsgit

Deploy guide

How to self-host Authentik with Docker Compose

Authentik Docker Compose setup with the official compose.yml: generated secrets, localhost ports, akadmin setup, HTTPS reverse proxy, backups and upgrades.

  • Updated
  • Intermediate
  • About 20 minutes

You will need

  • 2 vCPU / 2 GB RAM minimum
  • Docker + Docker Compose v2
  • A domain name for the login portal
  • SMTP credentials (recommended, for password resets)

What is Authentik?

Authentik is an open source identity provider. It gives all your self-hosted apps one login page with two-factor authentication, passkeys and user management, and speaks the standard protocols apps expect: OAuth2 and OpenID Connect, SAML, LDAP, RADIUS and SCIM. For apps with no login of their own, its proxy outposts add authentication in front of them, which makes it a common companion to Traefik, Caddy or Nginx Proxy Manager.

Requirements

  • A Linux host with at least 2 CPU cores and 2 GB of RAM, the official minimum.
  • Docker Engine and Docker Compose v2.
  • A domain such as auth.example.com for the login portal.
  • SMTP credentials, so users can reset passwords and receive enrollment emails.

Step 1: Prepare the server

This guide assumes Ubuntu 24.04 with Docker installed from the official Docker Engine guide.

mkdir -p ~/authentik && cd ~/authentik

Generate the database password and secret key exactly as the official docs do. These go straight into .env without printing them:

echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n')" >> .env
echo "COMPOSE_PORT_HTTP=127.0.0.1:9000" >> .env
echo "COMPOSE_PORT_HTTPS=127.0.0.1:9443" >> .env

The two port lines bind Authentik to localhost. Docker-published ports bypass ufw, and an unfinished install exposes the initial setup flow to anyone who finds it.

Step 2: Create the Docker Compose file

Download the official file for the current release:

wget https://docs.goauthentik.io/compose.yml

At the time of writing it contains the following (keys reordered for readability):

services:
  postgresql:
    image: docker.io/library/postgres:16-alpine
    restart: unless-stopped
    env_file: [.env]
    environment:
      POSTGRES_DB: ${PG_DB:-authentik}
      POSTGRES_PASSWORD: ${PG_PASS:?database password required}
      POSTGRES_USER: ${PG_USER:-authentik}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
      interval: 30s
      retries: 5
      start_period: 20s
      timeout: 5s
    volumes:
      - database:/var/lib/postgresql/data

  server:
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.8.3}
    command: server
    restart: unless-stopped
    shm_size: 512mb
    env_file: [.env]
    environment:
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
      AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
    ports:
      - ${COMPOSE_PORT_HTTP:-9000}:9000
      - ${COMPOSE_PORT_HTTPS:-9443}:9443
    volumes:
      - ./data:/data
      - ./custom-templates:/templates
    depends_on:
      postgresql:
        condition: service_healthy

  worker:
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.8.3}
    command: worker
    restart: unless-stopped
    shm_size: 512mb
    user: root
    env_file: [.env]
    environment:
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
      AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/data
      - ./certs:/certs
      - ./custom-templates:/templates
    depends_on:
      postgresql:
        condition: service_healthy

volumes:
  database:
    driver: local

The worker mounts the Docker socket so Authentik can deploy and manage outposts for you. That gives it root-equivalent access to the host; if you deploy outposts manually, remove that line. Do not mount /etc/localtime or /etc/timezone into these containers, because the docs warn it breaks OAuth and SAML.

Step 3: Start and open the app

docker compose pull
docker compose up -d

From your laptop, tunnel to the server with ssh -L 9000:127.0.0.1:9000 user@YOUR_SERVER_IP, then open http://localhost:9000/if/flow/initial-setup/ (the trailing slash matters). Set an email and a strong password for the default akadmin user. You land in the user interface; click Admin interface to create applications, providers and users.

Step 4: Put it behind HTTPS

With Caddy on the host:

auth.example.com {
    reverse_proxy 127.0.0.1:9000
}

Caddy passes the X-Forwarded-* headers and WebSockets Authentik needs. Then set up email by adding AUTHENTIK_EMAIL__HOST, AUTHENTIK_EMAIL__PORT, AUTHENTIK_EMAIL__USERNAME, AUTHENTIK_EMAIL__PASSWORD, AUTHENTIK_EMAIL__USE_TLS and AUTHENTIK_EMAIL__FROM to .env, and run docker compose up -d. Test it with docker compose exec worker ak test_email you@example.com.

Backups and upgrades

Back up the database, plus the data, certs and custom-templates folders and .env:

docker compose exec -T postgresql pg_dump -U authentik -d authentik > authentik-$(date +%F).sql

Losing AUTHENTIK_SECRET_KEY invalidates sessions and signed data, so keep .env with the backup. To upgrade, read the release notes, download the new compose.yml (or set AUTHENTIK_TAG in .env), then run docker compose pull && docker compose up -d. Upgrade one release at a time rather than skipping several.

Troubleshooting

  • Initial setup shows "Flow does not exist": the URL is missing the trailing slash, or the worker has not finished its first-run tasks. Wait a minute and check docker compose logs worker.
  • Redirect loops or wrong URLs behind the proxy: the proxy is not forwarding Host and X-Forwarded-Proto.
  • OAuth or SAML errors about time: a timezone file was mounted into the containers. Remove it.
  • Containers exit with "secret key required": .env is missing or not next to compose.yml.

Next steps

Enable two-factor authentication and passkeys, connect your first app over OpenID Connect, add a proxy outpost with forward auth for Traefik or Caddy, and create groups to control who can open which application.

Spotted something out of date? Tell us and we will update the guide.

FAQ

authentik questions

Still curious? Email info@appsgit.com.

What ports does Authentik use?

The Authentik server listens on port 9000 for HTTP and 9443 for HTTPS. The official Compose file publishes both, and you can change or restrict them with the COMPOSE_PORT_HTTP and COMPOSE_PORT_HTTPS variables in .env.

What is the default Authentik login?

The default admin user is akadmin, but it has no password until you run the initial setup flow at /if/flow/initial-setup/ on port 9000. Complete it immediately after starting, because whoever reaches it first sets the admin password.

Does Authentik still need Redis?

No. Current releases run with just the Authentik server, a worker and PostgreSQL. The official compose.yml no longer includes a Redis container.

Authelia vs Authentik: which should I use?

Authelia is a lightweight authentication server configured with YAML files, ideal for adding login and two-factor authentication in front of apps through a reverse proxy. Authentik is a full identity provider with a web admin UI, OAuth2/OpenID Connect, SAML, LDAP and SCIM, at the cost of more RAM.

Authentik vs Keycloak?

Both are full identity providers. Keycloak is a mature Java project backed by Red Hat and common in enterprises. Authentik is lighter to run, has a friendlier admin UI and built-in proxy outposts for apps without single sign-on support, which makes it popular in homelabs.

Is Authentik free?

Yes. The core of Authentik is open source and free to self-host with no user limit. Authentik Enterprise is a paid license on the same container images that adds identity provisioning, security, compliance and device access features, plus support.