Nginx faking ip address with proxy_pass - nginx

I need a proxied request appear as if it came from the localhost. I tried following nginx config:
proxy_set_header Host "127.0.0.1";
proxy_set_header X-Real-IP "127.0.0.1";
proxy_set_header X-Forwarded-For "127.0.0.1";
proxy_read_timeout 10m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://127.0.0.1:15674/stomp/websocket;
However underlying backend is still capable to recognize, that request is not local:
STOMP login failed - access_refused (user must access over loopback)

You are missing one Nginx header, proxy_bind
proxy_bind 127.0.0.1;
Here's the documentation for the effect of what this does:
Makes outgoing connections to a proxied server originate from the specified local IP address
That sounds like exactly what you need. The other headers you set to 127.0.0.1 may not be required.

Related

Error "Bad gRPC response. HTTP status code: 500" when set $var in NGINX grpc_pass

When i set $var in grpc_pass i can't connect grpc-client to server, I get the FAIL error
[Microsoft.Extensions.Hosting.Internal.Host)
[BackgroundServiceFaulted status BackgroundServledGrpc.Co.RpcException
(StatusCode="Unknown", Detail="Bad gRPC response. HTTP status code: 500")
The purpose of setting a variable is to bypass the situation where one of the services that proxies NGINX crashes, and when NGINX restarts, the other services continue to work.
With proxy_pass directive all works and tests are successful (Setup nginx not to crash if host in upstream is not found), with grpc_pass - no, BUT in manual says that
Parameter value can contain variables (1.17.8). In this case, if an address is specified as a domain name, the name is searched among the described server groups, and, if not found, is determined using a resolver.
version:
# nginx -v
nginx version: nginx/1.23.2
path myexamplenginx_conf:
location / {
resolver 127.0.0.11 valid=30s;
set $webuidev https://dev_webuidev;
proxy_pass $webuidev;
#proxy_pass https://dev_webuidev;
# Configuration for WebSockets
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_cache off;
# WebSockets were implemented after http/1.0
proxy_http_version 1.1;
# Configuration for ServerSentEvents
proxy_buffering off;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-URL-SCHEME https;
}
location /App.Room.Api.Contract.ApiService/UpdateOpcDaTags {
resolver 127.0.0.11 valid=30s;
set $grpc_webuidev grpcs://dev_webuidev;
grpc_pass $grpc_webuidev;
#grpc_pass grpcs://dev_webuidev;
}

Reverse Proxy HTTPS Requests as HTTP to Upstream Server

We are using NGINX on our cPanel server to reverse proxy ZKTeco ZKBioSecurity servers. Due to compatibility with some of their devices not supporting HTTPS, all our servers use HTTP, but, of course, all sessions to our NGINX server is secured with HTTPS and a Sectigo certificate provided by cPanel’s AutoSSL.
Here’s the problem: it seems that the ZKBioSecurity servers are detecting that the client is using HTTPS to connect to them through NGINX, and because of this, give the following prompt each time you want to log in, advising you to download and install the ISSOnline driver and certificate. The certificate, however, is issued to the ZKBioSecurity server for 127.0.0.1, so of course this is rather pointless as we are connecting to the NGINX server using a FQDN. This does not happen if we use HTTP:
So my question: is there something in the request (the HTTP header perhaps?) that NGINX forwards to the upstream server that contains the protocol (HTTPS) the client used to connect to the server? Because this somehow seems to be the case.
Here’s our NGINX config for ZKBioSecurity servers:
location /.well-known {
root /home/novacloud/public_html/subdomain/.well-known;
allow all;
try_files $uri = 404;
}
location / {
if ($scheme = http) {
return 301 https://$host$request_uri;
}
proxy_pass http://192.168.0.1:8080;
proxy_http_version 1.1;
proxy_cache_bypass $http_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
proxy_set_header X-Forwarded-Port $server_port;
}
The server_name directive is, of course, managed by cPanel. The above is an example of the include files we use in the main cPanel NGINX configuration file. I thought it was the proxy_set_header X-Forwarded-Proto $scheme, but even if I remove this, I still get the Driver Detection Exception prompt.
Here’s a Pastebin of a cURL of the ZKBioSecurity server from our cPanel/NGINX server

NGINX cannot forward https POST request to another port

I am running a NodeJS application and deployed using pm2 running on port 5000, this works fine with http requests. To get the https working I have created a reverse proxy in nginx to forward https request on port 5001 to forward to port 5000. It works fine if I disable the SSL, http request is correctly forwarded from port 5001 to port 5000 but https works only for GET method, but not for POST method.
server {
listen 5001 default_server;
ssl on;
ssl_certificate /home/ubuntu/xyz.crt;
ssl_certificate_key /home/ubuntu/xyz.key;
server_name mydomain.com www.mydomain.com;
root ~/mynodeapp; location / {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade; proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
I need to be able to call my API endpoint running on port 5000 over SSL through port 5001
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
I have no idea what the purpose of these headers is since they should only be used when forwarding WebSockets - which also means only in the context of GET. Thus it is likely wrong and might explain the problems you have.

Unable to connect to socket.io server

I have NGINX set up to route requests to example.com to nodejs server on port 3000 which serves the front end and example.com/api to nodejs api server on port 3001.
I try to connect to the socket on port 3001 like:
const socket = openSocket('example.com/api');
But I get an error in the console:
polling-xhr.js:265 POST https://example.com/socket.io/?
EIO=3&transport=polling&t=MWPLGiL 404 (Not Found)
It looks like socket.io is still trying to connect to only example.com.
Any idea why the /api is being ignored? I need this to go to example.com/api since that server is configured to handle the socket connections. Would be grateful if some one can help me. Thank you!
I solved the problem by adding the following in NGINX config:
location ~ ^/(api|socket\.io) {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 900s;
}
Sorry for asking the question without digging in more. Hope this helps some one else.

Proxying NGINX Traffic To Secondary Proxy with Proxy_Protocol Enabled

I am trying to route requests such that those requiring websockets will route to a long-lived nginx process, and all others will go to the general reverse-proxy which handles all other traffic. These nginx processes exist in our AWS cloud behind an ELB that has been configured to use Proxy Protocol. Note that all of this works correctly with our current setup which uses only one nginx process that is configured to use proxy_protocol.
The change to this setup is as follows:
The first nginx server handling all ingress uses proxy_protocol and forwards requests to either the websocket or non-websocket nginx servers locally:
server {
listen 8080 proxy_protocol;
real_ip_header proxy_protocol;
charset utf-8;
client_max_body_size 20M;
#send to websocket process
location /client {
proxy_pass http://localhost:8084;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $proxy_protocol_addr;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Proxy-Scheme $scheme;
proxy_set_header X-Proxy-Port $proxy_port;
proxy_set_header X-ELB-Proxy-Scheme "https";
proxy_set_header X-ELB-Proxy-Port "443";
# Always support web socket connection upgrades
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
#send to non-websocket process
location / {
proxy_pass http://localhost:8082;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $proxy_protocol_addr;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Proxy-Scheme $scheme;
proxy_set_header X-Proxy-Port $proxy_port;
proxy_set_header X-ELB-Proxy-Scheme "https";
proxy_set_header X-ELB-Proxy-Port "443";
# Always support web socket connection upgrades
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
When any non-websocket request is sent to localhost:8082, I get an empty reply. If I remove proxy_protocol from the first server, I get a response as expected. Obviously, I need proxy_protocol to support the ingress from our ELB, so removing it is not an option. However, I would like to know what pieces I am missing to route traffic correctly -- and I would also like to know why proxying a request locally from a proxy_protocol enabled server to another nginx process (regardless of this second process using proxy_protocol or not) fails.
For reference, the basic configuration of this secondary nginx process is below:
upstream console {
server localhost:3000 max_fails=3 fail_timeout=60 weight=1;
}
server {
listen 8082;
client_max_body_size 20M;
location /console {
proxy_pass http://console
}
.
.
.
}
Turns out the non-websocket proxy block should not set the various proxy and upgrade headers:
location / {
proxy_pass http://localhost:8082;
proxy_set_header Host $host;
}

Resources