Traefik反向代理:HTTPS带端口请求转对应HTTP服务配置求助
问题背景
已将www.example.com指向后端公网IP,后端配置NAT转发规则到不同服务。需求是:处理https://www.example.com:<端口>/health请求,将其路由到对应端口的/health路径。
尝试用Traefik RedirectRegex中间件实现失败,容器构建正常但SSL验证不通过——http://www.example.com:7001/health可正常访问,https://www.example.com:7001/health无法访问。因服务端口动态变化且数量多,不想为每个端口单独建容器(此前方案管理成本高,不利于SSL问题排查),需通用容器处理所有这类请求。
现有配置
.env 文件
REGEX_PATTERN=^(https://[^/]+):([^/]+)/?(.*)$ REGEX_REPLACEMENT=$${1}/$${3}:$${2}
docker-compose.yml 文件
services: whoami: image: "traefik/whoami" container_name: "simple-service" labels: - "traefik.enable=true" - "traefik.http.routers.whoami-rule1.rule=Host(`www.example.com`)" - "traefik.http.routers.whoami-rule1.entrypoints=websecure" - "traefik.http.routers.whoami-rule1.tls.certresolver=myresolver" - "traefik.http.routers.whoami-rule1.middlewares=whoami-rule1-port-redirect" - "traefik.http.middlewares.whoami-rule1-port-redirect.redirectregex.regex=${REGEX_PATTERN}" - "traefik.http.middlewares.whoami-rule1-port-redirect.redirectregex.replacement=${REGEX_REPLACEMENT}" - "traefik.http.middlewares.whoami-rule1-port-redirect.redirectregex.permanent=true"
解决方案
1. 修复SSL验证失败问题
当前Traefik仅监听websecure入口点(默认443端口),https://www.example.com:7001这类自定义端口的HTTPS请求未被Traefik处理,直接到达后端但后端未配置对应SSL证书,导致验证失败。
解决步骤:
- 在Traefik静态配置中添加覆盖服务端口范围的入口点,比如在Traefik的
traefik.yml或docker-compose的Traefik服务配置中:entryPoints: websecure: address: ":443" service-ports: address: ":7000-8000" # 替换为你的实际服务端口范围 - 在路由规则中将
entrypoints改为websecure,service-ports,让Traefik监听这些端口并提供TLS证书:- "traefik.http.routers.whoami-rule1.entrypoints=websecure,service-ports" - 确保Traefik容器映射了这些端口到主机:
在Traefik服务的ports字段添加:- "7000-8000:7000-8000"
2. 修正重定向/路由逻辑
原正则规则逻辑错误,会将https://www.example.com:7001/health转换为https://www.example.com/health:7001,这不符合需求。根据你的场景,反向代理比重定向更合适(无需修改URL,直接转发请求到后端对应端口):
调整为反向代理配置
修改whoami服务的Traefik标签,去掉重定向中间件,添加服务转发配置:
labels: - "traefik.enable=true" - "traefik.http.routers.health-proxy.rule=Host(`www.example.com`) && Path(`/health`)" - "traefik.http.routers.health-proxy.entrypoints=websecure,service-ports" - "traefik.http.routers.health-proxy.tls.certresolver=myresolver" # 转发到主机对应端口的/health(依赖后端NAT规则) - "traefik.http.services.health-proxy.loadbalancer.server.url=http://host.docker.internal:{{range $p, $conf := .ContainerConfig.ExposedPorts}}{{$p | splitSlice ":" | first}}{{end}}/health"
如果你的服务端口是动态的,也可以通过标签指定端口,或者利用Traefik的动态配置能力自动发现端口。
3. 简化通用配置建议
如果需要一个完全通用的容器处理所有/health请求,可以创建一个专门的代理容器,配置Traefik路由匹配所有带端口的www.example.com的/health路径,然后转发到主机对应端口:
services: health-proxy: image: nginx:alpine # 或用traefik/whoami测试 container_name: health-proxy labels: - "traefik.enable=true" - "traefik.http.routers.health-proxy.rule=Host(`www.example.com`) && Path(`/health`)" - "traefik.http.routers.health-proxy.entrypoints=websecure,service-ports" - "traefik.http.routers.health-proxy.tls.certresolver=myresolver" # 动态获取请求端口并转发到主机对应端口 - "traefik.http.middlewares.health-proxy-add-port.addprefix.prefix=http://host.docker.internal:{{index .Request.Port}}/" - "traefik.http.routers.health-proxy.middlewares=health-proxy-add-port" - "traefik.http.services.health-proxy.loadbalancer.server.port=80"
(注:{{index .Request.Port}}是Traefik的模板变量,需确保Traefik启用模板支持)
内容的提问来源于stack exchange,提问作者Saksham

