Docker Swarm下Traefik代理前端服务报invalid host header问题求助
问题:Docker Swarm中前端服务通过Traefik域名访问报"invalid host header",IP+端口正常
我搭建了单节点Docker Swarm集群,Traefik和Portainer已通过HTTPS正常运行。用和Portainer相同的Traefik标签配置部署前端服务后,域名访问出现"invalid host header"错误,但IP加端口访问正常,求解决。
前端服务配置(问题文件)
# Problem File : Frontend version: '3' networks: {{traefik_network_name}}: external: true services: frontend_portal: image: frontend_portal build: context: . dockerfile: Dockerfile ports: - 3000:3000 networks: - {{traefik_network_name}} volumes: - .:/app environment: - CHOKIDAR_USEPOLLING=true deploy: replicas: 1 labels: - traefik.enable=true - traefik.docker.network={{ traefik_network_name }} - traefik.constraint-label={{ traefik_network_name }} - traefik.http.routers.frontend_portal-http.rule=Host(`dashboard.my.domain`) - traefik.http.routers.frontend_portal-http.entrypoints=http - traefik.http.routers.frontend_portal-http.middlewares=https-redirect - traefik.http.routers.frontend_portal-https.rule=Host(`dashboard.my.domain`) - traefik.http.routers.frontend_portal-https.entrypoints=https - traefik.http.routers.frontend_portal-https.tls=true - traefik.http.routers.frontend_portal-https.tls.certresolver=le - traefik.http.services.frontend_portal.loadbalancer.server.port=3000
Traefik配置
# Traefik version: '3.3' services: traefik: image: traefik:v2.10 ports: - 80:80 - 443:443 deploy: replicas: 1 placement: constraints: - node.role == manager labels: - traefik.enable=true - traefik.docker.network={{traefik_network_name}} - traefik.constraint-label={{traefik_network_name}} - traefik.http.middlewares.admin-auth.basicauth.users={{traefikpassword.stdout}} - traefik.http.middlewares.https-redirect.redirectscheme.scheme=https - traefik.http.middlewares.https-redirect.redirectscheme.permanent=true - traefik.http.routers.traefik-public-http.rule=Host(`{{traefik_app_name}}.{{app_domain_name}}`) - traefik.http.routers.traefik-public-http.entrypoints=http - traefik.http.routers.traefik-public-http.middlewares=https-redirect - traefik.http.routers.traefik-public-https.rule=Host(`{{traefik_app_name}}.{{app_domain_name}}`) - traefik.http.routers.traefik-public-https.entrypoints=https - traefik.http.routers.traefik-public-https.tls=true - traefik.http.routers.traefik-public-https.service=api@internal - traefik.http.routers.traefik-public-https.tls.certresolver=le - traefik.http.routers.traefik-public-https.middlewares=admin-auth - traefik.http.services.traefik-public.loadbalancer.server.port=8080 volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - {{ storage_mount_path }}/{{ traefik_subdir }}:/certificates command: - --providers.docker - --providers.docker.constraints=Label(`traefik.constraint-label`, `{{traefik_network_name}}`) - --providers.docker.exposedbydefault=false - --providers.docker.swarmmode - --entrypoints.http.address=:80 - --entrypoints.https.address=:443 - --certificatesresolvers.le.acme.email={{email}} - --certificatesresolvers.le.acme.storage=/certificates/acme.json - --certificatesresolvers.le.acme.tlschallenge=true - --accesslog - --log - --api networks: - {{traefik_network_name}} networks: {{traefik_network_name}}: external: true
Portainer配置
# Portainer version: '3.3' services: agent: image: portainer/agent:2.18.4 environment: AGENT_CLUSTER_ADDR: tasks.agent volumes: - /var/run/docker.sock:/var/run/docker.sock - /var/lib/docker/volumes:/var/lib/docker/volumes networks: - {{portainer_network_name}} deploy: mode: global placement: constraints: - node.platform.os == linux portainer: image: portainer/portainer-ce:2.18.4 command: "-H tcp://tasks.agent:9001 --tlsskipverify --admin-password {{portainerpassword.stdout}}" volumes: - {{portainer_volume_name}}:/data networks: - {{portainer_network_name}} - {{traefik_network_name}} deploy: replicas: 1 placement: constraints: - node.role == manager labels: - traefik.enable=true - traefik.docker.network={{ traefik_network_name }} - traefik.constraint-label={{ traefik_network_name }} - traefik.http.routers.portainer-http.rule=Host(`{{portainer_app_name}}.{{app_domain_name}}`) - traefik.http.routers.portainer-http.entrypoints=http - traefik.http.routers.portainer-http.middlewares=https-redirect - traefik.http.routers.portainer-https.rule=Host(`{{portainer_app_name}}.{{app_domain_name}}`) - traefik.http.routers.portainer-https.entrypoints=https - traefik.http.routers.portainer-https.tls=true - traefik.http.routers.portainer-https.tls.certresolver=le - traefik.http.services.portainer.loadbalancer.server.port={{portainer_admin_port}} networks: {{portainer_network_name}}: driver: overlay attachable: true {{traefik_network_name}}: external: true volumes: '{{ portainer_volume_name }}':
解决方案
原因分析
"invalid host header"错误是因为前端应用(大概率是React/Vue这类开发服务器)默认会校验请求的Host头,只有匹配预设的允许列表才会响应。通过IP+端口访问时,Host头是IP:端口,符合开发服务器的默认允许规则;而通过Traefik域名访问时,Host头是dashboard.my.domain,不在前端应用的允许列表里,所以被拦截。
具体解决步骤
- 修改前端应用的Host头校验配置:
- 若为React(create-react-app):在启动命令中添加
HOST=dashboard.my.domain环境变量;开发环境临时测试可设置DANGEROUSLY_DISABLE_HOST_CHECK=true(生产环境禁用此参数)。 - 若为Vue:修改
vue.config.js,添加允许的域名:module.exports = { devServer: { allowedHosts: ['dashboard.my.domain'] } }
- 若为React(create-react-app):在启动命令中添加
- 更新前端服务的Docker配置:
在前端服务的environment中添加对应环境变量,确保配置传递到容器内:environment: - CHOKIDAR_USEPOLLING=true - HOST=dashboard.my.domain # React应用适用 - 移除不必要的端口映射:Swarm模式下通过Traefik暴露服务即可,删除前端服务中的
ports: - 3000:3000配置,避免端口冲突和冗余暴露。
验证步骤
重新部署前端服务后,检查Traefik仪表盘是否正常识别该服务;访问dashboard.my.domain确认服务正常响应。
内容的提问来源于stack exchange,提问作者Rabens
相关产品推荐
相关产品推荐

