How to Set Up Authentik SSO with Docker Compose
Set up Authentik 2026.8.3 with Docker Compose: generate the two secrets, bootstrap akadmin, and route Traefik forward auth for your hosted apps.
Login wey cover every app wey you host
Authentik na self-hosted SSO (single sign-on) server: your users go sign in once, and every app wey dey behind am go accept that session instead make each one ask for im own password. The install na official Docker Compose file plus two generated secrets. The part wey need real thinking come after that: point reverse proxy go 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.8.3 na the current release as of October 2026. Dem publish am on 17 September 2026 as the latest patch for the 2026.8 series, wey start with 2026.8.0 on 18 August, and the official Compose file now dey use am as im default image tag. The project ask for host wey get at least 2 CPU cores and 2 GB of RAM. Treat that one as the minimum. PostgreSQL and the worker both go hold memory after the box don dey up for one day.
Wetin you need before you start
You need Docker Engine with the Compose v2 plugin. You fit confirm say e dey available with docker compose version. If e print error instead of version, install the plugin before you continue. The basic steps dey for running apps with Docker Compose on a VPS. You also need DNS A record wey point to the server. For the examples below, na auth.example.com. Authentik dey build redirect URLs from the hostname wey browser use.
Run the stack as ordinary user wey dey inside docker group, instead of root. Membership of that group get the same power as root for the host. So give am to one deploy account only, and nobody else, like the approach for least-privilege user accounts on a VPS.
Official Compose file dey install am
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 should list three containers, with postgresql reporting healthy and server and worker reporting running. The first start runs the database migrations, so give it a minute before the web interface answers.
Both generated values important, but each get different reason. 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, e go log every user out and invalidate every API token wey you don issue. Keep .env for mode 600 and keep one copy for safe place, because if you restore database without the secret key wey match am, nobody fit log into the database.
Compose file dey read both values with ${PG_PASS:?database password required} form. This mean say Compose no go start if file dey missing. 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.
Di 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 go set email.host. Single underscore dey ignore without warning, and na this one dey commonly make setting look like say e no do anything.
AUTHENTIK_BOOTSTRAP_PASSWORDdey set password for built-inakadminuser when e start for the first time, so you no go ever type am inside public web form.AUTHENTIK_BOOTSTRAP_EMAILandAUTHENTIK_BOOTSTRAP_TOKENdey set that user address and API token the same way.COMPOSE_PORT_HTTPandCOMPOSE_PORT_HTTPSdey move published ports comot from 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. If dem no dey there, Authentik go 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 inside plain file, so treat the directory like any other credential store. Password manager like self-hosted Vaultwarden instance better for keeping recovery copy than note for your laptop.
First login and admin account
Open http://SERVER_IP:9000 for browser. Authentik go show im initial setup flow and ask you to set password for default akadmin user. If you don already set AUTHENTIK_BOOTSTRAP_PASSWORD, that step don finish and you go straight to 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 go spoil audit log, because every event go say akadmin and nothing go show who do am. This matter still apply downstream of Authentik: something like self-hosted OneCLI harness wey give each person their own agent fit only leave clear trail if the identity wey reach am belong to one person, instead of login wey the whole team dey share.
Put Authentik behind your reverse proxy
Publishing port 9000 to internet dey work, but you want TLS (transport layer security) and real hostname. If you already dey run setup from Traefik as reverse proxy for multiple Compose apps, join Authentik to the same external proxy network with 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 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 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 lose per-application authorization rules. If Traefik dey front, you need forward auth (single application). If you need one real app to practise with, something like self-hosted AFFiNE workspace na good first candidate, because na the kind internal tool wey you want make your own devices reach, and nobody else. Team tool make the reason stronger: put self-hosted Chatwoot support desk behind the same provider, so everybody wey dey answer the inbox sign in once for the day instead of sharing another password.
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 into its selected applications. The outpost only answers for applications wey you give am, so if you skip that last step, the correctly configured provider still no go return anything.
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-entitlements,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 copies 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 reads X-authentik-username for automatic login go remain logged out. This gap dey clear pass for front of app wey get its own sign-in, like self-hosted openGym workout tracker and its passkey login. The headers na the difference between one prompt and two for the same page.
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 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 for a private browser window. You suppose dey sent to auth.example.com, sign in, then come back to the app. docker compose logs -f server for the Authentik side prints one authorization event for each attempt. This one go tell you whether the request reach Authentik at all.
Wetin you go actually encounter
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 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 than the catch-all router for that host.
The app loads without ever asking for login. The middlewares label names a middleware wey no dey exist. Traefik no dey warn about this, so typo for authentik@docker simply mean say no middleware go run. 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 the older project, and Red Hat dey back am. E dey stronger for classic enterprise identity work: heavy SAML federation, brokering logins from plenty external identity providers at the same time, and realm export and import as documented migration path. Commercial support behind am fit matter to some organisations for paper. The trade-off be say Keycloak no get proxy of im own. So, to protect app wey no speak OIDC (OpenID Connect), you 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 mixed collection 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.gzStore that dump and .env together. The dump alone 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 .env to the release wey you want, then run docker compose pull followed by docker compose up -d. If you never set AUTHENTIK_TAG, the version go come from the default wey dey written inside compose.yml itself. So, downloading newer copy of that file na the upgrade, and na the method wey the official upgrade docs describe. Read the release notes first. Authentik dey use date-based versions. As of October 2026, its docs say upgrades must follow the sequence of major releases: move go the latest patch for the series wey you dey run, then move through each later series in order without skipping any one. Authentik no support downgrading, so take the database dump before the pull, no be after.
FAQ
Authentik free to self-host?
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 add support and some enterprise features, but nothing for here need licence.
I need Traefik before I fit 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: reverse proxy go ask Authentik about each request, and 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 browser dey use, most often http against https. Session cookie dey issued for one origin and 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 October 2026. This one cover PostgreSQL, the server, and the worker together. For 2 GB box, the worker na the first process wey kernel go kill when memory pressure dey. The symptom na background tasks and outbound email go stop while the login page still dey work. Give am 4 GB if the same server dey also run the apps wey you dey protect.