给自建服务加上统一登录门禁:Caddy + Authelia 保姆级部署手册

作者:war 发布时间: 2026-10-20 阅读量:3 评论数:0

适用场景:个人服务器、Authelia 以 Docker 部署、Caddy 以系统服务方式安装
示例域名:auth.demo.com(Authelia)、wud.demo.com (受保护应用)


1. 架构说明

宿主机(Caddy 以 systemd 服务运行)
├── 监听 80/443,自动 HTTPS
├── 通过 127.0.0.1:9091 访问 Authelia(Docker 容器)
└── 通过 forward_auth 保护各应用域名

Docker 网络 auth-net
├── authelia(容器)
└── authelia-redis(容器)

各应用容器(可各自独立网络)
├── wud
└── homepage

2. 目录结构建议

authelia/
├── docker-compose.yml
├── .env
├── config/
│   ├── configuration.yml
│   └── users_database.yml
├── secrets/
│   ├── JWT_SECRET
│   ├── SESSION_SECRET
│   └── STORAGE_ENCRYPTION_KEY
└── redis-data/

3. 安装 Caddy

参考官方文档:caddyserver.com/docs/install

以下以 Debian / Ubuntu / Raspbian 为例。该安装方式会自动将 Caddy 注册为 systemd 服务 caddy,并随系统启动。

sudo apt install --yes debian-keyring debian-archive-keyring apt-transport-https curl

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
  | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
  | sudo tee /etc/apt/sources.list.d/caddy-stable.list

sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list

sudo apt update
sudo apt install caddy

安装完成后,Caddy 服务通常已自动启动。确认状态:

sudo systemctl status caddy

如需手动启用开机自启并立即启动:

sudo systemctl enable --now caddy

Caddyfile 位置:通过 apt 安装后,默认配置通常位于 /etc/caddy/Caddyfile。修改后重载:

sudo systemctl reload caddy

其他发行版(Fedora、RedHat、静态二进制等)的安装命令请直接参考上述官方文档页面,步骤类似,核心是让 caddy 以系统服务方式运行。


4. 生成 Authelia 密钥文件

在 authelia/ 目录下执行:

mkdir -p secrets config redis-data

openssl rand -base64 48 | tr -d '=/+' | head -c 64 > secrets/JWT_SECRET
openssl rand -base64 48 | tr -d '=/+' | head -c 64 > secrets/SESSION_SECRET
openssl rand -base64 48 | tr -d '=/+' | head -c 64 > secrets/STORAGE_ENCRYPTION_KEY

chmod 600 secrets/*

三个文件内容均为随机字符串,不要加引号或换行。


5. .env 文件

# .env
TZ=Asia/Shanghai
AUTHELIA_DOMAIN=auth.demo.com

6. docker-compose.yml

services:
  authelia:
    image: docker.io/authelia/authelia:latest
    container_name: authelia
    restart: unless-stopped
    ports:
      # 关键:必须让宿主机上的 Caddy 能访问 9091
      # 使用 127.0.0.1 绑定,仅宿主机本地可达,不暴露公网
      - "127.0.0.1:9091:9091"
    volumes:
      - ./config:/config
      - ./secrets:/secrets
    environment:
      TZ: ${TZ}
      AUTHELIA_JWT_SECRET_FILE: /secrets/JWT_SECRET
      AUTHELIA_SESSION_SECRET_FILE: /secrets/SESSION_SECRET
      AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE: /secrets/STORAGE_ENCRYPTION_KEY
    networks:
      - auth-net
    depends_on:
      - redis

  redis:
    image: docker.io/library/redis:alpine
    container_name: authelia-redis
    restart: unless-stopped
    volumes:
      - ./redis-data:/data
    networks:
      - auth-net

networks:
  auth-net:
    name: auth-net
    driver: bridge
  • 使用 _FILE 环境变量从文件读取密钥,避免把密钥写进环境变量。
  • 127.0.0.1:9091:9091 确保 Authelia 不直接暴露公网。
  • Redis 用于 Lite 部署的会话存储,避免容器重启后登录状态丢失。

7. 用户数据库 config/users_database.yml

users:
  admin:
    displayname: "Admin"
    password: "$argon2id$v=19$m=65536,t=3,p=4$..."
    email: admin@demo.com

生成密码哈希:

docker run --rm authelia/authelia:latest \
  authelia crypto hash generate argon2 --password '你的密码'

将输出的整串 $argon2id$... 替换到 password 字段。


8. config/configuration.yml

###############################################################
# Authelia configuration
###############################################################

server:
  address: 'tcp://:9091'

log:
  level: 'info'

authentication_backend:
  file:
    path: '/config/users_database.yml'

access_control:
  default_policy: 'deny'
  rules:
    - domain: 'wud.demo.com'
      policy: 'one_factor'

session:
  cookies:
    - name: 'authelia_session'
      domain: 'demo.com'               # 必须覆盖 auth.demo.com 及各应用子域
      authelia_url: 'https://auth.demo.com'
      expiration: '1 hour'
      inactivity: '5 minutes'
  redis:
    host: 'authelia-redis'
    port: 6379

regulation:
  max_retries: 3
  find_time: '2 minutes'
  ban_time: '5 minutes'

storage:
  local:
    path: '/config/db.sqlite3'

notifier:
  filesystem:
    filename: '/config/notification.txt'

关键对应关系:

配置项 值 来源 / 说明
server.address tcp://:9091 容器内监听端口,与 compose 的 9091:9091对应
authentication_backend.file.path /config/users_database.yml 即之前创建的 config/users_database.yml
access_control default_policy: deny+ 显式规则 被列出的域名才受保护
session.redis.host authelia-redis 与 compose 中 Redis 容器名一致
session.cookies.domain demo.com 根域,必须覆盖 auth.demo.com 和所有受保护子域
storage.local.path /config/db.sqlite3 自动在 config/下生成,无需手动创建
notifier.filesystem.filename /config/notification.txt 用于记录通知(如密码重置),必填,否则容器无法启动

安全提醒:session.secret 和 storage.encryption_key 不要写进这个文件,它们已经通过 compose 的 _FILE 环境变量从 secrets/ 目录注入。


9. Caddyfile 配置

Caddy 以系统服务运行,Caddyfile 默认位于 /etc/caddy/Caddyfile。修改后用 sudo systemctl reload caddy 生效。

9.1 Authelia 自身的站点

让 auth.demo.com 正常访问登录页和 API,不要加 forward_auth,否则会死循环:

auth.demo.com {
    reverse_proxy 127.0.0.1:9091
}

9.2 保护 WUD

wud.demo.com {
    forward_auth 127.0.0.1:9091 {
        uri /api/authz/forward-auth
        copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
    }

    reverse_proxy 127.0.0.1:18005
}

这里 127.0.0.1:18005 是 WUD 映射到宿主机的端口。

9.3 关键说明

  • forward_auth 127.0.0.1:9091:因为 Caddy 在宿主机上,直接用 127.0.0.1:9091 访问 Authelia,不需要容器名,不需要加入任何 Docker 网络。
  • copy_headers:认证成功后,Authelia 返回的用户身份头部会被复制到发往后端的请求中。
  • 后续新增应用时,复制上面的块,替换域名和 reverse_proxy 的后端地址即可。

10. 文件清单

文件 作用
docker-compose.yml 启动 Authelia 和 Redis
.env 时区、域名等非敏感变量
config/configuration.yml Authelia 主配置
config/users_database.yml 用户数据库
secrets/JWT_SECRET JWT 密钥
secrets/SESSION_SECRET 会话密钥
secrets/STORAGE_ENCRYPTION_KEY 存储加密密钥
/etc/caddy/Caddyfile Caddy 系统服务配置,含 Authelia 自身反代及各应用 forward_auth

11. 通知器(Notifier)说明

从 Authelia v4.15.0 开始,通知器配置被纳入启动强制校验。如果不配置通知器,Authelia 容器启动时会直接报错并陷入无限重启(Restarting) 。

通知器用于发送密码重置链接、双因素认证令牌等消息。Authelia 强制要求必须且只能配置 filesystem 或 smtp 其中的一种:

11.1 文件通知器(个人服务器首选)

上文第 8 节使用的就是这种模式,它不需要外部邮件服务,直接将消息追加写入到本地文本文件。

notifier:
  filesystem:
    filename: '/config/notification.txt'
  • 验证方法:执行 docker exec authelia authelia debug notification,然后查看 config/notification.txt 是否生成了新内容。

11.2 SMTP 通知器(生产环境/需要真实邮件)

如果你需要将密码重置链接发送到真实邮箱,需要替换为 SMTP 配置:

notifier:
  smtp:
    address: 'smtp://127.0.0.1:25'
    sender: 'Authelia <admin@demo.com>'
    username: 'your-smtp-username'
    # 密码建议通过 AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE 环境变量注入

注意:如果配置了 SMTP,Authelia 启动时会去连接测试,如果连不上或者密码错,容器依然会启动失败。

11.3 关闭启动检查(不推荐)

如果实在无法连通,可以设置 disable_startup_check: true。但这会导致启动时跳过检查,直到真正需要发邮件时才会暴露错误。

Authelia 新增受保护域名完整操作

一、先判断:新域名的根域是否已覆盖?

拿到新域名后,第一步不是改配置,而是判断它的根域是否已经在 session.cookies 里配置过。

场景 示例(已有 demo.com) 需要改 session.cookies?
同一根域的新子域 newapp.demo.com 不需要,domain: demo.com 已覆盖
全新根域 app.demo.xyz 需要,新增一条 cookie 配置

判断标准:看根域是否相同。相同 → 走流程 A;不同 → 走流程 B。


二、流程 A:同一根域下新增子域

只需改两处。

步骤 1:Caddyfile 加站点块

newapp.demo.com {
    forward_auth 127.0.0.1:9091 {
        uri /api/authz/forward-auth
        copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
    }

    reverse_proxy 127.0.0.1:新应用端口
}

步骤 2:configuration.yml 的 access_control 加域名

access_control:
  default_policy: 'deny'
  rules:
    - domain: 'wud.demo.com'
      policy: 'one_factor'
    - domain: 'newapp.demo.com'      # 新增
      policy: 'one_factor'

如果已有 *.demo.com 通配符规则,这一步可以跳过。

步骤 3:重载

sudo systemctl reload caddy
docker compose restart authelia   # 仅当改了 configuration.yml 时需要

三、流程 B:全新根域

需要改四处,缺一不可。

步骤 1:configuration.yml 的 session.cookies 新增一条

session:
  cookies:
    - name: 'authelia_session_demo_com'
      domain: 'demo.com'
      authelia_url: 'https://auth.demo.com'
      expiration: '1 hour'
      inactivity: '5 minutes'

    - name: 'authelia_session_demo_xyz'      # 新增,name 必须不同
      domain: 'demo.xyz'
      authelia_url: 'https://auth.demo.xyz'  # 必须是 demo.xyz 的子域
      expiration: '1 hour'
      inactivity: '5 minutes'

三个硬性要求:

  1. name 必须与已有 cookie 不同名,否则浏览器视为同一 cookie 互相覆盖。
  2. authelia_url 必须是该根域的子域。写成 auth.demo.com 会让浏览器拒绝 Domain=demo.xyz 的 Set-Cookie,表现为“登录成功但一直回跳”。
  3. domain 写根域,自动覆盖该根域下所有子域。

步骤 2:configuration.yml 的 access_control 加规则

access_control:
  default_policy: 'deny'
  rules:
    - domain: '*.demo.com'
      policy: 'one_factor'
    - domain: '*.demo.xyz'      # 新增
      policy: 'one_factor'

注意:*.demo.com 的通配符不会覆盖 demo.xyz,必须单独加。

步骤 3:Caddyfile 加新的登录入口

新根域需要自己的 Authelia 入口,指向同一个容器:

auth.demo.xyz {
    reverse_proxy 127.0.0.1:9091
}

以及新应用自己的站点块(同流程 A 步骤 1)。

步骤 4:重载

sudo systemctl reload caddy
docker compose restart authelia

四、操作速查表

改动位置 流程 A(同根域子域) 流程 B(全新根域)
session.cookies 不动 新增一条(name/domain/authelia_url 都要对)
access_control.rules 加域名(有通配符可跳过) 加新根域通配符
Caddyfile:auth.新根域 入口 不需要 需要
Caddyfile:应用站点块 需要 需要
重启 Authelia 改了 configuration.yml 才需要 需要
重载 Caddy 需要 需要

评论