Once upon a time you could buy a domain name and hook it up to some cheap, shared hosting and that was all you had to do. You could build your website or install a WordPress blog and no further configuration was really required. These days you can still do this but you are leaving yourself open to security, speed, and privacy issues. Surfers becoming more aware of which browsers are safe and which aren’t through information from their browser and anti-virus programs. But not only this, search engines are also starting to penalize websites which do not protect the surfer’s privacy, are slow or are insecure.

There has been a desire to improve search engine rankings by doing SEO work for a long time. Now, in 2018, SEO is different to how it was 15 years ago and it’s importance is joined by security, speed and privacy as the four things everyone should be looking into. I have labeled each header to show which of the four sides the technology is used for.

These are just my thoughts at the moment, much of it will be my opinion. There are people who know much more about everything here so my advice would be to do more research before making any changes to your websites.

Best Practices for Websites in 2018

These best practices are the current general buzzwords for all websites that I think people may be slow to adopt. These should be added to the specific best practices for whichever kind of website you have concerning permissions, owerships, coding, code injection, etc.

This guide is just a quick look at all the topics. I may have missed some topics out. There is a short discussion and generally link(s) to follow to get more information, or tutorials to follow.

If you use a CDN, like CloudFlare, some of these may already be done without you having to think about it but they are good to know about, especially if you do not use a CDN. Also, if you use managed or shared hosting you may not be able to change some of these, but they may already be done for you by your hosting company.

Here are some best practices for websites in 2018. Some of these used to be nice-to-haves but are fast becoming must-haves, if they are not already.

Google Audit (speed)

Google Audit on the Chrome browser has replaced Google Pagespeed and offers a lot more detail than before as to how Google views your website.

Much of what Google Audit looks at is the speed of your website, especially over mobile networks. So, it wants the content that first appears on the browser to appear very quickly, loading content from further down the page afterward. The Audit is mainly the content of the website and how quickly it loads. The harshest test will be to run it in mobile mode with “3G/PC throttling” switched on. Google wants the above the crease content to be displayed quickly even on slow 3G.

Every time I do an Audit I have to be prepared for it to be painful reading. The good thing is that it highlights issues that you might not have seen, or you might have thought that they were fixed.

SSL/HTTPS (privacy)

Enabling SSL encryption and forcing your website to use HTTPS has hit the headlines, mainly because of the changes to browsers which are meaning that HTTP-only websites are starting to look like bad places to visit.

The docs for Apache SSL are here… link

The disadvantage with just using SSL encryption by itself is that the website can often be much slower than it would have been without the encryption due to the extra handshakes that are needed with HTTPS. But, there are ways to further tweak HTTPS that will improve the security and also the speed of HTTPS websites. Most of these changes can be made to the SSL config file in Debian if you add them to another file (e.g. apache2.conf or a vitualhost file) make sure that there are no conflicts.

To check your own site to see how it ranks for security this website gives a good overview and even gives you a grade to show exactly how secure it thinks your site is.

TLS Session Resumption (security/speed)

TLS Session Resumption is configured in the SSL config file on Apache web servers. By default, it should be enabled. Check whether this is enabled for your website at SSL Labs.

TLS Session Resumption is the default with Cloudflare Flexible SSL… link.

HTTPS/2 (speed)

If you use a CDN HTTP/2 may already be setup, or it may be an option that you can select. If you do not use a CDN you should check that your server is compatible with HTTP/2 like I did in this post.

Enabling HTTP/2 before HTTP/1.1 looks like this…
Protocols h2 http/1.1

HTTP/2 wiki… link

HSTS (speed/security)

HSTS wiki… link

How to use HSTS… link

On Debian you have to allow headers a2enmod headers then add this to the virtualhost file or the apache2.conf file…

15552000 seconds is 6 months.

# Use HTTP Strict Transport Security to force client to use secure connections only
Header always set Strict-Transport-Security "max-age=15552000; includeSubDomains;"
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options: nosniff

Then restart apache and test with SSL Labs.

Perfect Forward Secrecy (privacy/security)

Enabling Perfect Forward Secrecy (FPS)… link also link.

Use TLS (security)

Some cryptographic protocols are deprecated because they are able to be hacked and are thus insecure. Very old browsers may not use the TLS 1.1 or TLS 1.2, so you have to strike a compromise between security and accessibility. If you think a lot of your viewers may have older browsers you can keep SSL 2.0, SSL 3.0 and TLS 1.0 enabled, however, these are all insecure. Just allowing TLS 1.0+ is better. Just allowing TLS 1.1+ is much more secure. The risk of forcing too high a cryptographic protocol is that there may be people using browsers who do not support your current protocol. It’s a balancing act which comes down to your own decision about what is more important security or accessibility.

If you just wanted to allow TLS 1.1 and TLS 1.2 you would add this to your ssl.conf or apache2.conf (in Debian). Be careful that there are no conflicts between these two files and the individual virtualhost files…

SSLProtocol TLSv1.2 TLSv1.1

You can check which browsers use which cryptographic protocols at this link.

DNS CAA (security)

Specifying which domain(s) you want to issue certificates to your website also makes your website more secure. You do this through your domain registrar or CDN, where available.

On CloudFlare using their Flexible SSL you would need the following…

example.com. IN CAA 0 issue “comodoca.com”
example.com. IN CAA 0 issue “digicert.com”
example.com. IN CAA 0 issue “globalsign.com”
example.com. IN CAA 0 issuewild “comodoca.com”
example.com. IN CAA 0 issuewild “digicert.com”
example.com. IN CAA 0 issuewild “globalsign.com”

Taken from the CloudFlare blog

See also…

  • TLS False Start (Speed)
  • OCSP stapling

DNSSEC (security)

DNSSEC was designed to protect applications (and caching resolvers serving those applications) from using forged or manipulated DNS data, such as that created by DNS cache poisoning. All answers from DNSSEC protected zones are digitally signed. By checking the digital signature, a DNS resolver is able to check if the information is identical (i.e. unmodified and complete) to the information published by the zone owner and served on an authoritative DNS server. While protecting IP addresses is the immediate concern for many users, DNSSEC can protect any data published in the DNS, including text records (TXT) and mail exchange records (MX), and can be used to bootstrap other security systems that publish references to cryptographic certificates stored in the DNS such as Certificate Records (CERT records, RFC 4398), SSH fingerprints (SSHFP, RFC 4255), IPSec public keys (IPSECKEY, RFC 4025), and TLS Trust Anchors (TLSA, RFC 6698).

link

Caching (speed)

CDN

CDN. See also clouds.

Service Workers

Javascript creates a cache of the website on the viewer’s machine so that they can still view your website if they lose internet connection.

301 Redirects (SEO/speed)

Having pages that load quickly and not having duplicate content are big parts of SEO. 301 redirects tell search engines and browsers that they should be using a certain URL. For example, you should be redirecting from HTTP to HTTPS, and you can redirect from non-www to www or vice versa.

Canonical URLs (SEO)

With a canonical URL you are telling the search engine the exact URL it should be using. This is another method of ensuring that the pages are not going to be listed several times and appear to be duplicate content to search engines.

Schema.org (SEO)

You add schema to your HTML markup. This is mainly for search engines as it is not visible on the page… link

Have a Privacy Policy (privacy)

GDPR was launched in the EU in 2018. Data protection has been around for a long time, but the addition of GDPR means that websites who have European visitors should definitely consider having a privacy policy. This is all to do with collecting data on individuals, and how that data is used. It’s probably safer not to collect any data at all or as little as possible. I know useful stats-based websites that have closed as a direct result of GDPR, which is a shame. On the plus side, it gives Europeans more control over their data, which is probably a good thing.

Conclusion

Do an analysis of your website on SSL Labs and do a Google Audit. Both sets of results will give you a list of things that are good and things that are bad. You can seek to improve the things that are bad, some of which will be listed in this article. It is probably not possible for mere mortals to get 100% perfect, but a lot of these steps are both free and easy to implement so it’s worth trying to get as high a score as possible.

I have focussed on privacy, security, speed and SEO in this guide. There are considerations that have always been around or are not especially new for 2018 such as accessibility and having a mobile-friendly website which should also be looked at if you do not already.

Some of this is primarily aimed at mobile users. Google Audit and service workers, in particular, are very concerned with how the website behaves on mobile connections which may be intermittent. The benefit of working on these, along with having a mobile-friendly website is that you may well get more mobile visitors. Google wants to send mobile visitors to websites they’ll enjoy using, thus it is gradually increasing their importance on it’s mobile rankings.

Here are some tweaks you can make to various parts of Linux to make the whole experience a little easier and more intuitive. This guide is for Ubuntu and Debian flavours of Linux.

Change the Config Editor to Nano

The Debian default editor is Joe, if you do not know this text editor, change it to one you know, i.e. Nano. This command gives you all the options you have available…

sudo update-alternatives --config editor

Turn off passwords for a User

Once the config editor is nano, you can edit the sudoers file with the visudo command…

sudo visudo

One thing you might want to do is turn off passwords for yourself so that you do not have to keep typing the password when you run sudo commands. Add this like near the end of the file, after the “%sudo” group line…

myuser ALL=(ALL) NOPASSWD:ALL

Tweak Nano

Some changes I like to make when I first set up Linux are on Nano. I like to put smooth-scrolling on and to turn the keypad back to numeric. To do this, edit the nano config file by running this command as either root or with sudo…

sudo nano /etc/nanorc

Installing More Than One Version of PHP

To list all the versions of PHP that are installed you can type…

update-alternatives --list php

This then allows you to switch between them if you have more than one installed at any one time. Really this is more useful on a development machine, it is probably not needed on a web server.

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.

These days there are often WordPress apps on the control panel of hosting providers that enable you to install WordPress easily with a click. You can install and run WordPress entirely by FTP/SFTP and the admin dashboard, but this can be slow. However, if you are comfortable with the Linux command line, you can install WordPress, themes, and plugins at a lightning fast speed. This is particularly useful if you are moving from one hosting company to another and you have more than one WordPress blog to move at the same time.

Installing WordPress from the Command Line

Sometimes SFTPing to a host can be very slow. WordPress is made up of so many individual files that uploading everything when installing or updating can take a very long time.

This method is very quick and snappy way to download the latest version of WordPress when you are initially installing your blog…

wget http://wordpress.org/latest.tar.gz
tar xfz latest.tar.gz

WP CLI

These commands 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

You can do this from anywhere because the three lines are 1) download, 2) change permissions and 3) move.

If you install WP-CLI before installing WordPress you can even install WordPress with WP-CLI, see wp core install

wp core download –locale=nl_NL
wp core install –url=example.com –title=Example –admin_user=supervisor –admin_password=strongpassword –[email protected]
wp core version

The 3 lines are 1) download, 2) install and 3) check the version of WordPress that is installed.

Installing Plugins

Assuming you have already set up the WordPress blog (wp-config.php and database), you can then install and activate multiple plugins very easily like this…

wp plugin install wordpress-seo jetpack post-volume-stats add-target-fixer –activate

Another use might be that you can easily de-activate plugins if you ever have problems logging in…

wp plugin deactivate plugin-name

Search and Replace

One thing that you cannot do with SFTP and the WordPress admin dashboard is a sitewide search and replace. There are probably plugins that will help you do this, but it is made very easy with WP-CLI…

wp search-replace oldstring newstring

The --dry-run flag also helps you to see what you’re about to change before you change it.

Updating WordPress

Perhaps the most useful function of WP-CLI for me is the ability to update WordPress very easily and quickly. This is all it takes…

wp core update

Summary

For more info see the docs at WP-CLI.

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.

Following the setting up a Linux webserver tutorial. You may also wish to create a MySQL database. First, install MySQL in the Linux console and give the root user a password. Here is what you might do for PHP 7.0 (needs sudo unless a superuser)…
apt-get install mysql-server
mysql_secure_installation
apt-get install libapache2-mod-php7.0 php7.0-mysql php7.0-curl php7.0-json

Now, from the linux command line you can login to MySQL like this…
mysql -u root -p

Now, the rest of the commands in this tutorial are run from the mysql> prompt.

After installing MySQL the main reasons you’re probably wanting to access MySQL from the command line are to create a database and create another user. To create a database…
CREATE DATABASE [database name];

To create a user, grant the user privileges on a database then reload the privileges…
CREATE USER '[username]'@'localhost' IDENTIFIED BY '[password]';
GRANT ALL PRIVILEGES ON [database name] . * TO '[username]'@'localhost';
FLUSH PRIVILEGES;

If you wanted to grant the new user privileges to everything you could do this…
GRANT ALL PRIVILEGES ON * . * TO '[username]'@'localhost';

Or just a specific table of a specific database…
GRANT ALL PRIVILEGES ON [database name] . [database table] TO '[username]'@'localhost';

This is probably all you’ll need to do in the command line. Everything else you can either do in PHPMyAdmin or in an MVC framework.

You can get a list of the databases with this command…
SHOW DATABASES;

If you wanted to manually create a table you would first “use” a database…
USE [database name];

Then, these commands are starting to look more like SQL commands you may have written in PHP…
CREATE TABLE example ( id not null auto_increment, name varchar(20) not null, constraint pk_example primary key (id) );
INSERT INTO example ( name ) VALUES ( 'Sample data' );

To import a SQL file in the Linux command line, very similar to logging in normally…
mysql -u [username] -p < [SQL file name]

To find the version of MySQL you have installed run this command...
SHOW VARIABLES LIKE "%version%";

To exit out of MySQL, some of the normal ways of exiting a command line application may not work, you'll have to use...
quit

Using a CDN is a great way to optimize your website and protect against DDoS attacks. The process of setting up a CDN is pretty simple, often changing the nameservers on your registrar is as tricky as it gets. But there can be some potential issues. Here is a short guide on how to fix some potential issues when using CDN. The example I’m using is Cloudflare but some of these issues will be the same for other similar CDNs. Some of these issues arise from changing your nameservers to a CDN, others involve Cloudflare’s Flexible SSL. All of these issues are fixable, but it is good to be aware of the issues up front.

Note: The Flexible SSL should not be used for sensitive data. For credit card transactions and personal info “Full SSL” should be used, i.e. there is an SSL certificate on the web server itself. See this guide to adding SSL encryption.

There is Cloudflare Support which contains this SSL Cloudflare troubleshooting guide for more information and also Advanced Configuration.

1) Server configuration.

If your server is misconfigured using Cloudflare’s name servers and Flexible SSL can cause problems. Obviously, if you are redirecting visitors to HTTP on the server, then you ask Cloudflare to always redirect people to HTTPS there will be problems. Solution – make sure your server is correctly configured.

2) Cloudflare’s IPs and Visitor IPs.

You may need to whitelist Cloudflare’s IP addresses in .htaccess files…

#(IPv4)
Allow from 173.245.48.0/20
Allow from 103.21.244.0/22
Allow from 103.22.200.0/22
Allow from 103.31.4.0/22
Allow from 141.101.64.0/18
Allow from 108.162.192.0/18
Allow from 190.93.240.0/20
Allow from 188.114.96.0/20
Allow from 197.234.240.0/22
Allow from 198.41.128.0/17
Allow from 162.158.0.0/15
Allow from 104.16.0.0/12
Allow from 172.64.0.0/13

#(IPv6)
Allow from 2400:cb00::/32
Allow from 2405:8100::/32
Allow from 2405:b500::/32
Allow from 2606:4700::/32
Allow from 2803:f800::/32
Allow from 2c0f:f248::/32
Allow from 2a06:98c0::/29

Cloudflare acts like a proxy, all traffic to the server appears to be coming from Cloudflare itself. If you wish to know the IP of all visitors to your website you can install mod_cloudflare to your server. There are slightly different instructions here.

3) WordPress and Cloudflare Flexible SSL.

Full SSL or Strict SSL should not need any plugin for WordPress to work normally. Simple free plugins fix the errors with the Flexible SSL and WordPress. Just search the WordPress Plugin Repository for “Cloudflare” and use the plugin that you feel will work the best.

4) PHPMyAdmin and Flexible SSL.

The potential problem is that even after you’ve specified “ForceSSL” and “Absolute URI” in the PHPMyAdmin config, PHPmyadmin can sometimes append “:80” to your domain name when you are redirected after logging in. In some versions of PHPMyAdmin (e.g., 4.1.xx), you end up at a URL which looks like https://www.website.com:80/phpmyadmin/. Using the Flexible SSL you are using port 80 on the server, but the connection between Cloudflare and the user is using port 443. This means that the addition of the “:80” causes an error and does not display PHPMyAdmin until you remove it.

The problem can be fixed in the file phpmyadmin/libraries/Config.class.php. There is a part which checks that port and whether the URL is HTTP or HTTPS.

A solution is from here, you find the following code and fix this by commenting out the last OR condition:

if (! empty($url['port'])
&& (($url['scheme'] == 'http' && $url['port'] != 80)
|| ($url['scheme'] == 'https' && $url['port'] != 80)
//|| ($url['scheme'] == 'https' && $url['port'] != 443)
)) {
$pma_absolute_uri .= ':' . $url['port'];
}

It would be better to use Full SSL for PHPMyAdmin but this is a solution to the problem if you have to use Flexible SSL.

5) Full/Strict SSL or Flexible SSL.

When you first add Cloudflare to your website it will fetch the settings and it will decide whether to use Full SSL if the website has it’s own SSL certificate or Flexible SSL if it does not. If you want to change from Flexible to Full or vice versa after setup, make sure that the website is using the correct setting (Full or Flexible) in the “Crypto” tab.

Basic Steps After Installing Laravel 5.4

You have successfully installed Laravel 5.4 and you have directed the domain name at the public directory and you can see then Laravel test page. What next? Assuming that you are going to be using a database to run your website, here are some basic steps in how to build a Laravel website from the Laravel test page.

For this simple example, this guide may work for Laravel 5.x but this guide is specifically for Laravel 5.4.

Contents

Useful Commands
1) The Database
2) The .env file
3) The Model
4) The Migration
5) The Route
6) The Controller
7) The View
Conclusion
Errors and Solutions

Useful Commands

If you want to clear Composer cache (-o flag means optimized)… composer dump-autoload -o

Die and dump, like var_dump($variable); would be this in Laravel… dd($variable);

List all Artisan commands help… php artisan list then look at the help file for a specific command php artisan help controller:make

Run tinker… php artisan tinker. Then, exit with “q” or CTRL-C.

1) The Database

Create the database and give it a user.

2) The .env file

Add the database login info to the .env file which should be in your root (the level below “public“).

While you’re there you may aswell update as much of the info in the .env file as you can. If the name of the website has a space in it remember to use quotes. Not using quotes will cause an error.

You can also update the config/app.php file. If you get errors after updating this file double-check the permissions and ownerships and you may need to run composer dump-autoload -o afterwards if errors persist.

3) The Model

Laravel is an MVC framework. It is designed to use Models, Controllers and Views.

In this simple example, we’re just going to list some data from a database onto the page. The data we want to display are some names. One way to make a Controller for “names” is using Artisan like this… php artisan make:controller NameController. You can make the Model and the Controller separately, but we also need a Migration, why not make all three together in Artisan like this…

php artisan make:model Name -mc

The -mc literally means to create a Migration and a Controller at the same time as the Model.

If the Model is Name (capitalized and singular), the Controller would be NameController (camelcase), the Migration would be create_names_table, and the resulting table would be names (lowercase, plural). The Models are in the app directory.

Using this method the Model is already using Laravel’s database engine, Eloquent, and because of the naming convention, the Model knows which database it is connected to so we do not have to add it manually.

The Model can contain relationships and scopes, but in this simple example, we will not alter it at all.

4) The Migration

The Migration files are created for you in Step 3, they will be in the database/migrations directory. Now, you have to modify them for the data you want to use. I only want each name to have an ID and the name itself in this example, so I can modify the Migration to look like this using Laravel’s Schema…

public function up()
{
Schema::create('names', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
});
}

Here, id is an incremental integer and name is a string. For more database column types you can use in Migrations see Adding Columns. You can also specify indexes, foreign keys and set a default value for a column in the Database: Migrations.

Then, php artisan migrate builds the info from the Migration tables in the database.

If you change the migrations you can rollback and then make the migrations again with

php artisan migrate:refresh

5) The Route

Once you have a Controller and Model you can make a simple route. The routes directory has a file called “web.php”…

Route::get('/', '[email protected]');

'/' means when the URL is the root domain Laravel will call the Controller and method in the second parameter.

NameController is the name of the Controller that was created in Step 3.

index is the method we want to use. There are up to 7 default behaviours that a Controller should have: index, create, store, show, edit, update, and destroy. These methods within a Controller are called actions. If you find that your controller needs more than these 7 actions it may be a good idea to create a new Controller.

6) The Controller

The Controller is the file “NameController.php” that lives in the app/Http/Controllers directory. From Step 5, we said that we wanted to use the index method because we just want to list all the names. To do this we can use Eloquent and the all() function to simply grab all the rows from the table…

use App\Name;
public function index ()
{
$names= Name::all();
return view ( 'names.index', compact('names') );
}

If you “use” the Model in this way at the top, use App\Name;, you can refer to the Model in the methods like this Name::all(); as opposed to App/Name::all();. Instead of using all() you could also use Eloquent but order the results differently using get()

$names = Name::orderBy('name', 'desc')->get();

The same thing as all() but not using Eloquent would be…

$names= \DB::table('names')->get();

The \ is needed in front of the DB because you are inside the Controller and the DB class exists outside of it. Or, just “use” DB at the top of the controller, see Queries.

Out of these two different ways to interact with the database, it is better to use Eloquent and to keep most of the database-related logic inside the Model. In more complex projects than this example, the Model would contain Scopes and Statics that can be referred to from other places, such as Controllers.

The 'names.index' is the View we want to use and compact('names') is a way to pass the $names array into the View, alternative ways are listed in Passing Data to Views, for example…

return view('names.index')->with('name', $name);

7) The View

In the Controller we said the View we wanted to use was names.index. This means that Laravel will be looking in the resources/views/names/ directory for the file: “index.blade.php“. So make this file.

The View uses the Blade templating engine so ideally, the contents will be a mixture of HTML and simple logic. You can either use normal PHP, like <?php if($names){ ?>. Or, it may be better to use the blade templating system and write it using Blade like this @if ($names). With Blade you do not have to keep opening and closing the PHP making it a lot easier to write and cleaner to look at than normal PHP mixed into the HTML would be.

We want to display all our names on the page using Blade. In step 4, we gave the table 2 columns in the migration, “id” and “name”, and, in step 6, we got all the data from the “names” database. Now, they can be displayed very simply in a list like this within HTML using Blade…

@if ($names)
<ul>
@foreach ($names as $name)
<li>{{ $name->id }} - {{ $name->name }}</li>
@endforeach
</ul>
@endif

Now, when you go to the root domain of the Laravel website the Route sends you to the correct method of the Controller, which uses the Model and the View to grab the names and display them (assuming you have also inserted some rows to the database).

Conclusion

The 7 steps of this very simple beginners tutorial use the route, model, controller and view parts of Laravel.

  • The Route links the URL with a specific control and method, and can pass variables through to them.
  • The Model just links the table in the database to the controller in this simple example. In more complex examples the Model interacts with the database more and specifies relationships.
  • The Controller does what we want the page to do, in this case, it is to fetch the list of names from the Model (database) and it also says which view will display the data.
  • The View takes the data from the Controller and displays it on the page.

Errors and Solutions

An Artisan command produces an error like this…
[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table users add unique users_email_unique(email))

Edit your “AppServiceProvider.php” file in the app/Providers directory and add to the boot method a default string length. You also have to make sure to “use” the Schema at the top.

use Illuminate\Support\Facades\Schema;
function boot()
{
Schema::defaultStringLength(191);
}

****************************
If migrate:refresh produces an error like…

[Illuminate\Database\QueryException]
SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'users' alre
ady exists...

Manually drop the tables in tinker by running tinker (see Useful Commands) and running the command…
Schema::drop('users')

Now, you can now run php artisan migrate to migrate all the tables.

****************************
Pages aren’t loading at all (fatal error), looking at the logs gives the error message…
Fatal error: Uncaught exception 'UnexpectedValueException' with message 'The stream or file...

Solution, make the Laravel log files writable…
sudo chmod -R 777 storage/logs

What do you do when the Start button stops working on Windows 10? Here is the solution from here

1. Launch Task manager
Press the [Ctrl] + [Alt] + [Del] keys on your keyboard at the same time – alternatively, right click the Taskbar. Then select Task manager.

2. Run a new Windows task
When the Task manager window opens, click the More details option to expand it, then select Run new task from the File menu.

3. Run Windows PowerShell
When the Run new task dialog box opens, type powershell, tick the box for Create this task with administrative privileges and click OK.

4a. Run the System File Checker
Type sfc /scannow into the window and press the [Return] key.

4b. Reinstall Windows apps
Launch the Task manager and open a new PowerShell window with administrative privileges, as explained above. When the Windows PowerShell window opens copy the line below and paste it into the PowerShell window by simply right-clicking at the blinking PS C:\WINDOWS\system32> prompt, or by pressing [Ctrl] + [V] on the keyboard:

Get-AppXPackage -AllUsers | Foreach {Add-AppxPackage -DisableDevelopmentMode -Register "$($_.InstallLocation)\AppXManifest.xml"}

Wait until the app download and installation process completes — ignore any red text that appears — then restart Windows.

I was unable to find a single tutorial that would show exactly how to install Laravel on Debian, possibly because I was using PHP 7.0 on Debian, which no other examples seemed to use. As such, I had to take bits and pieces from different websites to make this tutorial on installing Laravel on Debian. The same tutorial will also work for Ubuntu but I found that on Ubuntu 16.04 a lot of the dependencies were already installed out of the box, Debian may require more care to make sure everything is present. Once you have all the requirements installed it should be easy to install composer, and once composer is installed Laravel should also be fairly simple if you are doing the right things.

I found that some methods of installing Laravel did not work on my setup, this may have been because it was Debian or because I’d missed a requirement. This is the method that worked for me, and also works on Ubuntu.

Installing Composer

Before starting the most important thing is to make sure to apt-get upgrade and apt-get update… and also, make sure all the Laravel server requirements are installed. Once that’s done, restart/reload and begin. From here, you can install composer by typing these commands into the Linux terminal…

curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

Installing Laravel

Then navigate to where you want to put the new website and create a new project. The name of the project will be the name of the directory, so here I’ve called it example.com, because it is a shared server…

cd /var/www
sudo composer create-project laravel/laravel example.com --prefer-dist

This way you can easily specify the directory name. There is an alternative method here.

After installation, the last thing it should tell you is what the encryption key is. A good thing to do right away would be to check that this is the same as the value in the .env file. If the installation was successful it should be there, but it is good to check and also to have a first encounter with the .env file!

Configuring your Website to Run Laravel

Now, set up this new domain as normal on your webserver, making sure that instead of pointing to the /var/www/example.com directory, you point to /var/www/example.com/public.

Next, one thing that I was not prepared for with Laravel was the need for the ownerships and permissions to be correct. All the files will probably be owned by the root user, so change them to whichever user they should be (i.e. not root). So, navigate to your web directory and change the owner as follows…

cd /var/www
sudo chown -R youruser example.com

Then, after that navigate to the public folder in your directory and it may not work. First make sure the storage directory has the correct owner, group and permissions…

cd /var/www/example.com
sudo chown -R youruser:www-data storage
sudo chmod -R ug+rwx storage

Changing storage may fix the problem, or if there are still problems you can also do this for the bootstrap/cache directory.

Now, make sure your site is pointing at the public directory and it should be working now and showing you the Laravel welcome page…

Laravel Welcome Page

If you see a page like this in your browser in the public directory, Laravel was installed and is working.

If not check the requirements are installed, then the permissions, owners, and groups. In particular, if it is a brand new web server with no other websites already running on it, check things like MySQL and all the requirements for both Composer and Laravel.

Finishing Up

From this stage, if you see the Laravel welcome page you’re all set up. You can set up a database and a database user in MySQL and enter the information in the .env file. You should also make sure that mod_rewrite is installed and that your Virtual host config file is allowing it to work.

Troubleshooting

If you run the composer create-project command but you get an error, maybe you have some missing dependencies, the files will be in the new directory but nothing will be installed yet. To install you’ll need to install the dependencies then run the command composer update laravel which will complete the installation. I got this error on Ubuntu 16.04 because PHPUnit was not installed.

If after following this guide you get an error like… No application encryption key has been specified. Run this command to generate a key (automatically adds it to the .ENV file)… php artisan key:generate