Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I redirect non-SSL traffic that comes in on an SSL port with Nginx

Tags:

nginx

I have a fairly standard setup with nginx fronting a django app. I want the django app to be SSL only, and so I have two listen blocks in my nginx conf, with the traffic coming in on port 80 (HTTP) being redirected to port 443 (SSL). This is working as expected.

I am running this setup inside a VM that has port forwarding turned on, such that I can browser the site from the host machine by going to port 8080 (HTTP) or 8081 (SSL). Again, this work fine, as expected.

The problem comes when I am redirected internally from the Django app during a registration workflow. Because Django never sees the SSL status (SSL is terminated at nginx, and traffic to the app is forwarded on port 5000 over HTTP), but does see the port, the redirect is getting mangled**.

The net result of all of this is that I have traffic being directed into nginx on the SSL port, that is not SSL, e.g. http://127.0.0.1:443/. Is there any way to configure nginx to handle this?

** NB I am setting the X-Forwarded-Proto header in Nginx, and Django is picking up the correct .is_secure() value, this is a specific problem with an external library not checking is_secure and just redirecting on the incoming URL scheme.

[UPDATE 1]

Attached are the relevant config settings. This is from the Vagrantfile itself, showing the port forwarding:

config.vm.forward_port 80, 8080     # website, via nginx (redirects to SSL:8081)
config.vm.forward_port 443, 8081    # website, via nginx (accepts SSL)
config.vm.forward_port 5000, 8180   # website, via gunicorn (direct)

Using the above port forwarding configuration, if I browse to the site on the host machine on the HTTP port (8080), then the request is accepted, and nginx (see below) redirects this request to HTTPS (running on port 8081). Once I am on HTTPS the site itself works fine:

(host) http://127.0.0.1:8080  -> forwarded to -> (guest vm) http://127.0.0.1:80  
(host) https://127.0.0.1:8081 -> forwarded to -> (guest vm) https://127.0.0.1:443

The problem occurs when I get a redirect internally from Django which mixed scheme & protocol, and ends up with a request to http:\\127.0.0.1:8081\..., which fails, as nginx is expecting traffic on 8081 to be SSL.

What I really want is a rule that says 'listen on 443 for both SSL and non-SSL and redirect non-SSL'.

This is the relevant nginx configuration:

# Django app is served by Gunicorn, running under port 5000 (via Foreman)
upstream gunicorn {
    server 127.0.0.1:5000 fail_timeout=0;
}

server {
    listen 80;
    # 8081 is the port I am forwarding to on the host machine
    rewrite ^ https://127.0.0.1:8081$request_uri? permanent;
}

server {
    listen 443;

    ssl on;
    ssl_protocols       SSLv3 TLSv1;
    ssl_ciphers         HIGH:!ADH:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_certificate     /etc/nginx/ssl/self-signed.crt;
    ssl_certificate_key /etc/nginx/ssl/self-signed.key;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    location /static/ {
        alias /app/static/;
    }
    location /media/ {
        alias /app/media/;
    }
    location / {
        # everything else is to be served by the django app (upstream 'gunicorn')
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # this is set to ensure that django is_secure returns True
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_host;
        proxy_pass http://gunicorn;
    }
}
like image 630
Hugo Rodger-Brown Avatar asked Jan 03 '13 18:01

Hugo Rodger-Brown


People also ask

How do I redirect traffic from HTTP to HTTPS in nginx?

Redirect HTTP to HTTPS version for Specified domain in Nginx Server_name domain-name.com www.domain-name.com – it specifies the domain names. So, replace it with your website domain name that you want to redirect. Return 301 https://domain-name.com$request_uri – it moves the traffic to the HTTPS version of the site.

What is SSL redirection?

Once you have SSL installed, you need to redirect visitors who are still accessing your old HTTP site to your new HTTPS site. You can redirect visitors to your HTTPS domain automatically—even when they try to use your old HTTP domain.


1 Answers

You should check out "Error Processing" section of this document:

http://nginx.org/en/docs/http/ngx_http_ssl_module.html

Non-standard error code 497 may be used to process plain HTTP request which has been sent to HTTPS port.

Something like this should work (untested):

error_page 497 https://$host$request_uri;

Named locations may also be used in error_page, see http://nginx.org/r/error_page for details.

like image 179
Andrei Belov Avatar answered Sep 28 '22 10:09

Andrei Belov