Reverse proxy applications
Proxy to an application
Send requests to a local application and understand how the proxypass URI changes upstream paths.
A reverse proxy accepts the public request and makes a separate request to an upstream application. Nginx terminates the client connection, then opens its own connection to your app on localhost or a Unix socket.
proxy_pass is the directive that does the forwarding. The trailing slash on the URL changes how Nginx rewrites the path, and this trips people up constantly.
Compare these two forms for a request to /api/users:
# Without trailing slash: full URI forwarded
location /api/ {
proxy_pass http://127.0.0.1:3000;
}
# Upstream receives: /api/users
# With trailing slash: location prefix stripped
location /api/ {
proxy_pass http://127.0.0.1:3000/;
}
# Upstream receives: /users
Most Node and Rails apps expect the prefix stripped, so the trailing slash form is what you want for a typical /api/ location. Test the exact upstream path instead of guessing.
Run a local test application that prints its request path. Proxy /app/ to it and compare both proxy_pass forms with and without a trailing slash.
Proxy one location to a local application:
location /api/ {
proxy_pass http://127.0.0.1:3000/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
Test the application directly first, then through Nginx. Notice the trailing slash behavior in proxy_pass. Inspect both access logs and application logs so you can follow one request across the proxy boundary.
Start the app and hit it directly:
curl -s http://127.0.0.1:3000/users
# {"path":"/users"}
curl -s http://app.example.com/api/users
# {"path":"/users"} <- prefix stripped correctly
If the proxied response shows /api/users instead of /users, your trailing slash is wrong. Fix the proxy_pass URL and test again before moving on.
When the upstream is down, Nginx returns 502 Bad Gateway and writes connect() failed to the error log. That is a different failure from a wrong path, which often returns 404 from the app itself. Check both the status code and the upstream path in the logs.
Try this on a test server with a small Node or Python app that logs each request path.
Lesson completed