When setting up Nginx as a reverse proxy for multiple applications, developers often encounter static file loading issues when applications are mounted under subpaths (like /app1, /app2). The root cause lies in how web applications typically generate absolute paths for static assets.
Consider this typical scenario:
location /app1 {
proxy_pass http://127.0.0.1:9001/;
}
While this routes requests to your application server, static assets break because:
- The application generates static file URLs relative to root (/static/...)
- Browser requests omit the /app1 prefix
We need to address both the reverse proxy configuration and application settings:
1. Nginx Configuration
server {
listen 80;
server_name mywebserver;
# Handle static files
location /app1/static/ {
alias /path/to/app1/static/;
expires 30d;
access_log off;
}
# Proxy configuration
location /app1/ {
proxy_pass http://127.0.0.1:9001/;
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;
# Important for applications that generate URLs
proxy_redirect ~^/(.*)$ /app1/$1;
}
}
2. Application Configuration
Most modern web frameworks support base URL configuration:
For Django:
# settings.py
FORCE_SCRIPT_NAME = '/app1'
STATIC_URL = FORCE_SCRIPT_NAME + '/static/'
For Flask:
app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/app1'
3. Alternative Approach: URL Rewriting
For applications you can't modify, use Nginx sub_filter:
location /app1/ {
proxy_pass http://127.0.0.1:9001/;
proxy_set_header Host $host;
sub_filter_once off;
sub_filter 'src="/' 'src="/app1/';
sub_filter 'href="/' 'href="/app1/';
}
Verify with curl:
curl -I http://mywebserver/app1/static/css/main.css
curl -v http://mywebserver/app1/api/health
Check for proper Content-Type headers and 200 responses for static files, while API calls should proxy through to your application.
- Enable gzip for static assets
- Set proper cache headers
- Consider using try_files for static assets before proxying
location /app1/ {
try_files $uri @proxy_app1;
}
location @proxy_app1 {
proxy_pass http://127.0.0.1:9001;
}
When setting up multiple web applications behind an Nginx reverse proxy with URL prefixes, developers often encounter static file loading issues. The root cause lies in how application paths are constructed versus how Nginx routes requests. Here's a deep dive into solving this properly.
# Current non-working setup
server {
listen 80;
server_name mywebserver;
location /app1 {
proxy_pass http://127.0.0.1:9001/;
# Missing static files handling
}
}
The key symptoms you'll observe in browser DevTools:
- 404 errors for JavaScript/CSS files
- Requests going to root (/) instead of prefixed paths (/app1)
- Mixed content warnings if using absolute paths
Here's the proper configuration that handles both proxying and static assets:
server {
listen 80;
server_name mywebserver;
# App1 configuration
location /app1 {
proxy_pass http://127.0.0.1:9001/;
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 static files
location /app1/static/ {
alias /path/to/app1/static/;
expires 30d;
access_log off;
}
}
# App2 configuration
location /app2 {
proxy_pass http://127.0.0.1:9002/;
# Similar proxy headers...
location /app2/assets/ {
alias /path/to/app2/assets/;
# Additional static file rules
}
}
}
For some frameworks, you'll need additional configuration:
Django Example
# settings.py
FORCE_SCRIPT_NAME = '/app1'
STATIC_URL = FORCE_SCRIPT_NAME + '/static/'
React/Vue SPA Solution
// vue.config.js
module.exports = {
publicPath: process.env.NODE_ENV === 'production'
? '/app1/'
: '/'
}
For applications that can't be easily configured:
# Rewrite static file paths
location /app1 {
proxy_pass http://127.0.0.1:9001/;
# Handle embedded paths
sub_filter_once off;
sub_filter 'href="/' 'href="/app1/';
sub_filter 'src="/' 'src="/app1/';
sub_filter 'url(/' 'url(/app1/';
}
- Check Nginx error logs:
tail -f /var/log/nginx/error.log
- Verify path mappings with
curl -v http://localhost/app1
- Use Chrome DevTools Network tab to inspect requests