An open collection of noteworthy things


Setting up SSL on nginx with CloudFlare

So you’ve already got nginx running, and want to make it more secure (and pretty, with that lovely green padlock in chrome)? Well, you’ve come to the right place. Here we’ll be getting SSL (“HTTPS”) working with CloudFlare and nginx.

Generating the key & CSR

Let’s quickly just make a directory to put all of our SSL-related stuff in.

sudo mkdir /etc/nginx/ssl

Then, we generate the key:

sudo openssl genrsa -out /etc/nginx/ssl/mysite.key 2048

(You’ll need openssl to do this; in all likeliness though, it’s already installed anyway.)

In this command, we’re getting a 2048-bit key (hence the 2048 at the end) out at the place we specify (/etc/nginx/ssl…). You can put it in another location if you’d like. Generally, a 2048 bit key will suffice; any more and it’ll take too much CPU, any less and it’ll be insecure. Take a look at this graph for processing time depending on the size of key.

Now we need to get a Certificate Signing Request, or CSR.

openssl req -new -key /etc/nginx/ssl/mysite.key -out /etc/nginx/ssl/mysite.csr

Then enter the requested fields; the FQDN will be the domain/subdomain that you want to have SSL on. However, due to CloudFlare you WILL be able to have it on subdomains/domains that you don’t enter here! It’s only if you want to have it actually signed by a proper CA (no CloudFlare) that what you enter here will be limiting.

However, because we’ll be doing things with CloudFlare, we can just self sign our certificate! So, let’s run the following to do that.

cd /etc/nginx/ssl
sudo openssl x509 -req -days 365 -in mysite.csr -signkey mysite.key -out mysite.crt

Finally, make sure that the files are readable by root only:

sudo chmod 0400 /etc/nginx/ssl/mysite.*

Okay, now we need to change the nginx config to allow clients to connect via HTTPS. You may need to open port 443 if you’re using some kind of firewall; that’s the usual port for SSL communication.

You will need to adapt this config to your needs.


server {
        #redirect http to https
        listen 80;
        return 301$request_uri;
server {

        server_name; #where our site is accessed from

        listen 443 ssl spdy; #Only use SPDY if your NGINX version supports it! Just remove it if not.
        listen [::]:443 ssl spdy;

        root /var/www/; # Change this
        index index.php index.html index.htm;

        ssl_certificate /etc/nginx/ssl/mysite.crt;
        ssl_certificate_key /etc/nginx/ssl/mysite.key;

        ssl_session_cache shared:SSL:20m;
        ssl_session_timeout 10m;

        ssl_prefer_server_ciphers on;

        ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

        ssl_dhparam /etc/nginx/ssl/dhparam.pem;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

        location / {
                try_files $uri $uri/ /index.php?q=$request_uri;
        error_page 404 /404.html;

        # redirect server error pages to the static page /50x.html
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
                root /usr/share/nginx/html;

        location ~ .php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+.php)(/.+)$;
                # With php5-fpm:
                fastcgi_pass unix:/var/run/php5-fpm.sock;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include fastcgi_params;

       # only use this if you want Authenticated Origin Pulls - check out our other article for that.
       # ssl_client_certificate /etc/nginx/ssl/cloudflare.crt;
       # ssl_verify_client on;


Make sure that you also activate “full SSL (with SPDY)” on the CloudFlare crypto page too – then, you’re done!

You now have SSL enabled on your site!