WordPress On Raspberry Pi – Part 1 – Preparation

Wordpress logo

In this series, I’ll walk you through all the steps to deploy WordPress on a Raspberry Pi.

I’ll cover the installation of:

In comparison to other existing tutorials I’ve read out there, I’ll go the extra mile in terms of explanations. So you won’t miss a beat and hopefully, you’ll understand why you’re doing what you’re doing.

In this first part, I’ll cover the basics. We’ll install Apache2 and a few other necessary packages. We’ll also download the latest versions of WordPress and phpMyAdmin.

1. Setting The Scene

The playground is a Raspberry Pi 3 Model B on which I installed Raspbian Stretch Lite.

I decided on the Lite version because I don’t need a fancy graphical layer. I’ll dedicate this Raspberry Pi to WordPress and the pi itself is “headless”. Therefore I only access the system over ssh on the command line (and through a browser evidently).

Feel free to install Raspbian Stretch with Desktop or any other operating system you see fit. Most of this guide should remain applicable, as long as you use a debian based GNU/Linux distribution.

Finally I can only recommend that you also go through the hands on setup and security tips I cover in Raspberry Pi: Hands On.

2. Apache

2.1 Packages Installation

Several servers and php frameworks could be used. I’ve decided to go for the most standard ones (i.e. Apache and PHP-FPM).

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install apache2 apache2-doc # apache2-doc is optional
$ sudo apt-get install php-fpm
$ sudo apt-get install mariadb-server php-mysql

Apache configuration files are in the /etc/apache2 directory while Apache website default root directory is /var/www/html.

$ cd /etc/apache2
$ sudo mv apache2.conf apache2.conf.bak
$ sudo cp apache2.conf.bak apache2.conf
$ sudo mv ports.conf ports.conf.bak
$ sudo cp ports.conf.bak ports.conf

At this point, we are one tweak away from accessing our web server default page…

2.2 Firewall Configuration

If you followed my security guidelines, you certainly set up the ufw firewall. Then you need to open port 80 (the default HTTP port) on your Raspberry Pi to allow incoming requests to Apache:

$ sudo ufw allow in from 192.168.0.0/24 to any app WWW
$ sudo ufw status verbose

Needless to say that you must adapt the 192.168.0.0/24 part to your own network configuration.

Wondering about the WWW ? ufw actually comes prepackaged with some standard application configurations. You can see the list by entering:

$ sudo ufw app list

The available application configuration definitions are in the /etc/ufw/applications.d directory. In this particular case, check the file ufw-webserver. The nice thing is: you can define your own application configurations. But enough on this as I digress.

Now, by entering your Raspberry Pi IP address in a browser, you should see Apache2 default page. Something like the screenshot below:

Apache2 default home page
Apache2 Default Home Page

2.3 Enters PHP

Next, let’s see if PHP is working properly as well.

Since we’re using PHP-FPM, we first need to proxy all requests for php files to the php engine. In order to do so, let’s edit Apache’s default configuration.

$ cd /etc/apache2
$ ls -l
$ ls -l /var/run/php
$ sudo vi apache2.conf

Now add the following directives at the end of the file, then restart Apache:

<FilesMatch \.php$>
    SetHandler "proxy:unix:/var/run/php/php7.0-fpm.sock|fcgi://localhost/"
</FilesMatch>

Update: Instead of modifying the apache2.conf file, it can be easier to simply rely on the default PHP-FPM configuration and load it on startup. The command a2enconf php7.0-fpm creates a link in the directory /etc/apache2/conf-enabled to the said configuration file in /etc/apache2/conf-available. Then we let Apache reload all its configurations.

$ sudo systemctl reload apache2

Finally, let’s create a very simply php file, to verify the php engine is triggered properly.

$ cd /var/www/html # Apache2's default website directory
$ sudo vi index.php

Enter the following text in the index.php file then save:

<?php phpinfo() ?>

Add index.php to your browser URL and voilà:

phpinfo details page
phpinfo() Details Page

But, as Steve Jobs would say, “there is one more thing”. Now we are confident everything is working fine, for security reasons, I would recommend to undo part of the things we did here and in particular: delete the index.php file.

3. WordPress & phpMyAdmin

3.1 Packages Installation

It’s time to download and extract WordPress and phpMyAdmin archives. Normally you should still be in the /var/www/html directory.

$ sudo wget https://wordpress.org/latest.tar.gz
$ sudo tar -xvzf latest.tar.gz
$ sudo wget https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-english.tar.gz

I’m going to pause here to discuss a little bit about security. If you’d rather go straight to the meat please jump to section 3.5 WordPress Setup.

3.2 Checking Files Integrity

It’s always a good idea to verify the integrity of a package you download. Therefore each time you have the option to get a checksum, test your download against it. Too bad there is none for WordPress actually.

A checksum is the output of a mathematical function. It allows to “validate” the contents you download. It’s very unlikely that 2 different unrelated documents produce the same checksum. It’s possible in theory, but statistically very very highly unlikely.

In other words, if your package checks against the checksum, you’re almost certain it’s not been tampered with. Furthermore, you know the transfer happened without error.

This can bring a false sense of security though: if both the file and its checksum come from the wrong person (in case a website has been hacked for instance), then sure, your file is valid, but you have no guarantee about its origin.

For instance, you should be able to do the following:

$ sudo wget https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-english.tar.gz.sha256
$ shasum -a 256 -c phpMyAdmin-latest-english.tar.gz.sha256

If the last command outputs OK you’re all good.

Unfortunately, at the time of writing, the SHA256 checksum for the archive we retrieved isn’t available. The link redirects to the archive package itself.

By the way, SHA256 is just the name of the mathematical algorithm used to compute the checksum. You may as well have heard of MD5 or SHA512.

3.3 Verifying PGP Signature

phpMyAdmin however proposes an even better way of checking the integrity of our archive: a detached PGP signature.

PGP stands for Pretty Good Privacy. Compared to checksums which basically are “one-way functions” (i.e. you provide them with a file you get a checksum hash in return and always the same hash provided the input file remains the same), PGP relies on asymmetric cryptography instead.

What that gibberish means is: an owner uses her or his private key to sign something (a message, a file, whatever actually). This private key has one public counterpart. Complex mathematical functions bind both keys. The public key can be used to verify the “whatever” against the signature.

So … There are 2 keys involved: one is private, the other is public. They are different (though mathematically bound), but work in pair for related tasks (signing / verifying, encrypting / decrypting), hence the “asymmetric” cryptography.

Simply put: you don’t use the same key to generate a signature and verify it.

But wait ! There is more to it. Key management comes with the notion of a “web of trust”. People can sign a public key they trust. When enough people trust a key truly allows to decrypt or verify contents from a known owner, you get a certain reassurance on the origin of the package.

A checksum only tells you if a file is valid. A signature also gives you a level of confidence that a signature has been issued by the right person.

Nevertheless, the next few paragraphs will be easier for those with some knowledge of GnuPG.

$ sudo wget https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-english.tar.gz.asc
$ sudo wget -O phpmyadmin.key https://keybase.io/ibennetch/pgp_keys.asc?fingerprint=3d06a59ece730eb71b511c17ce752f178259bd92
$ gpg --import phpmyadmin.key
$ gpg --list-keys
$ gpg --fingerprint
$ gpg --verify phpMyAdmin-latest-english.tar.gz.asc phpMyAdmin-latest-english.tar.gz

I assume the above may require some explanations.

3.4 What’s The Use For PGP Anyway?

First, we download the detached signature for our phpMyAdmin archive. A detach signature is a “kind of checksum” generated with PGP tools.

Then, we retrieve the public key of the person at phpMyAdmin responsible for signing the packages. The phpMyAdmin archive has been signed with a private key. The signature itself was downloaded in the previous step. The public key is used to verify that the signature is valid (and thus the archive pristine). Information about where to find the right public key is provided in the phpMyAdmin documentation.

Importing the public key in a local keyring is necessary so we can manipulate it. The next commands list the keys in the local keyring and display their fingerprints. The fingerprint is “a checksum for the key” so we are sure we’re using the appropriate key. The fingerprint must be checked against phpMyAdmin documentation.

The last command uses the public key we imported to finally check the archive integrity against the signature.

For those interested in learning more about cryptography concepts read The GNU Privacy Handbook (no mathematical knowledge required it’s accessible to anyone).

Public Cryptography Explained With Comics
Public Cryptography Explained With Comics

Now we’re quite sure that our phpMyAdmin archive has been created and submitted by the phpMyAdmin folks and that nobody has messed up with it.

3.5 WordPress Setup

We’re back in business, moving forward:

$ sudo tar -xvzf phpMyAdmin-latest-english.tar.gz
$ sudo mv phpMyAdmin-4.7.7-english phpMyAdmin

Obviously, the last command should reflect the current stable version of phpMyAdmin (4.7.7 at the time of writing).

$ sudo chown -R www-data: wordpress
$ sudo chown -R www-data: phpMyAdmin

The last 2 commands recursively change the user and group of all the files in the wordpress and phpMyAdmin directories. This is mandatory because Apache will need write access to those directories. Thanks to this change it’s as if Apache owned the directories and thus has full control over them.

However you may wonder where the www-data comes from though. It’s defined in the /etc/apache2/envvars file:

$ grep APACHE_RUN_USER /etc/apache2/envvars
$ grep APACHE_RUN_GROUP /etc/apache2/envvars

3.6 Apache Setup

As a last step let’s create a WordPress embryo VirtualHost configuration in Apache, starting from the default site configuration.

$ cd /etc/apache2/sites-available
$ sudo cp 000-default.conf wordpress.conf
$ sudo vi wordpress.conf

Modify the wordpress.conf file according the example below:

ServerAdmin {your email address here}
DocumentRoot /var/www/html/wordpress

Thanks to the DocumentRoot directive, you won’t need to add /worpress to the URL. Entering the Raspberry Pi IP address in your browser URL bar will provide a direct access to your blog.

Now, we’ve created a VirtualHost for WordPress. However it doesn’t mean it’s either active or enabled.

Indeed Apache only considers a site to be enabled if a link exists in /etc/apache2/sites-enabled to a configuration in /etc/apache2/sites-available. Furthermore we need to reload the configuration so Apache takes it into account:

$ cd /etc/apache2/sites-enabled
$ ls -lA
$ sudo a2dissite 000-default.conf
$ sudo a2ensite wordpress.conf
$ ls -lA
$ apache2ctl -t
$ sudo systemctl reload apache2

Apache provides commands to respectively enable and disable sites (i.e. a2ensite and a2dissite). Other similar commands exist as well to enable and disable modules and configurations (I may come back to that in a later post).

Note here that we’ve also disabled Apache’s default VirtualHost in favor of our WordPress installation.

The apache2ctl command checks the syntax of Apache configuration files. It’s a nice trick to make sure everything’s fine before actually reloading Apache’s configuration.

Finally if you point your browser once more to your Rapsberry Pi IP address you should be redirected to WordPress first setup page:

Wordpress Setup Configuration 1st Page
WordPress Setup Configuration 1st Page

And that’s it for now!

3.7 Final Words

We have covered a lot of ground in this post but there is still a lot to do. However I believe the next steps are a bit easier.

Please don’t hesitate to comment. If you find any errors in the text or commands, please let me know so I can update the post.

Finally is there anything missing you believe should be added to this article? Any other preparation step you believe is important to add ?

Leave a comment