前言
Homelab 玩到一定程度,你就会面临一个经典问题:服务越来越多。
PVE 管理后台、Docker 上的 Portainer、Home Assistant、Jellyfin 媒体服务器、Grafana 监控面板……每个服务都有一个不同的端口号,每次访问都要记 192.168.1.100:9000、:8123、:3000,不仅不方便,还容易搞混。
解决方案就是反向代理 —— 通过域名访问所有服务:
ha.yourlab.com → Home Assistantportainer.yourlab.com → Portainergrafana.yourlab.com → Grafanajellyfin.yourlab.com → Jellyfin
而 Traefik 是目前最适合 Docker 环境下的反向代理方案之一。相比 Nginx 需要手动维护配置文件,Traefik 可以自动监听 Docker 容器,通过容器 Label 自动配置路由,还能自动申请和续期 Let’s Encrypt SSL 证书。真正做到"加一个新服务,改几行 docker-compose 配置,Traefik 全自动搞定"。
本文带你从零搭建一套 Traefik 反向代理,完整覆盖 HTTPS、Let’s Encrypt 自动证书、Dashboard 监控和常见服务接入。
1. 架构概览
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| Internet
│
🔒 443 (HTTPS)
│
┌──────▼──────┐
│ Traefik │ ← 自动申请 Let's Encrypt 证书
│ (Proxy) │
└──┬──┬──┬───┘
│ │ │
┌────▼┐ │ └──────┐
│ HA │ │ │
└─────┘ │ ┌────▼──┐
│ │Jelly..│
┌─────▼──┐└───────┘
│Portn.. │
└────────┘
|
Traefik 监听宿主机的 80 和 443 端口,通过 Docker Socket 自动发现容器,根据容器 Label 自动配置路由。Let’s Encrypt 使用 HTTP-01 或 TLS-ALPN-01 验证域名所有权,自动签发和续期证书。
2. 准备工作
2.1 网络与域名
你需要:
- 一个公网域名(或内网 DNS)—— 推荐在 Cloudflare、阿里云、腾讯云等平台注册一个域名
- 域名解析到你的 Homelab 公网 IP(如果服务需要外网访问)
- 开放防火墙的 80 和 443 端口
如果你只在内网使用,也可以用内网 DNS 或修改 /etc/hosts,但 Traefik 的 Let’s Encrypt 功能仍需要域名能公网解析。对于纯内网场景,可以使用 Traefik 的自签证书或跳过 TLS,后续我会另写文章介绍。
2.2 创建 Docker 网络
为了让 Traefik 能和所有后端容器通信,先创建一个共享网络:
1
| docker network create traefik-net
|
所有需要经过 Traefik 反向代理的容器都要接入这个网络。
3. 部署 Traefik
3.1 目录结构
1
2
3
| mkdir -p ~/docker/traefik && cd ~/docker/traefik
touch acme.json # Let's Encrypt 证书存储文件
chmod 600 acme.json # 重要!权限必须是 600,否则 Traefik 拒绝启动
|
3.2 Docker Compose 配置
创建 docker-compose.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
| version: '3.8'
services:
traefik:
image: traefik:v3.1
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- traefik-net
ports:
- "80:80" # HTTP 重定向到 HTTPS
- "443:443" # HTTPS
# - "8080:8080" # Dashboard(建议通过反向代理访问,不暴露端口)
environment:
- CF_API_EMAIL=${CF_API_EMAIL}
- CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
# 使用其他 DNS 提供商时修改为对应的环境变量
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./acme.json:/acme.json
- ./config:/config
labels:
- "traefik.enable=true"
# Dashboard 路由
- "traefik.http.routers.dashboard.rule=Host(`traefik.yourlab.com`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=auth"
# 中间件:Dashboard 基础认证
- "traefik.http.middlewares.auth.basicauth.users=${DASHBOARD_USER}:${DASHBOARD_PASS_HASH}"
networks:
traefik-net:
external: true
|
3.3 Traefik 静态配置
创建 traefik.yml(注意不是 traefik.yaml,是 .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
| # 全局配置
global:
sendAnonymousUsage: false
# 日志级别: DEBUG, INFO, WARN, ERROR
log:
level: INFO
# API 和 Dashboard
api:
dashboard: true
debug: true
# 入口点
entryPoints:
web:
address: :80
http:
redirections:
entrypoint:
to: websecure
scheme: https
permanent: true
websecure:
address: :443
# 证书配置(Let's Encrypt)
certificatesResolvers:
letsencrypt:
acme:
email: your-email@example.com # ← 改成你的邮箱
storage: /acme.json
# DNS-01 挑战(推荐,支持通配符证书)
dnsChallenge:
provider: cloudflare # ← 根据你的 DNS 提供商修改
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
# 如果使用 HTTP-01 挑战,注释掉上面的 dnsChallenge,取消注释下面:
# httpChallenge:
# entryPoint: web
# 开启 Docker 服务发现
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false # 只有打了 traefik.enable=true 标签的容器才被代理
file:
directory: /config # 外部配置文件目录
watch: true
|
3.4 环境变量
创建 .env 文件:
1
2
3
4
5
6
7
| # DNS API 凭据(以 Cloudflare 为例)
CF_API_EMAIL=your-cloudflare-email@example.com
CF_DNS_API_TOKEN=your_cloudflare_api_token
# Dashboard 认证(用户名:密码的 bcrypt 哈希)
DASHBOARD_USER=admin
DASHBOARD_PASS_HASH=$(htpasswd -nb admin yourpassword | sed 's/\$/$$/g')
|
生成 bcrypt 密码哈希:docker run --rm httpd:alpine htpasswd -nb admin 你的密码
3.5 启动 Traefik
1
2
| docker compose up -d
docker compose logs -f # 查看启动日志
|
如果一切正常,你应该能看到 Let’s Encrypt 证书成功申请的信息。访问 https://traefik.yourlab.com 就能看到 Traefik Dashboard 了。
4. 添加反向代理服务
4.1 例 1:反向代理 Portainer
Portainer 是管理 Docker 的利器,给它加上 Traefik 路由:
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
| version: '3.8'
services:
portainer:
image: portainer/portainer-ce:latest
container_name: portainer
restart: unless-stopped
networks:
- traefik-net # 使用 Traefik 网络
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
labels:
- "traefik.enable=true"
- "traefik.http.routers.portainer.rule=Host(`portainer.yourlab.com`)"
- "traefik.http.routers.portainer.entrypoints=websecure"
- "traefik.http.routers.portainer.tls=true"
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
volumes:
portainer_data:
networks:
traefik-net:
external: true
|
docker compose up -d 之后,访问 https://portainer.yourlab.com 即可。Traefik 会自动为这个域名申请证书。
4.2 例 2:反向代理 Home Assistant
Home Assistant 运行在宿主机或 PVE 的 LXC 中时,可以用 file provider 方式代理。但如果 HA 也在 Docker 里,同样的 Label 方式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| homeassistant:
image: ghcr.io/home-assistant/home-assistant:stable
container_name: homeassistant
restart: unless-stopped
networks:
- traefik-net
volumes:
- ./ha_config:/config
- /etc/localtime:/etc/localtime:ro
labels:
- "traefik.enable=true"
- "traefik.http.routers.ha.rule=Host(`ha.yourlab.com`)"
- "traefik.http.routers.ha.entrypoints=websecure"
- "traefik.http.routers.ha.tls=true"
- "traefik.http.routers.ha.tls.certresolver=letsencrypt"
- "traefik.http.services.ha.loadbalancer.server.port=8123"
# 如果 HA 需要通过 HomeKit 或 WebSocket,可以额外暴露端口
# ports:
# - "8123:8123"
devices:
- /dev/ttyUSB0:/dev/ttyUSB0 # Zigbee 协调器直通
|
4.3 例 3:同时代理多个子域名(通配符证书)
如果使用 DNS-01 挑战,Traefik 可以申请通配符证书 *.yourlab.com。只需在路由上移除 certresolver 配置,Traefik 会自动使用已签发的通配符证书。
1
2
3
4
5
6
7
| # 所有服务都可以这样配置,无需单独申请证书
labels:
- "traefik.enable=true"
- "traefik.http.routers.xxx.rule=Host(`xxx.yourlab.com`)"
- "traefik.http.routers.xxx.entrypoints=websecure"
- "traefik.http.routers.xxx.tls=true" # 隐式使用通配符证书
- "traefik.http.services.xxx.loadbalancer.server.port=8080"
|
4.4 中间件:给服务加 IP 白名单
不想让某些服务暴露在公网?加个 IP 白名单中间件:
1
2
3
4
5
| labels:
- "traefik.enable=true"
- "traefik.http.routers.grafana.rule=Host(`grafana.yourlab.com`)"
- "traefik.http.routers.grafana.middlewares=whitelist"
- "traefik.http.middlewares.whitelist.ipwhitelist.sourcerange=192.168.0.0/16,10.0.0.0/8"
|
这样只有内网 IP 才能访问 Grafana,外网用户即使知道域名也打不开。
5. 踩坑记录
❌ 坑 1:acme.json 权限问题
Traefik 出于安全考虑,拒绝使用权限过于开放的 acme.json。
1
2
3
4
| # 正确姿势
touch acme.json
chmod 600 acme.json
# 如果 chmod 600 后还报错,确认不是 root:root 以外属主
|
错误日志:permission denied for /acme.json
❌ 坑 2:DNS 挑战失败(Cloudflare)
Traefik 使用 Cloudflare DNS 挑战时,需要 API Token 有 Zone:DNS:Edit 权限。如果只给了 Read,会一直报错:
1
| acme: error: 403 :: POST :: https://api.cloudflare.com/client/v4/zones/xxx/dns_records
|
需要去 Cloudflare Dashboard → My Profile → API Tokens,创建 token 时勾选 Zone → DNS → Edit 权限。
❌ 坑 3:Dashboard 暴露到公网
默认 Dashboard 绑定在 :8080,如果不加认证直接暴露到公网非常危险。我上面的配置通过反向代理访问 Dashboard,并加了 Basic Auth 中间件。或者你也可以在 traefik.yml 中只监听本地:
1
2
3
4
| api:
dashboard: true
# 只监听本地
# (不配置 entrypoint,仅在反向代理路由中暴露)
|
❌ 坑 4:容器重启后 IP 变化
Docker 容器重启后 IP 会变,但 Traefik 通过 Docker provider 自动感知容器变化,所以不用担心。但如果你用 file provider 配置了后端地址,记得用容器名而不是 IP:
1
2
3
4
5
6
7
| # /config/dynamic.yml
http:
services:
my-service:
loadBalancer:
servers:
- url: "http://my-container-name:8080" # ✅ Docker DNS 解析
|
6. 进阶:Uptime Kuma 监控你的所有服务
有了 Traefik 后,再部署一个 Uptime Kuma 来监控所有服务的可用性:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| uptime-kuma:
image: louislam/uptime-kuma:latest
container_name: uptime-kuma
restart: unless-stopped
networks:
- traefik-net
volumes:
- ./uptime-kuma-data:/app/data
labels:
- "traefik.enable=true"
- "traefik.http.routers.kuma.rule=Host(`status.yourlab.com`)"
- "traefik.http.routers.kuma.entrypoints=websecure"
- "traefik.http.routers.kuma.tls=true"
- "traefik.http.routers.kuma.tls.certresolver=letsencrypt"
- "traefik.http.services.kuma.loadbalancer.server.port=3001"
|
Uptime Kuma 可以监控 HTTP、TCP、Ping 等,一旦某个服务挂了,会通过 Telegram、邮件、Webhook 等方式告警,是 Homelab 运维的好帮手。
总结
有了 Traefik 之后,你的 Homelab 服务管理会变得无比清爽:
| 功能 | 效果 |
|---|
| ✅ 统一入口 | 所有服务通过域名访问,告别记端口号 |
| ✅ 自动 HTTPS | Let’s Encrypt 自动签发和续期,零维护 |
| ✅ 通配符证书 | 一个证书覆盖所有子域名 |
| ✅ Docker 自动发现 | 加新服务只需加 Label,无需重启 Traefik |
| ✅ 中间件生态 | IP 白名单、Basic Auth、Rate Limit 开箱即用 |
下一步可以做的事情:
- 部署 Uptime Kuma 实现服务可用性监控
- 集成 Grafana + Prometheus 监控 PVE 和 Docker 主机资源
- 使用 Traefik Plugin 实现更丰富的中间件功能(如 OAuth 代理、GeoIP 限制)
- 配合 Cloudflare Tunnel 实现无公网 IP 的内网穿透
如果你目前还在用 Nginx 手动维护反代配置,强烈建议试试 Traefik — 尤其是在 Docker 环境下,它带来的"声明式配置"体验是革命性的。
预告: 下一篇文章将介绍如何在 PVE 中部署 Grafana + Prometheus + Node Exporter 全面监控你的 Homelab 集群资源使用情况。