When working with Nginx configurations, developers often need to route requests directly from one location block to another named location (@location) without file existence checks. While try_files
is commonly used for this purpose, it requires at least two arguments and forces unnecessary filesystem checks when we simply want to route requests.
The current implementation using:
location /api/ {
try_files @app;
}
Is syntactically incorrect because try_files
requires at least two parameters. While we could use:
location /api/ {
try_files /nonexistent @app;
}
This creates an unnecessary filesystem check that impacts performance.
1. Using error_page Directive
A cleaner approach is using error_page
with HTTP 403:
location /api/ {
error_page 403 = @app;
return 403;
}
This immediately routes to the named location without filesystem checks.
2. Rewrite + Named Location
Another pattern using rewrite
:
location /api/ {
rewrite ^ /@app last;
}
location @app {
# proxy configuration
}
3. Direct proxy_pass (Simplest Solution)
If your named location only contains proxy directives, you can directly use:
location /api/ {
proxy_pass_request_headers on;
proxy_set_header ...;
proxy_pass http://app;
}
Each method has different performance characteristics:
try_files
with dummy file: 1 filesystem stat per requesterror_page
method: No filesystem accessrewrite
method: Minimal regex processing
Here's a complete production-ready example:
upstream backend {
server 127.0.0.1:9000;
}
server {
listen 80;
location /static/ {
root /var/www;
}
location /api/ {
# Method 1: error_page approach
error_page 418 = @backend;
return 418;
# Or Method 2: rewrite approach
# rewrite ^ /@backend last;
}
location @backend {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
When working with Nginx configuration, developers often need to route requests directly from one location block to another named location. The conventional approach using try_files
feels like a workaround when you don't actually need file existence checking.
# The common but suboptimal approach
location /api/ {
try_files non_existent_file @app; # Requires dummy file parameter
}
The most idiomatic alternative to try_files
for this specific case is using error_page
with 403 status code:
location /api/ {
# Your custom configuration here
error_page 403 = @app;
return 403;
}
This pattern creates a clean internal redirect without any file system checks. The 403 status is just a vehicle for the redirect and won't actually appear to clients.
Both methods are efficient, but the error_page
approach has some advantages:
- No dummy file parameter required
- More semantically correct for this use case
- Same internal redirect mechanism as try_files
- Minimal overhead (just one extra directive)
Here's how this fits into a complete server configuration:
upstream app_backend {
server unix:/tmp/app.sock fail_timeout=0;
}
server {
listen 443 ssl;
server_name example.com;
# Static file handling
location / {
try_files $uri $uri/ =404;
}
# API endpoint direct routing
location /api/ {
# Custom API-specific config
add_header 'API-Version' '1.0';
# Clean direct routing to named location
error_page 403 = @app;
return 403;
}
# Named location for proxy pass
location @app {
proxy_pass http://app_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Additional proxy settings...
}
}
For completeness, here's another method using rewrite
, though it's less preferred than error_page:
location /api/ {
rewrite ^ @app last;
}
While this works, it's generally better to reserve rewrite
for actual URL rewriting needs rather than simple internal routing.