前言
Traefik是反向代理、负载均衡工具,类似的工具还有nginx的Nginx Proxy Manager和nginxWebUI、SWAG等。
使用NPM对我而言最大的缺点就是不能在设置、变量上改容器http、https默认提供的80、443端口,只能通过端口映射,家宽无这两个端口情况下,想要访问https的页面,首次就只能完整输入https://xxx.com:[https端口];
而使用traefik则可以更改默认端口,且配合跳转实现输入xxx.com:[http端口],网页可以自动跳转到https且https端口。
还有其它优势,自动发现和配置(搭配容器编排工具);动态配置刷新等。
本篇教程为使用docker traefik配合ACME自动管理通过Let's Encrypt提供的SSL/(๐•ᴗ•๐)S证书,使用上http重定向到https,即https为主要访问方式。
请搭配自己情况(有无80/443端口、域名托管方)进行配置;
为了方便配置编辑,本篇编辑配置文件为主,权衡好再进行操作。
测试环境
traefik:v2.10.3(2.x与1.x版本差异大)
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
准备工作
- cloudflare账号
- 域名(建议托管到cloudflare)
- 泛域名dns记录已经指向目标ip
创建cf的api令牌
访问API令牌页面,创建令牌,使用【编辑区域DNS】模板
区域资源,选择指定的域名(特定区域)或改为所有区域
继续,创建令牌,保存好api令牌
创建traefik目录
providers存放手动配置代理文件
logs存放traefik的日志和访问记录
mkdir -p /mnt/user/appdata/traefik/providers
mkdir -p /mnt/user/appdata/traefik/logs
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
创建ACME文件
为了方便,直接在traefik映射目录下创建acme.json
,并给予600的权限,用于存储证书、私钥等信息。
touch /mnt/user/appdata/traefik/acme.json
chmod 600 /mnt/user/appdata/traefik/acme.json
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
代理通讯容器
默认访问主机上的docker容器如果通过映射/var/run/docker.sock目录的方式,会使对主机docker有完全控制权限,所以建议使用通过“代理”的方式,实现只读访问。
unraid应用搜索dockersocket,存储库为tecnativa/docker-socket-proxy
默认模板配置,其它系统可访问存储库参考
添加端口映射,2375:2375
docker run
-d
--name='dockersocket'
--net='bridge'
-e TZ="Asia/Shanghai"
-e HOST_CONTAINERNAME="dockersocket"
-e 'CONTAINERS'='1'
-e 'POST'='0'
-p '2375:2375/tcp'
-v '/var/run/docker.sock':'/var/run/docker.sock':'ro'
--restart unless-stopped 'tecnativa/docker-socket-proxy:latest'
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
应用
安装
unraid应用搜索traefik,点击安装
在默认模板的基础上
为了稳定,存储库建议改为指定tag版本
- 默认连接docker容器方式,建议移除,用代理通讯容器方式代替
- api变量的key和value根据域名托管方而定,cloudflare则填写上面获取的cf的api令牌
- 外网访问traefik面板的域名
- 是否开启traefik面板外网访问,true为开启,false为关闭
(此处我为了演示把映射目录改为了traefik_site,下面的traefik目录指的就是这个)
端口方面根据自己需求,确保不冲突,其余暂时不用管。
docker run
-d
--name='traefik'
--net='bridge'
-e TZ="Asia/Shanghai"
-e 'CF_DNS_API_TOKEN'='xxx'
-l 'traefik.http.routers.api.rule'='Host(`traefik.example.com`)'
-l 'traefik.http.routers.api.entryPoints'='https'
-l 'traefik.http.routers.api.service'='api@internal'
-l 'traefik.enable'='true'
-p '44301:44301/tcp'
-p '8001:8001/tcp'
-p '8185:8184/tcp'
-p '9080:9080/tcp'
-p '9443:9443/tcp'
-p '8184:8080/tcp'
-v '/mnt/user/appdata/traefik_site':'/etc/traefik':'rw' 'traefik:v2.10.3'
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
此处我添加映射了将需要使用的9080和9443作为http、https端口
应用运行容器后停止容器。
配置
当traefik启动时,会在下面目录中搜索静态配置文件,配置文件名为traefik.yml (traefik.yaml) 或 traefik.toml:
/etc/traefik/
$XDG_CONFIG_HOME/
$HOME/.config/
.
(工作目录)
所以在/etc/traefik映射目录下创建traefik.yml
nano /mnt/user/appdata/traefik/traefik.yml
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
内容可在官方提供的sample的基础上参考文档修改:
也可以直接复制这里的模板修改
# traefik.yml
################################################################
# Gl(๐•ᴗ•๐)al configuration
################################################################
gl(๐•ᴗ•๐)al:
# 新版本检查
checkNewVersion: true
# 匿名发送使用统计信息
sendAnonymousUsage: false
################################################################
# EntryPoints configuration
################################################################
# EntryPoints definition
#
# Optional
#
entryPoints:
web:
# http端口,默认80
address: :80
http:
# 重定向,http→https
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
# https端口,默认443
address: :443
# (๐•ᴗ•๐)s
http:
(๐•ᴗ•๐)s:
# certResolver为certificatesResolvers中自定义,例如myresolver
# main为顶级域名,sans是二级域名,可以填泛域名(需要单引号)
certResolver: myresolver
domains:
- main: example.com
sans:
- '*.example.com'
# 除此以外还有tcp、udp、metrics(暴露traefik的数据,可用于显示数据请求,运行状态、流量统计等)
# metrics:
# address: :8082
# tcp:
# address: :8083
# udp:
# address: :8084
#
serversTransport:
# 是否跳过证书验证,false时注意连接情况
# 为true时,traefik会忽略对服务器证书的验证,允许与不受信任或无效证书的服务器建立连接。
insecureSkipVerify: true
# ssl
certificatesResolvers:
# 名与上面同名
myresolver:
acme:
email: your-email@example.com
# 在traefik容器内acme.json文件目录
storage: /etc/traefik/acme.json
dnsChallenge:
# 域名提供方(dns托管方)
provider: cloudflare
# 延迟验证TXT记录,秒
delayBeforeCheck: 30
# used during the challenge
# entryPoint: web
################################################################
# Traefik logs configuration
################################################################
# Traefik logs
# Enabled by default and log to stdout
#
# Optional
# 日志
log:
# Log level
#
# Optional
# Default: "ERROR"
#
level: INFO
# Sets the filepath for the traefik log. If not specified, stdout will be used.
# Intermediate directories are created if necessary.
#
# Optional
# Default: os.Stdout
# 可设置日志输出到文件
filePath: /etc/traefik/logs/traefik.log
# Format is either "json" or "common".
#
# Optional
# Default: "common"
#
# format: json
################################################################
# Access logs configuration
################################################################
# Enable access logs
# By default it will write to stdout and produce logs in the textual
# Common Log Format (CLF), extended with additional fields.
#
# Optional
# 访问记录日志
accessLog:
# Sets the file path for the access log. If not specified, stdout will be used.
# Intermediate directories are created if necessary.
#
# Optional
# Default: os.Stdout
#
filePath: /etc/traefik/logs/access.log
# 异步方式
bufferingSize: 100
# Format is either "json" or "common".
#
# Optional
# Default: "common"
#
# format: json
################################################################
# API and dashboard configuration
################################################################
# Enable API and dashboard
#
# Optional
#
api:
# Enable the API in insecure mode
#
# Optional
# Default: false
# 是否可通过非安全方式访问traefik的api,true时可以通过http://ip:port访问面板
insecure: true
# Enabled Dashboard
#
# Optional
# Default: true
# traefik面板
dashboard: true
################################################################
# Ping configuration
################################################################
# Enable ping
#ping:
# Name of the related entry point
#
# Optional
# Default: "traefik"
#
# entryPoint: traefik
################################################################
# Docker configuration backend
################################################################
# 动态配置提供
providers:
# 间隔x秒重新加载配置
providersThrot(๐•ᴗ•๐)eDuration: 2s
# 文件方式,来源可以为指定文件或指定目录
file:
# 该目录下的yml、yaml或toml都为配置文件,便于编辑隔离
directory: /etc/traefik/providers
watch: true
# docker方式
docker:
watch: true
# docker的网络类型
network: bridge
# 替换example.com为自己域名
# 容器域名默认为 容器名.example.com
defaultRule: "Host(`{{ trimPrefix `/` .Name }}.example.com`)"
# swarm模式的轮询间隔
swarmModeRefreshSeconds: 15s
# 默认是否公开容器,false为不公开
exposedByDefault: false
# 连接docker方式
# 这里的ip根据自己主机docker网络
endpoint: "tcp://172.17.0.1:2375"
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
(缩进为两个空格)
根据自己情况修改web(http)和websecure(https)端口,bridge模式需要对应端口映射
修改example.com为自己顶级域名
acme中的email填写自己邮箱
dnsChallenge的providers,参考acme#providers,值为cloudflare时需要容器设置变量CF_API_EMAIL、CF_API_KEY 或 CF_DNS_API_TOKEN、[CF_ZONE_API_TOKEN]
已经在上面环境变量中设置了CF_DNS_API_TOKEN
其它根据自己需要,可以按照我的模板默认
保存
启动traefik容器
(记得开放traefik的http和https端口)
片刻后上cloudflare应该可以看到域名有证书
使用
分为容器标签和配置文件
标签
容器额外添加label
-l 'xxx'
- traefik.enable=true
开启通过traefik暴露该容器
- traefik.http.routers.[容器标识名].entryPoints=web/websecure
设置暴露方式,例traefik.http.routers.alist.entryPoints
web/websecure对应配置文件中entryPoints下方web、websecure名(也就是可以自定义,只要统一)
对于容器端口唯一开放和访问容器域名为容器名,一般这两个就🆗
- traefik.http.routers.[容器标识名].rule=Host(`x.example.com`)
为该容器指定域名,只修改x.example.com为目标域名
- traefik.http.services.[容器标识名].loadbalancer.server.port=端口
注意如果是容器则需要容器内部默认端口
例alist,容器webui默认端口是5244,映射到主机是6244,此处填写5244
应用后可以到traefik面板查看
无报错(后面显示由docker提供)
文件
在上面traefik/providers目录下创建test.yml(可以创建多个使用)
nano providers/test.yml
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
简单说明:
主要分开三个模块(注意各自唯一名)
- routers,定义请求流量规则,和对应动作(转发到哪个服务),与服务、中间件关联,一个(๐•ᴗ•๐)由可以使用多个中间件。
- services,后端服务,流量请求转发到这些服务。
- middlewares,逻辑处理,可以对到达服务前、后进行修改、处理、过滤等操作。例如使用traefik反代nextcloud时一些警告就需要中间件设置。
参考文档
# test.yml
http:
routers:
alistx_router:
entryPoints:
- websecure
rule: 'Host(`alistx.example.com`)'
service: alistx_service
middlewares: test_ipwhitelist
# 此处为了演示设置了白名单中间件
services:
alistx_service:
loadBalancer:
servers:
- url: http://192.168.1.10:5244
middlewares:
# 白名单
test_ipwhitelist:
ipWhiteList:
sourceRange:
- 192.168.1.0/24
- 192.168.2.0/24
deny-web:
plugin:
traefik-filter-plugin:
filterType: deny-web
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
- 编写services,唯一名,设置服务来源
- 编写routers,访问协议,访问域名,关联service
- 还可以编写middlewares,并在routers关联
保存
后面标识为由文件所提供
片刻后就可以尝试访问
显示被禁止访问了,符合预期(通过中间件设置仅能白名单ip访问),可查询traefik访问日志看到访问者的ip
tail logs/access.log
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
此处显示的是外网ip
(移除alistx_router中的middlewares: test_ipwhitelist键值对,外网就能正常访问)
从traefik面板也可以看到相关内容
额外
访问方式
因为设置了http重定向到https,所以在出次访问的浏览器上只需要输入[域名]:[web/http端口]就会自动跳转到https://[域名]:[websecure/https端口]
隔离
之所以文件方式编写选择监控整个traefik/providers目录,是因为可以做到隔离,如果都集中到一个file,编辑时如果其中一个出现语法问题,那该文件里配置的全部反向代理都无法使用。
中间件
标签方式如何添加配置文件定义的中间件
根据上图可以看到这个中间件在页面上显示完整名test_ipwhitelist@file,@file代表来自文件配置
容器添加label
- traefik.http.routers.[容器标识名].middlewares=test_ipwhitelist@file
简单的需要密码访问
http:
middlewares:
password_protect:
basicAuth:
users:
- "username:password"
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
nextcloud的您的网页服务器未正确设置以解析“/.well-known/caldav”警告,解决中间件为
http:
middlewares:
nextcloud-redirect:
redirectRegex:
permanent: true
regex: "https://(.*)/.well-known/(?:card|cal)dav"
replacement: "https://${1}/remote.php/dav"
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
主线完成
这些有时间再继续一起探讨
未完待续……
小结
自从diy装了NAS之后,首个系统是TrueNAS SCALE,反向代理自然而然用的就是Traefik,但是那时候出现了Breaking Change,加上其它原因,转UNRAID系统。前期也尝试过NPM,但有些功能难以实现又不想直接代码实现(不熟悉nginx😎),加上搜寻不到“重定向”的方法,于是就在UNRAID上用回Traefik。
Traefik功能丰富,配置文件也算清晰,缺点也是离不开配置文件,面板上只能作为查看。
参考