Deploy Django and Nginx under subpath
I'm trying to deploy a Django app with Gunicorn and Nginx under a subpath, I'm inside a corporate network, and the path www.example.com/myapp points to the IP 192.168.192.77:8080 of my PC on the local network (I have no control over the pathing nor the corporate network, just that port exposed to the internet through /myapp). I tried many things including this: How to host a Django project in a subpath? , but it doesn't show the Django welcome page, just the Nginx welcome page. I also can't access to the Django admin page that should be on the path /myapp/admin, just a 404 page.
This is the config of my site on the folder sites-available for Nginx:
server {
listen 8080;
server_name 192.168.192.77;
location /myapp/static/ {
root /home/user/myapp;
}
location /myapp/ {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}
I tried proxy_set_header SCRIPT_NAME /myapp; but it didn't work.
If I don't configure any paths, it shows the django welcome page at /myapp but then I can't acces /myapp/admin, also a 404.
Curiously, if I start the Django development server using python manage.py runserver without nginx it works, the django welcome page shows at /myapp and I can access /myapp/admin with the only problem that the CSS files don't load.
I already have FORCE_SCRIPT_NAME = /myapp and STATIC_URL = /myapp/staticin settings.py for Django.
In conclusion, how do I deploy this Django app to a subpath?
Best way (the method I usually use): Define a dedicated upstream block (a variable-like path) for each application you want to run behind Nginx. This makes your configuration cleaner and easier to scale — you can manage connection limits, failover settings, and keepalive behavior separately for each app. By defining reusable upstream names such as path_to_app_1 or path_to_app_2, you can later reference them in multiple location blocks using proxy_pass, which keeps the server section simple and consistent.
Add proxy_set_header X-Script-Name /myapp; to your Nginx location block. This tells Django it's running under a subpath, fixing /myapp/admin and other URL resolution issues. For root path you dont need to add it.
BTW I copied an example from my own nginx config that I use, but I changed the paths.
upstream path_to_app_1 {
least_conn;
server 127.0.0.1:8000 max_fails=3 fail_timeout=30s;
keepalive 100;
}
upstream path_to_app_2 {
least_conn;
server 127.0.0.1:9000 max_fails=3 fail_timeout=30s;
keepalive 100;
}
server {
listen 443 ssl;
server_name _;
ssl_certificate /opt/app/ssl/web.crt;
ssl_certificate_key /opt/app/ssl/web.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
location /static/ {
alias /opt/app/static/;
expires 1y;
add_header Cache-Control "public";
}
location /media/ {
alias /opt/app/media/;
expires 1y;
add_header Cache-Control "public";
}
location / {
proxy_pass http://path_to_app_1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /sub1/ {
proxy_pass http://path_to_app_2/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Script-Name /sub1;
}
location /sub2/ {
proxy_pass http://path_to_app_1/sub/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Script-Name /sub2;
}