之前在03服务器上搭了个wetty,用了Caddy的basic_auth实现的单次验证。感觉不够安全,需要增加2FA。
于是问了Deepseek和几个AI,很多方案都提到Authelia,而且Caddy的某个版本以上支持用forward_auth使用Authelia实现2FA。于是定下了这个方案。
在实现的过程中踩了很多坑。Deepseek和ChatGPT给的方案都没错,但是具体的配置文件却有很多问题,直接使用报错。记录了调试过程以便日后查询。
目前(2025.3)使用的是latest(4.39.1)版的authelia/authelia docker镜像
原始架构
1
| 用户 -> Caddy (host) -> 应用 (port 3000)
|
改造后架构
1
| 用户 -> Caddy (host) -> Docker Authelia -> 应用 (port 3000)
|
最终效果
访问https://wt.aaray.eu.org,自动跳转到Authelia的登录页面

登录

提示输入一次性密码(TOTP)

运行手机上的微软Authenticator程序,选择aaray.eu.org,点开会有6位密码,输入之后登录成功。
微软Authenticator无法截图。另外,还可以用Bitwarden或者类似程序代替微软的。
验证通过后回到Caddy原来的应用。

部署步骤
部署文件结构
~/docker/authelia
1 2 3 4 5 6 7 8 9 10 11
| authelia/ ├── config │ ├── configuration.yml │ ├── db.sqlite3 │ └── notification.txt ├── docker-compose.yml ├── secrets │ ├── jwt_secret │ └── storage_encryption_key └── users └── users.yml
|
创建 Authelia 容器
1 2 3 4 5 6
| # 创建配置目录 mkdir -p ~/docker/authelia/{config,users,secrets} # 生成密钥文件 openssl rand -base64 32 > ~/docker/authelia/secrets/jwt_secret openssl rand -base64 32 > ~/docker/authelia/secrets/storage_encryption_key
|
用户数据库 authelia/users/users.yml
1 2 3 4 5 6 7
| users: admin: displayname: "Admin" password: "$argon2id$v=19$m=65536,t=3,p=4$BpLnfgDsc2WD8F2q$..." email: admin@yourdomain.com groups: - admin
|
我的users.yml文件。如果需要添加用户,需要在文件里面添加。目前(2025.3)版本还不支持UI添加。
但是authelia除了使用本地users.yml文件,还支持ldap。所以如果需要此功能,可以引入ldap来实现更复杂的功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| users: admin: password: $argon2id$v=19$m=65536,t=3,p=4$qnAy4ozf/j+xu37IG*** displayname: Admin email: a***y@2***m groups: - admin given_name: "" middle_name: "" family_name: "" nickname: "" gender: "" birthdate: "" website: "" profile: "" picture: "" zoneinfo: "" locale: "" phone_number: "" phone_extension: "" disabled: false address: null extra: {} ubuntu: password: $argon2id$v=19$m=65536,t=3,p=4$VEGQS77uz9JMZ3DoC*** displayname: Ubuntu email: a***cn@g***m groups: - admin given_name: "" middle_name: "" family_name: "" nickname: "" gender: "" birthdate: "" website: "" profile: "" picture: "" zoneinfo: "" locale: "" phone_number: "" phone_extension: "" disabled: false address: null extra: {} aaray: password: $argon2id$v=19$m=65536,t=3,p=4$CrnfNabFimVO7D6PSa*** displayname: Ray email: a***n@g***m groups: - admin given_name: "" middle_name: "" family_name: "" nickname: "" gender: "" birthdate: "" website: "" profile: "" picture: "" zoneinfo: "" locale: "" phone_number: "" phone_extension: "" disabled: false address: null extra: {}
|
docker-compose.yml
1 2 3 4 5 6 7 8 9 10
| services: authelia: container_name: authelia ports: - 127.0.0.1:9091:9091 volumes: - /home/ubuntu/docker/authelia/config:/config - /home/ubuntu/docker/authelia/users:/etc/authelia/users - /home/ubuntu/docker/authelia/secrets:/secrets image: authelia/authelia:latest
|
authelia/config/configuration.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
|
server: address: 'tcp://0.0.0.0:9091/' log: level: 'debug' identity_validation: reset_password: jwt_secret: "@file:/secrets/jwt_secret" totp: issuer: aaray.eu.org authentication_backend: file: path: /etc/authelia/users/users.yml access_control: default_policy: deny rules: - domain: a1.aaray03.theworkpc.com policy: two_factor - domain: wt.aaray03.theworkpc.com policy: two_factor - domain: wt.aaray.eu.org policy: two_factor session: name: authelia_session secret: "@file:/secrets/jwt_secret" expiration: 3600 inactivity: 300 cookies: - domain: 'a1.aaray03.theworkpc.com' name: 'authelia_session' authelia_url: 'https://auth.a1.aaray03.theworkpc.com' default_redirection_url: 'https://a1.aaray03.theworkpc.com' same_site: 'lax' inactivity: '5 minutes' expiration: '1 hour' remember_me: '1 month' - domain: 'wt.aaray03.theworkpc.com' name: 'authelia_session' authelia_url: 'https://auth.wt.aaray03.theworkpc.com' default_redirection_url: 'https://wt.aaray03.theworkpc.com/wetty' same_site: 'lax' inactivity: '5 minutes' expiration: '1 hour' remember_me: '1 month' - domain: 'wt.aaray.eu.org' name: 'authelia_session' authelia_url: 'https://auth.wt.aaray.eu.org' default_redirection_url: 'https://wt.aaray.eu.org/wetty' same_site: 'lax' inactivity: '5 minutes' expiration: '1 hour' remember_me: '1 month' regulation: max_retries: 3 find_time: 120 ban_time: 300 storage: encryption_key: 'f8299616-****-4481-****-04acb13caf8d' local: path: /config/db.sqlite3 notifier: smtp: address: 'submission://smtp.gmail.com:587' username: 'a***n@g***m' password: '<google app password>' sender: 'a***n@g***m' timeout: '5s' identifier: 'localhost' subject: "[Authelia] {title}"
|
Caddy配置文件/etc/caddy/Caddyfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| ... a1.aaray03.theworkpc.com { # 新增认证网关 forward_auth localhost:9091 { uri /api/verify?rd=https://auth.a1.aaray03.theworkpc.com/auth #uri /api/authz/forward-auth copy_headers Remote-User Remote-Groups Remote-Name Remote-Email } # 保持原有代理配置 reverse_proxy localhost:4880 # 假设原应用运行在宿主机3000端口 } # Authelia管理界面 auth.a1.aaray03.theworkpc.com { reverse_proxy localhost:9091 } # SMTP4DEV管理界面 m.aaray03.theworkpc.com { basicauth / { aaray $2a$14$5El1SQdjjbT5SlfSk***C } reverse_proxy localhost:5000 } wt.aaray03.theworkpc.com { redir / /wetty 301 # 新增认证网关 forward_auth localhost:9091 { uri /api/verify?rd=https://auth.wt.aaray03.theworkpc.com/auth copy_headers Remote-User Remote-Groups Remote-Name Remote-Email } # 保持原有代理配置 reverse_proxy localhost:3000 # 假设原应用运行在宿主机3000端口 } # Authelia管理界面 auth.wt.aaray03.theworkpc.com { reverse_proxy localhost:9091 } wt.aaray.eu.org { redir / /wetty 301 # 新增认证网关 forward_auth localhost:9091 { uri /api/verify?rd=https://auth.wt.aaray.eu.org/auth copy_headers Remote-User Remote-Groups Remote-Name Remote-Email } # 保持原有代理配置 reverse_proxy localhost:3000 # 假设原应用运行在宿主机3000端口 } # Authelia管理界面 auth.wt.aaray.eu.org { reverse_proxy localhost:9091 }
|
部署与验证
启动服务
1 2 3 4
| docker-compose up –d
docker-compose down
|
测试流程
参见最终效果
访问 https://yourdomain.com
自动跳转至 https://auth.yourdomain.com
首次登录需:
输入用户名密码
配置 TOTP(使用 微软/谷歌 Authenticator 等应用扫码)
后续登录需密码 + 动态码
进阶配置
使用 Redis 提升性能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| services: redis: image: redis:alpine volumes: - redis_data:/data networks: - auth_net
volumes: redis_data:
session: redis: host: redis port: 6379
|
邮件自动注册
1 2 3 4 5 6 7 8 9 10
| identity_providers: oidc: hmac_secret: "@file:/etc/authelia/secrets/hmac_secret" clients: - id: myapp description: "My Application" secret: "supersecret" redirect_uris: - https://app.example.com/oauth2/callback
|
故障排查命令
查看容器日志:
1 2
| docker-compose logs -f caddy docker exec -it authelia authelia --config /etc/authelia/configuration.yml validate
|
进入容器调试:
1 2
| docker exec -it caddy sh docker exec -it authelia /bin/bash
|
网络连通性测试:
1
| docker run --rm --network auth_net curlimages/curl curl -v http://authelia:9091/api/health
|
安全加固建议
容器隔离
1 2 3 4 5
| services: authelia: security_opt: - no-new-privileges:true read_only: true
|
密钥管理:
1 2
| echo "smtp_password" | docker secret create authelia_smtp_pass -
|
维护命令速查
灾难恢复
1 2
| 0 3 * * * tar czf /backups/authelia-$(date +\%Y\%m\%d).tgz ~/authelia
|
Cloudflare配置
1 2
| CNAME/wt/wt.aaray03.theworkpc.com/Proxied/Auto A/auth.wt.aaray.eu.org/129.154.215.168/DNS only/Auto
|
第一行是增加CNAME代理wt.aaray.eu.org指向wt.aaray03.theworkpc.com以提高访问速度
第二行之所以auth.wt.aaray.eu.org加的是A记录不是CNAME,因为Cloudflare超过2级别域名,证书不免费。所以放弃代理功能,直接指向服务器IP。证书由Caddy搞定。
Authelia配置遇到的问题
用文件代替SMTP的通知
1 2 3
| notifier: filesystem: filename: /config/notification.txt
|
在配置好SMTP之前,可以用文件,原本需要发的邮件内容会写入notification.txt中,比如绑定/解绑设备等操作。
139邮箱没搞定
139邮箱没配置成功,
临时SMTP服务器smtp4dev
用smtp4dev搭建了一个smtp服务器,不能真转发邮件。邮件都保存在smtp4dev中,有web ui可以查看。
1 2 3 4 5 6 7 8
| services: smtp4dev: stdin_open: true tty: true ports: - 5000:80 - 2525:25 image: rnwood/smtp4dev
|

no route to host
两个独立的docker container之间通信需要打开防火墙
1
| sudo iptables -I INPUT -p tcp -m tcp --dport 2525 -j ACCEPT
|
用smtp4dev时,authelia的configuration.yml notifier配置如下
1 2 3 4 5 6 7 8
| notifier: smtp: address: 'smtp://172.17.0.1:2525' timeout: '5s' sender: "Ray <q***i@139.com>" identifier: 'localhost' subject: "[Authelia] {title}" disable_starttls: true
|
用Gmail做SMTP服务器
需要获得app password,而打开app password的前提是开启多重验证。详细信息看这里