News
9th December 2014 | By:

Using HTTPS on localhost

There are several ways to run a dev server on a local machine. We can achieve this with built-in tools in the dev environment (such as ‘Django server’) or by setting up ‘nginx’ locally etc. All these solutions are awesome to use during day-to-day work and development.

However, each of these connections runs on a standard insecure HTTP protocol. Sometimes we want to work with third party services which are served by HTTPS and that we can not access without HTTPS on our server or we just simply want to test our system with a secure connection. To do this we need to enable HTTPS on our localhost. If anyone has ever tried to set it up, you may have noticed that it is not as easy as it sounds, and can be a little bit tricky.

1. Tunnelling

The fastest way of achieving this is to use ‘ngrok’. It is quite slow to work with but we are getting it for free. It allows tunnelling between our local HTTP server and we can stream it as HTTPS so that we can access it online.

./ngrok --subdomain='our-domain-name' 8000

Where ‘subdomain’ is the address through which we can access our page, and ‘8000’ is the port our server is running on, on our local machine.

http://our-domain-name.ngrok.com
https://our-domain-name.ngrok.com

2. Create a certificate

Another way to use an HTTPS connection on our dev server is to create a self signed certificate. The important thing to notice is that this certificate is not working for a specific IP so we need to generate our certificate for an alias that is ‘localhost’.

2.1 Create a certificate and key

The following example is taken from here.

a) Generate the key

You can generate the key as follows:

openssl genrsa -des3 -out server.key 1024

b) Generate a CRT file

When executing this command remember to set all the required informations and set ‘Common name’ to ‘localhost’.

Screen Shot 2014-12-08 at 10.53.46

openssl req -new -key server.key -out server.csr

c) Remove the passphrase from the key

You need to remove the passphrase from the key as follows:

cp server.key server.key.org
openssl rsa -in server.key.org -out server.key

d) Generate a self-signed certificate

We can specify the period of time our certificate will be valid for by changing the ‘-days’ value.

openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

After that we can use our certificate.

2.2. Install certificate

Now we need to install the certificate on our system. This process is different for each system.

a) Mac:

Follow the following steps:

  • – Open the certificate (double click) using Key Chain
  • – Choose ‘System’ keychain
  • – Set ‘Always Trust’
  • – Edit the added certificate and expand the ‘Trust’ tab and set ‘When using this certificate’ to ‘Always trust’
b) Linux:

You simply need the following code:

sudo cp server.crt /etc/ssl/certs
sudo cp server.key /etc/ssl/private

Our self signed certificate is now registered on our system, so the browser will fetch it automatically and treat it as a proper SSL certificate.

2.3. Using the certificate

Now we are ready to run our server and use our certificate. We can do it in few ways as well:

a) Flask:

This is the simplest way of running our server with HTTPS protocol. We can provide the certificate and the key straight into the method run.

from flask import Flask
app = Flask(__name__)
app.run('0.0.0.0', debug=True, port=8100, ssl_context=('$PATH/server.crt', '$PATH/server.key'))

b) Django:

Unfortunately we can not use native Django to do this.

One of the solution is to install django-sslserver and provide certificate/key. After that we can run our django server in HTTPS mode.

pip install django-sslserver

Then we need to add it to our installed apps as follows:

INSTALLED_APPS = (
"sslserver",
...
)

Now we can run it by doing the following:

python manage.py runsslserver --certificate $PATH/certificate.crt --key $PATH/key.key

c) NGINX

The last described method, but also a really universal way of achieving this is to set up a local server with ‘nginx’.

I found a simple configuration file for ‘nginx’ here, which will detect your local server running on port 3000.

  • – Install ‘nginx'(instructions here)
  • – Replace default conf file ‘$PATH/nginx.conf’ with the one provided below.
  • – Reload ‘nginx’ settings

You can reload the nginx settings using:

sudo nginx -s reload

Sample ‘nginx’ configuration file.

# nginx.conf
worker_processes 1;
events {
    worker_connections 1024;
}
http {
    include mime.types;
    default_type application/octet-stream;
    send_timeout 1800;
    sendfile on;
    keepalive_timeout 6500;
    server {
        listen 80;
        server_name localhost;
        location / {
            proxy_pass http://localhost:3000;
            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-Client-Verify SUCCESS;
            proxy_set_header X-Client-DN $ssl_client_s_dn;
            proxy_set_header X-SSL-Subject $ssl_client_s_dn;
            proxy_set_header X-SSL-Issuer $ssl_client_i_dn;
            proxy_read_timeout 1800;
            proxy_connect_timeout 1800;
        }
    }
    # HTTPS server
    server {
        listen 443;
        server_name localhost;
        ssl on;
        ssl_certificate server.crt; # provide full path to the cert file
        ssl_certificate_key server.key; # provide full path to the key file
        ssl_session_timeout 5m;
        ssl_protocols SSLv2 SSLv3 TLSv1;
        ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
        ssl_prefer_server_ciphers on;
        location / {
            proxy_pass http://localhost:3000;
            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-Client-Verify SUCCESS;
            proxy_set_header X-Client-DN $ssl_client_s_dn;
            proxy_set_header X-SSL-Subject $ssl_client_s_dn;
            proxy_set_header X-SSL-Issuer $ssl_client_i_dn;
            proxy_read_timeout 1800;
            proxy_connect_timeout 1800;
        }
    }
}

There is no ‘best’ method for setting up HTTPS locally. We can choose whatever method we like to suit the application. Good luck.

Tags: , , ,