How to Migrate/Setup a WordPress site on Linode

Recently I decided to move away from my Hostgator shared hosting and set up camp on a new Linode VPS. I was able to do this despite having no server administration experience and just basic to moderate Linux terminal skills. This post is about how I did it.

This guide assumes you are running Windows on your local machine. So you will first need to install PuttY and WinSCP. Putty is a SSH Terminal and WinSCP will allow you to transfer files graphically.

Install and Secure

#1. Deploy a Ubuntu 14.04 Linux Distribution. To do this click on Deploy a Linux Distribution in your Linode configuration page. Set the distributions to Ubuntu 14.04 LTS, deployment disk size to the maximum size indicated below the entry box and leave the swap disk size at the default setting of 256 MB. Enter the password you want to use for your root Linux user.

#2. In your Linode dashboard watch the host job queue until your Linode finishes being created.

#3. Click the Boot button to boot up your new Ubuntu 14.04 Linode.

#4. Once booted go into the Remote Access tab and write down your Linode’s IP address.

#5. Open Putty. Choose SSH and type in the IP address on your Linode in the Host Name box. Set the Port to 22 if it is not already. Then press Open.

#6. You will now see a PuTTY Security Alert box. This is just alerting you to the fact that your computer has not previously connected to the Linode server. Click Yes.

#7. Now your terminal window will pop up and you will be able to log in. Log in as user: root and your password is the one you set when deploying your Ubuntu 14.04 Linode.

#8. Once logged into the system we should first update Linux. Type in

apt-get update
apt-get upgrade --show-upgraded

#9. Next we need to set the servers hostname. This is just a random name that identifies the server. In the Linode tutorial they use the name “plato”. Type in the following.

echo "plato" > /etc/hostname
hostname -F /etc/hostname

#10. Now we need to write to our hosts file to set our hostnames IP address. NOT DONE.

#11. Set your desired timezone by typing in

dpkg-reconfigure tzdata

#12. Next we want to add a new user as we do not want to log into our Linode as root. The root user has the power to do anything on the system and so it is easy to make a mistake like deleting important files. Create a new user with

adduser example_user

#13. Now we need to give the new user admin rights and add them to the www-data group which apache and PHP run as. Use the following.

usermod -a -G sudo example_user
usermod -a -G www-data example_user

#14. Now close and reopen your PuTTY session and log in as your new user.

#15. Next we want to secure our server by disabling the root login (most hack bots will try to log in using the root user). We also want to change the SSH port from the default of 22 to something else as most hack bots will only try to break in through port 22. Type in

sudo nano /etc/ssh/sshd_config

You will be asked to type in your user password now as you are not logged in as the root user.

Once in the file change the following as such. (To easily search for text in the nano text editor press CTRL+W and then type in what you want to search for, then press enter.)

PermitRootLogin no
Port 3333

#16. Next we will want to set up a firewall. A firewall will block access to all ports apart from the ones that we allow. Open the firewall rules by typing in

sudo nano /etc/iptables.firewall.rules

and then copy as paste in the following default firewall. (If you chose a different SSH port be sure to change it in the firewall line below)


# Allow all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT

# Accept all established inbound connections

# Allow all outbound traffic - you can modify this to only allow certain traffic

# Allow HTTP and HTTPS connections from anywhere (the normal ports for websites and SSL).
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

# Allow SSH connections
# The -dport number should be the same port number you set in sshd_config
-A INPUT -p tcp -m state --state NEW --dport 3333 -j ACCEPT

# Allow ping
-A INPUT -p icmp -j ACCEPT

# Log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

# Drop all other inbound - default deny unless explicitly allowed policy


#17. Now we need to activate the firewall with the following

sudo iptables-restore < /etc/iptables.firewall.rules

#18. The firewall is now set up, but if you restart the server the rules will be lost. To ensure the rules are loaded on boot open the following file

sudo nano /etc/network/if-pre-up.d/firewall

and then copy and paste in this script

/sbin/iptables-restore < /etc/iptables.firewall.rules

#19. Next close and save the file with CTRL+X and give the script permission to execute with the following.

sudo chmod +x /etc/network/if-pre-up.d/firewall

#20. Now we will want to set up fail2ban. This is a program which monitors logfiles and will stop any attempts by a hacker to brute force their way into your server by guessing login details very fast. Essentially, if an attacker fails to login X times in X seconds, fail2ban will ban the attackers IP for a set amount of time. To install fail2ban type in the following.

sudo apt-get install fail2ban

#21. Next to setup fail2ban by first copying the configuration file to a local file which will be used. This is so that your configurations survive updates. Then open the fail2ban configuration.

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local

#22. Under [ssh] and [ssh-ddoss] jails, set the ports to be whatever port you have chosen to use for SSH as configured in the previous steps.

#23. Close the file with CTRL+X and then restart fail2ban with the following.

sudo service fail2ban restart

I don’t recommend using fail2ban to block anything other than SSH attacks. This is because many hacker bots will used spoof IPs. In my case the bots where using Google IPs causing SEO rankings to drop.

Install Apache

#1. Next install the Apache webserver with the following.

sudo apt-get install apache2

#2. Backup the default Apache configuration just in case you mess something up.

sudo cp /etc/apache2/apache2.conf /etc/apache2/apache2.backup.conf

#3. Now edit the configuration file with the following.

sudo nano /etc/apache2/apache2.conf

#4. Add in this code at the bottom in order to optimize it for low memory usage. If you have a Linode with more than 1GB of RAM, you may wish to adjust these values for better performance. Here we assume that each Apache process uses about 30 MB of RAM and that we want to give at most 750 MB to Apache. So we set MaxClients to 25 x 30 = 750 MB.

<IfModule mpm_prefork_module>
StartServers 2
MinSpareServers 6
MaxSpareServers 12
MaxClients 25
MaxRequestsPerChild 3000

#5. Under  <Directory /var/www/>, change AllowOverride None to AllowOverride All as shown below. This will enable .htaccess files to be used which WordPress requires. This must be done otherwise you will get errors like ‘You are not authorized to view this page.’

<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted

Install MySQL

#1. Now let’s install MySQL to manage our databases. You will be asked to setup a root password. Go ahead and do this, choosing a strong password.

sudo apt-get install mysql-server

#2. Secure the MySQL setup by using the line below. Be sure to answer as N, Y, Y, Y, Y.

sudo mysql_secure_installation

#3. Now we will optimize the MySQL database for low RAM. If you have a Linode with more than 1 GB of RAM you might want to increase some of these values or use MySQL Tuner to determine optimal values. Open the file in the following location.

sudo nano /etc/mysql/my.cnf

#4. Change the following key as so.

max_connections = 75
key_buffer = 32M
max_allowed_packet = 1M
thread_stack = 128K
table_cache = 32

#5. Restart MySQL.

sudo service mysql restart

#6. Set MySQL to optimize the databases daily or weekly using a cron job. First open up the cronjob editor with the following. (Choose nano if it asks)

sudo crontab -e

#7. Now copy and paste in the following line making sure to change PASS to your own MySQL root user password.

@daily mysqlcheck -o --user=root --password='PASS' -A

Install PHP

#1. Install PHP with the following.

sudo apt-get install python-software-properties
sudo apt-get install php5
sudo apt-get install php5-mysql

#2. Optimize PHP for low memory performance by opening the following file.

sudo nano /etc/php5/apache2/php.ini

#3. Now make changes as follows. (Most of these will already be set, but you may need to add in some missing lines)

max_execution_time = 30
memory_limit = 128M
display_errors = Off
log_errors = On
error_log = /var/log/php/error.log
register_globals = Off

#4. Create the PHP log directory and give it the correct owner ship of www-data so that PHP can write to the folder.

sudo mkdir -p /var/log/php
sudo chown www-data /var/log/php

#5. Restart Apache.

sudo service apache2 restart

Create a Virtual Host

A virtual host is what will serve your website. You can run several virtual hosts on one server, meaning that you can host multiple websites on the same server.

#1. Go to to the following directory.

cd /var/www

#2. Create the following directories making sure to change to your own domain.

sudo mkdir -p{public,log,backup}

#2. Create a file as below, making sure to replace with your own domain name.

sudo nano /etc/apache2/sites-available/

#3. Copy and paste this into the file, changing to your own domain and your email address too.

# domain:
# public: /var/www/

<VirtualHost *:80>
# Admin email, Server Name (domain name), and any aliases

# Index file and Document Root (where the public files are located)
DirectoryIndex index.html index.php
DocumentRoot /var/www/

# Log file locations
LogLevel warn
ErrorLog /var/www/
CustomLog /var/www/ combined

#4. Now enable your site.

sudo a2ensite

#5. Restart Apache

sudo service apache2 restart

Test Your Site

Here we will create a simple test site to check that everything is running properly.

#1. In /var/www/ create a document index.php

sudo nano /var/www/

#2. Copy and paste the following into it.

echo 'Hello, PHP!';

#3. In your local machine hosts file (Windows: %systemroot%\system32\drivers\etc\) add a line as follows where XXX.XXX.XXX.XXX is the server IP and is your domain. This will allow you to visit your website even though you have not yet set up the DNS servers.


#3. Save your hosts file and then load your domain in a webbrowser. You should see the text “Hello, PHP!”

Migrate Your WordPress site to Linode

Now that our webserver is set up, we can begin migrating our WordPress site.

#1. Log on to your old webserver either through terminal or cPanel and make a backup of your WordPress database. In cPanel this can be done under the Backups icon and in terminal this can be done with the following command from the home directory.

mysqldump -u user -p  db_name > backup.sql

#2. Open WinSCP and log on to your old server. Find your WordPress installation folder (probably under public or public_html somewhere). Select all the files and choose custom commands Tar/GZip to compress the entire folder contents into a single example.tar.gz file.

#3. Using the WinSCP download button, download both the backup.sql database and your compressed WordPress installation folder to your local disk.

#4. Open a second WinSCP instance and log in to your new Linode server (remember to use the SSH port you specified in the security set up section).

#5. Copy the database and compressed WordPress install folder to the Linode server using WinSCP. Place the .tar.gz file into the /var/www/ folder and the .sql file anywhere convenient such as the home folder.

#6. Extract the contents of the WordPress install with tar -zxvf example.tar.gz.

#7. Set the permissions of your /var/www folder to be owned by you the user and to have group www-data.

sudo chown -R "$USER":www-data /var/www

#8. Set all files to have permissions of 0644.

sudo find /var/www/ -type f -exec chmod 0644 {} \;

#9. Set all folder to have permissions of 0755.

sudo find /var/www/ -type d -exec chmod 0755 {} \;

#10. If you were using WP-Supercache change the WP-Content folder to have permissions 0775.

sudo find /var/www/ -type d -exec chmod 0775 {} \;

#10. If you were using WP-Supercache set the permissions of /var/www/ to 0666.

sudo chmd 0666 /var/www/

#11. If you were using WP-Supercache set the .htaccess permissions to 0664.

sudo chmod 0664 .htaccess

#12. Enable Apache rewrite, expires and headers functionality.

sudo a2enmod rewrite
sudo a2enmod expires
sudo a2enmod headers

#13. Restart Apache.

sudo service apache2 restart

#14. Create a new database in MySQL as follows. I recommend you create a separate user for each database you create. (Don’t forget the semi-colons)

mysql -u root -p
create user 'NEW_DBUSER_USERNAME'@'localhost' identified by 'NEW_DBUSER_PASSWORD';
create database new_database;
grant all privileges on new_database.* to ' NEW_DBUSER_USERNAME'@'localhost' identified by 'NEW_DBUSER_PASSWORD';

#15. Go to the directory in which you stored the backup.sql file and then type the following to copy the old database  to your new one.

sudo mysql -u NEW_DBUSER_USERNAME -NEW_DBUSER_PASSWORD' new_database < backup.sql

#16. Now if you named your new WordPress database something different to what it was previously or changed the password open up your wp-config.php file.

sudo nano /var/www/

#17. Change DB_NAME, DB_USER and DB_PASSWORD to your new values.

define('DB_NAME', 'new_database');

#18. If you were previously using WP-Supercache also change the WPCACHEHOME defined variable to the new location of the WP-Supercache plugin folder.

define( 'WPCACHEHOME', '/var/www/' );

#19. Now if you visit your website it should all be up and running!!!

Setting up a Mail Server

Although the site is now up and running there is still some work to do. In order to allow WordPress to send out email when a comment is received or for any other reason we must first set up a mail server. The Linode tutorial on mail servers is pretty much all your need for this.

Setting up FTP

When you try to add new or delete plugins on your newly migrated or installed WordPress site you might get errors asking your for your FTP credentials. There are ways around this like granting WordPress the ability to directly write to the file system or by changing permissions to allow WordPress to write to directories but this may not be security safe. Instead it is best to install a FTP server and allow WordPress to work as it was designed.

#1. Install VSFTPD with the following.

sudo apt-get install vsftpd

#2. Edit the config file /etc/vsftpd.conf and set write_enable=YES.

#3. Edit your wp-config.php file and add in the following lines. Where LINUX_USER is the name of the user you are currently logged in as and LINUX_USER_PW is your Linux password.

define( 'FTP_USER', 'LINUX_USER' );
define( 'FTP_PASS', 'LINUX_USER_PW' );
define( 'FTP_HOST', '' );

What’s Left to do?

At this point everything should be set up and running fine. But now you may wish to do the following.

#1. Install mod_evasive to help block DOS attacks.

#2. Secure your wp-login page.

#3. Optimize your WordPress install.

#4. Run MySQL tuner to tune your database.

#5. Migrate or create new sites following the same process as above from “Create Virtual Host” onwards.