Traefik
是一个云原生的新型 HTTP 反向代理、负载均衡软件。作用类似于 nginx
,在全 docker
环境中,Traefik
会比 nginx
配置简略很多。我使用过 nginx
反代 docker
同网络(networks)下的其他服务,统一出口,使用泛域名解析,但是当 docker
数量变多时,每新增一个 docker
都要手动复制一份文件,尝试向 Traefik
迁移
本文借鉴官方文档 、traefik 仓库示例 、Traefik 全自动 HTTPS 方案
本文以反代 alist
举例,在以往 nginx
环境中通常需要在 nginx.conf
中为每个服务创建配置文件
nginx 举例 创建 nginx.conf
,并映射到 /etc/nginx/nginx.conf
nginx 的 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 services: nginx: image: nginx:1.25.3 container_name: nginx restart: always volumes: - ./data/conf/nginx.conf:/etc/nginx/nginx.conf - ./data/html:/usr/share/nginx/html - ./data/logs:/var/log/nginx - ./data/conf.d:/etc/nginx/conf.d - ./data/ssl:/etc/nginx/ssl - ../php/data:/var/www/html environment: - TZ=Asia/Shanghai - PUID=1000 - PGID=1000 mem_limit: 400m memswap_limit: -1 ports: - 80 :80 - 443 :443 networks: - my_net
nginx.conf
内容为
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 user nginx;worker_processes auto;error_log /var/log/nginx/error .log notice ;pid /var/run/nginx.pid;events { worker_connections 1024 ; } http { include /etc/nginx/mime.types; default_type application/octet-stream; server_tokens off ; proxy_intercept_errors on ; log_format main '$remote_addr - $remote_user [$time_local ] "$request " ' '$status $body_bytes_sent "$http_referer " ' '"$http_user_agent " "$http_x_forwarded_for "' ; access_log on ; access_log /var/log/nginx/access.log; proxy_cache_path /tmp/cache keys_zone=mycache:10m levels=1 :2 inactive=60s ; sendfile on ; keepalive_timeout 65 ; gzip on ; include /etc/nginx/conf.d/*.conf ; }
注意上面引入了 /etc/nginx/conf.d/*.conf;
/etc/nginx/conf.d 目录下的所有 .conf 文件
在 /data/conf.d
中创建 alist.conf
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 server { listen 80 ; listen 443 ssl; http2 on ; server_name alist.xx.cn; if ($server_port !~ 443) { rewrite ^(/.*)$ https://$host $1 permanent ; } include /etc/nginx/ssl/error .conf; include /etc/nginx/ssl/ssl.conf; location / { resolver 127.0.0.11 valid=30s ipv6=off ; resolver_timeout 2s ; set $upstream_host http://alist:5244; proxy_pass $upstream_host ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header X-Forwarded-Proto $scheme ; proxy_set_header Host $host :$server_port ; proxy_set_header X-Forwarded-Host $http_host ; proxy_set_header X-Real-IP $remote_addr ; proxy_set_header Range $http_range ; proxy_set_header If-Range $http_if_range ; proxy_redirect off ; client_max_body_size 20000m ; client_body_buffer_size 128k ; } }
写入如上内容,这样就将 alist.xx.cn
的请求全部转发到 http://alist:5244
中(alist 为 docker-compose.yml 配置中的服务名,docker 会自动添加 host 映射),alist 的 docker-compose.yml
示例
1 2 3 4 services: alist: restart: always ...
这种写法虽然简单清晰,但是需要为每种 docker 都创建一份 conf
配置,而 traefik
可以简化这点,通过简单的配置即可自动查找
Traefik 介绍及举例 Traefik 启动时会读取配置文件和 Docker Compose 配置中的各个服务。请求进入时候,将会按这样一个顺序解析:
1 2 3 4 -> Entrypoint (入口, 80/443) -> Router (规则, 例如子域名为 www) -> Service (服务) -> LoadBalancer (源地址, 这里可以设定用 Docker 容器内的哪个端口)
同时,启动时会根据你设定的域名,向 Let’s Encrypt 申请泛域名 ACME 证书,用于 HTTPS.
安装配置 首先当然需要 Docker 和 Docker Compose (Tutorial ).
然后,新建一个文件夹,新建一个 docker-compose.yml(我这里多写了 alist 的 docker 配置):
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 services: traefik: image: traefik:v3.3 command: --providers.docker container_name: traefik restart: always ports: - "80:80" - "443:443" security_opt: - no -new-privileges:true volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./traefik/static.yml:/traefik.yml:ro - ./traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro - ./traefik/acme.json:/acme.json:rw - ./traefik/traefik.log:/var/log/traefik.log:rw - /etc/localtime:/etc/localtime:ro environment: - CF_API_EMAIL= - CF_API_KEY= - CF_DNS_API_TOKEN= labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`dash.example.com`)" - "traefik.http.routers.dashboard.service=api@internal" network_mode: bridge alist: restart: always volumes: - "./alist:/opt/alist/data" container_name: alist environment: - PUID=1000 - PGID=1000 - UMASK=022 mem_limit: 300m memswap_limit: 400m image: "xhofe/alist:latest" labels: - traefik.enable=true - traefik.http.routers.alist.rule=Host(`alist.example.com`) - traefik.http.services.alist.loadbalancer.server.port=5244 network_mode: bridge
然后创建一个文件夹 traefik
存配置和日志
1 2 mkdir traefiktouch traefik/{static.yml, dynamic.yml, acme.json, traefik.log}
这几个文件分别的作用及内容:
traefik/static.yml
: 静态配置,改了需要重启 Traefik.traefik/dynamic.yml
: 动态配置,改了不需要重启 Traefik.traefik/acme.json
: 申请 HTTPS 时自动存储的密钥.traefik/traefik.log
: 日志文件.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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 global: checkNewVersion: true sendAnonymousUsage: true entryPoints: web: address: :80 websecure: address: :443 http: tls: certResolver: le-dns domains: - main: "example.com" sans: - "*.example.com" certificatesResolvers: le-dns: acme: email: xxx@gmail.com storage: "/acme.json" dnsChallenge: provider: cloudflare log: level: INFO filePath: /var/log/traefik.log api: insecure: false dashboard: true providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false network: web defaultRule: Host(`{{if index .Labels "com.docker.compose.service" }}{{ index .Labels "com.docker.compose.service" }}.example.com{{else}}{{ trimPrefix `/` .Name }}.example.com{{end}}`) file: filename: "/etc/traefik/dynamic.yml"
这里需要解释一下:
defaultRule
这一行,表示当启用 traefik 时,默认使用 docker-compose 中的服务名作为子域名.provider
这一行,如果不使用 cloudflare 作为 DNS 服务商,可以自行根据 WIKI 修改.第二个文件 traefik/dynamic.yml: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 http: routers: all-https: rule: "HostRegexp(`{host:.+}`)" entryPoints: - web tls: true middlewares: - to-https - gzip-compress priority: 500 service: noop@internal middlewares: to-https: redirectScheme: scheme: https gzip-compress: compress: defaultEncoding: gzip excludedContentTypes: - text/event-stream
解释:
all-https
这一行,表示在 web
入口 (80 端口,也就是 HTTP) 请求任何子域名时,使用 to-https
中间件 (也就是重定向到 https
). 该条目优先级为 500, 也就是我们如果设定某个服务优先级为 500 以上,就可以不自动跳转 HTTPS.gzip-compress
这一行代表开启 gzip 压缩最后调整环境变量: 1 2 3 4 environment: - CF_API_EMAIL= - CF_API_KEY= - CF_DNS_API_TOKEN=
这个主要是用于启用 HTTPS 时,需要通过 Let’s Encrypt
的所有权认证,Traefik
会自动新建一个临时的 DNS 解析记录用于认证。怎么获得?
进入 Cloudflare
控制台,进入 我的个人资料 中的 API 令牌,创建一个 Token, 需要在 所有区域
具有 区域读取
, DNS 编辑
权限,完成后复制 Token
填入.
然后,创建一个 Cloudflare
的泛解析记录到服务器:
然后运行
1 docker compose up -d --force-recreate --build