如何用Traefik基于协议将app.example.com路由到不同Docker容器?
用Traefik实现同一域名下REST与WebSocket服务的路由分流
这是Traefik里非常典型的基于请求特征的路由场景,咱们直接用Docker Compose来配置,步骤清晰又好维护。
核心思路
Traefik可以通过请求头特征区分WebSocket请求(因为WebSocket是从HTTP协议升级而来的,请求里会带Upgrade: websocket和Connection: Upgrade这两个关键头),再结合域名匹配,把普通HTTP请求转发到REST容器,把WebSocket升级请求转发到WebSocket容器。
完整Docker Compose配置
先上完整的docker-compose.yml,我会逐行解释关键部分:
version: '3.8' # 自定义网络,让Traefik和两个应用容器互通 networks: traefik-net: external: false services: # Traefik 反向代理服务 traefik: image: traefik:v2.10 # 用稳定版,避免兼容性问题 command: - "--api.insecure=true" # 开启API面板(仅测试用,生产建议关闭或加认证) - "--providers.docker=true" # 启用Docker自动发现 - "--providers.docker.exposedbydefault=false" # 只处理显式配置了Traefik标签的容器 - "--entrypoints.web.address=:80" # 监听80端口作为HTTP入口 ports: - "80:80" - "8080:8080" # API面板端口,测试用 volumes: - "/var/run/docker.sock:/var/run/docker.sock" # 挂载Docker套接字,让Traefik能发现容器 networks: - traefik-net # REST 服务容器 rest-service: image: your-rest-image:latest # 替换成你的REST应用镜像 networks: - traefik-net labels: - "traefik.enable=true" # 允许Traefik处理这个容器 - "traefik.http.routers.rest.rule=Host(`app.example.com`)" # 匹配域名app.example.com的请求 - "traefik.http.routers.rest.entrypoints=web" # 使用web入口点 - "traefik.http.services.rest.loadbalancer.server.port=80" # 转发到容器的80端口 # WebSocket 服务容器 ws-service: image: your-ws-image:latest # 替换成你的WebSocket应用镜像 networks: - traefik-net labels: - "traefik.enable=true" - "traefik.http.routers.ws.rule=Host(`app.example.com`) && Headers(`Upgrade`, `websocket`) && Headers(`Connection`, `Upgrade`)" # 匹配域名+WebSocket升级头 - "traefik.http.routers.ws.entrypoints=web" - "traefik.http.services.ws.loadbalancer.server.port=90" # 转发到容器的90端口
关键配置解释
- 自定义网络:
traefik-net确保三个容器在同一个网络内,Traefik可以直接通过容器名访问应用服务,不需要暴露端口到宿主机。 - Traefik核心配置:
--providers.docker=true:开启Docker自动发现,Traefik会自动读取容器上的Traefik标签来配置路由。--providers.docker.exposedbydefault=false:避免Traefik自动代理所有容器,只处理显式开启traefik.enable=true的容器。
- REST服务路由:
- 仅通过
Host(app.example.com)匹配所有发往该域名的HTTP请求,转发到容器的80端口。
- 仅通过
- WebSocket服务路由:
- 除了匹配域名,还通过
Headers规则筛选出带有WebSocket升级头的请求,转发到容器的90端口。Traefik会自动处理WebSocket的连接保持,不需要额外配置。
- 除了匹配域名,还通过
验证方法
- 测试REST服务:用curl发送普通HTTP请求
应该能得到REST服务的响应。curl http://app.example.com/your-rest-endpoint - 测试WebSocket服务:用
wscat(需要先安装npm install -g wscat)连接
如果连接成功,就说明路由生效了。wscat -c ws://app.example.com/your-ws-endpoint
生产环境注意事项
- 关闭Traefik的
api.insecure=true,改用认证(比如Basic Auth)或者直接关闭API面板。 - 建议配置HTTPS(Let's Encrypt自动证书),把WebSocket换成
wss://,对应Traefik的HTTPS入口点。 - 如果你的WebSocket服务有特定路径,可以在路由规则里加上
Path(/ws)之类的条件,进一步精准匹配。
内容的提问来源于stack exchange,提问作者dov.amir




