Nginx – X-Forwarded-Host Not Working in Nginx

dockerkubernetesnginx

Update 2. I want to add and forward all traffic to localhost/admin/ instead of localhost/.

  • App listen to those paths:
    • localhost/ (then gets 302 to localhost/login by application),
    • localhost/overview,
    • localhost/books/details, etc.
  • I want admin user to use those urls:
    • localhost/admin/(to get 302 localhost/admin/login by
      application)
    • localhost/admin/overview
    • localhost/admin/books/details
  • With my reverse proxy (see below):
    • localhost/admin/ (I get 302 localhost/login by application)

,

I could use also ingrees-nginx-controller instead of mounting file.

In docker nginx.conf (or similar to k8s)

server {
    listen 80 default_server;
    listen [::]:80 default_server;
        ...
        location /admin {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host/admin;
        proxy_pass http://<conteiner2>.docker-network;
    }
    ... 
}

Update1
For kubernetes I am trying to setup the the ingress-nginx
For this I installed the ingress-nginx-controller and I setup the ingress-nginx using this YAML:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "Host $host";
      more_set_headers "X-Real-IP $remote_addr";
      more_set_headers "X-Forwarded-For $proxy_add_x_forwarded_for";
      more_set_headers "X-Forwarded-Proto $scheme";
      more_set_headers "X-Forwarded-Host $host/admin";
  name: test-ingress
  namespace: <namespace>
spec:
  rules:
    - http:
        paths:
        - path: /admin
          backend:
            serviceName: <app1>-admin
            servicePort: 8002

Best Answer

So, there are a few things going on here; foremost:

proxy_set_header X-Forwarded-Host $host/admin;
proxy_pass http://<conteiner2>.docker-network;

is incorrect because x-forwarded-HOST should not contain a uri, as you have with /admin: it should just be the $host; what you really want is to update proxy_pass to contain the $request_uri as you can observe that the generated nginx.conf does when using the nginx Ingress controller. That wait the location's URI /admin along with whatever else matches in the location will be passed upstream as expected:

proxy_set_header X-Forwarded-Host $host;
proxy_pass http://<conteiner2>.docker-network$request_uri;
# or you're free to hard-code /admin if you prefer:
proxy_pass http://<conteiner2>.docker-network/admin;

Secondly, if you are experiencing that you want some configuration-snippet: applied to one URI but not both of them, then split out the two routes into two separate Ingress resources, so they can be managed independently:

kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      # this one just applies to /api
  name: test-ingress-api
spec:
  rules:
    - http:
        paths:
        - path: /api
          backend:
            serviceName: <app2>-api
            servicePort: 8000
---
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      # this one just applies for /admin
  name: test-ingress-admin
spec:
  rules:
    - http:
        paths:
        - path: /admin
          backend:
            serviceName: <app1>-admin
            servicePort: 8002

Any ideas how to debug nginx proxy?

There are two great ways: first, grab the generated nginx.conf and read over it to see what you were expecting to happen versus what did happen:

kubectl cp ${the_nginx_controller_pod}:/etc/nginx/nginx.conf ingress-nginx.conf

The other way is to turn the nginx log level to debug (which can be problematic if you're trying to debug in a production setting because of the absolutely insane amount of text it will generate, but it will almost certainly have the actual answer to whatever you are trying to debug):

# the ConfigMap may be named differently in your setup:
$ kubectl edit configmap nginx-ingress-controller

# and add:
data:
   error-log-level: debug

# then wait a few seconds for nginx to notice the configmap change
# and if it doesn't, kill the controller pods to force the reload