NGINX Proxy_pass : use proxy_host as the request header host - nginx

I am trying to proxy_pass to a website, But I want the request header host to be the same as the website I passed.
I have tried to use "proxy_set_header Host $proxy_host" (and tried change the value to $host, even the exact hostname I want. But when I use google chrome to check the request host, it is still the server IP that I used to set up the proxy_pass.
Below is my config, please help
location / {
proxy_pass https://example.com;
proxy_set_header Host $proxy_host;
proxy_set_header X-Original-URI $request_uri;
}
Thank you

Check the examples from the docs:
nginx first decides which server should process the request. Let’s start with a simple configuration where all three virtual servers listen on port *:80:
server {
listen 80;
server_name example.org www.example.org;
...
}
server {
listen 80;
server_name example.net www.example.net;
...
}
server {
listen 80;
server_name example.com www.example.com;
...
}
In this configuration, nginx tests only the request’s header field Host to determine which server the request should be routed to. If its value does not match any server name, or the request does not contain this header field at all, then nginx will route the request to the default server for this port. In the configuration above, the default server is the first one — which is nginx’s standard default behaviour. It can also be set explicitly which server should be default, with the default_server parameter in the listen directive:
server {
listen 80 default_server;
server_name example.net www.example.net;
...
}
Now keep in mind that $host is specifically the first server_name that is defined in the current server block. if you have multiple server_name's, only the first one will appear, but if want your backend to receive a fixed host name, use:
proxy_set_header Host "your.fixed.hostname";

Related

Nginx reverse proxy to an https address behind corporate proxy

I am trying to setup an Nginx reverse proxy to an AWS API Gateway address like https://12345.execute-api.eu-central-1.amazonaws.com/v2 behind a corporate proxy.
I tried the following setup to www.example.com and it works. But as soon as I add https to it like https://www.example.com it fails. I add https since my API Gateway address is not accessible without it.
Current working config:
server {
listen 80;
listen [::]:80;
listen 443;
underscores_in_headers on;
location / {
proxy_pass_request_headers on;
proxy_set_header Host www.example.com;
proxy_pass http://myCorporateProxy.org:8080;
}
}
What I want to achieve and error I get:
Redirect all incoming traffic to localhost to be redirected to API Gateway address which looks similar to https://123456.execute-api.region.amazonaws.com/v2/
When trying following config, I get a 302 temporarily Moved error.
In configuration it would look like this:
server {
listen 80;
listen [::]:80;
listen 443;
underscores_in_headers on;
location / {
proxy_pass_request_headers on;
proxy_set_header Host https://www.example.com;
proxy_pass http://myCorporateProxy.org:8080;
}
}
You should try something like this. To redirect from http to https is a little different.
server {
listen 80;
server_name myCorporateProxy.org www.myCorporateProxy.org;
return 301 https://myCorporateProxy.org$request_uri;
}

How to create reverse proxy for multiple websites in nginx

I have many different technologies serving APIs and sites on my local machine. I want to be able to see them via human-readable names, rather than ports.
For example, I have:
localhost:8000 => laravel api for user panel
localhost:8001 => laravel api for admin panel
localhost:3000 => react client for user panel
localhost:3001 => nextjs client for site
localhost:3002 => react client for admin panel
And this list goes on.
Remembering all these ports is not possible of course. Thus I thought to setup a reverse proxy for them:
api.user.example.local
api.admin.example.local
example.local
user.example.local
admin.example.local
I know I have to add these host headers to /etc/hosts file. I also read about how to configure nginx as a reverse proxy for one domain.
I don't know how to do it for many sites. And only as a reverse proxy, not as a server.
Please note: I'm not considering myself as really super nginx expert, just starting to learn nginx, but I think I can help you with this task.
Here is my approach:
First, make sure your default nginx config (usually /etc/nginx/nginx.conf) has line include /etc/nginx/conf.d/*.conf; in its http block, so you may specify internal servers in separate config files for ease of use.
Create additional config file /etc/nginx/conf.d/local_domains.conf and add following server blocks in it:
server {
listen 80;
server_name api.user.example.local;
location / {
set $target http://localhost:8000;
proxy_pass $target;
}
}
server {
listen 80;
server_name api.admin.example.local;
location / {
set $target http://localhost:8001;
proxy_pass $target;
}
}
server {
listen 80;
server_name example.local;
location / {
set $target http://localhost:3000;
proxy_pass $target;
}
}
server {
listen 80;
server_name user.example.local;
location / {
set $target http://localhost:3001;
proxy_pass $target;
}
}
server {
listen 80;
server_name admin.example.local;
location / {
set $target http://localhost:3002;
proxy_pass $target;
}
}
On the client machine, add these records to the hosts file
192.168.1.1 api.user.example.local
192.168.1.1 api.admin.example.local
192.168.1.1 example.local
192.168.1.1 user.example.local
192.168.1.1 admin.example.local
Where 192.168.1.1 is the address of your nginx server.
That's it, it should work if your internal servers are using HTTP protocol.
But if you need to use HTTPS for internal servers and for the main nginx server, modify each server block as follows:
server {
listen 443 ssl http2;
server_name api.user.example.local;
ssl_certificate /usr/local/share/ca-certificates/example.local.crt;
ssl_certificate_key /usr/local/share/ca-certificates/example.local.key;
add_header Strict-Transport-Security "max-age=31536000" always;
location / {
set $target https://api.user.example.local:8000;
proxy_pass $target;
}
}
and so on
ssl_certificate and ssl_certificate_key should point to correct certificate and key files for the domain.
If you would like nginx main server to listen port 80 and redirect all traffic to https, add additional server blocks for each server:
server {
server_name api.user.example.local;
listen 80;
# Force redirection to https on nginx side
location / {
return 301 https://$host$request_uri;
}
}
and so on
More information on NGINX Reverse Proxy
NGINX Reverse Proxy
Module ngx_http_proxy_module

Routing meant for a subdomain is also being applied to the root domain

Consider two websites hosted on the same server: domain.com and foo.domain.com. I want to start up a monitoring panel for each site on port 5555. Each site has a separate monitoring panel so I need to use nginx to route domain.com:5555 and foo.domain.com:5555 to two different places.
Here is the configuration for foo.domain.com:
server {
listen 5555;
server_name foo.domain.com;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://localhost:5678;
}
}
While this works fine for foo.domain.com:5555, it is also routing domain.com:5555 to the monitoring panel. This is acting like I had defined server_name domain.com foo.domain.com, but clearly I only defined it for foo.domain.com.
The only other nginx configs on the server are for ports 80 and 443. Neither of those configs use any wildcards and explicitly use the full name.
nginx always has a default server - if you do not define a default server, it will use the first server block with a matching listen directive.
If you want to discourage this behaviour, you will need to define a catch-all server for port 5555.
For example:
server {
listen 5555 default_server;
return 444;
}
See this document for more.

nginx upstream subdomain on the same server

I am configuring Nginx load balance with Nginx upstream module, configuration as follow:
upstream load {
server loadapi.example.com;
server loadapi.anotherdomain.com down;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://load;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 80;
server_name loadapi.example.com;
root /disk/projects/load/loadapi;
index index.html index.htm index.shtml index.php;
...
...
error_page 404 /404.html;
}
Notice that the api.example.com and loadapi.example.com are on the same server. loadapi.anotherdomain.com is resolved to another server which provides the same service.
Everything works fine with loadapi.anotherdomain.com, which are on another server.
But when I use the loadapi.example.com as the backend, it seems that Nginx cannot handle it correctly. I can get my service up and running on loadapi.example.com. But it is not working with the upstream.(look like Nginx cannot resolve the subdomain name correctly).
any advice? thx in advance.
nginx uses the Host header to determine which server block to use to process a request.
When the request passes through the proxy_pass http://load; statement, the Host header is set to the value load by default.
To make nginx choose the server block containing the server_name loadapi.example.com; statement, it either needs to be the default_server server, or include the name load in its server_name, or set the Host header using:
proxy_set_header Host loadapi.example.com;
Of course, using upstream for load balancing means that both servers receive the same value for the Host header, and must both respond correctly to it.
See this document for more.

All hosts redirecting to single nginx proxy_pass

I have the following in my .conf file:
server {
listen 80;
server_name mydomain.net;
access_log /var/log/nginx/mydomain.net.access.log main;
location / {
proxy_pass http://127.0.0.1:9000;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Which works just fine... except everything that hits the server is getting fed to this server block. My IP, another domain pointing at this block, and the actual mydomain.net all point to what only mydomain.net is pointing to.
As the documentation states:
In this configuration nginx tests only the request’s header field “Host” to determine which server the request should be routed to. If its value does not match any server name, or the request does not contain this header field at all, then nginx will route the request to the default server for this port. In the configuration above, the default server is the first one — which is nginx’s standard default behaviour.
This was the case here. I performed the suggested step to drop undefined hosts:
server {
listen 80 default_server;
server_name "";
return 444;
}
Which solved my issue.

Resources