Caddy跟Traefik都有反向代理的功能,主要用途是為平衡負載後端服務並提供自動HTTPS配置。最近我從Caddy轉到使用Traefik,下文來分享一下過程跟一點點感想。
Nginx到Caddy
在講Caddy前必須提一下老牌網頁伺服器Nginx,它一樣有反向代理的功能。在過了Apache2入門後,下一個接觸的網頁伺服器就是Nginx。但Nginx在配置上(尤其是HTTPS)還是挺自由複雜的,需要搭配Cert Bot之類的程式才能做到證書自動續約。雖然可以,但不好用。網上也有開源專案Nginx Proxy Manager幫忙整合HTTPS和提供人性化Web UI配置,(但偶爾會有點不穩定,所以放棄了)
這時候Caddy就出現在我眼前,標榜自動HTTPS和HTTP/2,配置檔案語法也簡單,於是我就毫不猶豫跳槽到Caddy。誰用誰知道,用過都說好,自從用上了Caddy,我就再也不想回去Nginx了。
Cloud Native時代 – Traefik
Caddy確實穩定地服務了好幾年,從在主機直接跑服務到用Docker跑服務,唯有Caddy一直不變(好的意義上)。如果沒有一點點契機,那我還不一定會去動我們的老大Caddy。(契機是什麼?就是我蹲到新的OVH Cloud新加坡機房的VPS機器啦,相同價錢,配置大升級)
Traefik的功能定位上其實跟Caddy是有些微差別,Caddy的定位是傻瓜式配置的Web伺服器,而Traefik則是Cloud Native反向代理伺服器,對Docker有良好支援。正好我99.9%的服務已經轉移到Docker上跑,搭配Traefik有如虎添翼的效果。
對的,Traefik也是用Docker就能跑起來,可以放我在正式環境跑的compose配置當例子:
services:
traefik:
image: traefik:v3.5
command:
- --api.dashboard=true
- --providers.file.filename=/etc/traefik/dynamic.yml
- --providers.docker=true
- --providers.docker.network=proxy
- --providers.docker.exposedByDefault=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entrypoints.websecure.http.tls=true
- --entrypoints.websecure.http.tls.certresolver=cloudflare
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --certificatesresolvers.cloudflare.acme.dnschallenge=true
- --certificatesresolvers.cloudflare.acme.dnschallenge.provider=cloudflare
- --certificatesresolvers.cloudflare.acme.email=example@example.com
- --certificatesresolvers.cloudflare.acme.storage=/letsencrypt/acme.json
environment:
- CF_DNS_API_TOKEN=${CLOUDFLARE_API_TOKEN}
ports:
- 80:80
- 443:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
- ./dynamic.yml:/etc/traefik/dynamic.yml
networks:
- proxy
labels:
- traefik.enable=true
- traefik.http.routers.traefik.rule=Host(`traefik.reinforce.moe`)
- traefik.http.routers.traefik.entrypoints=websecure
- traefik.http.routers.traefik.service=api@internal
- traefik.http.routers.traefik.middlewares=tinyauth
networks:
proxy:
external: true
上面的compose檔案分別做了以下幾件事:
- 監聽80和443端口
- TLS證書用Cloudflare DNS方式來驗證
- 自動將http導向到https
- 從Docker Label來動態設定服務路由(就是反向代理)
- 將Traefik Dashboard放到https://traefik.reinforce.moe並添加登入驗證
順帶一提我用的是CLI方式來設定Traefik,其實也可以用YAML檔案來配置,但直接寫在compose檔案的好處是可以用Docker網頁界面(例如Portainer)管理配置,跟SSH和Vim說再見。
Traefik跑起來之後,就可以在其他服務的compose檔案設定Docker Label。這裡繼續大方分享正式環境的compose檔案:
version: "3.9"
services:
server:
build: .
restart: always
environment:
TZ: Asia/Hong_Kong
volumes:
- ./data/www:/var/www/html
- ./data/my_php.ini:/usr/local/etc/php/conf.d/my_php.ini
- ./data/my_apache2.conf:/etc/apache2/conf-enabled/my_apache2.conf
extra_hosts:
- host.docker.internal:host-gateway
labels:
traefik.enable: true
traefik.http.routers.apache2.rule: Host(`reinforce.moe`)
networks:
- database
- proxy
networks:
database:
external: true
proxy:
external: true
要讓Traefik懂得將https://reinforce.moe/指到上面的PHP伺服器,只要兩行:啟用Traefik和設定域名;完。
還不夠?沒關係我再分享Portainer,這個比較困難,因為Portainer預設用https自簽證書跑,花了我5行Labels跟一個YAML設定檔案才搞定:
services:
portainer:
container_name: portainer
image: portainer/portainer-ce:lts
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/data
#ports:
#- 9443:9443
#- 8000:8000 # Remove if you do not intend to use Edge Agents
networks:
- proxy
labels:
traefik.enable: true
traefik.http.routers.portainer.rule: Host(`portainer.reinforce.moe`)
traefik.http.services.portainer.loadbalancer.server.port: 9443
traefik.http.services.portainer.loadbalancer.server.scheme: https
traefik.http.services.portainer.loadbalancer.serverstransport: skipssl@file
networks:
default:
name: portainer_network
proxy:
external: true
http:
serversTransports:
skipssl:
insecureSkipVerify: true
(不知道是Bug還是Feature,沒辦法用CLI或者Label來設定serversTransports,只好用YAML檔案了)
可以看到內部服務就這樣透過Traefik開放出來了,不需要再想要用哪個Port,每個服務實際跑在哪個網址也能一眼看到,開新服務也不用再SSH到主機上用Vim去手動修改Caddy配置檔案,所有東西在Web界面就能做,方便。