I'm trying to test a deployment config for a Django setup that works fine in development mode.
I have name-based routing via Nginx's ssl_preread module on a load balancer, and SSL terminates at another Nginx instance on the server itself where the requests are proxied to uwsgi by socket.
server {
server_name dev.domain.net;
listen 80 proxy_protocol;
listen [::]:80 proxy_protocol;
location / {
return 301 https://$host$request_uri;
}
}
server {
server_name dev.domain.net;
listen 443 ssl;
listen [::]:443 ssl;
location / {
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/website.sock;
}
location /favicon.ico {
access_log off; log_not_found off;
}
}
I have uwsgi set to log %(host) and %(referer), they match in the logs.
In my uwsgi_params I'm passing $host and $referer like so, since I'm using name-based routing I pick up the $server_name variable that triggered the Nginx response...
uwsgi_param HTTP_REFERER $server_name;
uwsgi_param HTTP_HOST $host;
Adding (or taking away) protocols and ports to these makes no difference. Taking them away predictably generates a Django ALLOWED_HOSTS debug error.
I've confirmed that my ALLOWED_HOSTS includes the $host. I've tried adding CSRF_TRUSTED_ORIGINS for the same $host variable. I've tried setting CSRF_COOKIE_DOMAIN for the same $host variable. I have CSRF_COOKIE_SECURE set to True per the docs recommendation.
No matter what combination of the above settings are used, I get:
Referer checking failed - Referer is malformed. on all POST requests.
Short answer: don't use the uwsgi unix socket, but rather use
http-socketand send the proxy request to localhost over unencrypted http (in uwsgi ini file):In nginx, get rid of uwsgi proxy params and simply
proxy_passwithproxy_protocolheaders enabled:At that point you can enable all of the recommended deployment settings in the Django docs, explicitly declare your
ALLOWED_HOSTSand everything works fine.These are a quite silly series of hoops with no apparent correct set of answers, especially considering referers are client headers that are easily forged.
The better answer is Django needs to get rid of a client referer check in its CSRF mechanism, it's pointless and makes no sense...