When setting up Nginx as a reverse proxy, one common requirement is to redirect requests while keeping the original URL visible in the browser. The specific scenario we're addressing involves:
http://example.com/some/path -> http://192.168.1.24
with subsequent requests like:
http://example.com/some/path/section/index.html -> http://192.168.1.24/section/index.html
The initial attempt using this configuration has two main issues:
server {
listen 80;
server_name www.example.com;
location /some/path/ {
proxy_pass http://192.168.1.24;
proxy_redirect http://www.example.com/some/path http://192.168.1.24;
proxy_set_header Host $host;
}
location / {
index index.html;
root /var/www/example.com/htdocs;
}
}
1. The backend server receives requests with /some/path
included
2. Links on served pages lose the /some/path
prefix
Here's the working configuration that solves both problems:
server {
listen 80;
server_name www.example.com;
location /some/path/ {
proxy_pass http://192.168.1.24/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Handle redirects properly
proxy_redirect ~^http://192.168.1.24/(.*)$ http://$host/some/path/$1;
# Rewrite links in HTML responses
sub_filter_once off;
sub_filter 'href="/' 'href="/some/path/';
sub_filter 'src="/' 'src="/some/path/';
}
location / {
index index.html;
root /var/www/example.com/htdocs;
}
}
1. The trailing slash in proxy_pass:
proxy_pass http://192.168.1.24/
ensures the /some/path
is stripped before reaching the backend.
2. Advanced proxy_redirect:
The regex pattern handles all possible redirects from the backend while preserving the original URL structure.
3. HTML content rewriting:
The sub_filter
directives modify links in the HTML response to maintain the /some/path
prefix.
After implementing this configuration:
- Restart Nginx:
sudo systemctl restart nginx
- Test with curl:
curl -v http://example.com/some/path/
- Verify the response headers and HTML content
For applications that use absolute URLs in JavaScript or CSS, you might need additional filters:
sub_filter 'url(/' 'url(/some/path/';
sub_filter '"/api/' '"/some/path/api/';
For WebSocket connections, add:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
When implementing reverse proxy configurations in Nginx, a common requirement is to maintain the original URL structure in the browser while routing requests to different backend servers. Our specific scenario involves:
- Original URL:
http://example.com/some/path
- Backend server:
http://192.168.1.24
- Need to preserve
/some/path
in browser address bar - Properly rewrite URLs in served content
The current configuration has two main problems:
1. Backend receives requests with /some/path included
2. Relative links in served pages don't maintain /some/path
Here's the working configuration that addresses both issues:
server {
listen 80;
server_name www.example.com;
location /some/path/ {
proxy_pass http://192.168.1.24/;
proxy_redirect ~^/(.*)$ /some/path/$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;
# Handle redirects from backend
proxy_redirect http://192.168.1.24/ /some/path/;
proxy_redirect ~^(http://192.168.1.24)(/.+)$ /some/path$2;
}
location / {
index index.html;
root /var/www/example.com/htdocs;
}
}
1. The trailing slash in proxy_pass:
proxy_pass http://192.168.1.24/
(with trailing slash) strips the /some/path
from the backend request.
2. Comprehensive proxy_redirect rules:
The regex patterns handle all redirect cases from the backend server while maintaining the original URL structure.
3. Header preservation:
Essential headers ensure the backend server receives proper client information.
To verify the configuration works:
# Original request:
curl -I http://example.com/some/path
# Should return content from 192.168.1.24 while showing:
# Location headers rewritten to maintain /some/path
# Test link navigation:
curl http://example.com/some/path/section/index.html
# Should properly serve content from 192.168.1.24/section/index.html
For complex setups with multiple backend servers:
map $request_uri $backend {
~^/some/path1/ 192.168.1.24;
~^/some/path2/ 192.168.1.25;
# Add more mappings as needed
}
server {
# ... other config ...
location ~ ^/(some/path\d)/ {
set $path_prefix $1;
proxy_pass http://$backend/;
proxy_redirect ~^/(.*)$ /$path_prefix/$1;
# ... other proxy settings ...
}
}
This dynamic approach scales better for managing hundreds of backend servers while maintaining clean URL structures.