Introduction
If you're running more than two or three self-hosted apps, you've probably noticed the problem: every single one wants its own username and password. Nextcloud has one login. Your Uptime Kuma dashboard has another. Gitea, Portainer, Grafana — all separate accounts, all separate passwords, all one bad habit away from becoming a security mess.
Authentik fixes that. It's a self-hosted identity provider that sits in front of your other apps and handles logins for all of them — one username, one password, one place to enable two-factor authentication. Big companies use tools like Okta or Azure AD for the same job. Authentik is the open-source, self-hosted version, and it runs perfectly well on a homelab Proxmox box.
This guide walks through installing Authentik inside its own LXC container on Proxmox VE, using Docker, since that's how the project is actually built to run. We're working from Proxmox VE 9.2 (Debian 13.5 "Trixie" underneath, kernel 7.0) and Authentik 2026.5.
What You Will Learn
- What Authentik does and why it's different from just "another app to install"
- How to build an LXC container that can actually run Docker
- Why nesting and keyctl matter for Docker inside an unprivileged container
- How to install Authentik with the official Docker Compose file
- How to get through the first-run setup wizard
- The errors people actually hit, and how to fix each one
- What to do after install so you're not stuck reconfiguring later
What Is This Feature?
Authentik is an open-source identity provider (IdP). In plain terms, it's a piece of software whose entire job is to answer one question — "is this really you?" — and then tell your other apps the answer, so they don't each have to ask you separately.
It speaks the standard protocols that most modern apps already understand: OAuth2/OIDC, SAML, and LDAP. If an app supports "log in with SSO" or "log in with an external provider," there's a decent chance Authentik can be that provider. It also has a built-in reverse-proxy mode called outposts, which can slap a login page in front of apps that have no SSO support at all.
Under the hood, Authentik isn't one program — it's four containers working together: a server (handles the web UI and API), a worker (runs background jobs like sending emails and syncing outposts), PostgreSQL (stores your users, apps, and settings), and Redis (handles sessions and task queues). The official install method is Docker Compose, which is exactly why this container needs Docker running inside it.
Why Would You Use It?
The honest answer: because password reuse across a dozen homelab apps is a bad idea, and remembering a dozen different passwords is worse. Centralizing logins through Authentik means you set a strong password and 2FA once, and every connected app inherits that protection.
It's also genuinely useful for anything you share with family. Set up an app for your partner or kids once in Authentik, and they get one login for everything you've connected — no separate account to create in Nextcloud, then again in Immich, then again in whatever you spin up next month.
I'd only push back on one thing: don't make Authentik the very first thing you self-host. It has a real learning curve, and if it goes down, every app tied to it can go down with it. Get comfortable with Docker and LXC containers first, then come back to this.
Prerequisites
- A working Proxmox VE 9.x host with a bit of free capacity — Authentik's own docs call for at least 2 CPU cores and 2 GB of RAM, and that's before LXC and Docker overhead
- At least 12 GB of free storage on whichever storage you'll use for the container's root disk
- A Debian 13 LXC template downloaded (or the ability to grab it through the Proxmox UI)
- Basic comfort with the Linux command line — you'll be pasting commands into a container shell
- A static IP or DHCP reservation for the container, so its address doesn't change out from under your other apps later
You don't need a domain name or a reverse proxy to follow this guide. We'll get Authentik running and reachable on your local network first; putting it behind HTTPS is a separate step worth doing before you rely on it for anything real.
Step-by-Step Tutorial
Log into the Proxmox web UI, then open a shell on the node (Datacenter → your node → Shell), or SSH in directly. Everything below runs from there unless it says otherwise.
1. Grab the Debian 13 template
pveam update
pveam available | grep debian-13
pveam download local debian-13-standard_13.5-1_amd64.tar.zst
If you already downloaded a Debian 13 template for another project, you can skip this and reuse it.
2. Create the container
pct create 200 local:vztmpl/debian-13-standard_13.5-1_amd64.tar.zst \
--hostname authentik \
--cores 2 \
--memory 4096 \
--swap 2048 \
--rootfs local-lvm:16 \
--net0 name=eth0,bridge=vmbr0,ip=dhcp \
--unprivileged 1 \
--features nesting=1,keyctl=1 \
--onboot 1
Adjust the VMID (200), storage name (local-lvm), and bridge (vmbr0) to match your own setup. If you'd rather click through the GUI: create the container as usual, then before starting it, go to Options → Features and tick Nesting and Keyctl. Skip this step and Docker simply won't start later.
3. Start it and log in
pct start 200
pct enter 200
You're now inside the container as root.
4. Update the base system
apt update && apt full-upgrade -y
Takes a minute or two on a fresh template. Reboot the container afterward if the kernel-related packages prompt for it (unlikely inside an LXC, since it shares the host kernel, but system libraries still get updated).
5. Install Docker
curl -fsSL https://get.docker.com | sh
This is Docker's own install script, and it's the fastest reliable way to get a current Docker Engine plus the Compose plugin onto a fresh Debian system. It adds Docker's repository, installs docker-ce, docker-ce-cli, containerd.io, and docker-compose-plugin, and enables the service. Give it a minute — it's downloading packages, not just configuring something local.
Check it worked:
docker --version
docker compose version
6. Download the Authentik Compose file
mkdir -p /opt/authentik && cd /opt/authentik
wget https://docs.goauthentik.io/compose.yml
This is the official file maintained by the Authentik project. It defines all four services — server, worker, PostgreSQL, and Redis — with sane defaults, so you don't have to hand-write a compose file yourself.
7. Generate your secrets
echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n')" >> .env
PG_PASS is the database password Postgres and Authentik will use to talk to each other. AUTHENTIK_SECRET_KEY signs cookies and session tokens — treat it like a password, back it up somewhere safe, and never commit it to a public repo. If you lose it, every logged-in session breaks and users have to sign in again.
Optionally, opt into anonymous crash reporting (off by default, and it's fine to skip this):
echo "AUTHENTIK_ERROR_REPORTING__ENABLED=true" >> .env
8. Bring it up
docker compose pull
docker compose up -d
The first pull downloads four images and can take a few minutes depending on your connection — the server image alone is a few hundred megabytes. up -d starts everything in the background. Give it another minute or two after that; the worker runs database migrations on first boot, and the server won't respond until those finish.
9. Check that everything's actually running
docker compose ps
You should see four containers, all showing Up (the Postgres and Redis ones may also show "healthy"). If the server container is restarting in a loop, jump to the Troubleshooting section below before going further.
10. Finish setup in the browser
Find the container's IP address (ip a inside the container, or check the Proxmox summary tab for CT 200), then visit:
http://<container-ip>:9000/if/flow/initial-setup/
This page only works once — the first time you load it, Authentik asks you to set a password for the built-in akadmin admin account. After that, the same URL just redirects to the normal login page, so set a strong password now.
Commands Explained
| Command | What it actually does |
|---|---|
pveam download local debian-13-standard... | Downloads an LXC template into Proxmox's local template storage so pct create can use it |
--features nesting=1,keyctl=1 | Lets an unprivileged LXC container run its own container runtime (Docker) inside it — without this, the Docker daemon can't start |
curl -fsSL https://get.docker.com | sh | Runs Docker's official install script, which adds their repo and installs Docker Engine plus the Compose plugin in one pass |
docker compose pull | Downloads the current images listed in compose.yml without starting anything yet |
docker compose up -d | Creates and starts all four containers, detached from your terminal so they keep running after you disconnect |
docker compose ps | Shows the status of every container defined in the compose file, so you can spot one that's crashing or restarting |
openssl rand -base64 36 | Generates 36 random bytes and encodes them as text — used here to create passwords and keys nobody could reasonably guess |
Common Errors
"Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?"
This almost always means nesting wasn't enabled before Docker tried to start. Check with pct config 200 on the Proxmox host — you should see features: nesting=1,keyctl=1 in the output. If it's missing, stop the container, add it (either via the GUI or pct set 200 -features nesting=1,keyctl=1), then start it again.
The server container restarts in a loop right after docker compose up -d
Usually a memory problem. Authentik's server and worker containers are both fairly hungry on first boot while they run migrations and build search indexes. If you gave the container less than 4 GB of RAM, bump it up — pct set 200 -memory 4096 — and restart the container.
The initial setup page just shows a blank screen or a 502
The worker probably hasn't finished its first-run database migration yet. This can take a couple of minutes on slower storage. Wait, then refresh — don't restart the stack, since that can interrupt a migration partway through.
"relation ... does not exist" in the server logs
Same root cause as above: the server started answering requests before Postgres finished being migrated. It should resolve itself once the worker catches up. If it doesn't after five minutes, check the worker's logs specifically.
Troubleshooting
Start with the logs — they'll tell you more than guessing ever will.
docker compose logs -f server
docker compose logs -f worker
Press Ctrl+C to stop following. If the server log is full of database connection errors, check that PG_PASS in your .env file matches what Postgres actually has — if you edited .env after the first up -d, the Postgres container already created its database with the old password and won't pick up the new one automatically.
If Docker itself won't start at all inside the container:
systemctl status docker
journalctl -u docker -n 50
An error mentioning cgroup or overlay here almost always traces back to nesting not being enabled, even if you're sure you enabled it — double-check by running cat /proc/self/cgroup and comparing your container config on the Proxmox host.
And if you're just not sure the container can reach the internet at all (which will silently break docker compose pull), test it before assuming Docker is the problem:
ping -c 3 1.1.1.1
curl -I https://hub.docker.com
Best Practices
Back up the whole container with vzdump before you connect any real apps to it — Authentik holds the keys to everything else once it's wired in, so losing it cleanly should mean restoring a backup, not rebuilding from scratch.
Don't expose port 9000 straight to the internet. Put it behind a reverse proxy with a real TLS certificate — Nginx Proxy Manager works fine for this if you're already running it — and only forward 443, never 9000 directly.
Keep your .env file's permissions locked down (chmod 600 .env), since it holds your database password and secret key in plain text.
Turn on 2FA for the akadmin account specifically, even before you set it up for anyone else. It's the one account that can undo everything.
Snapshot the container before running updates. Updating is just docker compose pull && docker compose up -d in /opt/authentik, but database migrations between major versions occasionally need a rollback path, and a Proxmox snapshot is the fastest one you'll have.
Frequently Asked Questions
Do I really need Docker inside an LXC container? Can't I just run it as a VM?
You can run it as a VM if you'd rather — Docker behaves more predictably there since there's no nesting to configure. LXC just uses less RAM and disk for the same workload, which is why this guide uses it.
Is Authentik actually free?
Yes. The core product used in this guide is open source under the MIT license. Authentik Security also sells a paid Enterprise tier with extra support and features aimed at larger organizations, but nothing in this tutorial requires it.
Can I use Authentik to log into the Proxmox web interface itself?
Yes — Proxmox VE supports OpenID Connect realms, and you can point one at Authentik. That's a separate configuration step on the Proxmox side, worth doing once you're comfortable with how Authentik's applications and providers work.
What happens if I lose the AUTHENTIK_SECRET_KEY?
Every active session gets invalidated and everyone has to log back in. It's annoying, not catastrophic — but back it up anyway so you're not caught off guard.
How much overhead does this actually add to logging into my other apps?
Barely any once it's set up. You'll notice one extra redirect to Authentik's login page the first time, then a normal session after that — same as logging into any single sign-on system at work.
Conclusion
Authentik is one of those tools that feels like overkill right up until the moment you're managing your fifth self-hosted app and typing yet another new password. Getting it running is mostly about respecting one detail — nesting has to be on before Docker will cooperate — and then following the same install steps the Authentik project documents for anyone running Docker Compose.
From here, the next move is connecting your first real application as an OAuth2 or SAML provider inside Authentik's dashboard. Start with something low-stakes, get comfortable with how providers and applications relate to each other, and expand from there once you trust the setup.