1

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/static'in settings.py for Django.

In conclusion, how do I deploy this Django app to a subpath?

7
  • 2
    did you check www.example.com/myapp/myapp? Commented Oct 29 at 23:10
  • @furas I can't belive I didn't thought of that. It's working at www.example.com/myapp/myapp/. If I delete the last / it doesn't load at all, why?. On the other hand I need to delete one of the /myapp in the sub path so it shows just www.example.com/myapp Commented Oct 30 at 6:37
  • 1
    probably Django is configured to expect only urls with / at the end. And built-in server can redirect myapp to myapp/, but when you use external server then you have to do it on your own - probably using command rewrite (like in regex - Add slash to the end of every url (need rewrite rule for nginx) - Stack Overflow) Commented Oct 30 at 13:16
  • 1
    I think you should use some more universal formula like rewrite [^/]$ $uri/ because this missing / can make problem with any URL which you have in Django - i.e. /myapp/admin Commented Oct 30 at 14:39
  • 1
    I can't test it but I think you do it in wrong direction. If you want to remove duplicate myapp then you should remove one myapp from django (ie. FORCE_SCRIPT_NAME = '/myapp') or from location /myapp/. As for me you could use rewrite rather to convert /myapp to /myapp/myapp - so when client will try to connect to /myapp then it will redirect it to current working /myapp/myapp Commented Nov 1 at 1:12

1 Answer 1

2

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;
    }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.