The idea here is to complete the whole process as quickly as possible and have the minimum downtime to your blog. While we are doing a lot of work on the new blog quite early in this guide you should note that we do not make any changes on the old blog, and we do not change the DNS until right at the end of the process. So, right up until we’re ready to change over the blog is up and running on the old hosting. Here is more information on WordPress and the Command Line.

The assumption here is that both the old hosting and the new hosting can be accessed at the same time, although once you have everything from the old hosting you shouldn’t need that again. You probably want to keep the old one intact in case you have any issues with the new hosting or transferring the data. This is also assuming that Apache is used on both old and new hosting and that the new hosting is Debian or Ubuntu.

I recently moved four blogs to Digital Ocean hosting with Debian 9 using this method. Please be careful if you follow this guide as some of the steps may be different on different hosting. If I have left out any details or you have any improvements, please let me know.

Backup the Files from the Old Hosting

  1. Export the SQL for the entire database to a SQL file. If it is shared hosting you can export using the PHPmyAdmin, or if you have shell access you can export using the mysqldump command.
  2. Make sure you have the .htaccess and wp-config.php files.
  3. Download the theme you’re using if it’s a custom theme, a child theme or if you have changed anything about it.
  4. Make sure you have downloaded all the uploads directory and anywhere you have uploaded content to.
  5. You just need the plugin folder names for all the plugins you have installed. (If you use a standard theme from the WP repository you can also install it from just it’s folder name too)

Setting Up the New Hosting

Install Apache, PHP and MySQL/MariaDB

You only have to do this once per hosting. There is a guide to doing this here.

You do not need to install PHPmyAdmin on the new hosting as that is not used in this guide.

Install WordPress

Something like this from the command line…

cd /var/www
wget http://wordpress.org/latest.tar.gz
tar xfz latest.tar.gz

This makes a directory called “wordpress” with all the files inside it. Then, to rename the directory to the name of your website you can do this…

mv wordpress newblog.com

At this point upload the .htaccess and wp-config.php files into the website’s root.

Check the .htaccess

Take a look at the .htaccess file and make sure it looks ok. Make sure you always have the original unadulterated .htaccess file backed up somewhere so that if you make any changes to it while troubleshooting, you can always re-add stuff at a later stage once everything is fixed.

Re-create the MySQL Database

Now, you have the latest version of WordPress sat on your new hosting but it will not work because it is not connected to any database. To create a new database you would login to MySQL on the command line and do something like…

create database name_of_new_database;
exit

Now, you’ve exited from MySQL, so now you can import the SQL file from the command line. Upload the SQL to anywhere you like, perhaps put it with the other WordPress files in the website’s root directory. Then, to import the MySQL do something like…

mysql name_of_new_database < /var/www/newblog.com/backup.sql

That should import all the tables. Check that everything is in place by logging in to MySQL and doing something like...

use name_of_new_database;
show tables;

If everything is there, create your blog user with a password and grant access. The easiest/quickest way would be to use the existing username and password from the wp-config.php file, but you can change the username and password here as long as you update the wp-config.php afterwards...

CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON name_of_new_database . * TO 'newuser'@'localhost';

After changing the privileges you'll also want to flush them for them to work...

FLUSH PRIVILEGES;

Re-add Uploads

At this point your blog should still be working on your old hosting, you have not changed anything on the old hosting. On the new hosting the WordPress files are in place and the new database is able to be read by the WordPress files.

Now is as good a time as any to upload the uploads directory, any custom plugins that are not in the WordPress repository and the theme you're using (unless the theme is on the WordPress repository). You can do this later but it's better to do it now before you forget.

Re-add Plugins

This stage has to be done after the blog is connected to the database. Using WP-CLI to re-add the plugins quickly while the website is still working on the old hosting. SFTP or FTP might take a long time, so this is a quick method. If you waited until you switched over the DNS you could login to the admin dashboard and re-add the plugins from there, however, certain plugins might be required to login to the dashboard (e.g. if you're using Cloudflare's flexible SSL) and why wait until then when you can easily get them all added beforehand.

Install WP-CLI...

curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp

Now, once WP-CLI is installed, you can navigate to your blog's root directory on the new hosting if you're not already there. Then have the old hosting open on SFTP/FTP and navigate to the plugins folder. The grab each plugin folder name and do something like this...

cd /var/www/newblog.com
wp plugin install wp-plugin-1 wp-plugin-2 wp-plugin-3 wp-plugin-4 wp-plugin-5 --activate

So, instead of "wp-plugin-1", you might have "jetpack", etc. If you are doing this as root you have to use the --allow-root flag then you should change the owner of all the files to a different user by doing...

chown -R differentuser:differentuser ../newblog.com

If you have not re-uploaded your theme you can also do this using WP-CLI by doing something like...

wp theme install twentysixteen --activate

It's probably a good idea to check everything is owned by differentuser, or just change the owner:group to differentuser after you're finished using WP-CLI.

Set Up the Virtual Host file and Add Site

At this stage, the blog on the old hosting is still working normally. On the new hosting, WordPress should be operational but you haven't changed the DNS over. Hopefully, if the database was copied across correctly and the .htaccess and wp-config.php files are ok you should be able to change over now with the minimum of disruption. However, you may wish to test the blog out on the new hosting to make sure it works before you change the DNS. You can do this if you have a unique IP for your hosting and the website is the default.

To make the new website the default so you can access it with the IP address, go to the sites-available directory and modify the 000-default.conf file...

cd /etc/apache2/sites-available
nano 000-default.conf

You may not have to change anything here apart from you want to point the document root to your blog's root to test it out using your unique IP...

DocumentRoot /var/www/newblog.com

Then, to make sure your .htaccess will work you may need to add something like this...

<Directory /var/www/newblog.com>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Require all granted
Order allow,deny
allow from all
</Directory>

The default may already be enabled, but if not you would do a...

a2ensite 000-default.conf
service apache2 restart

Now, you can find your IP address by running this command...

hostname -I

Copy-paste the IP address into the browser and your blog should be there. Clicking the links of the posts/pages will take you back to your old hosting. To check that the individual post pages work you'll have to modify the URLs so that they look something like http://123.123.13.13/name-of-post in the browser (i.e. swap the domain name with the new IP address).

If everything is working, copy the file and complete if for your new domain...

cp 000-default.conf newblog.com.conf
nano newblog.com.conf

In addition to the changes we made before, you'll also now want to add your domain name to the virtual host like...

ServerName newblog.com
ServerAlias www.newblog.com

You can also specify a unique error and access file so that you can see exactly what is happening with this one blog if there are any problems.

Now you can save, exit and enable the site...

a2ensite newblog.com.conf
service apache2 restart

Point the DNS at the New Hosting

If you're using something like Cloudflare the changeover might be very quick, otherwise you'll have to wait it out. Generally speaking, you'd just create change the A record to the new IP address however, different hosting works different ways.

After your DNS has propagated, the website works fine, and you can login to the admin dashboard and post as normal you should change the permissions of the .htaccess and wp-config.php to 0444.

Troubleshooting

This method is designed to be as quick as possible. The thing that will take the longest is downloading and uploading the uploads and theme. While this is happening you can either take a break or you can always be working on the other stuff.

If there are any problems with logging into the admin dashboard you can always de-activate the plugins using WP-CLI. To use any WP-CLI commands you must always be in the WordPress site's root directory that you want to work on. The same hosting can have more than one blog, so the location you're in on the command line makes a big difference...

wp plugin deactivate wp-plugin-1

where "wp-plugin-1" is the folder name of a specific plugin that is installed or, to deactivate them all quickly...

wp plugin deactivate --all

If deactivating the plugins does not help, take a look at the access and error logs. If there are any issues highlighted in the logs you can see which file(s) they are related to and then take another look at the .htaccess. The main things to check if there are problems... permissions, owners, .htaccess, plugins, wp-config.php.

After making changes to the .htaccess or plugins you may need to clear your cache to see whether the changes have worked. You may also need to purge everything if you are using a CDN like CloudFlare.

Some plugins need to write to your hosting, so if there are any problems with this you'll get errors, especially if a plugin wants to write to your .htaccess file after you've changed it to 0444. You may have to change the permissions on the .htaccess back to 0755 briefly, then change them back to 0444 afterward. Other plugins may have different problems writing to the uploads directory so making sure that everything is owned by www-data should fix this. Alternatively, it's probably a better idea not to have everything owned by www-data so giving your non-root user ownership of everything will mean that you can update everything with WP-CLI, then you'll have to tweak the uploads folder if you wish to upload using the admin dashboard.

Conclusion

Always consider security with WordPress blogs, especially where there is more than one blog on the same hosting.

I chose Digital Ocean because they were recommended to me. They seem good so far, if you'd like to try them too you can click the link to get $10 free credit with Digital Ocean.

Previously, I looked at setting up Debian 8 with PHP 7.0. But now, Debian 9 is the current stable version and Debian 8 is only due to receive security updates until May 2018. Sounds like a good time to upgrade!

The reason I started to look into upgrading was that I found out that the highest version of Apache available on Debian 8 is Apache 2.4.10 which is not capable of running HTTP/2. Having recently upgraded a lot of my websites to HTTPS, I also wanted to upgrade them to HTTP/2 aswell. Debian 8’s version of Apache was not able to be upgraded without doing so manually. However, Debian 9’s default version of Apache is 2.4.25 which is HTTP/2 capable, it also has PHP 7.0 as the default and has upgraded MySQL to MariaDB. All the more reason to upgrade!

From here

For those who don’t know, Debian codenames are based on the characters in the famous animated movie Toy Story. This release is named after the glittery purple rubber toy octopus, Stretch.

Alternatives to upgrading to Debian 9 (Stretch)

Upgrading from Debian Jessie to Stretch will not be for everyone. Here are some possible alternatives.

Manually installing a higher version of Apache.

This is generally thought of as possible but not recommended. You also have the gradual winding down of Debian support from May 2018 which may lead to security risks.

Changing to another flavor of Linux with a version of Apache that is capable of running HTTP/2.

Ubuntu 16.04 is one version that can run HTTP/2 without too much tinkering.

Ubuntu is similar to Debian in terms of the shell commands. I have some websites that use Ubuntu 16.04 but for this particular website, I wanted to stay with Debian. Ubuntu is thought of as more experimental, while Debian is thought of as more stable and faster.

Ubuntu 16.04 LTS looks like it will be supported until April 2021 from here so it will not need updating any time soon. The next version with long-term support (LTS) is released next month (April 2018) so I may look into upgrading the servers running Ubuntu when that arrives.

I have used AWS in the past and I have built websites on FreeBSD and CentOS servers that I can remember, but currently I am mainly using Debian and Ubuntu with un-managed VPS. This experience has made me want to try some different flavors, or at least learn about how the other flavors are different. What I’ve read so far makes me think that Debian is a decent choice for this site. Here’s a comparison between Debian, Ubuntu and CentOS for webservers.

Changing from Apache to Nginx.

While you’re still left with the Debian support for Jessie winding down, changing to Nginx is probably a good move. Debian 9 with Nginx may well be faster than it would be with Apache. The version of Nginx you install on Debian 8 with Jessie Backports can run HTTP/2.

The problem with changing to Nginx on a live website is that it is completely different as a webserver to Apache. Nginx does not have .htaccess files and the setup will be different in ways that I’m not aware of yet. I wanted to upgrade in less than a day on this live website so this option was not right for me at the time. But, I do plan to use Nginx in the near future.

Upgrading from Debian 8 (Jessie) to Debian 9 (Stretch)

The official Debian guide to doing this manually in the command line is here. I decided against doing it this way, although it may have lead to less downtime. I decided a fresh install may cause less problems in the future.

I decided to just re-install in the hosting company portal. This meant backing everything up, then with the installation, everything was erased and had to be re-added. There is only one website on the VPS which is a WordPress blog. There was nothing particularly complicated about the server setup which made life a lot easier. The main thing I had to do were to get MariaDB installed and to import the backed up SQL file from the MySQL, I referred to this guide for that. I also had to get Lets Encrypt installed and set up the SSL encryption again.

One of the things I had to change from when I set up Debian 8 with PHP 7.0 was the way PHP 7.0 is installed/served. mpm_prefork is not compatible with HTTP/2 (mod_http2) so I had to use another way of installing PHP (from here).

I was rushing the installation through as quickly as I could because the website was down. I probably did some things in the wrong order and I did encounter some problems. However, after about 45 minutes I had to leave the house and do some chores. At that stage, the WordPress blog was basically up and running but mod_rewrite was not configured correctly yet and the SSL was not set up yet either.

When I got back I started to finish off getting the site working but almost as soon as I sat down the server locked me out of SFTP and SSH. I could not even access the shell on the control panel’s console. I actually thought I’d locked myself out with the UFW firewall. I’m not sure what the problem was but it turned out to just be temporary and I hadn’t locked myself out at all.

Everything went pretty smoothly really. I got the occasional error when trying to reboot but nothing major. Every time it was pretty obvious what the problem was without doing much, if any, investigating. The dreaded error message when Apache won’t restart is definitely becoming less scary these days since I started ignoring the files it tells you to look at and just go straight for the main error.log or whatever you have set up as the main error log file.

Learning New Stuff

I was expecting more problems from exporting the MySQL then importing it into MariaDB. Even if the import/export went smoothly I was expecting to have some issues with WordPress itself. All I can say is no problems whatsoever with the database or WordPress at all. Maybe it’s because I’ve done this kind of thing a few times before and this time I was actually ready and prepared for it.

Because the website is just a WordPress blog I am not going to be doing a huge amount of work with MariaDB on that website. But, one of the things I did take a look at was the MariaDB tuning: mysqltuner. I can’t wait to do some more work with MariaDB in future.

I did all the database backup, set up and importing in the shell. I didn’t use PHPmyAdmin at all but decided to install it at the end incase I ever needed to use it. Then, setting up PHPmyAdmin needed some more shell work with the MySQL command line and MariaDB. Because of all this, I feel like I’m a lot more confident with the MySQL command line.

The Unattended Upgrades file that came with my installation seems to be the same one used with Jessie. Referred to articles such as Unattended Upgrades in Debian 9 for what to keep and what to remove.

Unattended Upgrades will need to send emails to tell you when it needs a reboot unless you have it automatically reboot or just do not want emails. I had the Jessie server set up to send emails directly from the server. This time I decided to send the server emails with Mailgun using this guide.

With trying to get the website up-and-running normally as soon as possible I feel like I got to know Nano a lot better. I even edited the nano config file, /etc/nanorc, to tweak some of the things I have disliked about using Nano.

Issues Encountered

The Sudoers file.

After setting up a user and adding it to the group, sudo, I was getting errors every time I wanted to use a sudo command. I may have done this before but the sudoers file is located at /etc/sudoers

Something like…

root ALL=(ALL:ALL) ALL

Problem installing Python and Let’s Encrypt… dependencies.

Once I’d fixed the Sudoers file I think there may have been another obstacle to installing Python and the Lets Encrypt dependencies but I have completely forgotten what it was.

PHPmyAdmin could not create the phpmyadmin table or the ‘pma’ user.

I did not use PHPmyAdmin at all but installing it at the end caused a few problems that were easily fixed.

Outcome

All-in-all I’m very happy I got the upgrade done. And, I’m pleased I was able to do it fairly quickly despite having to leave the house against my will during the process then getting locked out. I’m looking forward to playing with and configuring Debian 9 Stretch on this VPS. And I think I chose the right way to do the upgrade. Upgrading from Debian 8 Jessie to Debian 9 Stretch on a live website through the shell can be risky and I didn’t want to get to a situation where nothing worked and I didn’t know how to fix it. The cherry on the cake is that I now have HTTP/2 working which was the main thing I wanted to add at the start, plus I have some other upgrades. Debian 9 should be ok for at least a year before I need to start thinking about upgrading again – Debian Version History.

Future

Now, having researched HTTP/2, Debian and Apache for this project I am keen to try Nginx very soon. Nginx is a similar speed as Apache for some things but is much faster in others so I am looking forward to seeing what a life without .htaccess files looks like.

The internet is gradually becoming more and more encrypted and secure. While this is most important for websites where you might enter sensitive data, like credit card info, it is generally a good thing to have for any website. Browsers now warn surfers if a website is not encrypted. As I write this unsecure, unencrypted websites just have an exclamation mark inside a circle in the location bar, but the trend is towards this warning getting more and more visible on the surfers browser.

As well as having quality content for surfers, you can also try to not turn surfers off your content by having an unencrypted website. Maybe secure websites will rank higher than unsecured ones.

Contents

Setting up a SSL Certificate to make a Secure Website

When trying to set up a free SSL certificate from Let’s Encrypt the information I found to begin with was quite confusing. Then, once I got my head around what I was doing, the sites I tried to add it to were not able to use Let’s Encrypt certificates for different reasons.

Once I finally got a VPS that could handle Let’s Encrypt certificates I followed this guide… Install Let’s Encrypt to Create SSL Certificates.

I would say that starting off it is important to pay attention to detail. Make sure everything is updated to begin with, and you have all the server requirements. Also, whereas you may not have specified the IP address in your virtual host config file before, you will need to specify the IP there for this to work.

Luckily, for a Linux administration beginner there are plenty of error logs and hints to find out what if anything has gone wrong. Not all the online guides state all the pitfalls. That’s why I am putting this information together in one place on how to make your website secure with SSL encryption…

Installing Let’s Encrypt

To begin with, make sure port 443 is open in the firewall (see troubleshooting). In these lines of code make sure to change “example.com” to your website domain.

Start off by getting and installing the Let’s Encrypt software, then use it to get the certificates. The order of the two domains in the final command are fairly important because the virtual directory containing the certificates will be named after the first domain, so you might want to use the one without www for simplicity…

sudo apt-get install git
sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt

Installing Let’s Encrypt SSL Certificates

Go to the directory you have cloned to when installing Let’s Encrypt…

cd /opt/letsencrypt
sudo -H ./letsencrypt-auto certonly --apache -d example.com -d www.example.com

If there are any errors after the final command, it should tell you what the error is related to, but if it does not or it is unclear there are some ideas in the troubleshooting section.

Check the certificates by typing the following commands, below. The directory should be your domain instead of “example.com“, if it does not exist or is misspelt then you’ll have to get the certificates again as it will not work. When you get the certificates you should specify both www and non-www. Let’s Encrypt does not work for wildcards so every subdomain has to be specified. If it is a subdomain with a different config file then it will need a separate set of certificates…

sudo ls /etc/letsencrypt/live/example.com
sudo stat /etc/letsencrypt/live/example.com/fullchain.pem

Modify the VirtualHost file to look for SSL Certificates

Then, once you have the certificates. Modify the config file for the website, e.g. “/etc/apache2/sites-available/example.com.conf“. You can Keep the same file just change the port from 80 to 443 and the VirtualHost tags should contain the following. The file path to the certificates should be the actual paths to your certificates. And, I believe for this to work you must have the IP address in the VirtualHost tag, a wildcard will not work…

<VirtualHost 123.123.123.123:443>
SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
</VirtualHost>

Then, make sure SSL is enabled and restart apache…

a2enmod ssl
service apache2 restart

By this stage when you go to https://www.example.com your website should work! If that’s the case you can make sure that everyone gets the secure version of your site, below.

Redirecting to Force HTTPS Encryption

Once the SSL certificates are working properly you’ll want to make sure everyone gets the secure version of your website. There are a few different methods to do this but perhaps the simplest for people who are new to Linux is using .htaccess. How to force HTTPS using the .htaccess file

RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]

This will still allow https://example.com/ to work so you may choose to add another line for that.

Or, have two VirtualHost tags for ports 80 and 443 in the “/etc/apache2/sites-available/example.com.conf” file and redirect port 80 as suggested here

<VirtualHost 123.123.123.123:80>
ServerName www.example.com
ServerAlias example.com
Redirect permanent / https://www.example.com/
</VirtualHost>

Now, you’ll all done!

Checking the Expiration Date of Let’s Encrypt Certificates

Let’s Encrypt certificates last for 90 days, you do not want them to expire unless you want to stop encrypting the website. To check when your current certificates are du to expire type this into the terminal…

openssl x509 -noout -dates -in /etc/letsencrypt/live/example.com/cert.pem

Which will give you the date they were created and the date they are valid until…

notBefore=May 7 14:33:00 2017 GMT
notAfter=Aug 5 14:33:00 2017 GMT

From here there is also “ssl-cert-check” for Debian-like versions of Linux. It needs installing first if it is not already installed, so…

apt-get install ssl-cert-check

Then, run it by typing this simple code (needs superuser privileges so use “sudo”)…

ssl-cert-check -c /etc/letsencrypt/live/example.com/cert.pem

Which gives something like this…

Host                                             Status   Expires     Days
---------------------------------------------------------------------------
FILE:/etc/letsencrypt/live/example.com/cert.pem   Valid   Aug 5 2017   90

Renewing Let’s Encrypt SSL Certificates

To renew the Let’s Encrypt certificates, navigate to the Let’s Encrypt directory… cd /opt/letsencrypt.

Then, this is one way to renew the certificates…

sudo service apache2 stop
sudo -H ./letsencrypt-auto certonly --standalone --renew-by-default -d example.com -d www.example.com
sudo service apache2 restart

The “standalone” flag means that you would have to stop apache because Let’s Encrypt needs to be the only application using port 443.

However, by using --apache or --webroot you can do the same thing while apache is running, from here. This may reload or restart apache but apache would not be stopped for nearly as long as it would be if apache was manually stopped and then restarted again at the end…

sudo -H ./letsencrypt-auto certonly --apache --renew-by-default -d example.com -d www.example.com

To automatically renew the Let’s Encrypt certificates one a month, enter this command to make a monthly task in your crontab…

echo '@monthly root /opt/letsencrypt/letsencrypt-auto certonly --quiet --apache --renew-by-default -d example.com -d www.example.com >> /var/log/letsencrypt/letsencrypt-auto-update.log' | sudo tee --append /etc/crontab

To automatically renew the Let’s Encrypt software, enter this command…

echo '@monthly root cd /opt/letsencrypt && git pull >> /var/log/letsencrypt/letsencrypt-auto-update.log' | sudo tee --append /etc/crontab

Alternative Method for Debian 8 (Certbot)

Another way is to install the Let’s Encrypt certificates is to install Certbot on Debian 8 using Backports… How to Set Up Let’s Encrypt Certificates for Multiple Apache Virtual Hosts on Ubuntu 14.04.

sudo nano /etc/apt/sources.list

Then, enter this line if it is not already there…

deb http://ftp.debian.org/debian jessie-backports main

Save and exit nano, then…

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install python-certbot-apache -t jessie-backports

Troubleshooting and Checking

Check which sockets are open using ss (socket statistics)…

ss -tlnp

More information on ss here.

Check apache version and check which modules are installed

apache2 -v
apache2ctl -M

or

dpkg-query -l

For your second secure website on the same webserver you will have already enabled the SSL module and port 443 will already be serving your first website to the world. When you try to install the certificate for the second website there may be problems if you are using the --standalone flag, because Let’s Encrypt wants to use the same port as is already serving the website. To continue using --standalone you can stop Apache for a few seconds while you install the certificates.

service apache2 stop

Then, once the Let’s Encrypt certificates are done, you can restart Apache again…

service apache2 restart

To avoid having to stop and start apache like this on a production website you can use the --apache flag instead.

If you are using UFW as a firewall, the following command will show you whether socket 443 is allowed…

sudo ufw status

Also, Apache problems when trying to set up SSL (Debian).

Further Checks to make your Website Secure (Green Padlock)

If your website is working with HTTPS in the location bar (“https://www.example.com/”) but you do not have a green “SECURE” you have an “i” with a circle around it, check to see what it says by clicking on it. If it says you are not fully secure it probably means that the files and/or images you are linking to are not using the SSL encrytion. To fix this simply either fix your absolute image/file locations by changing them from HTTP to HTTPS, or just use relative linking.

Another thing that may cause errors is your .htaccess file, if you have one. Make sure that the error documents are all updated from http:// to https:// for the site in qustion.

Adding more Secure websites to the same Webserver

When “Let’s Encrypt” is already installed you do not have to re-install it, you can simply create the new certificates for the next website you want to make secure. When you are trying to create the certificates there may be an error saying that port 443 is already in use. In this case, you may have to stop apache briefly while you make the certificates, then restart apache as soon as they’re made.

Here is a guide to Setting up a Linux Webserver with SSH. This is for Debian 8 (Jessie) although other versions of Debian will be similar, and Debian-based versions of Linux, like Ubuntu will also use similar commands. I’ll just call it the webserver because it can be a dedicated server, a VPS, or a cloud instance.

A lot of this comes from these excellent guides… Getting Started with Linode and Securing your Server… but I’d say that searching around and getting different information from different sources is definitely a good way to go. I wanted to install PHP 7.0 so some of this guide is different to other guides, which tend to use PHP 5.6. This guide is also primarily for people using a Windows PC to talk to a remote Linux webserver, but other operating systems will be the same for most of the stages. Most of the contents of this guide uses a terminal and an SSH connection, which windows needs software for (e.g. Putty), but other operating systems may have it built-in. This guide doesn’t talk about FTPing (or SFTPing) much, but a good SFTP client for Windows is WinSCP.

There is often more than one way to get the same results. For example, you can reboot the system in a number of different ways. I tend to use the methods that appear simplest to me.

Requirements

  • A linux server (Debian 8, in this case).
  • The IP address of the server.
  • The root password of the server.
  • A computer to access your remote linux webserver, in this case a Windows PC with Putty installed.

Contents

1) Login to the server with SSH
2) Update/upgrade
3) Install Apache2
4) Find your webserver’s IP address
5) Set a Hostname
6) Configure the Apache virtual hosts
7) Create the web directory
8) Install PHP7
9) Your webserver’s Timezone
10) Unattended upgrades
11) Install Sudo
12) Add a user
13) Public/private key pair
14) Turn off root login
15) Sending email
16) Fail2ban
17) Firewall: UFW
18) Install MySQL and PHPmyAdmin
19) Monitor
20) Apache Config file
Conclusion

1) Login to the server with SSH

With Windows you can download and install some software, such as Putty, then connecting to your instance should be pretty straight-forward with the login information from your hosting company. To begin with you’ll probably be logging in as “root” so you will not need to type sudo as root is the master login (this is handy because sudo is not installed, yet). The commands on this guide may need sudo adding at the beginning if you are not logging in as “root”.

2) Update/upgrade

Once you are logged in the first thing to do is to make sure everything is updated so that you are installing the latest versions of everything when you get to that stage.

apt-get update && apt-get upgrade

or, later if you login as another user, you’ll need sudo…

sudo apt-get update && sudo apt-get upgrade

3) Install Apache2

First, you can check if Apache is already installed by typing…

which apache2

If it is not already installed, i.e. the above does not give you any results. To install Apache type…

apt-get install apache2

4) Find your webserver’s IP address

If your hosting company has not told you what the IP address is, this shows all IP’s installed on your instance…

hostname -I

5) Set a Hostname

The hostname can be anything. If you have more than one instance you might name your instances so that they are all plant species, stars, geographical locations, chemical elements, Roman Emperors or Greek philosophers.

Add the hostname by opening up the hosts file in nano…

nano /etc/hosts

Then, the hosts file might look like using the IP address that you already know, above…


127.0.0.1 myhostnamegoeshere.example.com myhostnamegoeshere localhost
127.0.1.1 myhostnamegoeshere
123.123.456.789 example.com

Also, edit the hostname file…

nano /etc/hostname

Then, after this you’ll need to reboot the instance from the control panel of the hosting company or by rebooting from the control panel: shutdown -r now.

The hostname and FQDN are important for all kinds of server functions. Test your hostname settings like this…

hostname hostname
hostname -i ip address
hostname -f or hostname --fqdn fully qualified domain name

6) Configure the Apache Virtual Hosts

Make sure 000-default.conf is off, copy it to mywebsite.com.conf and enable. link

cd /etc/apache2/sites-available
cp 000-default.conf example.com.conf
nano example.com.conf

Then, edit the example.com.conf so that it looks like this…

ServerAdmin [email protected]
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com

Then, enable the site by typing…

a2ensite example.com

7) Create the web directory

We specified the DocumentRoot should be /var/www/example.com, above. So, now we need to make it!

Move to the place for all your web directories…

cd /var/www/

Then, create the web directory…

mkdir example.com

Once you have the directory you can add an index.html inside it.

If you have not restarted apache2 since typing the a2ensite command you need to do that before the domain name will work in your browser. Restart then test it by typingthe domain name into a browser.

8) Install PHP7

You can install any version of PHP. For Debian 8, it seems that PHP5.6 is the default, whereas with Ubuntu 16.04 LTS PHP7.0 is the default. I wanted to go with PHP7.0 so followed this guide for setting it up on Debian 8… Installing PHP7

Add these two lines to your /etc/apt/sources.list file:

deb http://packages.dotdeb.org jessie all
deb-src http://packages.dotdeb.org jessie all

Add the GPG key:

wget https://www.dotdeb.org/dotdeb.gpg
apt-key add dotdeb.gpg

Install PHP 7:

apt-get update
apt-get install php7.0

Then, straight away before you do too much else you’ll want to add the other modules you need. There is information abput some common ones from here..

apt-get install php7.0-cli php7.0-common libapache2-mod-php7.0 php7.0 php7.0-mysql php7.0-fpm php7.0-curl php7.0-gd php7.0-bz2

You can then test out the PHP by making a page that has phpinfo(); on it to show you 1) that it’s working and 2) the modules that are installed and enabled. Assuming everything works fine it’s time to do more setting up…

At this stage I normally make sure everything is installed that I’ll need for phpmyadmin. Then enable mod_rewrite

a2enmod rewrite

9) Your webserver’s Timezone

Set your server timezone by typing the following command…

dpkg-reconfigure tzdata

Then, this command shows you the current time on your server…

date

10) Unattended upgrades

You will want to keep everything as up-to-date as possible on your instance. You can do this by configuring the Unattended upgrades… Automatic updates. Then if you don’t want to have to login to your instance and reboot/restart it after every upgrade, you can automatically reboot, if needed, after upgrading. First install the package…

apt-get install unattended-upgrades

Then configure the settings you want in nano…

nano /etc/apt/apt.conf.d/50unattended-upgrades

To test unattended-upgrades as root or with sudo run…

unattended-upgrade -d

11) Install sudo

From Installing sudo on Debian

apt-get install sudo

12) Add a user

adduser myname

Then, add the user to sudo…

usermod -aG sudo myname

You can check which users are in the group sudo by running…

getent group sudo

Then logout of root, login as myname and test sudo out by doing something that requires sudo privileges, e.g. restarting apache: service apache2 restart.

13) Public/private key pair

This is the main thing that is different on Windows PCs than it is with either Linux or Macs. For Windows PCs you have to use downloadable software, such as putty. This guide: Use Public Key Authentication with SSH talks you through the process.

The most important thing to note is that you should either be logged in as the user you want to make the key pair for when you make the ~/.ssh directory and put the authorized_keys file in it, or if you do it as root the location should be “/home/yourusername/.ssh/authorized_keys” and the owner should the yourusername not root. So, if you’re logged in as root you can run su yourusername to login as the user you’ve just created, then when you go to cd ~/ it will take you to “/home/yourusername/”. If you do it this way you have to make sure to check that the owner of the “authorized_keys” file is yourusername… chown yourusername:yourusername -R ~/.ssh as suggested here.

Then, logout of root and login with your user to check that the new user works correctly with the public key authentication. You should be asked for the keyphrase, as opposed to the password.

14) Turn off root login

If you can login with the username you set up with the public/private key pair you can “turn off” root logins.

Turn off root logins and turn off password authentication in the sshd_config file using nano…

nano /etc/ssh/sshd_config

For the changes you have made to work, you will need to restart SSH…

service ssh restart

15) Sending email

You will need to be able to send emails from the server to get the unattended-upgrades emails (if you have asked it to send emails).

Rather than send the emails manually this guide walks you through setting up postfix with Mailgun.

The only thing I found a little confusing was the mapping on this line…

[email protected]_hostname [email protected]_subdomain_for_mailgun

Really, as you’ll mainly be sending emails as a user (e.g. www-data or root) you should have lines like this to allow that…

root [email protected]

If you’ve set up your Mailgun account to use a subdomain, e.g. mail.example.com you can still use an address like an[email protected] here!

Alternatively, https://www.debian.org/releases/jessie/amd64/ch08s05.html.en allows server to send email.

16) Fail2ban

Fail2ban

apt-get install fail2ban

Then, you can edit the config file, and/or make a local file…

nano /etc/fail2ban/fail2ban.conf

17) Firewall

For a firewall, UFW (Uncomplicated Firewall) is there for Debian systems. This is a good guide: Configure firewall with UFW

apt-get install ufw

As the guide says, you’ll have to be very careful when switching on the firewall that you do not lock yourself out of SSH.

18) Install MySQL and PHPmyAdmin

Here are two useful guides: MySQL and MySQL on PHP7.

apt-get install mysql-server
mysql_secure_installation
apt-get install libapache2-mod-php7.0 php7.0-mysql php7.0-curl php7.0-json

Then, once MySQL is installed there is more MySQL information here about how to create a database and a new user.

A good place to begin before installing PHPmyAdmin is by checking the phpmyadmin prerequisites and installing everything needed (e.g. mbstring). If 500 server errors, check the prerequisites again, installing anything that isn’t already installed, then re-install phpmyadmin to get rid of the error. Install PHPmyAdmin on Debian 8

sudo apt-get install phpmyadmin

For each virtual host that you would like to give access to your PHPMyAdmin installation, create a symbolic link from the document root to the phpMyAdmin installation location (/usr/share/phpmyadmin). You do this by moving into the public directory of each virtual host, then creating a symlink…

cd /var/www/example.com/public_html
sudo ln -s /usr/share/phpmyadmin

19) Monitor

You can monitor the performance and usage of the web server by using top… Just type top into the terminal and you’ll get a summary of the usage every few seconds.

Linux TOP command explained

You can also set up a script that will email you if certain conditions are met (RAM usage, for example).

20) Apache Config file

It’s a good thing to take a look at the apache2 config file to make sure it is configured correctly. One of the things you’ll want to check is that KeepAlive is set to off. From Setting up LAMP on Debian 8.

sudo nano /etc/apache2/apache2.conf
KeepAlive Off

TL;DR / Conclusion

Different setups are all slightly different. If you are getting errors the best thing to do is to either examine the error itself or find the relevant error logs and do some problem solving. Unix & Linux Stack Exchange and Server Fault tend to have a lot of problems already answered.

This is just a general guide to setting up a Linux Webserver with SSH with a Windows PC talking to a Debian 8 remote webserver. You may want to change the order I have followed here and there may well be steps I’ve missed out here, errors I get that you do not get, or vice versa. But, I hope it can be useful to someone.

After getting this far there will probably still be thing you need to do to your webserver. There will be other PHP and Apache modules that your web applications and/or frameworks require, such as mod_rewrite… As before, figure out what you need for your application and add it as required. Have fun!