Nginx Configuration Change: Isolating /api/me/* Requests to Port 3001 for API Routing Optimization
I needed to optimize my API routing and strengthen service isolation. I identified a few areas for improvement in my existing infrastructure setup and decided to modify my Nginx configuration. Specifically, I wanted to route requests for certain APIs, like /api/me/*, to a separate port for management.
Attempt and Pitfall
Initially, I tried a simple approach by adding a location block. I intended to pass requests coming to /api/me/ to http://localhost:3001 using proxy_pass.
server {
listen 80;
server_name example.com;
location /api/me/ {
proxy_pass http://localhost:3001;
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;
}
location / {
proxy_pass http://localhost:3000; # Other APIs
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;
}
}
The problem was that the paths following /api/me/ weren't being passed correctly. For example, a request to /api/me/profile would only be forwarded to http://localhost:3001/, resulting in a 404 error. I hadn't fully grasped how Nginx's location blocks work. After about 3 hours of trial and error, I realized my understanding of how location blocks match paths was insufficient.
The Cause
Nginx's location blocks, by default, use prefix matching. While location /api/me/ matches any path starting with /api/me/, it had the issue of appending the matched part to the URL specified in proxy_pass, rather than passing the remaining path correctly. To preserve the path following /api/me/, additional consideration was needed for the proxy_pass configuration.
The Solution
To resolve this, I changed the location block's path to use a regular expression and employed the rewrite directive to rewrite the path. I modified the configuration to accurately proxy requests starting with /api/me/ to http://localhost:3001/.
server {
listen 80;
server_name example.com;
location ~ ^/api/me/(.*)$ {
proxy_pass http://localhost:3001/$1;
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;
}
location / {
proxy_pass http://localhost:3000; # Other APIs
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;
}
}
The regular expression ~ ^/api/me/(.*)$ matches any string starting with /api/me/, followed by any characters ((.*)). Then, $1 is appended to the URL in proxy_pass, ensuring that the remainder of the original request path is passed through correctly.
Results
- Requests to
/api/me/*were successfully isolated to thelocalhost:3001port. - API routing was optimized, leading to more efficient request handling.
- Service isolation was strengthened, minimizing the impact of an outage in one API on other services.
Key Takeaways — Avoiding the Same Trap
- [ ] Accurately understand Nginx's
locationblock path matching behavior (prefix vs. regular expression). - [ ] When rewriting paths with
proxy_pass, consider using therewritedirective or regular expression capture groups ($1). - [ ] When separating specific path patterns, the order and priority of
locationblocks are also important. - [ ] After making changes, always test with various paths to ensure they function as expected.