0x00: 效果展示
首先来看看最后达成的效果
1. 你会得到一个精制的Dashboard,展示的服务基于Docker服务发现(也就是说你部署一个服务后,板子上就会自动出现对应的入口,删除服务后自动消失)

2. 所有的服务都是用域名访问的,不需要记忆端口。也不需要你在局域网内单独架设dns服务。


3. docker对外只监听一个80和443端口,干净(不是Http协议的服务还是要port forward出来的,比如MySQL)

4. 自动为公网的服务签发https证书(放在下期会讲,大概)


0x01: Avahi的安装与配置
- 对于标准的Linux发行版,直接从包管理器上安装Avahi就行(很多发行版都会预装),然后启动它,比如对于Archlinux
pacman -S avahi
systemctl enable --now avahi-daemon.service
- 对于品牌NAS(群晖,威联通等)自带的Linux我不清楚其是否预装了Avahi,也不知道如何安装(毕竟我没有 我是学生,白送我),你可以通过下面的命令来判断下其是否预装了。
which avahi-daemon

如果没有的话去Google下如何安装,实在找不到的话到这你就可以关闭这个页面了。

0x02: 安装Portainer
如果已经安装过了这里可以跳过。
这里只给出docker命令,用面板的(品牌NAS的自带的docker管理工具)需要自行翻译下。
# 创建卷,用来存储portainer的配置
docker volume create portainer_data
# 拉起portainer
docker run -d \
--name=portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 9000:9000 \
portainer/portainer-ce
然后使用 http://<NAS的IP>:9000 来访问portainer

0x03: 安装Traefik
首先创建一个叫traefik的network(随便你叫啥,记得住就行)

创建traefik的stack


yaml的内容如下
version: "3"
services:
traefik:
image: traefik:v2.10.5
restart: always
environment:
TZ: Asia/Shanghai # 设置时区
command:
# 开启 traefik 自带的 dashboard
- --api.dashboard=true
# 开启 traefik 对 docker 的支持
- --providers.docker=true
# 关闭自动 docker 服务暴露
- --providers.docker.exposedbydefault=false
# 设置一个叫 web 的 entrypoint,监听 80 端口
- --entrypoints.web.address=:80
labels:
traefik.enable: true
# 在 80 端口上暴露traefik-api
# “路由”你就理解为十字路口的交警,根据情况指引你到合适的车道上(后端)
# 路由 “traefik-api” 的后端指向 traefik 自己的API(你应该去的车道)
traefik.http.routers.traefik-api.service: api@internal
# 路由 “traefik-api” 的匹配条件是:Host 为 traefik.local 或 traefik(交通规则,第二个Host是给homepage用的)
traefik.http.routers.traefik-api.rule: Host(`traefik.local`,`traefik`)
# 路由 “traefik-api” 的入口是来自一个叫 web 的 entrypoint(你从哪来)
traefik.http.routers.traefik-api.entrypoints: web
# Homepage 相关,后面解释
homepage.group: Devs
homepage.name: Traefik
homepage.icon: traefik.png
homepage.href: http://traefik.local/
homepage.description: Traefik Dashboards
homepage.widget.type: traefik
homepage.widget.url: http://traefik:80
# 暴露 80 端口
ports:
- 80:80
# 绑定 docker 的 sock,使 traefik 能与 docker 通信
volumes:
- /var/run/docker.sock:/var/run/docker.sock
avahi-helper:
# 这个容器会将以 .local 结尾的 Host 广播出去(比如26行的 traefik.local)
# 在同一个同一个局域网的用户就都能访问到了
image: hardillb/traefik-avahi-helper
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /run/dbus/system_bus_socket:/run/dbus/system_bus_socket
# 加入 traefik 的网络
networks:
default:
external:
name: traefik
部署后你应该就能从 http://traefik.local 访问 traefik的面板了
如果你想玩的更花的话请看Traefik的官方文档 https://doc.traefik.io/traefik/


0x03.5: Traefik的访问日志(选修)
如果你要收集traefik的访问日志的话可以在commad中添加如下条目,然后访问日志会保存到
/var/log/traefik/access.log(别忘了挂载出来)
- --accessLog
- --accesslog.filepath=/var/log/traefik/access.log
- --accesslog.fields.names.StartUTC=drop
可以创建 /etc/logrotate.d/traefik 配合logrotate做日志切分(注意容器名)
/var/log/traefik/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
postrotate
/usr/bin/docker kill -s USR1 traefik-traefik-1
endscript
}

0x04: 部署Homepage
新建一个stack,内容如下
version: "3"
services:
homepage:
image: ghcr.io/gethomepage/homepage:latest
restart: always
labels:
traefik.enable: true
# traefik这坨label的解释见上边,这里不在赘述
traefik.http.services.homepage.loadbalancer.server.port: 3000
traefik.http.routers.homepage.service: homepage
# 在 home.local 暴露
traefik.http.routers.homepage.rule: Host(`home.local`)
traefik.http.routers.homepage.entrypoints: web
volumes:
- config:/app/config
- /var/run/docker.sock:/var/run/docker.sock:ro
volumes:
config:
# 注意加入 traefik 网络
networks:
default:
external:
name: traefik
之后访问 http://home.local/ 你就能看到 homepage 的页面了,当然你也会看到一个traefik的入口,哪么他是怎么出现的呢?

我们这时来回头看部署traefik的labels中和homepage有关的几段
# 分类
homepage.group: Devs
# 名字
homepage.name: Traefik
# 图标
homepage.icon: traefik.png
# 地址,和路由 Host 里面的填写的一样
homepage.href: http://traefik.local/
# 描述
homepage.description: Traefik Dashboards
# 可选的小组件,用来展示状态的
homepage.widget.type: traefik
# traefik的API地址(注意要写容器内的地址,.local结尾的是找不到的)
homepage.widget.url: http://traefik:80
有了这些内容,homepage就会自动添加一个入口啦
更多关于homepage的配置和功能请参考其官方文档 https://gethomepage.dev/latest/configs/ ,受限篇幅这里不再展开

0x05: 实战!部署一个qBittorrent
再新建一个stack,内容如下
version: "3"
services:
qbittorrent:
image: linuxserver/qbittorrent:4.5.4
restart: always
# 用于 Bt 下载的端口,由于不是 HTTP 协议所以还是要单独暴露出来
ports:
- 63637:63637
- 63637:63637/udp
labels:
# traefik配置
# 开启 traefik
traefik.enable: true
# 定义一个叫 qbittorrent 的 service(服务),端口为 qbittorrent 的网页端口 8080
traefik.http.services.qbittorrent.loadbalancer.server.port: 8080
# 定义一个叫 qbittorrent 的 router(路由),指向刚刚创建的叫 qbittorrent 的 service(服务)
traefik.http.routers.qbittorrent.service: qbittorrent
# 所有 Host 为 qbittorrent.local 会被匹配 qbittorrent 路由匹配
traefik.http.routers.qbittorrent.rule: Host(`qbittorrent.local`)
# qbittorrent 路由的入口是 web(80端口)
traefik.http.routers.qbittorrent.entrypoints: web
# homepage 配置
# 分类
homepage.group: 下载
# 名字
homepage.name: qBittorrent
# 图标
homepage.icon: qbittorrent.png
# 地址,和 20 行 Host 中的内容要相同
homepage.href: http://qbittorrent.local/
# 描述
homepage.description: qBittorrent
# 可选的小组件,用来在主页展示 qb 的情况
homepage.widget.type: qbittorrent
# qb 的 API地址,要填容器的名字(第四行)和对应端口
homepage.widget.url: http://qbittorrent:8080
# qb 的用户名
homepage.widget.username: admin
# qb 的 密码
homepage.widget.password: adminadmin
environment:
PUID: 1000
PGID: 998
TZ: Asia/Shanghai
# 把下载目录和配置目录出来
volumes:
- /mnt/hgst500g/downloads:/downloads
- /mnt/hgst500g/downloads/.qbittorrent:/config
# 加入 traefik 网络
networks:
default:
external:
name: traefik
部署后就能从homepage上进入qb的页面了

0x06: 让 Portainer 也加入吧
其实就是在刚刚部署 portainer 的脚本多加几个labels,记得先把之间的容器删了
docker run -d \
--name=portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
-p 9000:9000 \
--network=traefik \
-l 'traefik.enable=true' \
-l 'traefik.http.services.portainer.loadbalancer.server.port=9000' \
-l 'traefik.http.routers.portainer.service=portainer' \
-l 'traefik.http.routers.portainer.rule=Host(`portainer.local`)' \
-l 'traefik.http.routers.portainer.entrypoints=web' \
-l 'homepage.group=Devs' \
-l 'homepage.name=Portainer' \
-l 'homepage.icon=portainer.png' \
-l 'homepage.href=http://portainer.local' \
-l 'homepage.description=Portainer' \
-l 'homepage.widget.type=portainer' \
-l 'homepage.widget.url=http://portainer:9000' \
-l 'homepage.widget.env=2' \
-l 'homepage.widget.key=ptr_XXX' \
portainer/portainer-ce
homepage.widget.env 的 env id在这里

homepage.widget.key在这里获取



