how to deploy django under a suburl behind nginx

2020-02-03 10:41发布

问题:

I have a django application running on http://localhost:12345 . I'd like user to access it via url http://my.server.com/myapp . I use nginx to reverse proxy to it like the following:

... ...
server_name my.server.com;
location /myapp {
    rewrite /myapp(.*) $1 break;        
    ... ... # proxy param 
    proxy_pass http://localhost:12345;
}
... ...

The question is, when configured like the above, how to make the urls in my response pages to have a prefix of "/myapp" so that the nginx can direct them correctly to myapp. E.g., the urls in a page like "/foo/far" ought to be changed to "/myapp/foo/bar" to allow nginx proxy to myapp. what is the right nginx configure to use to achieve this ?

I can use settings variables of django to specify the root url prefix, but it's not flexiable to my mind, since the variable have to be modified according to different nginx configuration(say one day nginx may change the suburl from "/myapp" to "/anotherapp").

回答1:

As the prefix is set in Nginx, the web server that hosts the Django app has no way of knowing the URL prefix. As orzel said, if you used apache+mod_wsgi of even nginx+gunicorn/uwsgi (with some additional configuration), you could use the WSGIScriptAlias value, that is automatically read by Django.

When I need to use a URL prefix, I generally put it myself in my root urls.py, where I have only one line, prefixed by the prefix and including an other urls.py

(r'^/myapp/', include('myapp.urls')),

But I guess this has the same bottleneck than setting a prefix in settings.py, you have redundant configuration in nginx and Django.

You need to do something in the server that hosts your Django app at :12345. You could set the prefix there, and pass it to Django using the WSGIScriptAlias or its equivalent outside mod_wsgi. I cannot give more information as I don't know how your Django application is run. Also, maybe you should consider running your Django app directly from Django, using uWSGI or gunicorn.

To pass the prefix to Django from the webserver, you can use this :

proxy_set_header SCRIPT_NAME /myapp;

More information here



回答2:

You'll need to update your setting:

USE_X_FORWARDED_HOST = True
FORCE_SCRIPT_NAME = /myapp

And update your MEDIA_URL and STATIC_URL accordingly.

I haven't had the experience of deploying under nginx, but under apache, it works fine. refer to: https://docs.djangoproject.com/en/dev/ref/settings/#use-x-forwarded-host



回答3:

Here is part of my config for nginx which admittedly doesn't set FORCE_SCRIPT_NAME, but then, I'm not using a subdirectory. Maybe it will be useful for setting options related to USE_X_FORWARDED_HOST in nginx rather than Django.

upstream app_server_djangoapp {
    server localhost:8001 fail_timeout=0;
}

server  {
    listen xxx.xxx.xx.xx:80;
    server_name mydomain.com www.mydomain.com;
    if ($host = mydomain.com) {
        rewrite ^/(.*)$ http://www.mydomain.com/$1 permanent;
    }
    ...
    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;

        if (!-f $request_filename) {
            proxy_pass http://app_server_djangoapp;
            break;
        }
    }
    ...
}