携带Host头访问ingress-nginx主机返回404错误排查
问题根源
- Ingress规则匹配失败:nginx-ingress控制器依据请求的
Host头匹配Ingress资源的spec.rules.host字段。你的请求携带Host: xyz.foo.com,但Ingress配置的是bar.example.com,控制器找不到对应路由规则,直接返回404。 - Host头被默认重写:即便Ingress规则匹配成功,nginx-ingress默认会将转发到后端的
Host头替换为Ingress规则中定义的host值(即bar.example.com),而非保留客户端原始Host头,导致后端服务因收到的Host头不符合预期(需要xyz.example.com)无法正常处理请求。
解决方案
1. 调整Ingress规则匹配目标Host头
根据需求选择以下一种方式配置:
- 添加多Host规则:如果需要支持多个
Host头访问同一后端,直接在Ingress的spec.rules中添加对应host条目:apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: backend-ingress annotations: nginx.ingress.kubernetes.io/affinity: cookie nginx.ingress.kubernetes.io/session-cookie-expires: "172800" nginx.ingress.kubernetes.io/session-cookie-max-age: "172800" nginx.ingress.kubernetes.io/session-cookie-name: SESSION spec: rules: - host: bar.example.com http: paths: - path: /api/foo pathType: Prefix backend: service: name: backend-service port: number: 9900 - host: xyz.example.com http: paths: - path: /api/foo pathType: Prefix backend: service: name: backend-service port: number: 9900 - host: xyz.foo.com http: paths: - path: /api/foo pathType: Prefix backend: service: name: backend-service port: number: 9900 - 使用通配符Host:若域名有统一后缀(如
.example.com),可简化为通配符规则:spec: rules: - host: "*.example.com" http: paths: - path: /api/foo pathType: Prefix backend: service: name: backend-service port: number: 9900
2. 配置保留客户端原始Host头
添加Ingress注解,让nginx-ingress将客户端发送的Host头原样转发给后端:
- 推荐方式:使用
upstream-vhost注解metadata: annotations: # 保留原有注解 nginx.ingress.kubernetes.io/affinity: cookie nginx.ingress.kubernetes.io/session-cookie-expires: "172800" nginx.ingress.kubernetes.io/session-cookie-max-age: "172800" nginx.ingress.kubernetes.io/session-cookie-name: SESSION # 新增:保留客户端Host头 nginx.ingress.kubernetes.io/upstream-vhost: "$http_host" - 替代方式:使用
proxy-set-header注解显式设置metadata: annotations: # 保留原有注解 nginx.ingress.kubernetes.io/proxy-set-header: "Host $http_host"
3. 验证配置
- 应用修改后的Ingress:
kubectl apply -f <你的Ingress配置文件>.yaml - 检查nginx-ingress生成的配置,确认Host头转发规则:
应能看到类似kubectl exec -it <nginx-ingress-controller-pod-name> -n <ingress命名空间> -- grep -A 10 "backend-service" /etc/nginx/nginx.confproxy_set_header Host $http_host;的配置。 - 重新发送测试请求,确认返回200:
curl --location 'http://bar.example.com/api/foo' \ --header 'Host: xyz.example.com' \ --header 'Content-Type: application/json' \ --data-raw '{ "foo": "bar" }'
额外说明
若需求是不管客户端发送什么Host头,只要访问IP对应bar.example.com就转发到后端,可配置不指定host的默认Ingress规则(spec.rules中省略host字段),配合保留Host头的注解即可。
内容的提问来源于stack exchange,提问作者Parvez Kazi
相关产品推荐
相关产品推荐

