I set up an nginx/gunicorn server with this tutorial. This worked like a charm with a local docker-compose file. Then I pushed the containers to AWS fargate, and set up a load balancer in front of the nginx. This worked too, but I got a "CSRF failed" exception, when trying to login to django admin.
This is because the host, port and protocol are not correctly forwarded from the user request though the load balancer and the nginx proxy to django gunicorn.
How do I have to configure nginx and django?
I ended up with this nginx configuration, which works behind a load balancer and with my local docker-compose config, where the user directly requests to nginx. rg_ is just the prefix for my project.
# Set proto and port to forwarded value, or to nginx value if
# forwarded value not set
map $http_x_forwarded_proto $rg_forwarded_proto {
default $scheme;
"~^(.*)$" $1;
}
map $http_x_forwarded_port $rg_forwarded_port {
default $remote_port;
"~^(.*)$" $1;
}
# Gunicorn proxy
upstream rg_serve {
server localhost:8100;
}
# Server
server {
listen 8090;
location / {
proxy_pass http://rg_serve;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $rg_forwarded_proto;
proxy_set_header X-Forwarded-Port $rg_forwarded_port;
proxy_set_header X-Forwarded-Host $host:$rg_forwarded_port;
proxy_redirect off;
}
location /static/ {
alias /home/app/rg_serve/web/static_collect/;
}
}
I have to set
USE_X_FORWARDED_HOST = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
in my django settings, to make it work.
What feels a bit strange is, that I have to add the port to X-Forwarded-Host to make it work in django. When I just do not add it, and set django settings to
USE_X_FORWARDED_HOST = True
USE_X_FORWARDED_PORT = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
Is does not work. I get the csrf exception.
Related
I have the following code running in production
The Nginx config is as follows:
# first we declare our upstream server, which is our Gunicorn application
upstream hello_server {
# docker will automatically resolve this to the correct address
# because we use the same name as the service: "djangoapp"
server webapp:8888;
}
# now we declare our main server
server {
listen 8558;
server_name localhost;
location / {
# everything is passed to Gunicorn
proxy_pass http://hello_server;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
}
Nginx server has port forwarding: 8555:8558
And the gunicorn command running is
gunicorn --bind :8888 basic_django.wsgi:application
Now in my browser i open this url:
http://127.0.0.1:8555/login_register_password/user_login_via_otp_form_email
Now my code in one of my views is
prev_url = request.META['HTTP_REFERER']
# EG: prev_url = http://127.0.0.1:8555/login_register_password/user_login_via_otp_form_email
# we want to get the url from namespace . We use reverse. But this give relative url not the full url with domain
login_form_email_url_reverse = reverse("login_register_password_namespace:user_login_via_otp_form_email")
# EG: login_form_email_url_reverse = "/login_register_password/user_login_via_otp_form_email"
# to get the full url we have to use do the below
login_form_email_url_reverse_full = request.build_absolute_uri(login_form_email_url_reverse)
# EG: login_form_email_url_reverse_full = "http://127.0.0.1/login_register_password/user_login_via_otp_form_email"
I am execpting prev_url and login_form_email_url_reverse_full to be same but it differs
prev_url domain is http://127.0.0.1:8555 whereas login_form_email_url_reverse_full domain is http://127.0.0.1
why this is happening.
This does not happen in development server. using runserver
"HTTP_HOST": "127.0.0.1:8555",
"HTTP_REFERER": "http://127.0.0.1:8555/login_register_password/user_login_via_otp_form_email",
Where as with nginx server: HTTP_HOST changes i.e now without port number
"HTTP_HOST": "127.0.0.1",
"HTTP_REFERER": "http://127.0.0.1:8555/login_register_password/user_login_via_otp_form_email",
I solved the problem by changing
proxy_set_header Host $host;
To
proxy_set_header Host $http_host;
in the server {} of local.conf of nginx
Got the answer from https://serverfault.com/a/916736/565479
Good day.
I have a web app that I have developed using django. I tested fine on my local, and I'm happy with how it works.
However I'm facing an issue bringing it online I used those two guides to reach my deployment:
https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-16-04
and
http://michal.karzynski.pl/blog/2013/06/09/django-nginx-gunicorn-virtualenv-supervisor/
However my page is giving me a forbidden page.
I suspect my issue is with the way I'm handling the subdomain. So the site . has been developed using php, and I have worked on my part with django and been provided with a subdomain which is member.domain.com, So I'm deploying it on the VPS and have to make it use the subdomain.
This is how my allowed hosts looks in the settings.py
ALLOWED_HOSTS = ['member.domain.com']
and
in my nginx:
upstream app_server {
# fail_timeout=0 means we always retry an upstream even if it failed
# to return a good HTTP response (in case the Unicorn master nukes a
# single worker for timing out).
server unix:/home/path/project/run/gunicorn.sock fail_timeout=0;
}
server {
listen 80;
server_name member.domain.com;
client_max_body_size 4G;
access_log /home/path/project/logs/nginx-access.log;
error_log /home/path/project/logs/nginx-error.log;
location /static/ {
alias /home/path/project/src/static/;
}
location /media/ {
alias /home/path/project/src/media/;
}
location / {
# an HTTP header important enough to have its own Wikipedia entry:
# http://en.wikipedia.org/wiki/X-Forwarded-For
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# enable this if and only if you use HTTPS, this helps Rack
# set the proper protocol for doing redirects:
# proxy_set_header X-Forwarded-Proto https;
# pass the Host: header from the client right along so redirects
# can be set properly within the Rack application
proxy_set_header Host $http_host;
# we don't want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;
# set "proxy_buffering off" *only* for Rainbows! when doing
# Comet/long-poll stuff. It's also safe to set if you're
# using only serving fast clients with Unicorn + nginx.
# Otherwise you _want_ nginx to buffer responses to slow
# clients, really.
# proxy_buffering off;
# Try to serve static files from nginx, no point in making an
# *application* server like Unicorn/Rainbows! serve static files.
if (!-f $request_filename) {
proxy_pass http://app_server;
break;
}
}
# Error pages
error_page 502 503 504 /500.html;
location = /500.html {
root /home/path/project/src/static/;
}
}
I'm not sure what I am doing wrong.
I will appreciate any help
To respond to 'example.com' and any subdomains, start the domain with a dot
ALLOWED_HOSTS = ['.example.com', '203.0.113.5']
I didn't even try how to run django on subdomains, but from article link you shared, you missed some configuration in your settings.py
ALLOWED_HOSTS = ['member.domain.com']
Changed
ALLOWED_HOSTS = ['.domain.com']
Hope this will solve your problem
To distribute load and implement security in our application we have taken elastic Load Balancer from amazon and SSL is configured on it.Now the redirection from http to https is not working in nginx configuration on server or instances which is attached on ELB.
Here is following nginx configuration:-
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name new.example.com;
access_log /var/log/nginx/domain-access.log;
location / {
proxy_read_timeout 90;
proxy_connect_timeout 90;
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;
proxy_pass http://127.0.0.1:8000;
}
}
Firstly the server is not supporting https URLs then I add some proxy settings in configuration but now issue is that redirection is not working i have used the following commands in ngnix configuration to redirect http to https :-
#version 1
server{
return 301 https://$server_name$request_uri;
}
#version 2
server {
rewrite ^(.*) https://$host$1 permanent;
}
Application deployed on server is build using django framework.
When I've done something similar, then I've set up the ELB HTTPS to redirect to HTTP port 80 on the node. I've then set up a second nginx vhost on the node, e.g. on port 81, which directs to return 301 https://$server_name$request_uri; and set up the ELB http listener to redirect to that port (where $server_name obviously points to the domain CNAME of the ELB)
I then make sure that the instances behind the ELB cannot be accessed from outside my VPC using security groups.
If you are using Django, you can use it to do the redirection, this give a lot of flexibilty like enabling HTTPS redirects only on production server or choose which urls to redirect from:
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
# Redirect to HTTPS in production
SECURE_SSL_REDIRECT = not DEBUG
# Disable redirection on this urls
SECURE_REDIRECT_EXEMPT = [
'^legacy/api/',
]
I upgraded Django from 1.8 to 1.9. Afterwards, I get this error on my localhost after the Django admin login:
Referer checking failed - Referer is insecure while host is secure.
Everything works fine in production.
Below is a snippet of my settings.py file:
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
I had this error when I was switching from ssl setup to no ssl and forgot to remove last line from upstream configuration in nginx config:
location / {
proxy_pass http://127.0.0.1:8085;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host; #:8080;
#proxy_set_header X-FORWARDED-PROTO https;
}
Those lines in your settings.py file are fine on production because you're using an SSL certificate attached to your domain. However, on local you're probably using http://localhost:8000 or something similar. If you try to connect via https://localhost:{{YOUR_PORT_NUMBER}} you'll most likely get an error like ERR_SSL_PROTOCOL_ERROR.
The issue is in lines 167-168 of django/django/middleware/csrf.py. When you're using https on production, request.is_secure() is returning True...which requires that the HTTP_REFERER also be true or you'll get the error you referenced.
One solution would be to adjust your settings.py file depending on whether you're in your local or production environment. That way you can add those three lines to a settings_production.py file that imports other settings that are common to both localhost and your production server. Your localhost would use a different set of settings that don't include those lines.
I am using Nginx + supervisord to host a django site behind SSL. The site index loads fine. Everything locally works fine without HTTPS using local server. I am using Django 1.4.2
For some reason I get weird redirections.
When using admin if I edit any item I get redirected to home page.
When submitting new item for save I get 404 (but data is saved).
Non admin:
Again form submit returns me to homepage instead of "success".
The reason for going to homepage I can explain. My nginx redirects all not http traffic to https://localhost with a 301 redirect. So I am guessing django does not think I need secure URLs in places.
The problem is django is not assuming secure url or rather
request.is_secure is False.
I have noted this SO
Accessing Django Admin over HTTPS behind Nginx
Made the changes for proxy pass, i dont think it does anything to handle this. But here it is as is.
settings.py
SESSION_COOKIE_SECURE = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
CSRF_COOKIE_SECURE = True
warning: I am fairly new to django.
I removed the Nginx redirection. Django already handles the redirection correctly.
This was the settings.py values I used together with my nginx proxy pass
SESSION_COOKIE_SECURE = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
CSRF_COOKIE_SECURE = True
Nginx proxy
location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_connect_timeout 10;
proxy_read_timeout 10;
proxy_pass http://localhost:8000/;
}
where localhost:8000 is where gunicorn is running.
I still have other issues but redirection problem is solved.