I've spent a day trying to debug an NGINX proxy issue for a client. I thought it might be worthy of a blog post.

When building applications in a microservices architecture, it is common for the UI--Angular or React--to be on an entirely different web domain than the services. The browser can't call services on a different domain directly due to cross site scripting issues. A common solution is to set use a server side proxy, and NGINX has one built right in.

I want to set something up so that when my UI loads:


The server will know to forward that to:


And my UI code gets the results w/o issue.

Since the call to the remote service is being done by NGINX--a server software--the browser does not block it. Server to server network traffic is generally considered safer and less interceptable than browser to server network traffic.

Take your nginx config file. Inside HTTP section, there should be a server section. Inside the server section you probably have multiple locations set up. Let's set up a new one:

view plain print about
1location /thirdPartyService/ {

Now, whenever the server sees the "my-ui.com/thirdPartyService" it knows to process it in that location block. Let's flesh it out. First we need to add a resolver:

view plain print about
1resolver valid-15s;

The resolver tells the server the IP of where the remote URL is. For simplicity here I have it redirecting to my local machine, but your real world app is going to be more complex I bet.

How add some proxy headers into the location block:

view plain print about
1proxy_set_header X-Forwarded-Proto http;
2proxy_set_header X-Real-IP $remote_addr;

These just adds header.

X-Forwarded-Proto is the standard header used for connecting to a proxy or load balance.

The X-Real-IP doesn't have a lot of documentation available on the Internet. I think it might be an NGINX specific thing. It is a way to send the proxy the client's IP address instead of the proxy's address. So when calling this new URL on my server, the client will see me--the user sitting at my browser--and not the IP address of the server.

The $remote_addr is an NGINX variable, representing the client's IP address.

Now, I need to add a rewrite rule. I spent quite a bit of time debugging the lack of this last week:

view plain print about
1rewrite ^/thirdPartyService/(.*) /$1 break;

This rule introspects your URL, and pulls out all portions of it after the `thirdPartyService` and saves it in the $1 variable. We'll re-use this value in a second.

For example, this:


And saves it to:


We use that $1 rewrite rule along with proxy_pass:

view plain print about
1proxy_pass https://my-service.com/$1/$args;

$1 comes from the rewrite rule. $args is a special variable with all URL arguments pulled out of the URL.

The full location block, for reference:

view plain print about
1location /thirdPartyService/ {
2 resolver valid-15s;
3 proxy_set_header X-Real-IP $remote_addr;
4 proxy_set_header X-Forwarded-Proto http;
5 rewrite ^/thirdPartyService/(.*) /$1 break;
6 proxy_pass https://my-service.com/$1/$args;

So, when our UI loads:


The server will know to forward that to:


Stuff like this is often something I set up once or twice and then they just persist w/o issue. As such, I don't have to set them up too often and it usually takes a lot of grinding to remember how I got it to work last time. Hopefully this post will help me remember next time.