How to Run Authentik SSO with Docker Compose
Run Authentik 2026.5 with Docker Compose: set the key env values, bootstrap akadmin, and use Traefik forward auth for one login across your apps.
One login for every app wey you host
Authentik na self-hosted SSO (single sign-on) server: your users go sign in once, and every app behind am go accept that session instead of asking for im own password. The installation na official Docker Compose file plus two generated secrets. The part wey need real thinking come after: point reverse proxy to am, then put one existing app behind forward auth.
Authentik dey ship as three services for that Compose file: PostgreSQL database, one server process, and one worker process. The server container still dey run the embedded outpost, wey be the component wey dey answer “this request don sign in?” for every protected app. Version 2026.5 na the current release as of July 2026, and the project dey ask for host wey get at least 2 CPU cores and 2 GB of RAM. Treat that as the minimum. PostgreSQL and the worker go hold memory after the box don run for one day.
Wetin you need before you start
You need Docker Engine with the Compose v2 plugin. You fit confirm am with docker compose version. If e print error instead of version, install the plugin before you continue; how to run apps with Docker Compose for VPS cover the basics. You also need DNS A record wey dey point to the server, auth.example.com for the examples below. Authentik dey build im redirect URLs from the hostname wey browser use.
Run the stack as ordinary user wey dey inside docker group, instead of root. Membership for that group get the same power as root for the host. So give am to one deploy account only, and nobody else, like user accounts with least privilege for VPS.
Install with the official Compose file
sudo install -d -o "$USER" -g "$USER" /opt/authentik
cd /opt/authentik
wget https://docs.goauthentik.io/compose.yml
echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n')" >> .env
docker compose pull
docker compose up -ddocker compose ps go suppose list three containers, with postgresql reporting healthy and server and worker reporting running. The first start dey run the database migrations, so wait one minute before the web interface go answer.
Both generated values dey important, but for different reasons. PG_PASS na the PostgreSQL password, and e get hard limit of 99 characters. AUTHENTIK_SECRET_KEY dey sign sessions and tokens, so if you change am later, every user go log out and every API token wey you don issue go stop to work. Keep .env for mode 600 and keep one copy for safe place, because database wey you restore without the matching secret key na database wey nobody fit log into.
The Compose file dey read both values with the ${PG_PASS:?database password required} form, so Compose no go start when the file no dey. If you run docker compose up -d from wrong directory, e go print required variable AUTHENTIK_SECRET_KEY is missing a value: secret key required and stop. That message na path problem, no be config problem.
The environment values wey matter
Everything else go enter the same .env file. Authentik dey map double underscore to nested configuration key, so AUTHENTIK_EMAIL__HOST dey set email.host. E dey ignore one underscore without warning, and na the most common reason why setting go look like say e no do anything.
AUTHENTIK_BOOTSTRAP_PASSWORDdey set the password for the built-inakadminuser for first start, so you no go ever type am inside public web form.AUTHENTIK_BOOTSTRAP_EMAILandAUTHENTIK_BOOTSTRAP_TOKENdey set that user's address and an API token the same way.COMPOSE_PORT_HTTPandCOMPOSE_PORT_HTTPSdey move the published ports comot from the default 9000 and 9443.AUTHENTIK_EMAIL__HOST,AUTHENTIK_EMAIL__PORT,AUTHENTIK_EMAIL__USERNAME,AUTHENTIK_EMAIL__PASSWORD,AUTHENTIK_EMAIL__USE_TLSandAUTHENTIK_EMAIL__FROMdey configure outbound mail. Without dem, Authentik dey trylocalhostfor port 25, so password-reset mails go end as connection error for worker log.AUTHENTIK_LOG_LEVEL=debugdey turn on the detail wey you need when login flow dey misbehave. Set am back toinfoafterwards.AUTHENTIK_ERROR_REPORTING__ENABLEDnafalseby default. Set am totrueonly if you dey okay with sending crash reports upstream.
These ones na secrets for plain file, so treat the directory like any other credential store. Password manager like self-hosted Vaultwarden instance better pass note for your laptop as the place to keep recovery copy.
First login and the admin account
Open http://SERVER_IP:9000 for browser. Authentik go show im initial setup flow and ask you to set password for the default akadmin user. If you don set AUTHENTIK_BOOTSTRAP_PASSWORD already, that step don finish and you go straight to the login page.
Create normal admin user for yourself under Directory and then Users. Add am to authentik Admins group, then sign in with that account. Leave akadmin as break-glass account, with long password wey you store offline. Everyday work with shared built-in account dey spoil the audit log, because every event dey show akadmin and nothing dey show who do am.
Put Authentik behind your reverse proxy
Publishing port 9000 to internet dey work, but you want TLS (transport layer security) and a real hostname. If you already dey run the setup from Traefik as reverse proxy for plenty Compose apps, join Authentik to the same external proxy network with an override file. Create docker-compose.override.yml beside compose.yml:
services:
server:
networks:
- default
- proxy
labels:
traefik.enable: "true"
traefik.docker.network: proxy
traefik.http.routers.authentik.rule: Host(`auth.example.com`)
traefik.http.routers.authentik.entrypoints: websecure
traefik.http.routers.authentik.tls.certresolver: le
traefik.http.services.authentik.loadbalancer.server.port: "9000"
networks:
proxy:
external: trueApply am with docker compose up -d. Compose go merge the override automatically, so server service go keep everything from the official file and gain the labels. Check am with curl -I https://auth.example.com/if/user/, wey suppose answer HTTP/2 200. A 404 page not found from Traefik mean say the container no dey for proxy network, and Traefik no fit route traffic to container wey e no fit reach.
Once the hostname dey work, bind the published ports to 127.0.0.1 for the override, so na only through the proxy person fit enter.
Protect one app with forward auth
Authentik proxy provider get three modes, and if you choose the wrong one, e fit waste one hour. Proxy mean say the outpost itself dey forward traffic go the upstream app. Forward auth (single application) mean say your own reverse proxy still dey move the traffic, and e only dey ask Authentik whether the request don sign in. Forward auth (domain level) dey protect every app under one parent domain with one provider, but you no go get authorization rules for each app. If Traefik dey front, you need forward auth (single application).
For the web interface, open Applications and then Providers, create a Proxy Provider, choose the forward auth single application mode, and set the external host to https://app.example.com. Create an Application wey point to that provider. Then open Outposts, edit the authentik Embedded Outpost, and move the new application enter its selected applications. The outpost only dey answer for applications wey you give am, so if you skip that last step, na why correctly configured provider still dey return nothing.
Define the middleware once, for the Authentik container, and reference am from every protected app:
traefik.http.middlewares.authentik.forwardauth.address: http://server:9000/outpost.goauthentik.io/auth/traefik
traefik.http.middlewares.authentik.forwardauth.trustForwardHeader: "true"
traefik.http.middlewares.authentik.forwardauth.authResponseHeaders: X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid,X-authentik-jwt,X-authentik-meta-jwks,X-authentik-meta-outpost,X-authentik-meta-provider,X-authentik-meta-app,X-authentik-meta-versionauthResponseHeaders na the list of headers wey Traefik dey copy from Authentik answer enter the request wey e sends upstream. If you omit am, the app still dey protected, but e no go know who the user be. So anything wey dey read X-authentik-username for automatic login go remain logged out.
The protected app itself need two routers, no be one:
labels:
traefik.enable: "true"
traefik.http.routers.myapp.rule: Host(`app.example.com`)
traefik.http.routers.myapp.entrypoints: websecure
traefik.http.routers.myapp.tls.certresolver: le
traefik.http.routers.myapp.middlewares: authentik@docker
traefik.http.routers.myapp-auth.rule: Host(`app.example.com`) && PathPrefix(`/outpost.goauthentik.io/`)
traefik.http.routers.myapp-auth.entrypoints: websecure
traefik.http.routers.myapp-auth.tls.certresolver: le
traefik.http.routers.myapp-auth.priority: "15"
traefik.http.routers.myapp-auth.service: authentikThe second router na the part wey everybody dey leave out. After sign-in, Authentik sends the browser back to a path under /outpost.goauthentik.io/ for the app's hostname, no be for auth.example.com. If router no dey send that path prefix go the Authentik service, the request go reach your app, the app go answer 404, and the login no go finish. The higher priority na wetin make the specific path rule win over the plain Host() rule for the same domain.
Test am inside a private browser window. You suppose go to auth.example.com, sign in, and come back to the app. docker compose logs -f server for the Authentik side dey print one authorization event for every attempt, and this one tells you whether the request reach Authentik at all.
The failures wey you go really meet
Redirect loop wey no dey end between the app and the login page. The external host for the provider no match wetin browser dey use, usually http:// for the provider against https:// for the address bar. The session cookie go then set for another origin, so every return go look like fresh anonymous request. Fix the external host and clear cookies for both domains before you test again.
404 for /outpost.goauthentik.io/start. The outpost router no dey, or its priority lower pass the catch-all router for that host.
The app loads but e never ask for login. The middlewares label dey name middleware wey no exist. Traefik no dey warn about this, so typo for authentik@docker simply mean say no middleware runs. Open the Traefik dashboard and confirm say the router list the middleware.
403 from Authentik after successful login. The user don authenticate but e no get authorization: the application get policy binding, or group requirement, wey this user no satisfy. The Events log for the admin interface go show the policy wey deny am.
When Keycloak dey fit pass
Keycloak na di older project wey Red Hat dey back, and e stronger for classic enterprise identity work: heavy SAML federation, brokering logins from several external identity providers at once, and realm export and import as documented migration path. Commercial support behind am matter to some organisations for paper. Di trade-off be say Keycloak no get proxy of im own, so to protect app wey no speak OIDC (OpenID Connect), you go need run something like oauth2-proxy beside am. Authentik built-in proxy provider na that missing part, and e don already integrate am. Na why most self-hosters wey get different kinds of apps dey choose Authentik.
Backups and upgrades
Three things dey make restore possible: the PostgreSQL database, the ./data directory, and .env.
cd /opt/authentik
docker compose exec -T postgresql pg_dump -U authentik authentik | gzip > authentik-$(date +%F).sql.gzKeep that dump and .env together. The dump by itself no dey enough, because the secret key wey dey protect session and token data dey inside .env.
Upgrades na tag change. Set AUTHENTIK_TAG for inside .env to the release wey you want, then run docker compose pull followed by docker compose up -d. Read the release notes first, because Authentik dey use date-based versions, and some releases get migrations wey expect say you don come from the previous one. Make the database dump before the pull, no be after.
FAQ
Authentik free to self-host ke?
The open source edition free, and e cover everything wey dey above: the proxy provider, forward auth, OIDC (OpenID Connect), SAML, and the flows engine. Paid enterprise tier dey add support and some enterprise features, but nothing for here need licence.
I need Traefik to use Authentik?
No. Forward auth dey work with nginx through auth_request and with Caddy through forward_auth. The pattern dey the same for every case: the reverse proxy dey ask Authentik about each request, and the path prefix /outpost.goauthentik.io/ for the protected hostname must route go Authentik instead of the app.
Why my protected app dey bounce between login and error forever?
The external host wey you configure for the proxy provider no match the URL wey the browser dey use, most times http against https. The session cookie dey issued for one origin and dey read for another one, so Authentik dey see anonymous request every time. Correct the external host, then clear cookies for both hostnames before you test again.
How much RAM Authentik need?
The documented minimum na 2 CPU cores and 2 GB of RAM as of July 2026, covering PostgreSQL, the server and the worker together. For a 2 GB box, the kernel go first kill the worker when memory pressure happen, and the symptom na background tasks and outbound email stop while the login page still dey work. Give am 4 GB if the same server also dey run the apps wey you dey protect.