Score:0

Django / Gunicorn with Nginx reverse proxy - Wrong redirect to base path

in flag

I have a Django app successfully running with Gunicorn/Uvicorn, under a subpath of my domain (example.com/myapp).

The Nginx vhost looks like this:

server {

    server_name example.com;

    location /myapp/ {
        proxy_pass http://myapp_gunicorn/;
        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;
    }

    location /myapp/static/ {
        alias /home/www/myapp/static/;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

upstream myapp_gunicorn {
    server 127.0.0.1:8002;
}

server {
    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
    server_name example.com;
    listen 80;
    return 404; # managed by Certbot
}

Here is the systemd service with the start command of Gunicorn:

[Unit]
Description=myapp gunicorn daemon
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/home/www/myapp
ExecStart=/home/venvs/myapp/bin/gunicorn myapp.asgi:application -b 0.0.0.0:8002 -w 8 -k uvicorn.workers.UvicornWorker --log-file /home/www/myapp.log

[Install]
WantedBy=multi-user.target

Reading on SO about Django in subfolder with Nginx, I added the following settings to my Django settings.py:

FORCE_SCRIPT_NAME = '/myapp'
USE_X_FORWARDED_HOST = True
# To make Django trusts the https from the Nginx proxy
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

I can successfully access my app and its subpaths like https://example.com/myapp/endpoint and the Django admin page https://example.com/myapp/admin (successfully rewritten as https://example.com/myapp/admin/login/?next=/admin/) for example.

However, when clicking on the validation button Django admin page, I get wrongly redirected to the base path (https://example.com/admin/login/?next=/admin/). Also, I get a 404 for all the static files, they are also served under the base path https://example.com/static/xxx instead of the subpath https://example.com/myapp/static/xxx, although I thought it was correctly setup in the vhost.

I have been looking at similar issues on SO (including this very similar one), but it didn't help me.

Any idea?

Michael Hampton avatar
cz flag
Did you tell your app what the base path is?
in flag
In the Django setting, I set the BASE_DIR constant: `BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))`, which is the system bas path of the app. By I'm not sure that's what you're referring to?
Michael Hampton avatar
cz flag
But where did you tell it that the base of all your routes is `/myapp`?
in flag
Nowhere, but I thought Django was managing that on its own. Locally it works fine. Should I set the base route? How?
in flag
From what I understand, FORCE_SCRIPT_NAME setting is supposed to fill this role in this precise case. Looks very much like this (unresolved ) issue: https://stackoverflow.com/questions/19103470/django-admin-force-script-name-login-redirects-incorrectly
in flag
FYI I gave up, didn't find a solution and it seems there are none according to this https://stackoverflow.com/questions/19103470/django-admin-force-script-name-login-redirects-incorrectly. So I created different vhosts and subdomains for each of my Python apps.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.