Accessing Django Admin over HTTPS behind Nginx - django

I've got django running in uwsgi behind nginx. When I try to access https://site/admin/ I get the expected login screen. Logging in via the form seems to succeed, however, I simply end up back at the login screen. Firebug shows a redirect to the plain http://site/admin/ url which is then redirectec by nginx to the https url.
Help! I'm confused as to how to force the admin app to use only https urls.
Note this seems to be a related, unanswered question: https://example.com/admin redirects to https://admin in Django Nginx and gunicorn

Adding the following to nginx.conf fixed the issue for me.
location / {
...
include uwsgi_params;
uwsgi_param HTTP_X_FORWARDED_PROTOCOL https;
uwsgi_param UWSGI_SCHEME $scheme;
}
Along with adding the following to settings.py:
SESSION_COOKIE_SECURE = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
CSRF_COOKIE_SECURE = True

the following should be all you need to have all traffic to the admin app redirected to
https
location /site/admin/ {
rewrite ^ https://$host/$request_uri permanent;
}
If that doesn't work, can you post your actual nginx config bits? Can't really suggest more then that without your actual config to look at.

Update for Django 1.8 settings.py:
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True
SECURE_REDIRECT_EXEMPT = [r'^(?!admin/).*']
And for your developement rig you may want to overwrite SECURE_SSL_REDIRECT = False in your local settings.

Related

allowed_host changes not effective

I've got an address say example.com and have added it to the allowed_hosts list. But when I access the site I get
ALLOWED_HOSTS ['127.0.0.1', '::1', '178.XX.XX.XXX', 'xx80::xx81:xxx:xx3x:x12x%eth0']
in the debug error page, while the actual settings.py file reads ['178.XX.XX.XXX','example.com']. I figured the changes to settings.py aren't registered as I can remove 178.XX.XX.XXX from the list and still access the site (after clearing the browser cache) I've restarted nginx, gunicorn and the whole server to no avail. The whole thing is set up on ubuntu 16.04 running django 1.8 and using nginx and gunicorn. Any ideas where this override of allowed_hosts could be coming from?
Ok this is embarassing but the One-cick install for django on 16.04 from Digital Ocean adds a line at the very end of settings.py where ALLOWED_HOSTS is redefined.
# Find out what the IP addresses are at run time
# This is necessary because otherwise Gunicorn will reject the connections
def ip_addresses():
ip_list = []
for interface in netifaces.interfaces():
addrs = netifaces.ifaddresses(interface)
for x in (netifaces.AF_INET, netifaces.AF_INET6):
if x in addrs:
ip_list.append(addrs[x][0]['addr'])
return ip_list
# Discover our IP address
ALLOWED_HOSTS = ip_addresses()
ALLOWED_HOSTS.append('.example.com') #I added this line
So adding an append to the line fixes the problem.

Django - static/CACHE files not found

I'm using Django 1.10 + uWsgi + nginx.
In Prod mode the static files do not show up, this is what my nginx error-log tells me:
404 ... static/CACHE/js/e3a6fa7588d1.js" failed (2: No such file or directory),
The folder static/CACHE remains empty (so the 404's make sense), but why?
I already set the permissions to 775 for static/CACHE .
nginx conf:
# /etc/nginx/sites/available/mysite_nginx.conf
# the upstream component nginx needs to connect to
upstream bdjango {
server unix:///tmp/mysite.sock; # for a file socket
}
# configuration of the server
server {
# the port your site will be served on
listen 80;
# the domain name it will serve for
server_name dev.mysite.com; # substitute your machine's IP address or FQDN
charset utf-8;
# max upload size
client_max_body_size 8M; # adjust to taste
# Django media
location /media {
alias /var/www/mysite/src/media; # your Django project's media files - amend as required
}
location /static {
alias /var/www/mysite/src/static; # your Django project's static files - amend as required
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass adjango;
include /var/www/mysite/src/uwsgi_params; # the uwsgi_params file you installed
}
}
Django settings contains
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__) + "../../../")
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static')
So, why are my js/css files not in static/CACHE ?
EDIT:
solved it: uwsgi_pass was pointing at the wrong upstream location (which happened to be a different website):
uwsgi_pass adjango;
Are you using CACHE?
Have you defiened STATIC_URL and STATIC_ROOT correctly.
Is DEBUG = False?
Are you using any 3rd party tool to cache/pipline your static files?
It could be that django-compressor is failing.
Have you tried having DEBUG = True and COMPRESS_ENABLED = True in your settings and seeing if it works?
https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_ENABLED
Alternatively, I suggest having ADMINS setup in production so it emails you any errors, or setup sentry in your production setup.

Error "You're accessing the development server over HTTPS, but it only supports HTTP"

When I try to write the server link like http:// .... it redirects to https:// and in the terminal :
message Bad HTTP/0.9 request type ('\x16\x03\x01\x00\x8b\x01\x00\x00\x87\x03\x01Ð\x118¿JÄ\x19[Òç\x01<O')
You're accessing the development server over HTTPS, but it only supports HTTP.
I think you should create different settings.py ( base_settings.py, local_settings.py, production_settings.py). And in your settings.py do something like this:
import socket
if socket.gethostname()=="Raouf-PC":
from local_settings import *
Change 'Raouf-PC' to the hostname of your PC.
P:S: I'm using Windows 10.
After doing that place the below data in your production_settings.py and save. Then clear your browser cache and visit your site in development server.
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True
If the above doesn't suit your needs, then in your local_settings.py paste the below data, save and clear your browser cache and visit your site.
SESSION_COOKIE_SECURE = False
CSRF_COOKIE_SECURE = False
SECURE_SSL_REDIRECT = False
Note: at the beginning of production_setttings.py and local_settings.py put:
from base_settings.py import *
Your base settings should contain 'settings' that will be used both on local and production server so you won't be repeating it everytime.
P:S If my answer is accepted, I dedicate it to the good people on SO who have helped me in one way or the other. This is my first time of answering a question. I hope to do more in the future. :)
You probably have the setting SECURE_SSL_REDIRECT set to True
This setting should be False when running the development server
Instead of using the command
python manage.py runserver
I used
python manage.py runserver 8080
Just by changing the port number, it is working for me.
CORS_REPLACE_HTTPS_REFERER = False
HOST_SCHEME = "http://"
SECURE_PROXY_SSL_HEADER = None
SECURE_SSL_REDIRECT = False
SESSION_COOKIE_SECURE = False
CSRF_COOKIE_SECURE = False
SECURE_HSTS_SECONDS = None
SECURE_HSTS_INCLUDE_SUBDOMAINS = False
SECURE_FRAME_DENY = False
1. Put this settings at the end of your settings.py
2. Clear your browser cache and then run your project.
If you are part of a team, you can use a variable to set the development environment. I use DJANGO_DEV=development
for e.g., on the computer that will be used for development, you add this to your ~/.bashrc file:
export DJANGO_DEV=true
or you can use django-environ
After that you can check, if current environment is a DEV env and set the specific values.
import os
if os.environ.get('DJANGO_ENV') is not None:
SECURE_SSL_REDIRECT = False
SESSION_COOKIE_SECURE = False
CSRF_COOKIE_SECURE = False
else:
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
If there are multiple settings, that you can go and define specific files as described in #yoyo's answer.
Simply change the path in your .env file to http://localhost:8000/
It worked for me. I'm using the Django backend and React frontend with the Django rest framework.
Nothing above helped me so digged in setting.py and
changed this to ACCOUNT_DEFAULT_HTTP_PROTOCOL = "https"
this ACCOUNT_DEFAULT_HTTP_PROTOCOL = "http"
it fixed the problem for me hope it helps
I also recommend to be sure that you are not trying access page by some port. For example by running Django server on PyCharm with some port.
Insert the below configs at the end of your settings.py file or completely comment them out(if you already had)
SECURE_CONTENT_TYPE_NOSNIFF = False
SECURE_BROWSER_XSS_FILTER = False
SECURE_SSL_REDIRECT = False
SESSION_COOKIE_SECURE = False
CSRF_COOKIE_SECURE = False
X_FRAME_OPTIONS = 'DENY'
then-,
2. Clear your browser cache and then re-run your project.
its clearly telling that you are accessing development server over https, but it only supports http.
usually we access development server like http://127.0.0.1:8000 but in your case its https://127.0.0.1:8000 as it's mentioned we cannot access development server over https.
I have gone through the same problem, but in my case when I was sending the email verification to gmail account, I was sending endpoint as https://127.0.0.1:8000/verify. https was used instead of http, so I corrected it to http then it worked fine.
Check the Django's site URL. It may have https.
Disable following variables in settings.py or .env
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
CSRF_TRUSTED_ORIGINS = ['yoursite.com']
Set DEBUG as True
DEBUG = True
Clear the Django site's(what you developed) cookies and sessions on the browser. For Google Chrome, steps are below.
Settings-> Privacy and Security -> Cookies and other site data -> See all cookies and site data -> Search your site name or IP and click 'Trash' icon.
Close the browser and reload the site now.

how to deploy django under a suburl behind nginx

I have a django application running on http://localhost:12345 .
I'd like user to access it via url http://my.server.com/myapp .
I use nginx to reverse proxy to it like the following:
... ...
server_name my.server.com;
location /myapp {
rewrite /myapp(.*) $1 break;
... ... # proxy param
proxy_pass http://localhost:12345;
}
... ...
The question is, when configured like the above, how to make the urls in my response pages to have a prefix of "/myapp" so that the nginx can direct them correctly to myapp. E.g., the urls in a page like "/foo/far" ought to be changed to "/myapp/foo/bar" to allow nginx proxy to myapp.
what is the right nginx configure to use to achieve this ?
I can use settings variables of django to specify the root url prefix, but it's not flexiable to my mind, since the variable have to be modified according to different nginx configuration(say one day nginx may change the suburl from "/myapp" to "/anotherapp").
As the prefix is set in Nginx, the web server that hosts the Django app has no way of knowing the URL prefix. As orzel said, if you used apache+mod_wsgi of even nginx+gunicorn/uwsgi (with some additional configuration), you could use the WSGIScriptAlias value, that is automatically read by Django.
When I need to use a URL prefix, I generally put it myself in my root urls.py, where I have only one line, prefixed by the prefix and including an other urls.py
(r'^/myapp/', include('myapp.urls')),
But I guess this has the same bottleneck than setting a prefix in settings.py, you have redundant configuration in nginx and Django.
You need to do something in the server that hosts your Django app at :12345. You could set the prefix there, and pass it to Django using the WSGIScriptAlias or its equivalent outside mod_wsgi. I cannot give more information as I don't know how your Django application is run. Also, maybe you should consider running your Django app directly from Django, using uWSGI or gunicorn.
To pass the prefix to Django from the webserver, you can use this :
proxy_set_header SCRIPT_NAME /myapp;
More information here
You'll need to update your setting:
USE_X_FORWARDED_HOST = True
FORCE_SCRIPT_NAME = /myapp
And update your MEDIA_URL and STATIC_URL accordingly.
I haven't had the experience of deploying under nginx, but under apache, it works fine.
refer to: https://docs.djangoproject.com/en/dev/ref/settings/#use-x-forwarded-host
Here is part of my config for nginx which admittedly doesn't set FORCE_SCRIPT_NAME, but then, I'm not using a subdirectory. Maybe it will be useful for setting options related to USE_X_FORWARDED_HOST in nginx rather than Django.
upstream app_server_djangoapp {
server localhost:8001 fail_timeout=0;
}
server {
listen xxx.xxx.xx.xx:80;
server_name mydomain.com www.mydomain.com;
if ($host = mydomain.com) {
rewrite ^/(.*)$ http://www.mydomain.com/$1 permanent;
}
...
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://app_server_djangoapp;
break;
}
}
...
}

Django sessions not working in Internet Explorer

Sessions work perfectly in all other browsers that I have tested.
If I try to get the session id with sessionid = request.COOKIES['sessionid'], I get this error: KeyError: 'sessionid'
This is what I have in my settings.py:
CACHE_BACKEND = 'memcached://127.0.0.1:11211/'
SESSION_COOKIE_DOMAIN = '.vb.is'
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
Sites are vb.is, fiskifrettir.vb.is and hestabladid.vb.is
Server setup is: apache2 (mod_wsgi) and nginx
Setting a cookie on XX.XX won't work in general. See Q#6 here: http://blogs.msdn.com/b/ieinternals/archive/2009/08/20/wininet-ie-cookie-internals-faq.aspx and see http://blogs.msdn.com/b/ieinternals/archive/2009/09/19/private-domain-names-and-public-suffixes-in-internet-explorer.aspx.
You can avoid the problem by setting the cookie with domain=WWW.vb.is instead.