Welcome to my blog, friends. Here I will be detailing my current events, like today’s event, which was installing WordPress proxied behind Nginx (and subsequently a full LEMP stack). Beyond that, using a .Dev top-level domain brought it’s own challenges, so here is how I got it done.

First thing’s first. I’m running this website on Ubuntu 20.04.1 directly on a Raspberry Pi 4B 8GB model. Check it out in my Homelab Equipment section here. Interestingly, if you use the Raspberry Pi Imager for Windows, it will download the Ubuntu binaries for you, and it is also already configured to allow SSH access. So you can SSH in immediately upon first boot, change the password, and you are off to the races.

Install the LEMP Stack
This sounds harder than it is, but here are all of the steps

sudo apt update
sudo apt install nginx -y 
sudo apt install mariadb-server mariadb-client -y
sudo mysql_secure_installation

During this step, you will go through a series of questions to set up the database. You can basically accept the defaults across the board here
Current password: [Enter]
Set a root password? Y
… Answer Y to everything else after setting a password

sudo apt install php php-mysql php-fpm -y
MySQL will be used by PHP

Now it is time to move on towards the PHP installation and setup. By default, PHP opens and listens on a socket. We will end up binding Nginx to that socket so that it can forward requests internally directly to the process. Take note of the socket that will be listed in this file

sudo nano /etc/php/7.4/fpm/pool.d/www.conf 

Then look for this line beginning with listen = /run/php/:

;   '/path/to/unix/socket' - to listen on a unix socket.
; Note: This value is mandatory.
listen = /run/php/php7.4-fpm.sock

; Set listen(2) backlog.
; Default Value: 511 (-1 on FreeBSD and OpenBSD)

That is the socket that PHP must bind to. You cannot imagine how many times I typed “pho” and then began craving the bowl of deliciousness.

So at this point, you have a LEMP stack. Sort of. We still have to point Nginx to PHP.
And thus begins the journey into WordPress

Download and extract all of the WordPress base files

wget -c http://wordpress.org/latest.tar.gz
tar -xzvf latest.tar.gz


mkdir /var/www/html/yoursitehere.com
sudo cp -R wordpress/ /var/www/html/yoursitehere.com
sudo chown -R www-data:www-data /var/www/html/yoursitehere.com
sudo chmod -R 775 /var/www/html/yoursitehere.com

Next we will setup the database in MySQL and then point PHP to the database

sudo mysql -u root
CREATE DATABASE yoursitehere;
GRANT ALL PRIVILEGES ON yoursitehere.* TO 'yoursiteadmin'@'localhost' IDENTIFIED BY  'Str0ngPas$word!';

Now we will configure PHP to point to the database (Hang in there, you’re almost done)

cd /var/www/html/yoursitehere.com
sudo mv wp-config-sample.php wp-config.php
sudo nano wp-config.php

define('FORCE_SSL_ADMIN', true);
if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false)

// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'yoursitehere' );

/** MySQL database username */
define( 'DB_USER', 'yoursiteadmin' );

/** MySQL database password */
define( 'DB_PASSWORD', 'Str0ngPas$word' );

Note: The first lines above force the Admin portal to use SSL, which will be a requirement if you are using a .Dev domain (and its just a good practice). Now let’s wrap up by editing Nginx config to point to PHP and accept our website

sudo nano /etc/nginx/conf.d/yoursitehere.com.conf
server {
        listen 80;
        listen [::]:80;
        root /var/www/html/yoursitehere.com;
        index  index.php index.html index.htm;
        server_name yoursitehere.com;

        error_log /var/log/nginx/yoursitehere.com_error.log;
        access_log /var/log/nginx/yoursitehere.com_access.log;
        client_max_body_size 100M;
        location / {
                try_files $uri $uri/ /index.php?$args;
        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/run/php/php7.4-fpm.sock;
                fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;

Lastly, remove the default websites and restart the services

sudo rm /etc/nginx/sites-enabled/default
sudo rm /etc/nginx/sites-available/default
sudo systemctl restart nginx

At this point you should be able to go to http://IP-ADDRESS , but if you are using a .Dev domain, you may still have some issues.

Go to HTTP://IP_ADD/ first, and go through the initial setup steps to create an admin user account

The .dev top-level domain requires SSL be installed. Luckily, Nginx makes it pretty easy with Certbot. NOTE: You must be able to access the HTTP front end of your website at this point from the public internet. So make sure you adjust your firewall to forward port 80 inbound to your web server. If you are using a .dev domain, a curl operation will still work despite web browsers forcing HTTPS. Try “curl http://yoursitehere.com” from any device outside of your network.

sudo add-apt-repository ppa:certbot/certbot
sudo apt install python3-certbot-nginx
sudo ufw allow 22
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo certbot --nginx -d yoursitehere.com

You will go through a series of prompts, such as entering your email address, accepting the terms, and most importantly, forcing HTTP traffic to redirect to HTTPS which is again a requirement for a .dev domain. The cool thing is that using that certbot app, it will automatically handle cert renewal for you, too.

Final steps: Enable SSL from the Portal

Login to WordPress Admin via IP address: https://IP_ADDR/wp-admin with the account you created earlier.

Go to the Settings section and update BOTH URLs to show HTTPS and the FQDN

And that does the trick. You now have WordPress up and running with a LEMP stack on Ubuntu 20.04.1 ARM64 running on a Raspberry Pi with a .dev top-level domain.