ScaleScaleScaleScale

Tips / Nginx


Moving WordPress from HTTP to HTTPS (SSL) on Nginx

Today I did one thing I had pending for a long time, and that was moving WordPress from http to https on Nginx. This blog had two different subdomains, the first: www.site.com and the other static.site.com for static files like javascript, stylesheet and images.

Tweaking your WordPress security with a SSL certificate is a must if you are working with e-commerce or collect sensitive data… but there is another good reason to install a SSL on WordPress, and that is SEO… The big guys at Google can make your site rank better in search engines if you use HTTPS instead of HTTP, they announced this a few months ago at this post.

wordpress ssl https

Moving WordPress to https / SSL on Nginx

Key points:

  • If you have multiple subdomains like the one I mentioned, each will need an SSL certificate, unless you use a Wilcard SSL that costs a lot, I don’t recommend it unless you have lot of subdomains.
  • I recommend using RapidSSL certificates, are very cheap and work fantastic.
  • You will also need a dedicated IP for each SSL you will install.
  • Nginx is a must on this tutorial, if you use apache or another crap, forget it.
  • I will assume the Nginx main directory is: /etc/nginx (tweak as you need)
  • I will use yoursite.com as example, replace it with your own real domain.
  • SSH with root privileges is a must. So, if you don’t have your VPS or Dedicated server, you can take a look at this great hosting providers:
    • A Small Orange
    • A2 Hosting

Assign a dedicated server IP

In order to use SSL certificates, you will need to assign a dedicated IP to your main website www.yoursite.com for example, then wait a few hours to it propagates all over the world. If you have multiple subdomains for your website content, they will all require a single dedicated IP for each.

Generate the SSL keys and CSR files on your Linux server

First create the required directories:

mkdir /etc/nginx/{ssl.key,ssl.csr,ssl.crt}

As root, run this comand:

openssl req -nodes -newkey rsa:2048 -keyout /etc/nginx/ssl.key/www.yoursite.com.key -out /etc/nginx/ssl.csr/www.yoursite.com.csr

This will generate the .key and .crt codes. Grab your CSR code and then deliver that to your SSL provider, they will need it to generate the CRT code (next step):

cat /etc/nginx/ssl.csr/www.yoursite.com.csr

Install the SSL CRT code

nano -w /etc/nginx/ssl.crt/yoursite.com.crt

And paste the CRT code your SSL provider gave you.

Configure Nginx virtual host file to force SSL usage

nano -w /etc/nginx/conf.d/yoursite.com.conf

Let’s suppose you have a virtual host file like this, just as example:

### yoursite.com without SSL

server {
access_log off;
log_not_found off;
error_log  logs/yoursite.com-error_log warn;

listen 80;
        server_name  www.yoursite.com; 

        location ~* .(gif|jpg|jpeg|png|ico|wmv|3gp|avi|mpg|mpeg|mp4|flv|mp3|mid|js|css|wml|swf)$ {
        root   /var/www/yoursite.com;

                expires max;
                add_header Pragma public;
                add_header Cache-Control "public, must-revalidate, proxy-revalidate";
        }

        location / {
            root   /var/www/yoursite.com;
            index  index.php index.html index.htm;

        # WordPress permalinks configuration
        try_files $uri $uri/ /index.php?$args;
        }


# php-parsing
        location ~ .php$ {
            root           /var/www/yoursite.com;
            try_files $uri =404;
            fastcgi_pass   unix:/tmp/php5-fpm.sock;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
            fastcgi_buffer_size 128k;
    fastcgi_read_timeout 150;
            fastcgi_buffers 256 4k;
            fastcgi_busy_buffers_size 256k;
            fastcgi_temp_file_write_size 256k;
       }
}

As you see, this is a very simple WordPress – Nginx configuration, with static file caches, worpdpress permalinks defined and php-fpm running with unix sockets. In order to force SSL usage on this website, I will modify a few lines. We will define a new server {} block configuration to force the SSL 301 redirection, and then below that, you will see the SSL host configuration:

### yoursite.com without SSL
server {
   listen 80;
   server_name www.yoursite.com;
   rewrite ^(.*) https://www.yoursite.com$1 permanent;
}


### yoursite.com SSL configuration
server {
access_log off;
log_not_found off;
error_log  logs/yoursite.com-error_log warn;

        listen 208.167.252.238:443 ssl spdy;
        server_name  www.yoursite.com; 

 ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
 ssl_prefer_server_ciphers On;
 ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;
        ssl_certificate /etc/nginx/ssl.crt/www.yoursite.com.crt;
        ssl_certificate_key /etc/nginx/ssl.key/www.yoursite.com.key;

        location ~* .(gif|jpg|jpeg|png|ico|wmv|3gp|avi|mpg|mpeg|mp4|flv|mp3|mid|js|css|wml|swf)$ {
        root   /var/www/yoursite.com;

                expires max;
                add_header Pragma public;
                add_header Cache-Control "public, must-revalidate, proxy-revalidate";
        }

        location / {
            root   /var/www/yoursite.com;
            index  index.php index.html index.htm;

        # WordPress permalinks configuration
        try_files $uri $uri/ /index.php?$args;
        }


# php-parsing
        location ~ .php$ {
            root           /var/www/yoursite.com;
            try_files $uri =404;
            fastcgi_pass   unix:/tmp/php5-fpm.sock;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
            fastcgi_buffer_size 128k;
    fastcgi_read_timeout 150;
            fastcgi_buffers 256 4k;
            fastcgi_busy_buffers_size 256k;
            fastcgi_temp_file_write_size 256k;
       }
}

As you see, I added a few lines related to the SSL configuration:

        listen xx.xx.xx.xx:443 ssl spdy;
        server_name  www.yoursite.com; 

 ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
 ssl_prefer_server_ciphers On;
 ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;
        ssl_certificate /etc/nginx/ssl.crt/www.yoursite.com.crt;
        ssl_certificate_key /etc/nginx/ssl.key/www.yoursite.com.key;

On this config:

  • You must change ‘xx.xx.xx.xx:443’ with your real IP, example: 133.55.22.67:443.
  • The ‘ssl spdy’ option enables the SPDY protocol for faster SSL communication between hosts (recommended).
  • ‘ssl_protocols TLSv1 TLSv1.1 TLSv1.2;’ option defines the supported protocols, don’t alter that unless you know what you are doing.
  • ssl_ciphers are the most common and secured ssl cypers to use, don’t alter that unless you know what you are doing.
  • ssl_certificate and ssl_certificate_key are the variables to set with the key and crt file you created before.

Restart Nginx to apply the changes:

/etc/init.d/nginx restart

Now open your browser, delete all the cache and temporary files you have. Then load https://www.yoursite.com and a green lock should appear in your URL address bar.

You can also test if the HTTP to HTTPS redirection is working fine by using CURL from the terminal:

[user@server ~]$ curl -I http://www.yoursite.com
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 06 Nov 2014 01:50:16 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: https://www.yoursite.com/

As you see, the site has a 301 Moved Permanently redirection and it’s working as expected, redirecting all your WordPress HTTP traffic to HTTPS.

Update your WordPress Upload path to use HTTPS

Login to your WordPress site and install a plugin called WP Original Media Path.

After installing and activating that plugin, search for the options in Settings – WP Original Media Path and set the Full URL path to files:

https://www.yoursite.com/wp-content/uploads

Or if you use a static subdomain for uploads, use:

https://static.yoursite.com/wp-content/uploads
https://static.yoursite.com

Or whatever, just update it to reflect what your subdomain structure is.

Force SSL on Wordpress uploaded files

Connect to your MySQL server:

mysql -u root -p

Then, select the database and run the replace command to update your url structure with https:

use yourdatabase;
UPDATE wp_posts SET post_content = REPLACE(post_content,'http://www.yoursite.com/wp-content/uploads','https://www.yoursite.com/wp-content/uploads')

What if you use a subdomain for your WordPress Uploads?
Repeat the tutorial and apply the same for your Upload subdomain, you may need to change some paths and url names but that’s not a big deal.

What if you use Cloudflare in your WordPress upload subdomain?
Then you are a lucky guy, as Cloudflare already has free SSL enabled for all the subdomains, just launch https://your.subdomain.com and it should work.

What if you use another CDN service for your WordPress upload subdomain?
Ask your CDN provider, all modern CDN providers provide SSL support.

Popular search terms:

  • wordpress ssl nginx
  • https://www scalescale com/tips/nginx/moving-wordpress-http-https-ssl-nginx/
  • https://www scalescale com/tips/nginx/moving-wordpress-http-https-ssl-nginx/#
  • wordpress nginx https
profile

Esteban Borges

Linux Geek, Webperf Addict, Nginx Fan. CTO @Infranetworking

  • Nice writeup. Just made the switch some days ago and was a really smooth transition. Now need to polish some rough edges. Basically dealing with Google Webmaster tools and continue fighting with ngx_pagespeed (they say that works, my previous experience is not).

    • nginxadmin

      Glad you like it Alfonso. What are u talking about when you say: “Dealing with Google Webmaster tools”. Did you had to do apply any special config after the http to https switch?

      Regards.

  • Needed to update the site and the preferred form (with or without www.) along the change of protocol (made a 301 redirect where the old server answered), resubmitted the new sitemap.xml, crossed fingers to not forget anything and implemented HSTS and Anti-Clickjack (look with a curl -I on my site. 😉 ).

    Love the site, was one of my preferred sites to check when switched from Apache to Nginx.

    • nginxadmin

      Ah.. nice. Cool info about HSTS and Anti-CLickjack (will reasearch on that later), thanks for your reply Alfonso!

  • I’m always getting too many redirect error after adding rewrite ^(.*) https://www.yoursite.com$1 permanent; function. But after that when I curl from cli, I can see that html redirected to https successfully. What can be the problem is?