How to Exclude Specific Subdirectories from Nginx Reverse Proxy: A Complete Guide


2 views

When configuring Nginx as a reverse proxy, there are cases where you need to exclude certain subdirectories from being proxied to the backend server. This is particularly common when:

  • Some static content needs to be served directly from Nginx
  • Certain paths should bypass the proxy for security reasons
  • You need to mix proxied and non-proxied content in the same server block

The proper way to handle this in Nginx is to use location blocks with careful ordering of directives. Here's the correct implementation:

server {
    listen 80;
    server_name example.com;

    # First handle the excluded subdirectory
    location /subdir/ {
        root /var/www/site;
        try_files $uri $uri/ =404;
    }

    # Then proxy everything else
    location / {
        proxy_pass http://localhost:9999/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

The example in the question didn't work because:

  1. The root directive path was incorrect - it shouldn't include the "subdir" in the path
  2. Missing try_files to properly handle static file serving
  3. The order of location blocks matters in Nginx

Multiple Excluded Directories

server {
    # ... other server configuration ...

    location /static/ {
        alias /var/www/static/;
        expires 30d;
        access_log off;
    }

    location /uploads/ {
        alias /var/www/uploads/;
        try_files $uri $uri/ =404;
    }

    location / {
        proxy_pass http://backend;
    }
}

Case-Sensitive Matching

location ~* ^/specialpath/ {
    root /var/www/special;
    try_files $uri $uri/ @proxy;
}

When implementing these exclusions:

  • Use alias instead of root when the filesystem path doesn't match the URI path
  • Consider disabling access logs for static content to reduce I/O
  • Implement proper caching headers for static assets

If your configuration isn't working as expected:

  1. Check Nginx error logs (/var/log/nginx/error.log)
  2. Verify file permissions on your static content directories
  3. Use curl -v to inspect headers and responses
  4. Test with nginx -t before reloading

When migrating from Apache to Nginx, one common stumbling block is handling reverse proxy exceptions. In Apache, we'd simply use ProxyPass /subdir ! to exclude paths, but Nginx requires a different approach due to its location matching logic.

The issue with your initial attempt comes down to Nginx's location processing order. Unlike Apache's straightforward exclusion syntax, Nginx evaluates locations in a specific sequence:

# Correct implementation
server {
    listen 80;
    server_name example.com;

    # Precise match takes precedence
    location = /subdir {
        root /var/www/site;
    }

    # Prefix-based matching
    location /subdir/ {
        root /var/www/site;
    }

    # Default proxy pass
    location / {
        proxy_pass http://localhost:9999/;
        include proxy_params;
    }
}

For more complex scenarios, you might need regular expression matching:

location ~ ^/(subdir|anotherdir)(/|$) {
    root /var/www/site;
    try_files $uri $uri/ =404;
}

location / {
    proxy_pass http://localhost:9999;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

When excluding multiple directories, consider these optimizations:

  • Use exact matches (location =) for static assets
  • Limit regular expressions to necessary cases
  • Place most frequently accessed paths earlier

If your exclusion isn't working:

  1. Check Nginx's error logs (tail -f /var/log/nginx/error.log)
  2. Verify file permissions in the excluded directory
  3. Test with curl -v to inspect headers