Traefik 入门及全自动 HTTPS

tsvico Lv5

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:
#jenkins服务/其他服务(web服务/nginx服务等)
image: nginx:1.25.3 #nginx镜像
#image: jungsoft/alpine-nginx-forward-proxy:1.25.4
container_name: nginx #容器的名称
restart: always #跟随docker的启动而启动
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 # php映射路径
environment:
- TZ=Asia/Shanghai
- PUID=1000
- PGID=1000
mem_limit: 400m
memswap_limit: -1
ports:
- 80:80 #宿主主机端口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; #添加,关闭版本号
#fastcgi_intercept_errors on;
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;
#tcp_nopush 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;# 服务器地址或绑定域名

#HTTP_TO_HTTPS_START
if ($server_port !~ 443) {
rewrite ^(/.*)$ https://$host$1 permanent;
}
#HTTP_TO_HTTPS_END

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;
# the max size of file to upload
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:
# The official v3 Traefik docker image
image: traefik:v3.3
command: --providers.docker
container_name: traefik
restart: always
ports:
# The HTTP port
- "80:80"
- "443:443"
# - "8080:8080"
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 traefik
touch traefik/{static.yml, dynamic.yml, acme.json, traefik.log}

这几个文件分别的作用及内容:

  • traefik/static.yml: 静态配置,改了需要重启 Traefik.
  • traefik/dynamic.yml: 动态配置,改了不需要重启 Traefik.
  • traefik/acme.json: 申请 HTTPS 时自动存储的密钥.
  • traefik/traefik.log: 日志文件.

第一个文件 traefik/static.yml (请将 example.com 替换为你的域名):

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 configuration
################################################################

# EntryPoints definition
#
# Optional
#
entryPoints:
web:
address: :80

websecure:
address: :443
http:
tls:
# 通过 路由部分的host自动生成证书(Let's Encrypt)
certResolver: le-dns
domains:
- main: "example.com"
sans:
- "*.example.com"

certificatesResolvers:
le-dns:
acme:
email: xxx@gmail.com
storage: "/acme.json"
dnsChallenge:
provider: cloudflare

################################################################
# 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: /var/log/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: /path/to/log/log.txt

# Format is either "json" or "common".
#
# Optional
# Default: "common"
#
# format: json

################################################################
# API and dashboard configuration
################################################################

# Enable API and dashboard
#
# Optional
#
api:
insecure: false
dashboard: true

################################################################
# Ping configuration
################################################################

# Enable ping
#ping:
# Name of the related entry point
#
# Optional
# Default: "traefik"
#
# entryPoint: traefik

################################################################
# Docker configuration backend
################################################################

providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: web
# 当启用 traefik 时, 默认使用 docker-compose 中的服务名作为子域名
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:
# 在 web 入口 (80端口, 也就是 HTTP) 请求任何子域名时, 使用 to-https 中间件 (也就是重定向到 https). 该条目优先级为 500, 也就是我们如果设定某个服务优先级为 500 以上, 就可以不自动跳转 HTTPS.
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 填入.
pECcKjU.png
pECcUgK.png

然后,创建一个 Cloudflare 的泛解析记录到服务器:

pECcsUA.png

然后运行

1
docker compose up -d --force-recreate --build
  • 标题: Traefik 入门及全自动 HTTPS
  • 作者: tsvico
  • 创建于 : 2025-01-09 18:47:36
  • 更新于 : 2025-01-09 21:42:50
  • 链接: https://blog.tbox.fun/2025/3450057868.html
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论