翻车的home server经验分享-反向代理 [traefik]
创作立场声明:仅个人折腾
接着上篇,反向代理选的是traefik,为啥不选nginx,因为我没找到新手教程。还有,用traefik有个好处,比如traefik的ip和端口是192.168.0.3:80,直接访问这个是会出现404的。只有用域名才能正常访问。
欢迎各位直接去看traefik官网说明,谁能一次性看明白我就拜谁为师。总之先去看看,看完后就能明白我学得是多么辛苦了。甚至不用看我写的,快点去看官网。![翻车的home server经验分享-反向代理 [traefik]](https://res.smzdm.com/images/emotions/34.png)
介绍
首先介绍下啥是反向代理,事实上我也不清楚,我就知道它们是怎么干活的,举个不恰当的例子:反向代理就像小餐馆的服务员,服务就像厨房。你向服务员点菜,他们把菜端上来,你是不能进厨房的,虽然没进到厨房但是你吃到了要吃的菜。所以把反向代理当成中间人就行了。在http服务是这样的,假设你有3个服务,然后你反向代理的ip是192.168.0.3,反向代理的端口是80,然后在没有证书的情况下。
懂了吧,你以为你访问域名时访问的是服务的真实ip,其实你访问的是反向代理的ip。所以反向代理所在的机器需要消耗cpu性能进行解码。
接下来就是安装和使用traefik了,对于搭建traefik来说,用docker-compose更方便一点。对了,用的是traefik 2.x版本,1.x的我不会用,好像过不久就会出3.x了,会不会给我gui呢,不懂。总之先从简单的http反代开始吧。虽然是这么说,但是traefik得读取静态配置才能用的下去,然后静态配置有3种方式,1是用文件,就是等下要用的,2是命令行,我经常把它和下一种方式混淆,3是环境变量,用过docker的都懂吧。
安装
在安装traefik前先装portainer,方便管理容器。
先创建custom network。默认的是bridge模式。网关默认的是.1。
docker network create --subnet=172.20.0.0/16 traefik_proxy
然后用docker cli装portainer。6053537的portainer是中文的,比较好用。
docker run -dit --restart=always--name="portainer" -p 9001:9000 -v /var/run/docker.sock:/var/run/docker.sock -v /home/用户名/docker/portainer/data/:/data --net traefik_proxy --ip 172.20.0.2 6053537/portainer-ce
然后开始安装traefik,先建好文件夹,再建一个叫traefik.yml的文件,填入以下内容,并不需要更改。
global:
checkNewVersion: true
sendAnonymousUsage: false
log:
level: DEBUG
filePath: /etc/traefik/logs/traefik.log
accessLog:
filePath: /etc/traefik/logs/access.log
api:
dashboard: true
debug: true
insecure: true
serversTransport:
insecureSkipVerify: true
entryPoints:
web:
address: :80
providers:
docker:
exposedByDefault: false
network: traefik_proxy
watch: true
file:
directory: /etc/traefik/config
watch: true
然后就是docker-compose了,记得在portainer的堆叠里创建。
version: '3'
services:
traefik:
image: traefik:latest
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
traefik_proxy:
ipv4_address: 172.20.0.3
ports:
- 80:80
- 8080:8080
environment:
- TZ=Asia/Shanghai
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /home/用户名/docker/traefik/traefik.yml:/traefik.yml:ro
- /home/用户名/docker/traefik/logs:/etc/traefik/logs
- /home/用户名/docker/traefik/config:/etc/traefik/config
networks:
traefik_proxy:
external: true
好了,现在就能用http://ip:8080访问traefik dashboard了。然后开始第一次的反向代理。
使用
HTTP
假设要绑定这个域名:traefik.子域名.duckdns.org,在/traefik/config里创建rp-traefik.yml,然后输入:
http:
routers:
traefik:
entryPoints:
- web
rule: "Host(`traefik.子域名.duckdns.org`)"
middlewares:
service: api@internal
然后要在phole local dns里把域名和dns绑定好,保存后就能访问http://traefik.子域名.duckdns.org:80了。在traefik dashboard也能看到详细。恭喜你,你学会最简单的反代了。
Traefik的3个核心是entrypoint和router和service,entrypoint在traefik.yml出现了,router在rp-traefik.yml出现了,推理下就能举一反三了,接下来就是service了。因为traefik自己反代自己,所以知道service是谁,现在反代下其它容器,给你们看看service怎么写。假设host的ip是192.168.0.20。我注册了个临时子域名lastview.duckdns.org,拿nginx来当示范吧。
version: '3'
services:
nginx:
image: nginx:latest
container_name: nginx
restart: unless-stopped
networks:
traefik_proxy:
ipv4_address: 172.20.0.4
ports:
- 180:80
networks:
traefik_proxy:
external: true
在/traefik/config里创建rp-nginx.yml,然后输入(service选一种就行了):
http:
routers:
portainer:
entryPoints:
- web
rule: "Host(`lastview.duckdns.org`)"
service: nginx
services:
nginx:
loadBalancer:
servers:
- url: "http://172.20.0.4:80"
- url: "http://192.168.0.20:180"
- url: "http://nginx:80"
你们能明白ip和端口为什么那么写吧。因为在同一个custom network,所以用名字用行。Servers的3种里面选1种用就好。
所以traefik的service也能这样写,不过不推荐就是了:
services:
traefik:
loadBalancer:
servers:
- url: "http://172.20.0.3:8080"
- url: "http://192.168.0.20:8080"
- url: "http://traefik:8080"
Http的反代就是这么简单,连middlewares都不需要。
HTTPS
现在开始https,需要做点小更改,但是要一个个举出来太累了,直接把全部放出来好了。只要改邮箱就能用了。对了,修改traefik.yml完后,需要重启traefik才能生效。
global:
checkNewVersion: true
sendAnonymousUsage: false
log:
level: DEBUG
filePath: /etc/traefik/logs/traefik.log
accessLog:
filePath: /etc/traefik/logs/access.log
api:
dashboard: true
debug: true
insecure: true
serversTransport:
insecureSkipVerify: true
entryPoints:
web:
address: :80
websecure:
address: :443
certificatesResolvers:
staging:
acme:
email: 注册letsencrypt用的email
storage: /etc/traefik/certs/acme.json
caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
dnsChallenge:
provider: duckdns
production:
acme:
email: 注册letsencrypt用的email
storage: /etc/traefik/certs/acme.json
caServer: "https://acme-v02.api.letsencrypt.org/directory"
dnsChallenge:
provider: duckdns
tls:
options:
default:
minVersion: VersionTLS12
curvePreferences:
- secp521r1
- secp384r1
cipherSuites:
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
mintls13:
minVersion: VersionTLS13
providers:
docker:
exposedByDefault: false
network: traefik_proxy
watch: true
file:
directory: /etc/traefik/config
watch: true
然后是traefik的docker-compose:
version: '3'
services:
traefik:
image: traefik:latest
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- traefik_proxy:
ipv4_address: 172.20.0.3
ports:
- 80:80
- 443:443
environment:
- DUCKDNS_TOKEN=自己的TOKEN
- TZ=Asia/Shanghai
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /home/用户名/docker/traefik/traefik.yml:/traefik.yml:ro
- /home/用户名/docker/traefik/certs:/etc/traefik/certs
- /home/用户名/docker/traefik/logs:/etc/traefik/logs
- /home/用户名/docker/traefik/config:/etc/traefik/config
networks:
traefik_proxy:
external: true
好了,开始https反代,接着拿nginx当示范。如果不搞http,直接搞https的话,会出现这情况,访问lastview.duckdns.org,浏览器识别成http://lastview.duckdns.org,然后出现404,但是直接访问https://lastview.duckdns.org又正常。rp-nginx.yml:
http:
routers:
nginx-http:
entryPoints:
- web
rule: "Host(`lastview.duckdns.org`)"
middlewares:
- https-redirectscheme
service: nginx
nginx-https:
entryPoints:
- websecure
rule: "Host(`lastview.duckdns.org`)"
middlewares:
- default-headers
tls:
certResolver: staging #production
domains:
- main: "lastview.duckdns.org"
sans:
- "*.lastview.duckdns.org"
service: nginx
services:
nginx:
loadBalancer:
servers:
- url: http://nginx:80
middlewares:
https-redirectscheme:
redirectScheme:
scheme: https
permanent: true
default-headers:
headers:
frameDeny: true
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 15552000
customFrameOptionsValue: SAMEORIGIN
customRequestHeaders:
X-Forwarded-Proto: https
先用staging挑战证书,成功的话访问https就会出现熟悉的自签证书的味道。
看看证书先。
现在把acme.json清空了,然后把浏览器的cookie清了,换production挑战。有可能需要重启traefik 。
看,成了。CA证书。
然后泛域名的证书也一起注册了,剩下的容器直接用现成证书就可以了,现在拿portainer演示。rp-portainer.yml:
http:
routers:
portainer-http:
entryPoints:
- web
rule: "Host(`portainer.lastview.duckdns.org`)"
middlewares:
- https-redirectscheme
service: portainer
portainer-https:
entryPoints:
- websecure
rule: "Host(`portainer.lastview.duckdns.org`)"
middlewares:
- default-headers
tls: {}
service: portainer
services:
portainer:
loadBalancer:
servers:
- url: "http://portainer:9000"
吐槽
嘛,反代就这样结束了,接下来解释下哪里翻车了,我也不知道怎么一下子说出来,所以请听我的废话。
静态配置
现在把traefik.yml一段段拆出来解释。
global:
checkNewVersion: true
sendAnonymousUsage: false
Global嘛,有和没有都行,checkNewVersion是检查更新的,sendAnonymousUsage是traefik搜集匿名消息的。
log:
level: DEBUG
filePath: /etc/traefik/logs/traefik.log
accessLog:
filePath: /etc/traefik/logs/access.log
log嘛,就是日志。Fail2ban需要用到access.log。traefik.log是用来debug的。logLevel有DEBUG,PANIC,FATAL,ERROR,WARN,INFO。默认好像是ERROR。
api:
dashboard: true
debug: true
insecure: true
Dashboard是api的一种,所以需要开dashboard必须要开api,具体的api在traefik官网里看吧。Insecure设置为true就能用ip:端口访问dashboard了。虽然dashboard没啥鸟用。重点是所有api都会暴露traefik的重要设置,开api前三思而后行。至于api怎么看,请去官网看。
serversTransport:
insecureSkipVerify: true
如果有容器有https证书,又想反代,必须设置为true。这个好像是动态配置来着。
entryPoints:
web:
address: :80
websecure:
address: :443
入口就是访问反向代理的端口,可以随便设。现场搞个新的示范,名字叫public,端口是666的:
public:
address: :666
嘛,你懂的,80和443不能用,换个端口就行了。
certificatesResolvers:
staging:
acme:
email: 注册letsencrypt用的email
storage: /etc/traefik/certs/acme.json
caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
dnsChallenge:
provider: duckdns
production:
acme:
email: 注册letsencrypt用的email
storage: /etc/traefik/certs/acme.json
caServer: "https://acme-v02.api.letsencrypt.org/directory"
dnsChallenge:
provider: duckdns
这里就是获得letsencrypt证书的地方,把email换成自己的就能用了。如果跳过staging,直接挑战production,失败次数太多是会被ban的哦。因为Let's Encrypt挑战次数有限,先用staging挑战,失败了也不会被ban,成功后再换production挑战。有时候会出现怎么也挑战不成功的情况,解决的方法就是重启机器。还有acme.json不要自己创建,要不然会出现权限问题,它需要用的权限是0600。
tls:
options:
default:
minVersion: VersionTLS12
curvePreferences:
- secp521r1
- secp384r1
cipherSuites:
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
mintls13:
minVersion: VersionTLS13
翻车的时候到了,我完全看不懂这是什么,也不知道这是不是给人看的。你懂的吧,把别人的代码直接copy过来就和闭眼过独木桥一样。
providers:
docker:
exposedByDefault: false
network: traefik_proxy
watch: true
file:
directory: /etc/traefik/config
watch: true
Provider就是提供动态配置的地方。在docker可以用cli和label。然后用file,就是我前面展示的方法。把exposedByDefault设置为false就能避免traefik自动反代容器的情况了。这个traefik_proxy是自建的,名字随便取,这样可以避免单容器多网络状态下traefik识别不了网络。把watch设置为true,那么修改完后,traefik就能自动更新,不需要重启traefik了。还有就像前面的rp-traefik.yml和rp-nginx.yml,把config文件分开保存,可以避免一个文件写错然后全军覆没的风险。还有动态配置文件只能放在config里,不能是上级目录或者下级目录。
docker-compose
接下来是traefik的docker-compose:
services:
traefik:
image: traefik:latest
container_name: traefik
restart: unless-stopped
这里应该都懂吧。
security_opt:
- no-new-privileges:true
这是不给traefik新权限,为了避免traefik被攻破后继续坏事。但是我觉得没什么用。![翻车的home server经验分享-反向代理 [traefik]](https://res.smzdm.com/images/emotions/82.png)
networks:
- traefik_proxy:
ipv4_address: 172.20.0.3
你们懂的吧,不固定ip会乱变的。然后traefik反代172.20.x.x段的容器就不用经过nat,减少损失。至于traefik_proxy,在同一网络下,像之前说的可以直接指向容器的名字。
ports:
- 80:80
- 443:443
- 8080:8080
在上面说过了。
environment:
- DUCKDNS_TOKEN=自己的TOKEN
- TZ=Asia/Shanghai
填了TOKEN才能挑战证书,每个支持的dns提供商的名字都不一样,具体上traefik官网看。
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /home/用户名/docker/traefik/traefik.yml:/traefik.yml:ro
- /home/用户名/docker/traefik/certs:/etc/traefik/certs
- /home/用户名/docker/traefik/logs:/etc/traefik/logs
- /home/用户名/docker/traefik/config:/etc/traefik/config
要用docker提供动态配置就需要mount docker.sock。
networks:
traefik_proxy:
external: true
用docker-compose的custom network必需要有指向的内容。至于external是因为traefik_proxy是已存在的网络,不设置为true那docker就会新建个网络。
动态配置
然后是file提供的动态配置。
http:
这里是http的反代,还有tcp和udp的,虽然我不会用。
routers:
router名:
router名必须是唯一的,如果相同,那么新的就会把旧的覆盖。
entryPoints:
- web
入口得选一个,这里是http的80端口。
rule: "Host(`域名`)"
rule是个复杂的东西,既能直接用域名,也能同时用多个域名,也能域名+路径,等等。不要把服务硬塞进路径里,会变得不幸。![翻车的home server经验分享-反向代理 [traefik]](https://res.smzdm.com/images/emotions/97.png)
middlewares:
- https-redirectscheme
为了让http自动转https才需要这个middleware。Middleware很复杂的,我看不懂几个,具体上traefik官网看。又翻车。
service: service名
service可以重复用。
新router名:
entryPoints:
- websecure
这里是https的443端口。
rule: "Host(`域名`)"
middlewares:
- default-headers
我完全不知道headers是干嘛用的。
tls:
certResolver: staging #production
domains:
- main: "域名"
sans:
- "*.域名"
用这个可以把域名和泛域名证书一起申请了,申请一次就够了,其它容器的tls就照portainer的做。
service: service名
services:
service名:
loadBalancer:
servers:
- url: https?://ip:端口
在servers可以填http或者https地址,在tcp服务填tcp,udp填udp。然后既然是loadBalancer,就能同时填多个服务地址。
middlewares:
https-redirectscheme:
redirectScheme:
scheme: https
permanent: true
这是一个叫redirectScheme的middleware。
default-headers:
headers:
frameDeny: true
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 15552000
customFrameOptionsValue: SAMEORIGIN
customRequestHeaders:
X-Forwarded-Proto: https
这是啥,天书吗,完全不知道从哪下手,也不知道怎么查相关资料,再次翻车。
一个容器翻了3次车,我也是不容易啊。
附件
接上篇的webmin和pihole。这2个反代是有坑的。记得域名绑定的对象是traefik所在机器的IP。
rp-webmin.yml:
http:
routers:
webmin:
entryPoints:
- web
rule: "Host(`webmin.子域名.duckdns.org`)"
middlewares:
- https-redirectscheme
service: webmin
webmin-secure:
entryPoints:
- websecure
rule: "Host(`webmin.子域名.duckdns.org`)"
middlewares:
- default-headers
tls: {}
service: webmin
services:
webmin:
loadBalancer:
servers:
- url: https://192.168.0.130:10000
在traefik只能做这么多,然后访问webmin会出现警告,具体是啥我也忘了,好像是非信赖域名的锅,我好像是去了networking那又跳提示,我跟着做,改了什么设置后就行了。
rp-pihole.yml:
http:
routers:
pihole:
entryPoints:
- web
rule: "Host(`pihole.子域名.duckdns.org`)"
middlewares:
- https-redirectscheme
service: pihole
pihole-secure:
entryPoints:
- websecure
rule: "Host(`pihole.子域名.duckdns.org`)"
middlewares:
- default-headers
- pihole-redirectprefix
tls: {}
service: pihole
services:
pihole:
loadBalancer:
servers:
- url: "http://192.168.0.140:80"
middlewares:
pihole-redirectprefix:
redirectRegex:
regex: "^(https?://pihole.子域名.duckdns.org/)$"
replacement: "/admin"
permanent: false
用ip访问pihole的ip:端口时不是会提示Did you mean to go to the admin panel?吗。反向代理后不会出现这页面,会出现error,不信你试试。解决方法就是加/admin这个路径。不会正则表达式我只能那么写了。
好了,下篇翻车的sso+mfa。

![翻车的home server经验分享-反向代理 [traefik]](https://qna.smzdm.com/202208/12/62f5e5e2dcc944267.jpg_e1080.jpg)
![翻车的home server经验分享-反向代理 [traefik]](https://am.zdmimg.com/202208/12/62f61606843cb2535.png_e1080.jpg)
![翻车的home server经验分享-反向代理 [traefik]](https://am.zdmimg.com/202208/12/62f61632457621986.png_e1080.jpg)
![翻车的home server经验分享-反向代理 [traefik]](https://qnam.smzdm.com/202208/12/62f617964bd4c3637.png_e1080.jpg)
![翻车的home server经验分享-反向代理 [traefik]](https://am.zdmimg.com/202208/12/62f6180b1fc7f7941.png_e1080.jpg)
![翻车的home server经验分享-反向代理 [traefik]](https://am.zdmimg.com/202208/12/62f619629483e5070.png_e1080.jpg)

![翻车的home server经验分享-反向代理 [traefik]](https://qnam.smzdm.com/202208/12/62f61bd5e326d3760.png_e1080.jpg)
![翻车的home server经验分享-反向代理 [traefik]](https://am.zdmimg.com/202208/12/62f61be84566b6359.png_e1080.jpg)
![翻车的home server经验分享-反向代理 [traefik]](https://qnam.smzdm.com/202208/12/62f61c097c4f18727.png_e1080.jpg)
![翻车的home server经验分享-反向代理 [traefik]](https://qnam.smzdm.com/202208/12/62f61c317e2999249.png_e1080.jpg)
![翻车的home server经验分享-反向代理 [traefik]](https://qnam.smzdm.com/202208/12/62f61c42efee69247.png_e1080.jpg)
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案
校验提示文案