SSL on Django, Nginx, and Gunicorn - django

I am using Nginx and gunicorn to serve my Django project. I currently have it working for ssl (https), but do not quite understand the correct settings for the settings file and nginx. Could someone have a look at my setup and tell me if anything blatantly looks wrong, or horribly executed?
My Nginx File, Please Note that some lines are commented out. When I uncomment them, the site stops working. Edit: When I uncomment them all at the same time/
server {
server_name example.com;
listen 443 ssl;
ssl on;
ssl_certificate /etc/ssl/mycrt.crt;
ssl_certificate_key /etc/ssl/mykey.key;
location = /favicon.ico {access_log off; log_not_found off;}
location /static/ {
gzip on;
gzip_types text/css;
alias /home/project/static/;
}
location / {
include proxy_params;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
# proxy_set_header Host $http_host;
# proxy_redirect off;
proxy_pass http://unix:/home/project/myproject/project.sock;
}
}
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
My Gunicorn File
[Unit]
Description=gunicorn daemon
After= network.target
[Service]
User=tyler
Group=www-data
Environment="Production=production"
WorkingDirectory=/home/project/myproject
ExecStart=/home/project/projectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/projecty/myproject_a$
[Install]
WantedBy=multi-user.target
And lastly, the dajngo settings
SECURE_SSL_REDIRECT = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
Are there any issues with this setup? I am very confused about the Nginx settings that I had to comment out in order for https to start working. Also, I know Django is very cautious on using the SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') setting. Does all look well?
Thanks!

It works for me. I don't sure it will work for you, but you can try.
location / {
proxy_set_header Host $http_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://unix:/home/project/myproject/project.sock;
}

Related

CSS files loaded but not rendered Django Rest Framework

I have a Django app with Gunicorn and Nginx deployed on AWS ECS. NGINX can load static files but the page still shows only text.
Nginx:
server {
listen 80;
listen [::]:80;
server_name api.example.com;
location /health {
access_log off;
return 200;
}
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_send_timeout 300;
# Main app
location / {
if ($request_method !~ ^(GET|POST|HEAD|OPTIONS|PUT|DELETE|PATCH)$) {
return 405;
}
include /etc/nginx/mime.types;
proxy_pass http://example-api:8000;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header X-Forwarded-Port $http_x_forwarded_port;
}
location /static/ {
autoindex on;
alias /my_app/static/;
}
}
In settings.py
STATIC_URL = '/static/'
STATIC_ROOT = '/my_app/static/'
When I inspect the webpage, all CSS files are loaded, no 404 (It was an issue before but I fixed that). So not sure what else I am missing here.
The UI works fine when running without Nginx and runserver, but on AWS ECS, I use gunicorn.

Getting rid of port in URL for django installation in production

I'm trying for the first time to deploy my Django application on a server but so far I wasn't able to get rid of port in my URL. Right now I'm using Gunicorn with Nginx with the following configuration.
Nginx /etc/nginx/sites-enabled/site.conf
server {
listen 8000;
server_name example.com;
location = /favicon.ico {access_log off;log_not_found off;}
location /static/ {
root /home/webapp/um;
}
location /media/ {
root /home/webapp/um;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/webapp/um/um.sock;
}
}
/etc/nginx/proxy_params
proxy_set_header Host $http_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;
Gunicorn /etc/systemd/system/gunicorn.service
Description=gunicorn service
After=network.target
[Service]
User=root
Group=www-data
WorkingDirectory=/home/webapp/um/
ExecStart=/root/um/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/webapp/um/um.sock um.wsgi:application
[Install]
WantedBy=multi-user.target
Gunicorn binding
gunicorn --bind 0.0.0.0:8000 um.wsgi:application
Changing port 8000 with port 80 in /etc/nginx/sites-enabled/site.conf gives me a 404 on nginx. Using port 8000 I'm able to see the site using http://example.com:8000/myapp but I'm aiming at using http://example.com/myapp as my address.
As a side note, the VPS I'm installing the app on came with Plesk already installed with which I'm also not familiar with. I don't know if Plesk might be interferring in catching traffic from port 80.
Thanks in advance
You just need to listen this server on port 80 instead of 8000
save gunicorn as described
server {
listen 80;
server_name 52.14.64.58 example.com www.example.com;
location = /favicon.ico {access_log off;log_not_found off;}
location /static/ {
root /home/webapp/um;
}
location /media/ {
root /home/webapp/um;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/webapp/um/um.sock;
}
}
52.14.64.58 => is ipv4 of your virtual machine, it could be anything in your case.
Now time to make changes in our django settings
ALLOWED_HOSTS = ['IP_ADDRESS', 'example.com', 'www.example.com']
Now check nginx status then restart gunicorn and nginx . I hope it would work for you.
sudo nginx -t
sudo systemctl restart nginx
sudo systemctl restart gunicorn
Now setup your domain by it's dns settings.
After a bit of struggling, I found the solution. Turns out my config was correct, but there was an nginx config file automatically written by plesk that was catching requests on port 80. The content of such file is
server {
listen 111.111.111.111:80;
location ^~ /plesk-site-preview/ {
proxy_pass http://127.0.0.1:8880;
proxy_set_header Host plesk-site-preview.local;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cookie_domain plesk-site-preview.local $host;
access_log off;
}
location / {
proxy_pass http://111.111.111.111:7080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 111.111.111.111:443 ssl;
ssl_certificate /opt/psa/var/certificates/certWpPLaPv;
ssl_certificate_key /opt/psa/var/certificates/certWpPLaPv;
location ^~ /plesk-site-preview/ {
proxy_pass http://127.0.0.1:8880;
proxy_set_header Host plesk-site-preview.local;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cookie_domain plesk-site-preview.local $host;
access_log off;
}
location / {
proxy_pass https://111.111.111.111:7081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Once I removed that file from inclusion in nginx.conf everything started working. As a suggestion for whoever is facing a similar situation, I would recommend to check what Nginx is processing using the following command
nginx -T

Where is robots.txt coming from (Nginx + Gunicorn + Django)?

I am running a server with Nginx + Gunicorn + Django.
I have configured Django to show a robots.txt file, and this works just fine when I test Django on its own, without Nginx+Gunicorn.
However, when I run the whole stack, /robots.txt suddenly gets replaced with a different file that I didn't write.
Why is this happening? I never wrote anything to tell Nginx or Gunicorn to do such a thing. Is there a default somewhere that I need to overwrite or deactivate?
The folder /etc/nginx/sites-enabled contains only my own sites file, and it doesn't mention /robots explicitly. It just has a location block targeting / which gets routed to Gunicorn+Django, and for every site except robots.txt this works just fine.
My Gunicorn config:
[Unit]
Description=gunicorn daemon
After=network.target
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=root
Group=www-data
WorkingDirectory=/root/lod/collab/collab
ExecStart=/root/lod/CollabVenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/root/lod/collab.sock collab.wsgi:application
[Install]
WantedBy=multi-user.target
My Nginx config:
server {
# if no Host match, close the connection to prevent host spoofing
listen 80 default_server;
listen [::]:80 default_server;
return 444;
}
server {
# redirect any http requests to https
listen 80;
listen [::]:80;
server_name example.com www.example.com localhost;
return 301 https://example.com$request_uri;
}
server {
# this is the main server application, serving example.com with https
listen 443;
listen [::]:443;
server_name example.com;
# SSL certificate
ssl on;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
# allow large request bodies, which may be necessary for some JSON commands
client_max_body_size 4G;
# ignore a missing favicon
location = /favicon.ico { access_log off; log_not_found off; }
# Django media
location /media {
alias /root/lod/CollabData/media_public; # your Django project's media files
}
# Django static
location /static {
autoindex on;
alias /root/lod/collab/collab/static_processed; # your Django project's static files
}
# send all non-media requests to the Django server
location / {
# necessary for SSL
# note:
# I have no idea what most of these do. I just followed tutorials on the internet.
# Feel free to improve this if you know what you are doing.
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host:443;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
# the connection to Gunicorn
proxy_pass http://unix:/root/lod/collab.sock;
}
}
EDIT:
It just started working correctly, even though I made no changes since the last time I opened the site. Maybe some background process or cache took a while to update? I'm leaving this question open in case someone can explain what caused this, so that other people won't have to spend as much time with this problem as I did.

Nginx, SSL, Django, CSRF verification failed (custom port)

I am working on a project using Django, nginx and Gunicorn. Everything is good except for POST requests. Django raise a CSRF error.
I dont know what is missing or wrong in my django and/or nginx conf.
Edit: I found out what was wrong. Because of my exotic SSL port.
I replaced this line in the 'location /' block:
proxy_set_header Host $host;
by:
proxy_set_header Host localhost:8443;
Django error:
Forbidden (403):
CSRF verification failed. Request aborted.
Reason given for failure:
Referer checking failed - https://localhost:8443/accounts/login/ does not match https://localhost/
Here is my nginx conf:
server {
listen 8880;
server_name localhost:8443;
rewrite ^ https://$server_name$request_uri? permanent;
}
#Gunicorn
upstream project {
server localhost:8888;
}
# HTTPS server
server {
listen 8443 ssl default_server;
ssl on;
server_name localhost;
ssl_certificate /path/file.crt;
ssl_certificate_key /path/file.key;
#Disable SSLv3
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
location / {
proxy_pass http://localhost:8888;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Ssl https;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 8443;
proxy_set_header Host $host; #Replaced by proxy_set_header Host localhost:8443;
}
}
and in my settings.py:
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
Try add in your location / this: proxy_pass_header X-CSRFToken;

nginx location path with proxy_pass

I have following problem, i'm trying to put a Django app with an gunicorn server on my VPS running Nginx. My nginx config looks like this:
upstream app_name {
server unix:/path/to/socket/file.sock fail_timeout=10;
}
server {
listen 80 default_server;
listen[::]:80 default_server ipv6only=on;
root /webapps/;
server_name my_hostname.com;
location / {
proxy_set_header Host $http_host;
}
location /appname/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_name;
}
}
However when i navigate to my_server.com/appname/ i constantly get 404 error. I'm still new to Nginx, could someone point me in the right direction on how to set the proxy_pass for /appname/ path? I should point out that when location for /appname/ is replaced with / the django app is running fine.
You just need a trailing slash for proxy_pass:
proxy_pass http://app_name/;
it helps you to cut the "appname" prefix so the config looks like:
upstream app_name {
server unix:/path/to/socket/file.sock fail_timeout=10;
}
server {
listen 80 default_server;
listen[::]:80 default_server ipv6only=on;
root /webapps/;
server_name my_hostname.com;
location /appname/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_name/;
}