How to Remove Subdirectory Path in Nginx Reverse Proxy Configuration


2 views

When setting up an Nginx reverse proxy with multiple backend services, a common challenge arises: the subdirectory path gets passed through to the backend servers. For example, accessing https://example.com/site1 currently proxies to http://localhost:8081/site1 instead of the desired http://localhost:8081/.

Here's the current problematic configuration:

location /site1 {
    proxy_pass http://localhost:8081;
    # Other proxy settings...
}

This setup preserves the /site1 prefix when forwarding requests to the backend service.

To remove the subdirectory prefix, we need to modify the proxy configuration in two ways:

location /site1/ {
    proxy_pass http://localhost:8081/;
    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_redirect http:// https://;
}

Key differences from the original:

  1. Added trailing slash to location block (/site1/)
  2. Added trailing slash to proxy_pass URL (http://localhost:8081/)

When your backend performs redirects (like Rails' redirect_to), we need to ensure they maintain the original subdirectory structure for external clients:

location /site1/ {
    proxy_pass http://localhost:8081/;
    proxy_redirect http://localhost:8081/ /site1/;
    proxy_redirect https://localhost:8081/ /site1/;
    # Other proxy settings...
}

Here's a full working example for both sites:

server {
    listen 443;
    server_name mysitename.com;

    ssl on;
    ssl_certificate ssl/mysitename.com.crt;
    ssl_certificate_key ssl/mysitename.com.key;
    keepalive_timeout 60;

    location /site1/ {
        proxy_pass http://localhost:8081/;
        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_redirect http://localhost:8081/ /site1/;
        proxy_redirect https://localhost:8081/ /site1/;
    }

    location /site2/ {
        proxy_pass http://localhost:8082/;
        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_redirect http://localhost:8082/ /site2/;
        proxy_redirect https://localhost:8082/ /site2/;
    }

    # Redirect from /site1 to /site1/ (with trailing slash)
    location = /site1 {
        return 301 /site1/;
    }

    location = /site2 {
        return 301 /site2/;
    }
}
  • Always include trailing slashes in both location and proxy_pass directives
  • The proxy_redirect directives ensure backend redirects maintain the proper subdirectory
  • The separate location = blocks handle naked subdirectory redirects properly
  • Test your configuration thoroughly with nginx -t before reloading

If you encounter issues:

  1. Check Nginx error logs: tail -f /var/log/nginx/error.log
  2. Verify backend receives proper requests: examine backend application logs
  3. Test with simple curl commands: curl -v https://mysitename.com/site1
  4. Ensure all trailing slashes match in your configuration

When setting up a reverse proxy with NGINX, a common requirement is to remove the subdirectory prefix before passing the request to backend servers. In your case, accessing https://www.mysitename.com/site1 should proxy to http://localhost:8081/ without the /site1 prefix, but currently it's passing the full path.

The key is to use URL rewriting in the proxy_pass directive. Here's the corrected configuration:

server {
    listen                  443;
    server_name             mysitename.com;

    ssl                     on;
    ssl_certificate         ssl/mysitename.com.crt;
    ssl_certificate_key     ssl/mysitename.com.key;
    keepalive_timeout       60;

    location /site1 {
        proxy_pass http://localhost:8081/;
        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_redirect http:// https://;
    }

    location /site2 {
        proxy_pass http://localhost:8082/;
        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_redirect http:// https://;
    }
}

1. Added trailing slash (/) to proxy_pass URLs
2. This tells NGINX to replace the matched prefix (/site1) with /
3. Now /site1/login becomes /login on the backend

For applications that generate redirects (like Rails), you'll need additional configuration:

location /site1 {
    proxy_pass http://localhost:8081/;
    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_redirect http:// https://;
    proxy_redirect ~^/(.*)$ /site1/$1;
}

For more complex scenarios, you can use regex locations:

location ~ ^/site1(/?)(.*) {
    proxy_pass http://localhost:8081/$2$is_args$args;
    # Other proxy settings...
}

Always test with:

nginx -t
systemctl reload nginx

Then verify with curl:

curl -v https://www.mysitename.com/site1/login