Reputation: 1962
I'm running a simple Django application without any complicated setup (most of the default, Django allauth & Django Rest Framework).
The infrastructure for running both locally and remotely is in a docker-compose file:
version: "3"
services:
web:
image: web_app
build:
context: .
dockerfile: Dockerfile
command: gunicorn my_service.wsgi --reload --bind 0.0.0.0:80 --workers 3
env_file: .env
volumes:
- ./my_repo/:/app:z
depends_on:
- db
environment:
- DOCKER=1
nginx:
image: nginx_build
build:
context: nginx
dockerfile: Dockerfile
volumes:
- ./my_repo/:/app:z
ports:
- "7000:80"
... # db and so on
as you see, I'm using Gunicorn the serve the application and Nginx as a proxy (for static files and Let's Encrypt setup. The Nginx container has some customizations:
FROM nginx:1.21-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d
And the nginx.conf file is a reverse proxy with a static mapping:
server {
listen 80;
location / {
proxy_pass http://web;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /static/ {
alias /app/my_repo/static/;
}
}
Running this on the server after setting up let's encrypt in the Nginx container works without any issue, but locally I get the "CSRF verification failed. Request aborted." error every time I submit a form (e.g. create a dummy user in Django Admin). I exposed the web port and used it to submit the forms and it worked.
Because of that, I deduce that there is something missing in the Nginx config or something to "tell" Django how to handle it. So, what I'm missing and how should I investigate this?
Upvotes: 19
Views: 21951
Reputation: 767
Add this to nginx.conf
:
proxy_set_header X-Forwarded-Proto $scheme;
And this to Django's settings.py
:
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
This will allow Django to recognize the connection as secure despite nginx translating https into http, and you can leave CSRF_TRUSTED_ORIGINS
empty.
Upvotes: 2
Reputation: 43
No Idea if this is any helpful but consider the non standarized input of environment variables as a common source for errors.
For example, latest release of netbox configuration.py stating to put the different origins not in a array like @rahmatns mentioned. So maybe take a closer look into how the env is handled in the python code.
CSRF_TRUSTED_ORIGINS=https://demo.netbox.dev http://demo.netbox.dev
# Cross-Site-Request-Forgery-Attack settings. If Netbox is sitting behind a reverse proxy, you might need to set the CSRF_TRUSTED_ORIGINS flag.
# Django 4.0 requires to specify the URL Scheme in this setting. An example environment variable could be specified like:
# CSRF_TRUSTED_ORIGINS=https://demo.netbox.dev http://demo.netbox.dev
CSRF_TRUSTED_ORIGINS = _environ_get_and_map('CSRF_TRUSTED_ORIGINS', '', _AS_LIST)
Upvotes: 1
Reputation: 549
If you're using Nginx as a reverse proxy, make sure that it's passing the HTTP_REFERER header to Django correctly. You might need to adjust your Nginx configuration to allow the Referer header:
location / {
proxy_set_header Referer $http_referer;
...
}
Upvotes: 3
Reputation: 1033
Since you're using a proxy that translates https requests into http, you need to configure Django to allow POST requests from a different scheme (since Django 4.0) by adding this to settings.py
:
CSRF_TRUSTED_ORIGINS = ["https://yourdomain.com", "https://www.yourdomain.com"]
If this does not solve your problem, you can temporarily set DEBUG = True
in production and try again. On the error page, you will see a "Reason given for failure" that you can post here.
Upvotes: 37