Tech

Migrate existing WordPress site to AWS Lightsail

As usual the plan is to save money, isn’t it?  But also to make the site more open to modifications as a good developer would like it to be.  We all know we like to tinker…

At the same time, my wife is starting a personal site/blog, so why not hosting all together and save some money.

I did some digging and noticed that AWS is now offering a more streamlined version of its cloud called Lightsail, their offering is really simple to use and has a number of VM images available for you to launch.  For as little as $5 per month you can have your own Ubuntu VM to run and manage.  Great!  Exactly what I wanted!

Before getting into the details of the migration, I must point out that the Ubuntu image available through Lightsail, is by Bitnami  which is a company that packages application for any platform and makes it available for different cloud provider.   In this case this is important as they have their own way of configuring the system (Apache, MySql, etc.), so if you think to just follow regular Ubuntu/Wordpress instructions, you will soon find yourself in trouble. I will list below all the links for Binami docs.

Lastly, this all process is done from a Windows user stand point. For Linux or Mac users some of these steps might be more obvious.

Ok let’s get started.  This is a bit of a step by step mostly for me, just in case I will need to re-do this process in the future.  So feel free to skip the steps you are already familiar with.

Start with Lightsail

First of all you will have to have a AWS account, then you can chose the VM that you would like to run, and I picked their WordPress version:

Instance selection

At this point you have a VM at your disposal with your public IP address and with a WordPress site up and running. I am not going into how to point your domain to this public IP address (DNS setting), you can find plenty of instructions online.  You can also move your domain to AWS (Route 53) if you would like, and Lightsail has settings to manage the DNS from Route 53.

Log into the machine

Now we will need to log into the new Ubuntu machine to work on some of the settings. Lightsail has a simple connect button that opens a terminal in the browser:

Or you can use the Windows Linux subsystem and open a bash terminal directly in your windows machine.  Or you can install PuTTY and use it to connect via SSL. In the end this was my choice as it abstracts away all the security ceremony to connect with a .pem file.  Here are some instructions on how to use the AWS .pem file to connect to your VM with PuTTY.

Now that you are in, what?  Well, first thing is to retrieve your wordpress password, so that you can log into your new WordPress site.  As you can see below in your home folder there is a file called “bitnami_application_password”, self explanatory, isn’t it?

Just use the cat command to read the file at the command line:

~$ cat bitnami_application_password

Ok now that you have your password, access the admin dashboard by adding “wp-admin” after your AWS Lightsail public ip address:

http://my-ip-address/wp-admin

Export and Import WordPress

At this point export all your posts and data from your old site to by clicking here:

Save this file on your PC and then by clicking Import in the same screen above but on your new WordPress instance, you will import all the post and data to your new WordPress Site.  Take a note of your theme and all your plugins as you will have to reinstall them in the new site. Plenty of instructions online.

Install a Second WordPress Site

Now the fun part is starting.  Luckily Bitnami has the possibility of installing multiple version of an application on the same machine.  You can download the module your are interested in here.   Then upload the module installer file to your machine via putty.  Here are the instructions and here is the key terminal command to be run from your Windows machine:

pscp c:\bitnami-wordpress-4.9.4-4-module-linux-x64-installer.run bitnami@your-public-ip-address:~/bitnami-wordpress-4.9.4-4-module-linux-x64-installer.run

With this you will be dropping the file in your server home folder.  Now you are ready to install a new Worpress site in your machine, follow these instructions, recapped here:

First make the installer such that you can run it:

$ sudo chmod a+x bitnami-wordpress-VERSION-module-linux-x64-installer.run

Then run it with a flag that names the new wordpress site:

$ sudo ./bitnami-wordpress-VERSION-module-linux-x64-installer.run --wordpress_instance_name NEW_BLOG_NAME

Go through the wizard and answer all the questions:

At the end of this process you will find an additional folder in your apps folder with the new WordPress site. In my case “wordpress” is my site and “angelawp” is my wife’s:

There is also a good readme here, that walks through the Bitnami way for the wordpress stack.

Configure Apache

Now it is time to configure Apache to support 2 websites on the same IP address (obviously at this point, you will have already taken care of DNS and pointed both domains to this public IP address).

Apache handles this via its Virtual Host configuration (here is a good walk through) , but Bitnami handles Apache configuration in its own way.  It uses a number of configuration files that import each other based on the Bitnami apps structure within the machine. The instruction below can be found here.

The Binami wordpress configuration, in case of multiple wordpress site in the same machine,  is in “prefix” mode.  Meaning that each site is accessed by http://example.com/wordpress1 and http://example.com/worpress2.  We need to change this as we actually have 2 separate domains that must point to the correct worpress site and this is done via virtual host.

Each Bitnami wordpress site has a prefix configuration file at /opt/bitnami/apps/MYSITE/conf/httpd-prefix.conf and a virtual host file at /opt/bitnami/apps/MYSITE/conf/httpd-vhosts.conf . In turns out both files are then called in by way of “Include” from the main Apache config files:

Prefix: /opt/bitnami/apache2/conf/bitnami/bitnami-apps-prefix.conf

VirtualHost: /opt/bitnami/apache2/conf/bitnami/bitnami-apps-vhosts.conf

Here is what we need to modify:

1 – Delete the following line in the /opt/bitnami/apache2/conf/bitnami/bitnami-apps-prefix.conf file:

Include "/opt/bitnami/apps/MYSITE/conf/httpd-prefix.conf"

2 – Add a new link in the /opt/bitnami/apache2/conf/bitnami/bitnami-apps-vhosts.conf file:

Include "/opt/bitnami/apps/MYSITE/conf/httpd-vhosts.conf"

3 – Modify the httpd-vhosts.conf as follows. I like to use nano, it seems more intuitive then Vim, so open the file with this:

$ nano /opt/bitnami/apps/wordpress1/conf/httpd-vhosts.conf

then change it with this code:

<VirtualHost *:80>
  ServerName website1.com
  ServerAlias www.website1.com
  DocumentRoom "/opt/bitnami/apps/mysite1/htdocs"

  Include "/opt/bitnami/apps/mysite1/conf/httpd-app.conf"
</VirtualHost>

Now do the same for website2:

$ nano /opt/bitnami/apps/wordpress2/conf/httpd-vhosts.conf

then change it with this code:

<VirtualHost *:80>
  ServerName website2.com
  ServerAlias www.website2.com
  DocumentRoom "/opt/bitnami/apps/mysite2/htdocs"

  Include "/opt/bitnami/apps/mysite2/conf/httpd-app.conf"
</VirtualHost>

Now you need to restart Apache:

$ sudo /opt/bitnami/ctlscript.sh restart apache

If all is good it will restart and you should be able to access your websites independently: website1.com and website2.com

Issue with Preview Post

What has happened is that when writing a post and trying to preview it…

…I was getting a 500 status code.  After long searching I found this post and solved the problem with this. I changed the AllowOverride  to All from None in this file:  /opt/bitnami/apps/wordpress1/conf/httpd-app.conf

<Directory "/opt/bitnami/apps/wordpress/htdocs">
    Options +MultiViews +FollowSymLinks
    AllowOverride All

Add SSL Certificate

Now we need to make our site secure with https and a SSL certificate. I did some research and I decided to stay open source and use Let’s Encrypt.

It turns out that Bitnami already thought about this and has a tutorial on how to implement Let’s Encrypt in their apps. Here is the link.  As I did before I will recap the procedure here:

1 – First you need to install the Lego Client in the server.  Lego client is a Let’s Encrypt client written in Go.  It generates a certificate based on Let’s Encrypt protocol and let’s you renew such certificate when needed (every 90 days, as Let’s Encrypt certs are issued with a 90 days expiration).

Log into the server as the bitnami user and run this commands:

$ cd /tmp
$ curl -s https://api.github.com/repos/xenolf/lego/releases/latest | grep browser_download_url | grep linux_amd64 | cut -d '"' -f 4 | wget -i -
$ tar xf lego_linux_amd64.tar.xz
$ sudo mv lego_linux_amd64 /usr/local/bin/lego

These steps will download, extract and copy the Lego client to a directory in your path.

2 – Let’s generate the certificate. To do so you need to make sure your domain is pointing to the public IP address of this server.

Turn off all Bitnami services:

$ sudo /opt/bitnami/ctlscript.sh stop

Request a new certificate for your domain as below. Remember to replace the DOMAIN placeholder with your actual domain name, and the EMAIL-ADDRESS placeholder with your email address.  Additionally, we will be requesting a certificate for the DOMAIN and the www.DOMAIN version of it. This is done by adding the –domains flag as many time as the number of sub-domains you would like to add to the certificate.

$ sudo lego --email="EMAIL-ADDRESS" --domains="DOMAIN" --domains="www.DOMAIN" --path="/etc/lego" run

A set of certificates will now be generated in the /etc/lego/certificates directory. This set includes the server certificate file DOMAIN.crt and the server certificate key file DOMAIN.key.

3 – Configure Apache to use these certificates. We will created a linked file to the certificate and the key file in the /opt/bitnami/apps/MYSITE/conf/certs directory and we will give them root permission:

$ sudo ln -s /etc/lego/certificates/DOMAIN.key /opt/bitnami/apps/MYSITE/conf/certs/server.key
$ sudo ln -s /etc/lego/certificates/www.DOMAIN.key /opt/bitnami/apps/MYSITE/conf/certs/www.server.key
$ sudo ln -s /etc/lego/certificates/DOMAIN.crt /opt/bitnami/apps/MYSITE/conf/certs/server.crt
$ sudo ln -s /etc/lego/certificates/www.DOMAIN.crt /opt/bitnami/apps/MYSITE/conf/certs/www.server.crt
$ sudo chown root:root /opt/bitnami/apps/MYSITE/conf/certs/server*
sudo chmod 600 /opt/bitnami/apps/MYSITE/conf/certs/server*

Obviously we are doing it also for the www.DOMAIN cert and key.

4 – Renew the certificate: Let’s Encrypt certificates are only valid for 90 days. To renew the certificate before it expires, we will write a script to perform the renew tasks and schedule a cron job to run the script periodically.

Create a script at /etc/lego/renew-certificate.sh with the following content.  Remember to replace the DOMAIN placeholder with your actual domain name, and the EMAIL-ADDRESS placeholder with your email address.

#!/bin/bash

sudo /opt/bitnami/ctlscript.sh stop apache
sudo /usr/local/bin/lego --email="EMAIL-ADDRESS" --domains="DOMAIN" --domains="www.DOMAIN" --path="/etc/lego" renew
sudo /opt/bitnami/ctlscript.sh start apache

Make the script executable:

$ chmod +x /etc/lego/renew-certificate.sh

Execute the following command to open the crontab editor:

$ sudo crontab -e

Add the following lines to the crontab file and save it:

0 0 1 * * /etc/lego/renew-certificate.sh 2> /dev/null

5 – Configure Apache  Virtual-Hosts to work with https.  Open the /opt/bitnami/apps/MYSITE/conf/httpd-vhosts.conf with nano and modify it as follows:

<VirtualHost *:80>
  ServerName DOMAIN.com
  ServerAlias www.DOMAIN.com
  DocumentRoot "/opt/bitnami/apps/MYSITE/htdocs"

  RewriteEngine On
  RewriteCond %{HTTPS} !=on
  RewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [R,L]

  Include "/opt/bitnami/apps/MYSITE/conf/httpd-app.conf"
</VirtualHost>

<VirtualHost *:443>
  ServerName DOMAIN.com
  DocumentRoot "/opt/bitnami/apps/MYSITE/htdocs"
  SSLEngine on
  SSLCertificateFile "/opt/bitnami/apps/MYSITE/conf/certs/server.crt"
  SSLCertificateKeyFile "/opt/bitnami/apps/MYSITE/conf/certs/server.key"
  Include "/opt/bitnami/apps/MYSITE/conf/httpd-app.conf"
</VirtualHost>

<VirtualHost *:443>
  ServerName www.DOMAIN.com
  DocumentRoot "/opt/bitnami/apps/MYSITE/htdocs" 
  SSLEngine on 
  SSLCertificateFile "/opt/bitnami/apps/MYSITE/conf/certs/www.server.crt" 
  SSLCertificateKeyFile "/opt/bitnami/apps/MYSITE/conf/certs/www.server.key"

  Include "/opt/bitnami/apps/MYSITE/conf/httpd-app.conf" 
</VirtualHost>

Note that I added a redirect rule to push all http requests to be https. We also have 2 VirtualHosts for port 443. One for the regular DOMAIN with its certificates and another for the www.DOMAIN with its certificates.

6 – Configuration is done let’s restart the bitnami services:

$ sudo /opt/bitnami/ctlscript.sh start

The above process for the SSL certificate must be repeated for the second site on this same machine (my wife site).

One last thing before closing this long blog. It might happen that the second site cannot load images. If that is the case follow these instructions.  We basically need to update the database with the second site domain. Run these commands:

$ sudo mysql -u root -p -e "USE bitnami_MYSITE2; UPDATE wp_options SET option_value='http://DOMAIN2/' WHERE option_name='siteurl' OR option_name='home';"

MYSITE2 is the name of the second site you installed with the Bitnami procedure at the top of this blog and DOMAIN2 is the domain of your second site (wife).

And this is all for this migration. I hope you will find this helpful.