求助:使用Traefik配置多Docker容器在自定义域名80端口运行失败
问题描述
我尝试用Traefik和Docker Desktop配置多个容器,让它们通过同一自定义域名dev.mydomain.com的80端口访问,具体需求:
- 容器
content对应访问地址:http://dev.mydomain.com/docs/contents/swagger - 容器
basket对应访问地址:http://dev.mydomain.com/docs/baskets/swagger
已修改本地hosts文件,将dev.mydomain.com指向127.0.0.0(注:此处为错误配置,正确回环地址应为127.0.0.1)。
当前Traefik运行脚本:
docker run -d --name traefik \ --network dev-mobile \ --publish 80:8080 --publish 8099:8099 \ --volume /var/run/docker.sock:/var/run/docker.sock \ traefik:v2.10 --api.insecure=true --providers.docker=true --entrypoints.dev-mobile.address=:8080 --entrypoints.traefik.address=:8099
Basket容器的Dockerfile(其他容器配置类似):
FROM mcr.microsoft.com/dotnet/sdk:8.0 ARG VERSION ENV DD_VERSION=${VERSION} WORKDIR /app COPY ./<my files> . EXPOSE 8080 USER app ENTRYPOINT ["dotnet", "<my dll entrypoint>"]
构建命令:
docker build -t basket_image -f ./local-docker/Dockerfile.Basket .
运行命令:
docker run -d --name basket \ --network dev-mobile \ -e ASPNETCORE_ENVIRONMENT=Local \ --label "traefik.enable=true" \ --label "traefik.http.routers.basket.rule=Host(`dev.mydomain.com`)" \ --label "traefik.http.services.basket.loadbalancer.server.port=80" \ basket_image
问题现象:直接访问http://dev.mydomain.com/docs/baskets/swagger出现404错误,但如果给容器加端口映射(比如-p 8090:8080),并把Traefik服务端口改成8090,就能通过http://dev.mydomain.com:8090/docs/baskets/swagger正常访问。
错误分析与修正方案
你的配置存在三个核心问题,逐一修正即可解决:
1. Hosts文件地址错误
将dev.mydomain.com指向127.0.0.0是无效的回环地址,必须改成127.0.0.1。修改后刷新DNS缓存:
- Windows:执行
ipconfig /flushdns - macOS/Linux:执行
sudo killall -HUP mDNSResponder
2. Traefik入口点与容器端口不匹配
- 你定义了
dev-mobile入口点绑定Traefik容器内部的8080端口,但未指定路由器使用该入口点,Traefik默认会尝试使用未定义的web入口点,导致路由失效。 - .NET容器默认监听8080端口(Dockerfile也声明了
EXPOSE 8080),但你在Traefik标签中写了server.port=80,完全不符合容器实际监听端口。
3. 路由规则缺少路径区分
两个容器的路由规则都是Host(dev.mydomain.com),Traefik无法判断请求该转发给哪个容器,必须添加路径前缀匹配规则。同时因为外部访问路径带前缀/docs/baskets,而容器内Swagger路径是/swagger,需要用中间件剥离前缀后再转发。
修正后的完整配置
1. 修正Traefik启动命令
指定路由器默认使用dev-mobile入口点,关闭默认暴露容器,避免干扰:
docker run -d --name traefik \ --network dev-mobile \ --publish 80:8080 --publish 8099:8099 \ --volume /var/run/docker.sock:/var/run/docker.sock \ traefik:v2.10 \ --api.insecure=true \ --providers.docker=true \ --providers.docker.exposedbydefault=false \ --entrypoints.dev-mobile.address=:8080 \ --entrypoints.traefik.address=:8099 \ --api.dashboard=true
2. 修正Basket容器运行命令
添加路径匹配、入口点绑定、前缀剥离中间件:
docker run -d --name basket \ --network dev-mobile \ -e ASPNETCORE_ENVIRONMENT=Local \ --label "traefik.enable=true" \ --label "traefik.http.routers.basket.entrypoints=dev-mobile" \ --label "traefik.http.routers.basket.rule=Host(`dev.mydomain.com`) && PathPrefix(`/docs/baskets`)" \ --label "traefik.http.services.basket.loadbalancer.server.port=8080" \ --label "traefik.http.routers.basket.middlewares=basket-stripprefix" \ --label "traefik.http.middlewares.basket-stripprefix.stripprefix.prefixes=/docs/baskets" \ basket_image
3. 修正Content容器运行命令
同理配置对应路径规则:
docker run -d --name content \ --network dev-mobile \ -e ASPNETCORE_ENVIRONMENT=Local \ --label "traefik.enable=true" \ --label "traefik.http.routers.content.entrypoints=dev-mobile" \ --label "traefik.http.routers.content.rule=Host(`dev.mydomain.com`) && PathPrefix(`/docs/contents`)" \ --label "traefik.http.services.content.loadbalancer.server.port=8080" \ --label "traefik.http.routers.content.middlewares=content-stripprefix" \ --label "traefik.http.middlewares.content-stripprefix.stripprefix.prefixes=/docs/contents" \ content_image
关键说明
- 前缀剥离中间件:外部访问路径
/docs/baskets/swagger会被剥离/docs/baskets,转发给容器的/swagger路径,匹配容器内的Swagger端点。 - 端口正确性:严格匹配.NET容器实际监听的8080端口,不能随意填写其他端口。
- 入口点绑定:明确指定路由器使用
dev-mobile入口点,确保Traefik能正确接收并转发宿主机80端口的请求。
内容的提问来源于stack exchange,提问作者Zen Pak
相关产品推荐
相关产品推荐

