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.comfor 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
HostandX-Forwarded-Proto. - OAuth or SAML errors about time: a timezone file was mounted into the containers. Remove it.
- Containers exit with "secret key required":
.envis missing or not next tocompose.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.