Setting Up Rasberry Pi Server

I’ve just finished migrating all of my websites from AWS Lightsail to a Raspberry Pi I have running on my home network. This includes this WordPress blog, an OpenProjects instance, and my static portfolio website. The process was fairly straightforward, but I want to write a post to consolidate the process and highlight some problems I ran into. I know very little about networking so this was a good introductory project that allowed me to learn some of the tools available for web hosting.

Hardware

I am using a Raspberry Pi 4 compute module Lite with 8GB of RAM loaded on the official IO Board. I decided to use the Raspberry Pi to host my site due to the low volume of traffic between my sites and the low cost of the hardware. It doesn’t have any onboard flash but it does have a port for a single lane PCIe which I used to connect a 250GB Samsung 970 EVO Plus through this Xiwai Low Profile PCI-E 3.0 x1 Lane to M.2 adapter. I am using a 12V 1.5A Globtec power supply to power the entire setup through the IO board which contains all the necessary regulators for the PCIe port and compute module. I used 12V over 5V to ensure I would have enough headroom for the PCIe port regulator. The device is networked through a gigabit switch that I have connected to my AX3000 router. On the compute module I am running Raspbian GNU/Linux 11 (Bullseye) with kernel: Linux 5.10.63-v7l+. I do not have a static IP and rely on my ISP to dynamically provide me with an address via their DHCP server.

Methodology

I need to set the address of the compute module to a static value in the LAN. Once I have a static LAN address I can set rules on my router to forward the necessary web port (port 80 in this case) to only allow WAN traffic through that port. I can then forward my public IP to the DNS server that was configured when I purchased my domain. I will need to update the records on the DNS server whenever my ISP provides me with a new public IP such as when the power on my modem is cycled.

Once I have the networking configured I will need to set up the OpenProject web app, the WordPress CMS, and my static website. Since I only have one public IP address I will need to associate different site requests with their respective directories on the Pi server. Because I am porting my existing WordPress blog, I will need to export the old blog and database and import it into the new server.

PCIe SSD Configuration

I needed to load the Raspian OS onto the M.2 SSD and configure the Pi bootloader to use the PCIe port as a boot source. With the SSD inserted into the PCIe slot, I installed the Raspian OS to an SD card with the Raspberry Pi Imager and inserted it into the IO Board. After booting from the SD Card I copied the installation from the SD Card to the SSD with the rpi-clone tool. I had a Raspberry Pi 400 on hand so I booted that up and installed the usbboot tool onto it. I connected the IO Board with the compute module to the Raspberry Pi 400 with a micro USB cable and updated the EEPROM on the compute module to add the PCIe as a boot source.

The instructions to install usbboot and update the bootloader configuration for the CM4 can be found here. To understand which value to set for the BOOT_ORDER variable you can look here. After completing these steps I removed the SD card and the compute module booted properly from the SSD.

Network Configuration

I first configured my router to reserve an arbitrary unassigned address (192.168.0.100) that I chose within the subnet range that my router was configured to provide through its DHCP server. The router reserves the address (192.168.0.100) for a specific device by associating it with the device’s MAC address, which was the MAC address of the Pi in this circumstance. I don’t believe it’s necessary, but I also configured the Pi to use the same static address by adding the address to the “/etc/dhcpcd.conf” file with the following lines.

#Static IP Configuration
interface eth0
static ip_address=192.168.0.100/24
static ip6_address=fd51:42f8:caae:d92e:ff/64
static routers=192.168.0.1
static domain_name_servers=192.168.0.1 8.8.8.8 fd51:42f8:caae:d92e

The DNS server for my domain is hosted on AWS’ Route 53 which I dynamically update with the correct public IP address through a script I run periodically with crontab using the AWS CLI. The script I used for this is available here. I couldn’t get the precompiled binary for the AWS CLI to work so I just downloaded the source from here and built it on the Pi. Make sure the python version you are using is the recommended version to build the AWS CLI. I initially built it with Python 3.10.0 but was getting strange errors that didn’t obviously indicate the problem was my Python version. I would recommend you use something like pyenv to install the correct version of Python recommended on the AWS CLI GitHub page.

I use pyenv to manage different versions of python so my default installation location for the AWS CLI executable was “/home/pi/.pyenv/shims/aws”. To find the installation on your system you can run “which aws”. I updated the calls in the script to reference the location directly and replaced the first two variables with parameters so I could update the records for multiple sites and hosted zones more easily. The two variables I take as parameters defined in the script look like this:

#Variable Declaration
HOSTED_ZONE_ID=$1
NAME=$2

All of my Route 53 CLI calls were changed from:

aws route53

to the following:

/home/pi/.pyenv/shims/aws route53

The reason for adding absolute paths to the script is because when crontab executes the script, it doesn’t have the environment variable containing the AWS executable. More detailed instructions on how to configure and use the script are here.

To add calls to the script in crontab so the public IP is checked and updated if needed every minute I added the following call using “crontab -e”

* * * * * /home/pi/scripts/update_dns.sh "REPLACE_WITH_HOST_ID" "openproject.scottlaboe.com." >/var/log/update_dns.log 2>&1

I added three of these calls for each of my sites only changing the name parameter for each site. You can check if crontab has executed the script by calling “systemctl status cron”. It will show a timestamp to indicate when the script was called. You can call the script with sudo if you need to.

Next Post

After setting up the basic structure for the network I began working on installing the OpenProject app, WordPress CMS, and static website. In my next post, I will go into the details for installing these on the Pi.

Leave a comment

Your email address will not be published. Required fields are marked *