Installing WordPress (on a Raspberry Pi Zero)

Having used WordPress for a few years now I decided it was time I tried setting up a WordPress server on my network, and just to make it interesting I decided to use a Raspberry Pi Zero W – why not!

These instructions should also work on any system running Debian 10.0 (and will proabably work on Ubuntu and other versions of Debian, though you may need to change some of the packages names to reflect the versions available on those systems).

As usual the first thing to do is to make sure your system is up to date as this will avoid any potential issues later with out of date packages..

apt-get update
Hit:1 buster InRelease
Hit:2 buster InRelease
Reading package lists... Done
apt-get upgrade
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Calculating upgrade... Done
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

Setting up the Web Server

The next thing to do is to decide which web server you are going to use, this could be Apache or NGINX, but as the Pi Zero doesn’t have a lot of memory I decided to use lighttpd.

apt-get install lighttpd
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
Suggested packages:
  fam openssl rrdtool php-cgi apache2-utils lighttpd-doc
Recommended packages:
  lighttpd-modules-ldap lighttpd-modules-mysql spawn-fcgi perl:any
The following NEW packages will be installed:
  libfam0 lighttpd
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 317 kB of archives.
After this operation, 1007 kB of additional disk space will be used.
Do you want to continue? [Y/n] 
Processing triggers for libc-bin (2.28-10+rpi1) ...

I prefer to keep all my data including web pages in my home folder on a separate partition, that way if I have to restore my system from a backup (usually because I messed something up) I can just restore the root partition without losing my data.

To do this you need to modify the default configuration.

nano /etc/lighttpd/lighttpd.conf

server.modules = (
#server.document-root        = "/var/www/html"
server.document-root        = "/home/wordpress"
server.upload-dirs          = ( "/var/cache/lighttpd/uploads" )
server.errorlog             = "/var/log/lighttpd/error.log"             = "/var/run/"
server.username             = "www-data"
server.groupname            = "www-data"
server.port                 = 80
# strict parsing and normalization of URL for consistency and security
# (might need to explicitly set "url-path-2f-decode" = "disable"
#  if a specific application is encoding URLs inside url-path)
server.http-parseopts = (
  "header-strict"           => "enable",# default
  "host-strict"             => "enable",# default
  "host-normalize"          => "enable",# default
  "url-normalize-unreserved"=> "enable",# recommended highly
  "url-normalize-required"  => "enable",# recommended
  "url-ctrls-reject"        => "enable",# recommended
  "url-path-2f-decode"      => "enable",# recommended highly (unless breaks app)
 #"url-path-2f-reject"      => "enable",
  "url-path-dotseg-remove"  => "enable",# recommended highly (unless breaks app)
 #"url-path-dotseg-reject"  => "enable",
 #"url-query-20-plus"       => "enable",# consistency in query string
index-file.names            = ( "index.php", "index.html" )
url.access-deny             = ( "~", ".inc" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
compress.cache-dir          = "/var/cache/lighttpd/compress/"
compress.filetype           = ( "application/javascript", "text/css", "text/html", "text/plain" )
# default listening port for IPv6 falls back to the IPv4 port
include_shell "/usr/share/lighttpd/ " + server.port
include_shell "/usr/share/lighttpd/"
include "/etc/lighttpd/conf-enabled/*.conf"
#server.compat-module-load   = "disable"
server.modules += (

The next step it to create the new folder we specified in the configuration file.

mkdir /home/wordpress

Then we can copy the default web page into the new folder and change the file ownership, otherwise you will get a ‘404 not found’ error.

cp -Rv /var/www/html/* /home/wordpress/
'/var/www/html/index.lighttpd.html' -> '/home/wordpress/index.lighttpd.html'
mv -v /home/wordpress/index.lighttpd.html /home/wordpress/index.html 
renamed '/home/wordpress/index.lighttpd.html' -> '/home/wordpress/index.html'
chown -R www-data /home/wordpress
chgrp -R www-data /home/wordpress

Time to check that the files and permissons look right before continuing.

ls -alis /home/wordpress
total 12
  42 4 drwxr-xr-x 2 www-data www-data 4096 Nov  2 19:59 .
8200 4 drwxr-xr-x 4 root     root     4096 Nov  2 19:55 ..
  63 4 -rw-r--r-- 1 www-data www-data 3388 Nov  2 19:58 index.html

If you have UFW installed then you will need add a new firewall rule to allow inbound conenctions from your network.

ufw allow from n.n.n.0/24 to any port 80 proto tcp
Rule added

For these changes to take effect you need to restart the service or reload the configuration.

service lighttpd restart

If everything so far has worked then you should be able to see the default home page…

Installing PHP

The next step is to install PHP and configure the server to enable CGI scripts.

apt-get install php7.3 php7.3-cgi php7.3-mysql
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  libicu63 libmagic-mgc libmagic1 libpcre2-8-0 libsodium23 libxml2
  php-common php7.3-cli php7.3-common php7.3-json php7.3-opcache
  php7.3-readline psmisc tzdata
Suggested packages:
  file php-pear
The following NEW packages will be installed:
  libicu63 libmagic-mgc libmagic1 libpcre2-8-0 libsodium23 libxml2
  php-common php7.3 php7.3-cgi php7.3-cli php7.3-common php7.3-json
  php7.3-mysql php7.3-opcache php7.3-readline psmisc tzdata
0 upgraded, 17 newly installed, 0 to remove and 0 not upgraded.
Need to get 12.7 MB of archives.
After this operation, 60.7 MB of additional disk space will be used.
Do you want to continue? [Y/n] 
Setting up tzdata (2019c-0+deb10u1) ...

Select the correct timezone for your system when prompted to do so.

When you have selescted your timezone then the installation will continue.

Current default time zone: 'Europe/London'
Local time is now:      Sat Nov  2 17:35:32 GMT 2019.
Universal Time is now:  Sat Nov  2 17:35:32 UTC 2019.
Run 'dpkg-reconfigure tzdata' if you wish to change it.
Setting up libpcre2-8-0:armhf (10.32-5) ...
Setting up libxml2:armhf (2.9.4+dfsg1-7+b3) ...
Setting up php-common (2:69) ...
Setting up php7.3-common (7.3.11-1~deb10u1) ...
Creating config file /etc/php/7.3/cgi/php.ini with new version
Setting up php7.3 (7.3.11-1~deb10u1) ...
Processing triggers for libc-bin (2.28-10+rpi1) ...

Having installed PHP you need to enable the processes needed to handle CGI requests using the following commands.

lighty-enable-mod fastcgi
Enabling fastcgi: ok
Run "service lighttpd force-reload" to enable changes
lighty-enable-mod fastcgi-php
Enabling fastcgi-php: ok
Run "service lighttpd force-reload" to enable changes
service lighttpd force-reload

It is a good idea to test that everything is working at this stage so the following commands will create a trivial PHP script in the document root folder.

echo "<?php phpinfo ();?>" > /home/wordpress/index.php
chown -R www-data /home/wordpress
chgrp -R www-data /home/wordpress

Reloading the home page should now display the PHP version and configuration information, if it does then you have installed PHP and configured the web browser correctly.

Installing the SQL Database

The last thing that WordPress needs is a database to store stuff, originally this would have been MySQL but this dependancy is now met by MariaDB.

apt-get install mariadb-server mariadb-client
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  galera-3 gawk libaio1 libconfig-inifiles-perl libdbi-perl libgdbm-compat4
  libgdbm6 libmpfr6 libperl5.28 libreadline5 libsigsegv2 libsnappy1v5
  libtinfo5 lsof mariadb-client-10.3 mariadb-client-core-10.3 mariadb-common
  mariadb-server-10.3 mariadb-server-core-10.3 mysql-common perl
  perl-modules-5.28 rsync socat
Suggested packages:
  gawk-doc libclone-perl libmldbm-perl libnet-daemon-perl
  libsql-statement-perl gdbm-l10n mailx mariadb-test netcat-openbsd tinyca
  perl-doc libterm-readline-gnu-perl | libterm-readline-perl-perl make
  libb-debug-perl liblocale-codes-perl
Recommended packages:
  libdbd-mysql-perl libterm-readkey-perl libhtml-template-perl netbase
The following NEW packages will be installed:
  galera-3 gawk libaio1 libconfig-inifiles-perl libdbi-perl libgdbm-compat4
  libgdbm6 libmpfr6 libperl5.28 libreadline5 libsigsegv2 libsnappy1v5
  libtinfo5 lsof mariadb-client mariadb-client-10.3 mariadb-client-core-10.3
  mariadb-common mariadb-server mariadb-server-10.3 mariadb-server-core-10.3
  mysql-common perl perl-modules-5.28 rsync socat
0 upgraded, 26 newly installed, 0 to remove and 0 not upgraded.
Need to get 25.2 MB of archives.
After this operation, 190 MB of additional disk space will be used.
Do you want to continue? [Y/n] 
Processing triggers for libc-bin (2.28-10+rpi1) ...

If the installation succeeded you should be able to start the client and show all the default databases.

mysql -u root
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 47
Server version: 10.3.17-MariaDB-0+deb10u1 Raspbian 10
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> SHOW DATABASES;
| Database           |
| information_schema |
| mysql              |
| performance_schema |
3 rows in set (0.004 sec)
MariaDB [(none)]> QUIT;

Before installing WordPress it is a good idea to check that you can connect to the database server using PHP by creating a short test script.

nano php-mysqldb-connection-test.php

Enter the following commands into the script and save it.

# php-mysqldb-connection-test
# Execute using 'php -f php-db-connect-test.php'
$_db_username = 'root';
$_db_servername = 'localhost';
$_db_connection = mysqli_connect($_db_servername, $_db_username) or die("ERROR: Unable to connect to '$_db_servername'.\n");
$_str_query = "SHOW DATABASES"; # Should show three databases on a fresh install
$_db_result = mysqli_query($_db_connection, $_str_query)or die("ERROR: Unable to execute '$_str_query'.\n") ;
$_count = 0;
while($_record = mysqli_fetch_array($_db_result)) { # List the database
  echo "  - ".$_record[0]."\n";
if (!$_count) die ( "ERROR: No tables found.\n");

Running this script from the command line should print a list of the same three default databases as you saw above.

php -f ./php-db-connect-test.php
  - information_schema
  - mysql
  - performance_schema

Installing WordPress

Finally – we can start to install and configure WordPress! First we need to download it and extract the files in the tar archive to the correct folder.

--2019-11-02 18:19:34--
Resolving (
Connecting to (||:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 11199173 (11M) [application/octet-stream]
Saving to: â€˜latest.tar.gz’

latest.tar.gz       100%[===================>]  10.68M   350KB/s    in 32s     

2019-11-02 18:20:07 (346 KB/s) - â€˜latest.tar.gz’ saved [11199173/11199173]

tar -xzvf latest.tar.gz -C /home

Then we need to modify the file ownership of the new files we just extracted so the web server has access to them.

chown -R www-data /home/wordpress
chgrp -R www-data /home/wordpress

The result should look like this.

ls -alis /home
total 16
8200 4 drwxr-xr-x  4 root     root     4096 Nov  2 19:55 .
   2 4 drwxr-xr-x 21 root     root     4096 Nov  2 16:27 ..
  18 4 drwxr-xr-x  2 system   system   4096 Oct 23 00:21 system
  42 4 drwxr-xr-x  5 www-data www-data 4096 Oct 14 21:37 wordpress
# ls -alis /home/wordpress/
total 212
   42  4 drwxr-xr-x  5 www-data www-data  4096 Oct 14 21:37 .
 8200  4 drwxr-xr-x  4 root     root      4096 Nov  2 19:55 ..
   63  4 -rw-r--r--  1 www-data www-data  3388 Nov  2 19:58 index.html
24727  4 -rw-r--r--  1 nobody   www-data   420 Nov 30  2017 index.php
24762 20 -rw-r--r--  1 nobody   www-data 19935 Jan  1  2019 license.txt
24713  8 -rw-r--r--  1 nobody   www-data  7447 Apr  8  2019 readme.html
26910  8 -rw-r--r--  1 nobody   www-data  6919 Jan 12  2019 wp-activate.php
26911  4 drwxr-xr-x  9 nobody   www-data  4096 Oct 14 21:37 wp-admin
21537  4 -rw-r--r--  1 nobody   www-data   369 Nov 30  2017 wp-blog-header.php
27462  4 -rw-r--r--  1 nobody   www-data  2283 Jan 21  2019 wp-comments-post.php
24743  4 -rw-r--r--  1 nobody   www-data  2898 Jan  8  2019 wp-config-sample.php
24763  4 drwxr-xr-x  4 nobody   www-data  4096 Oct 14 21:37 wp-content
24742  4 -rw-r--r--  1 nobody   www-data  3847 Jan  9  2019 wp-cron.php
25718 12 drwxr-xr-x 20 nobody   www-data 12288 Oct 14 21:37 wp-includes
25716  4 -rw-r--r--  1 nobody   www-data  2502 Jan 16  2019 wp-links-opml.php
25717  4 -rw-r--r--  1 nobody   www-data  3306 Nov 30  2017 wp-load.php
24744 40 -rw-r--r--  1 nobody   www-data 39551 Jun 10 14:34 wp-login.php
25715 12 -rw-r--r--  1 nobody   www-data  8403 Nov 30  2017 wp-mail.php
24747 20 -rw-r--r--  1 nobody   www-data 18962 Mar 28  2019 wp-settings.php
24726 32 -rw-r--r--  1 nobody   www-data 31085 Jan 16  2019 wp-signup.php
27461  8 -rw-r--r--  1 nobody   www-data  4764 Nov 30  2017 wp-trackback.php
18712  4 -rw-r--r--  1 nobody   www-data  3068 Aug 17  2018 xmlrpc.php

The last step before actually setting up WordPress is to create an empty database that WordPress can use. The database name and user name can be anything you want (so long as it is valid), but you will need to know the values later when you are configuring up WordPress itself.

mysql -u root
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 51
Server version: 10.3.17-MariaDB-0+deb10u1 Raspbian 10
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> CREATE DATABASE wp_database;
Query OK, 1 row affected (0.003 sec)
MariaDB [(none)]> GRANT ALL PRIVILEGES ON wp_database.* TO wp_admin@localhost IDENTIFIED BY "<password>";
Query OK, 0 rows affected (0.012 sec)
Query OK, 0 rows affected (0.004 sec)
MariaDB [(none)]> QUIT;

You can now start the ‘five minute’ WordPress configuration process using your web browser.

Enter the database name, user name and the password you used then creating the empty database, and leave the host name and table prefix unchanged.

Now you just have to wait while WordPress configures itself – you may need to be a little paitent at this point!

The next step it to enter the name of your new WordPress site and create a user account that you will use when logging in (this is different from the database admin account you created earlier).

If everything works then you can go ahead and login, when you will be presented with the default site administration page.

If you click on ‘View your site’ you will see the default post that was automatically created during the installation – you can chose to modify this post or just delete it.

You now have a working WordPress server and can continue to install any additional plugins and themes to customise your site.

On my server I have installed the classic editor and twenty ten theme as that theme gives me a bit more room for text on the page and classic editor give me the ability to include HTML tags in my posts.

This entry was posted in Debian, Linux, Raspbian, Ubuntu and tagged , , , . Bookmark the permalink.

Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.