
最近折腾了一把 Authelia,一个开源的身份认证与授权网关,主要是想给手头几个 Web 应用统一加上 SSO(单点登录)、双因素认证和基于策略的访问控制。Authelia 原生支持通过 forward-auth 模式与主流反向代理集成,配置起来比较干净。这篇记录一下完整的部署过程:Docker Compose 跑服务、Traefik 处理自动 HTTPS、用文件存储用户、TOTP(基于时间的一次性密码算法)做二次验证,再用一个 whoami 容器演示被保护的效果。跑完之后,你就能用 SSO + 双因素认证访问多个子域名,全程走 HTTPS。
1. 创建项目目录:
$ mkdir -p ~/authelia/{config,secrets,logs}
$ cd ~/authelia
2. 创建环境变量文件:
$ nano .env
DOMAIN=example.com
LETSENCRYPT_EMAIL=admin@example.com
确保 DNS A 记录中 auth.${DOMAIN}、app.${DOMAIN}、traefik.${DOMAIN} 都指向这台服务器。
1. 设置 secrets 目录权限:
$ sudo chown 8000:8000 ./secrets
$ sudo chmod 0700 ./secrets
2. 一键生成 session、storage 和 JWT 密钥:
$ docker run --rm -u 8000:8000 -v ./secrets:/secrets docker.io/authelia/authelia:4.39 \
sh -c "cd /secrets && authelia crypto rand --length 64 session_secret.txt storage_encryption_key.txt jwt_secret.txt"
1. 创建配置文件:
$ nano config/configuration.yml
server: address: 'tcp4://:9091' log: level: 'info' file_path: '/var/log/authelia/authelia.log' keep_stdout: true identity_validation: elevated_session: require_second_factor: true reset_password: jwt_lifespan: '5 minutes' jwt_secret: {{ secret "/secrets/jwt_secret.txt" | mindent 0 "|" | msquote }} totp: disable: false issuer: 'example.com' period: 30 skew: 1 authentication_backend: file: path: '/config/users.yml' password: algorithm: 'argon2' argon2: variant: 'argon2id' iterations: 3 memory: 65535 parallelism: 4 key_length: 32 salt_length: 16 access_control: default_policy: 'deny' rules: - domain: 'app.example.com' policy: 'two_factor' - domain: 'traefik.example.com' policy: 'one_factor' session: name: 'authelia_session' secret: {{ secret "/secrets/session_secret.txt" | mindent 0 "|" | msquote }} cookies: - domain: 'example.com authelia_url: 'https://auth.example.com' regulation: max_retries: 4 find_time: 120 ban_time: 300 storage: encryption_key: {{ secret "/secrets/storage_encryption_key.txt" | mindent 0 "|" | msquote }} local: path: '/config/db.sqlite3' notifier: disable_startup_check: false filesystem: filename: '/config/notification.txt'
2. 生成第一个用户的 argon2 密码哈希:
$ docker run --rm authelia/authelia:4.39 authelia crypto hash generate argon2 --password 'your-secure-password'
3. 用生成的哈希创建用户数据库:
$ nano config/users.yml
users: authuser: displayname: 'Auth User' password: '$argon2id$v=19$m=65536,t=3,p=4$BpLnfgDsc2WD8F2q$Zis.ixdg9s/UOJYrs56b5QEZFiZECu0qZVNsIYxBaNJ7ucIL.nlxVCT5tqh8KHG8X4tlwCFm5r6NTOZZ5qRFN/' email: 'authuser@example.com' groups: - 'admin'
1. 创建 Docker Compose 编排文件:
$ nano docker-compose.yaml
services: traefik: image: traefik:v3.6 container_name: traefik depends_on: - authelia command: - "--api.dashboard=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - "--entrypoints.web.http.redirections.entrypoint.scheme=https" - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" - "--certificatesresolvers.letsencrypt.acme.email=${LETSENCRYPT_EMAIL}" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" ports: - "80:80" - "443:443" volumes: - "./letsencrypt:/letsencrypt" - "/var/run/docker.sock:/var/run/docker.sock:ro" labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`traefik.${DOMAIN}`)" - "traefik.http.routers.dashboard.entrypoints=websecure" - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=authelia@docker" restart: unless-stopped authelia: image: authelia/authelia:4.39 container_name: authelia volumes: - "./secrets:/secrets:ro" - "./config:/config" - "./logs:/var/log/authelia" environment: TZ: "UTC" X_AUTHELIA_CONFIG_FILTERS: "template" labels: - "traefik.enable=true" - "traefik.http.routers.authelia.rule=Host(`auth.${DOMAIN}`)" - "traefik.http.routers.authelia.entrypoints=websecure" - "traefik.http.routers.authelia.tls.certresolver=letsencrypt" - "traefik.http.middlewares.authelia.forwardAuth.address=http://authelia:9091/api/authz/forward-auth" - "traefik.http.middlewares.authelia.forwardAuth.trustForwardHeader=true" - "traefik.http.middlewares.authelia.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email" restart: unless-stopped whoami: image: traefik/whoami container_name: whoami depends_on: - authelia labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`app.${DOMAIN}`)" - "traefik.http.routers.whoami.entrypoints=websecure" - "traefik.http.routers.whoami.tls.certresolver=letsencrypt" - "traefik.http.routers.whoami.middlewares=authelia@docker" restart: unless-stopped
2. 启动所有服务:
$ docker compose up -d
3. 验证服务运行状态:
$ docker compose ps
$ docker compose logs
1. 打开登录门户:
访问 https://auth.example.com,用 authuser 账号登录。
2. 注册 TOTP 设备:
点击 Register device,然后从文件系统通知器中获取验证码:
$ docker compose exec authelia cat /config/notification.txt
用身份验证器 APP(如 Google Authenticator、Microsoft Authenticator)扫描二维码,输入 6 位动态验证码完成注册。
3. 访问受保护的应用:
打开 https://app.example.com,请求会被重定向到 Authelia 完成密码 + TOTP 验证,验证通过后 whoami 容器会返回注入的身份头信息。
4. 确认 SSO 生效:
在同一浏览器中打开 https://traefik.example.com,无需再次认证,直接放行。
现在 Authelia 已经可以为多个子域名提供 SSO 和双因素认证保护了。接下来可以:
traefik.http.routers.<svc>.middlewares=authelia@docker 标签,并配置对应的 access_control 规则notifier 配置,用邮件发送验证码,替换掉文件通知的方式