Django, Nginx, HTTPs and HttpResponseRedirect - django

I'm receiving a 404 error from Nginx when attempting to return an HttpResponseRedirect from Django. This is all happening under HTTPs The flow goes something like this:
User goes to a page
Enters some information in a form
The view process the form after POST and then attempts to redirect the user to a different page.
Except, instead of redirecting to the page, Nginx just eventually servers its 404 page.
I can get this to work in development while not under Nginx and HTTPs, so I suspect this has something to do with my Nginx setup. I have this working successfully on other servers so I'm unsure why I cannot get it working here
Sample Django view:
#login_required()
def index(request):
if request.method == 'POST':
form = ShortenerForm(request.POST)
if form.is_valid():
# Do stuff
return HttpResponseRedirect(reverse('shortener_thankyou'))
else:
form = ShortenerForm()
return render(request, 'shortener/index.html', {'form': form})
Nginx
upstream apollo2_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:/webapps/apollo2/run/gunicorn.sock fail_timeout=0;
}
server {
listen 80;
server_name apollo.mydomain.com;
rewrite ^ https://$server_name$request_uri? permanent;
}
server {
listen 443;
ssl on;
ssl_certificate /etc/nginx/ssl/bundle.crt;
ssl_certificate_key /etc/nginx/ssl/mydomain.com.key;
server_name apollo.mydomain.com;
client_max_body_size 4G;
keepalive_timeout 70;
access_log /webapps/apollo2/logs/nginx-access.log;
error_log /webapps/apollo2/logs/nginx-error.log;
location /static/ {
alias /webapps/apollo2/static/;
}
location /media/ {
alias /webapps/apollo2/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://apollo2_app_server;
break;
}
}
# Error pages
error_page 500 502 503 504 /500.html;
location = /500.html {
root /webapps/apollo2/static/;
}
}
Nginx error
2015/04/24 11:04:10 [error] 18139#0: *3395 upstream prematurely closed connection while reading response header from upstream, client: 192.168.0.119, server: apollo.mydomain.com, request: "POST /shortener/ HTTP/1.1", upstream: "http://unix:/webapps/apollo2/run/gunicorn.sock:/shortener/",
I've tried a number of different solutions involving proxy_set_header X-Forwarded-Protocol $scheme; in Nginx and Djangos SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https') but without luck.

It turned out that this had nothing to do with Nginx, SSL or Django. IT changed one of our DNS servers without notifying me. The response was timing out because it could not resolve DNS. Updating to the new DNS server in /etc/resolv.conf solved the issue.

Related

site cannot reached after nginx restart - AWS EC2

I am following the tutorial and completed it without any error, when I start nginx it showed me welcome page but after I restart nginx chrome is showing
This site can’t be reached.
I am accessing it by my public IP.
Here is my security group of instance (Inbound)
(Outbound)
Here is my nginx conf file:
upstream sample_project_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/ubuntu/django_env/run/gunicorn.sock fail_timeout=0;
}
server {
listen 80;
server_name <my public ip>;
client_max_body_size 4G;
access_log /home/ubuntu/logs/nginx-access.log;
error_log /home/ubuntu/logs/nginx-error.log;
location /static/ {
alias /home/ubuntu/static/;
}
location /media/ {
alias /home/ubuntu/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://sample_project_server;
break;
}
}
# Error pages
error_page 500 502 503 504 /500.html;
location = /500.html {
root /home/ubuntu/static/;
}
}
any suggestions ? I am really frustrated, because every thing done perfectly but after restarting nginx, site is not reachable.

Nginx always falls back to default config

My stack is django, gunicorn, nginx and supervisor running on a VPS from DigitalOcean.
Supervisor is running the program correctly but I always get the NGINX welcome page. If I delete the default nginx config file everything works and I get the website.
Here are my custom settings:
upstream maet_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:/webapps/maet/run/gunicorn.sock fail_timeout=0;
}
server {
listen 80;
server_name maet.bg www.maet.com;
client_max_body_size 4G;
access_log /webapps/maet/logs/nginx-access.log;
error_log /webapps/maet/logs/nginx-error.log;
location /static/ {
alias /webapps/maet/website/static/;
}
location /media/ {
alias /webapps/maet/website/static/;
}
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://maet_app_server;
break;
}
}
# Error pages
error_page 500 502 503 504 /500.html;
location = /500.html {
root /webapps/maet/website/static/;
}
}
How do I change it to use this config instead of the default one?
I don't want to delete the default file because I need it for let's encrypt ssl.

How to deploy django on VPS with external subdomain.?

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

Unable to get nginx internal redirect to work

I'm using ubuntu 14.04 and running nginx 1.4.6 as reverse proxy server to talk to my django backend which runs on uwsgi. I'm unable to get the internal redirect to work, that is, the request does not reach django at all. Here is my nginx configuration /etc/nginx/site-enabled/default file. Please let me know what is wrong with my configuration.
server {
listen 8080;
listen 8443 default_server ssl;
server_name localhost;
client_max_body_size 50M;
access_log /var/log/nginx/nf.access.log;
error_log /var/log/nginx/nf.error_log debug;
ssl_certificate /etc/ssl/nf/nf.crt;
ssl_certificate_key /etc/ssl/nf/nf.key;
location / {
proxy_pass http://localhost:8000;
}
location /static/ {
root /home/northfacing;
}
location /media/ {
internal;
root /home/northfacing;
}
}
Adding my uwsgi configuration.
[uwsgi]
chdir=/home/northfacing/reia
module=reia.wsgi:application
master=True
pidfile=/home/northfacing/reia/reia-uwsgi.pid
vacuum=True
max-requests=5000
daemonize=/home/northfacing/reia/log/reia-uwsgi.log
http = 127.0.0.1:8000
Adding my uwsgi startup script
#!/bin/bash
USER="northfacing"
PIDFILE="/home/northfacing/reia/reia-uwsgi.pid"
function start(){
su - ${USER} /bin/sh -c "source /home/northfacing/nfenv/bin/activate && exec uwsgi --pidfile=${PIDFILE} --master --ini /etc/init.d/reia-uwsgi.ini"
}
function stop(){
kill -9 `cat ${PIDFILE}`
}
$1
/home/northfacing/nfenv is my python environment directory.
If you want django to handle permissions for accessing your media files, first thing to do is to pass all requests into django. I'm assuming that /home/northfacing is your project root dir (dir where by default manage.py will be placed), your static files are collected into public/static subdirectory in your project and media files are stored in public/media.
Basing on that assumptions, here is basic configuration for that behaviour:
server {
listen 8080;
server_name localhost;
client_max_body_size 50M;
access_log /var/log/nginx/nf.access.log;
error_log /var/log/nginx/nf.error_log debug;
ssl_certificate /etc/ssl/nf/nf.crt;
ssl_certificate_key /etc/ssl/nf/nf.key;
root /home/northfacing/public/;
location #default {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
include /etc/nginx/proxy_params;
proxy_pass softwaremind_server;
break;
}
location /static/ {
try_files $uri #default; # just some simple default action, so you can show django's 404 page instead of nginx default
}
location /media/ {
internal;
error_page 401 403 404 = #default;
}
location / {
try_files /maintenance.html #default; # you can disable whole page with simple message simply by creating maintenance.html with that message
}
}
Simple explanation: all requests to urls in /media/ are treated as internal, so nginx will serve 404, 401 or 403 error if entered directly. But in that location our proxy server (django in that case) is set as handler, so it will get request and will be able to check if user have access rights.
If there is no access, django can throw it's own error. If acces is granted, django should return an empty response with X-Accel-Redirect set to file path. Simple view for that can look like this:
class MediaView(View):
def get(self, request):
if not request.user.is_authenticated():
raise Http404
response = HttpResponse()
response.status_code = 200
response['X-Accel-Redirect'] = request.path
# all this headers are cleared-out, so nginx can serve it's own, based on served file
del response['Content-Type']
del response['Content-Disposition']
del response['Accept-Ranges']
del response['Set-Cookie']
del response['Cache-Control']
del response['Expires']
return response
And in urls.py:
url(r'^media/', MediaView.as_view(), name="media")
It was my mis-understanding of how internal redirect works. According to the doc below
http://nginx.org/en/docs/http/ngx_http_core_module.html#internal
an internal settings in the nginx configuration means that any request with that uri from the external source will be served with 404. It has to come only from the internal. In my case, the /media is used from the client as well. So, this was ignored by nginx. The following configuration worked.
In nginx, I have the following configuration. Note that /media is removed.
location /protected/ {
internal;
alias /home/northfacing/media/;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://127.0.0.1:8000;
}
and in python views,
def protect_uploads(request):
if settings.DEBUG == False:
response = HttpResponse()
response.status_code = 200
protected_uri = request.path_info.replace("/media", "/protected")
response['X-Accel-Redirect'] = protected_uri
del response['Content-Type']
del response['Content-Disposition']
del response['Accept-Ranges']
del response['Set-Cookie']
del response['Cache-Control']
del response['Expires']
logger.debug("protected uri served " + protected_uri)
return response
Thanks for all your suggestions. That lead to different experiments and eventually a fix.

Using Django, switched from heroku + gunicorn to digitalocean + nginx + gunicorn, site now broken

I had my django app on heroku for a while with no problems. I now want to move it to a digital ocean droplet, partly as a learning exercise, partly for scalability (and cost) reasons.
After following this excellent tutorial almost to the letter, the app is working but with a huge gotcha: I now get an infinite redirect loop when I try to log in to the admin site. The first request is a POST ?next=/admin/ with the username and password, this gets a 302 response to redirect to GET /admin/, which gets a 302 response redirect to ?next=/admin/, and so on.
I have spent 2 or 3 hours with google and various nginx tutorials and this is the first time my "google the error message, copy and paste random code snippets, repeat" algorithm has ever failed me, I'm hoping the reason is that the error is trivial to solve and I just can't see it?
If it's not trivial to solve, let me know and I'll post more info.
Thanks in advance
edit 1: my nginx config file for the app is basically a verbatim copy of the tutorial. It looks like this:
upstream hello_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:/webapps/hello_django/run/gunicorn.sock fail_timeout=0;
}
server {
listen 80;
server_name example.com;
client_max_body_size 4G;
access_log /webapps/hello_django/logs/nginx-access.log;
error_log /webapps/hello_django/logs/nginx-error.log;
location /static/ {
alias /webapps/hello_django/static/;
}
location /media/ {
alias /webapps/hello_django/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://hello_app_server;
break;
}
}
# Error pages
error_page 500 502 503 504 /500.html;
location = /500.html {
root /webapps/hello_django/static/;
}
}