On production I use the chain Django - UWSGI - Docker - Nxing. UWSGI works with the port 50012 and Ngxin is configured as:
proxy_pass http://localhost:50012;
Django process thinks that its host is localhost:50012
instead of the domain that Nginx listens to. So when the function build_absolute_uri
is called there's localhost:50012
instead of my domain. Is there a way to make Django use the custom host name when build_absolute_uri
is called?
Notice: in some libraries build_absolute_uri
called implicitly (like social-django
, or example), so avoiding this function is not a solution in my case.
When the public hostname you use to reach the proxy differ from the internal hostname of the application server, Django has no way to know which hostname was used in the original request unless the proxy is passing this information along.
From MDN:
The X-Forwarded-Host (XFH) header is a de-facto standard header for identifying the original host requested by the client in the Host HTTP request header.
Host names and ports of reverse proxies (load balancers, CDNs) may differ from the origin server handling the request, in that case the X-Forwarded-Host header is useful to determine which Host was originally used.
There are two things you should do:
X-Forwarded-Host
headerUSE_X_FORWARDED_HOST
in the settingsSECURE_PROXY_SSL_HEADER
to a meaningful value and set the server to send the corresponding headerWhen USE_X_FORWARDED_HOST
is set to True
in settings.py
, HttpRequest.build_absolute_uri
uses the X-Forwarded-Host
header instead of request.META['HTTP_HOST']
or request.META['SERVER_NAME']
.
I will not delve too much into the proxy setup part (as it is more related to professional network administration than to programming in the scope of this site) but for nginx it should be something like:
location / {
...
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
...
proxy_pass http://upstream:port;
}
Probably the best solution as it is fully dynamic, you don't have to change anything if the public scheme/hostname changes in the future.
If the internal and external scheme differ as well you may want to set SECURE_PROXY_SSL_HEADER
in settings.py
to something like this:
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
And then add the following to the server config:
proxy_set_header X-Forwarded-Proto https;
Lets say your public hostname is "host.example.com": you can add a line like this to your /etc/hosts
(on Windows %windir%\System32\drivers\etc\hosts
):
127.0.0.1 host.example.com
Now you can use the hostname in the nginx config:
proxy_pass http://host.example.com:port;
When the internal and external scheme differ as well (external https, internal http), you may want to set SECURE_PROXY_SSL_HEADER
as described in the first solution.
Every time the public hostname changes you will have to update the config but I guess this is OK for small projects.
I got mine working using proxy_redirect
Lets say you have a container
or an upstream
with the name app
and you want it to return 127.0.0.1
as the host, Then your config should include:
server {
listen 80;
location / {
proxy_pass http://app:8000;
proxy_redirect http://app:8000 http://127.0.0.1:8000;
}
}
Here's my final config:
server {
listen 80;
location / {
proxy_pass http://app:8000;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect http://app:8000 http://127.0.0.1:8000;
}
}
Also checkout this article for a detailed explanation https://mattsegal.dev/nginx-django-reverse-proxy-config.html
I had a problem same as the question, I used nginx, gunicorn and django on production without docker.
get_current_site(request).domain
returned localhost
so I have some issue in drf yasg base url. Simply I solved it by adding
include proxy_params;
to nginx conf.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With