【保姆级】从零构建家庭数据中心的安全堡垒:Caddy + Authelia 部署全指南

在折腾 NAS 和家庭实验室(HomeLab)的过程中,我们经常面临一个矛盾:想把服务暴露到公网方便访问,又担心后台裸奔被黑客扫爆。

单纯的 Basic Auth(浏览器弹窗输入密码)体验差且不支持双重验证(2FA),而 VPN 又稍显繁琐。今天,我们来部署一套企业级的零信任身份认证系统Caddy + Authelia

🌟 为什么选择这套方案?

  • Caddy:配置最简单的现代化 Web 服务器,自动申请 HTTPS 证书,原生支持 forward_auth
  • Authelia:开源的轻量级认证中心,支持 2FA (两步验证)、单点登录 (SSO)。
  • 效果:访问你所有的服务(飞牛、群晖、Portainer、Jellyfin)前,都会先跳转到一个漂亮的登录界面,验证通过后自动放行。

🛠️ 准备工作

  1. 一台服务器/NAS:安装好 Docker 和 Docker Compose。
  2. 一个域名:并解析到你的服务器 IP(推荐泛解析,如 *.example.com)。
  3. 基础知识:会使用 SSH 连接服务器。

第一步:目录结构与环境搭建

为了方便管理,建议在 /data/authelia 目录下统一存放文件。

mkdir -p /data/authelia/config
mkdir -p /data/caddy/config
mkdir -p /data/caddy/data

创建 docker-compose.yml

/data 目录下创建一个 docker-compose.yml,我们将 Caddy 和 Authelia 放在同一个网络中。

version: '3.8'

services:
  # --- 认证中心服务 ---
  authelia:
    image: authelia/authelia
    container_name: authelia
    restart: unless-stopped
    volumes:
      - ./authelia/config:/config
    environment:
      - TZ=Asia/Shanghai
    networks:
      - caddy_net
    # Authelia 不需要端口映射到宿主机,因为它只跟 Caddy 对话

  # --- Redis (可选,推荐) ---
  # 用于存储 Session,比文件存储更稳定
  redis:
    image: redis:alpine
    container_name: authelia_redis
    restart: unless-stopped
    networks:
      - caddy_net

  # --- 网关/反向代理 ---
  caddy:
    image: caddy:latest
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./caddy/Caddyfile:/etc/caddy/Caddyfile
      - ./caddy/data:/data
      - ./caddy/config:/config
    networks:
      - caddy_net

networks:
  caddy_net:
    driver: bridge

第二步:配置 Authelia (核心难点)

Authelia 的配置比较严格,请务必细心。我们需要在该目录下新建两个文件:configuration.yml (主配置) 和 users_database.yml (用户库)。

1. 生成用户密码 Hash

Authelia 不保存明文密码,我们需要先生成一个加密后的密码。运行以下命令(将 你的密码 换成你想设置的):

docker run --rm authelia/authelia authelia crypto hash generate pbkdf2 --password '你的密码'

你会得到一串类似 $pbkdf2-sha512$.... 的字符串,复制下来

2. 创建用户文件 (users_database.yml)

/data/authelia/config/ 下新建 users_database.yml

users:
  admin:
    displayname: "Administrator"
    password: "$pbkdf2-sha512$..."  # 粘贴刚才生成的 Hash 字符串
    email: [email protected]
    groups:
      - admins
      - dev

3. 创建主配置文件 (configuration.yml)

/data/authelia/config/ 下新建 configuration.yml

⚠️ 注意: 请将文中 example.com 替换为你自己的域名!
###############################################################
#                   Authelia Configuration                    #
###############################################################

theme: light

# 1. JWT 密钥 (生成一个随机字符串填进去)
jwt_secret: a_very_important_secret_random_string_12345

# 2. 默认访问策略
access_control:
  default_policy: deny # 默认拒绝所有,必须登录
  rules:
    # 内网免密 (根据需要开启)
    # - domain: "*.example.com"
    #   networks:
    #     - 192.168.1.0/24
    #   policy: bypass

    # 特定子域名需要双重认证
    - domain: "secure.example.com"
      policy: two_factor

    # 其他子域名只需要单因素密码
    - domain: "*.example.com"
      policy: one_factor

# 3. Session 存储 (使用 Redis)
session:
  name: authelia_session
  secret: another_very_important_secret_random_string
  expiration: 3600  # 1小时过期
  inactivity: 300   # 5分钟无操作过期
  domain: example.com  # ⚠️ 必须是根域名
  redis:
    host: authelia_redis
    port: 6379

# 4. 存储后端 (这里使用轻量级的文件存储)
storage:
  local:
    path: /config/db.sqlite3

# 5. 通知方式 (用于发送 2FA 验证码或重置密码)
# 初次测试建议使用 filesystem,它会把邮件内容保存到文件中
notifier:
  filesystem:
    filename: /config/notification.txt

# 6. 身份验证后端 (引用刚才创建的文件)
authentication_backend:
  file:
    path: /config/users_database.yml

第三步:配置 Caddy (连接桥梁)

/data/caddy/ 下创建 Caddyfile。这是 Caddy 能够通过 Authelia 验证的关键。

# --- 定义 Authelia 中间件 ---
(authelia) {
    forward_auth authelia:9091 {
        # 这里的地址是 Authelia 容器内部地址
        uri /api/verify?rd=https://auth.example.com
        copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
    }
}

# --- 1. Authelia 认证门户 ---
auth.example.com {
    reverse_proxy authelia:9091
}

# --- 2. 需要保护的服务 (例如 Whoami 测试页) ---
whoami.example.com {
    # 引用认证模块,这就加上了锁
    import authelia
    
    # 认证通过后转发给后端
    reverse_proxy 127.0.0.1:2001 
}

# --- 3. 保护飞牛/NAS ---
nas.example.com {
    import authelia
    reverse_proxy 192.168.1.100:5000
}

第四步:启动与验证

启动服务

/data 目录下执行:

docker-compose up -d

首次登录验证

  1. 在浏览器访问 https://whoami.example.com
  2. 你会发现 URL 自动跳转到了 https://auth.example.com
  3. 输入你在 users_database.yml 里设置的账号 admin 和密码。
  4. 配置 2FA (双重认证)

    • 页面会提示你注册设备。
    • 点击注册,Authelia 会发送一封“邮件”。
    • 查看邮件:由于我们配置的是 filesystem 通知,请去服务器查看文件:

      cat /data/authelia/config/notification.txt
    • 复制文件里的链接,在浏览器打开。
    • 你会看到一个二维码,使用 Google Authenticator 或 Microsoft Authenticator 扫码。
  5. 验证通过后,你将成功跳转回 whoami.example.com

💡 进阶技巧:解决 WebDAV/App 无法连接问题

加上 Authelia 后,你会发现手机上的 Infuse、RaiDrive 或者 Emby 客户端连不上了。这是因为这些 App 不会处理网页跳转。

解决方案: 在 Caddy 中针对 API 路径绕过认证。

修改 Caddyfile 中的 NAS 配置:

nas.example.com {
    # 定义 WebDAV 或 API 的路径匹配器
    @bypass_paths {
        path /dav* /webdav* /emby* /api*
    }

    # 1. 针对 App/API:直接放行 (或仅使用 Basic Auth)
    handle @bypass_paths {
        reverse_proxy 192.168.1.100:5000
    }

    # 2. 针对网页访问:强制 Authelia 认证
    handle {
        import authelia
        reverse_proxy 192.168.1.100:5000
    }
}

❓ 常见问题排查 (Troubleshooting)

  1. 无限重定向 (Redirect Loop)

    • 检查 configuration.yml 中的 session.domain 是否设置正确,必须是根域名(如 example.com),不能是子域名。
    • 检查 Caddyfile 中的 rd=https://auth.example.com 地址是否正确。
  2. Caddy 报错 "dial tcp: lookup authelia..."

    • 确保 Caddy 和 Authelia 在同一个 Docker Network 下。
  3. 无法写入 notification.txt

    • 检查 /data/authelia/config 目录的权限,Docker 容器内的用户需要有写入权限。

结语

通过这套 Caddy + Authelia 的组合,你已经成功将家庭数据中心的安全等级提升到了企业标准。现在,你可以放心地将服务暴露在公网,享受随时随地访问的便利,同时把所有恶意扫描拒之门外!