2

How can I re-use the X-Forwarded-Host variable as an argument for server_name ?

1 Answer 1

3

You can't. Sorry. Server names are used to construct a hash table at the nginx startup, where lookups for the required server block according to the Host header value will be made with the O(1) complexity time. Server names specified by regex patterns is a different story, those regex patterns will be matched upon the Host header value if the hash-based table lookup would fail. However you can't use variables in regex patterns too, all regex patterns are being compiled at the nginx startup. If you describe the task you are trying to solve, maybe I can suggest you some other way to solve it.


Update according to OP comment:

Well the the URL that is passed to our nginx is transformed in local path where the domain is removed. The only way to retrieve the actual domain is from the X-Forwarded-Host header.

If I understand you correctly, you can try proxying incoming requests to your own nginx instance using the received X-Forwarded-Host HTTP header value as an issued request Host header value. A minimal example is as follows:

server { listen 80; location / { proxy_set_header Host $http_x_forwarded_host; proxy_pass 127.0.0.1:8080; } } server { listen 127.0.0.1:8080; server_name one.example.com; location / { return 200 "Server one, request URI is $request_uri\n"; } } server { listen 127.0.0.1:8080; server_name two.example.com; location / { return 200 "Server two, request URI is $request_uri\n"; } } 

Testing:

> curl -H 'X-Forwarded-Host: one.example.com' http://127.0.0.1/some/path/ Server one, request URI is /some/path/ > curl -H 'X-Forwarded-Host: two.example.com' http://127.0.0.1/other/path/?arg=value Server two, request URI is /other/path/?arg=value 

Since nginx is proxying requests to itself, it may be more efficient to use a UNIX socket instead of a TCP port for communication. This approach eliminates the network stack overhead, resulting in slightly better performance:

server { listen 80; location / { proxy_set_header Host $http_x_forwarded_host; proxy_pass http://unix:/tmp/nginx.sock; } } server { listen unix:/tmp/nginx.sock; server_name one.example.com; ... } server { listen unix:/tmp/nginx.sock; server_name two.example.com; ... } ... 

If you need to use an HTTP/1.1 protocol version, where the Host request header cannot be empty according the specification (resulting in HTTP 400 Bad Request error otherwise), to ensure every your proxied request will have a Host header, you can use the following map block:

map $http_x_forwarded_host $proxied_host { '' stub.example.com; default $http_x_forwarded_host; } server { listen 80; location / { proxy_http_version 1.1; proxy_set_header Host $proxied_host; proxy_pass http://unix:/tmp/nginx.sock; } } server { # a server block to process requests without `X-Forwarded-Host` HTTP header listen unix:/tmp/nginx.sock; server_name stub.example.com; ... } ... 
2
  • Well the the URL that is passed to our nginx is transformed in local path where the domain is removed. The only way to retrieve the actual domain is from the X-FORWARDED-HOST header. Commented Jul 8, 2022 at 10:34
  • 2
    @Tolsadus It's certanly too late, but I'm updated my answer, showing a possible approach to solve this. Commented Dec 2, 2024 at 6:10

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.