Skip to content

Notes on Setting Up My Raspberry Pi

I recently purchased a Raspberry Pi 4 Model B for some projects at home. Here are some notes on how I set it up/what I did. They are mostly for my future self but might be helpful to others that try to do something similar.

Basically, the main goal was to use it for Pi-Hole (network-wide ad blocking on the DNS level), Gitea (self-hosted git service), and to set up a private cloud for all our data (using Nextcloud) instead of having them with one of the cloud providers. So far we used Boxcryptor to encrypt the data and store it in the cloud but it makes it a bit inconvenient for pictures since you can't see a preview (thumbnail). Since there is potentially a lot of data I intended to store the data on an external drive. The Pi4 has USB3 so I mounted a solid state drive (SSD) using a SATA-to-USB3 enclosure/adapter.

Preparing the Raspbian Image

Most guides mention the use of an HDMI cable when setting up the Raspberry Pi (using NOOBS to select to install Raspbian from a screen). However, that's not necessary if you just want to use it as a server and intend to SSH into it (called headless setup).

I simply downloaded the Raspbian Buster Lite image and wrote it to the Micro SD card. You can use the recommended Etcher tool but existing Unix system tools are sufficient if you have access to a terminal. Since I am on a Mac I followed the instructions from the Official Raspberry Pi Documentation.

The last step in preparation is to enable SSH for the headless setup. By default it is not enabled. To enable it, a file called ssh needs to be added to the root of the volume on the Micro SD card. See step 3 of the SSH Pi documentation for more details. Basically cd to the root of the volume (most likely /Volumes/boot) on your machine and do touch ssh.

With this it is possible to plug the card into the RPi and boot it. Then ssh pi@<IPOfRaspberryPi> should work.

Setting Up Raspbian

Since Raspbian is based on Debian you can follow any guide on initial server setup for Debian (or Raspbian). In short, I basically did the following steps:

  • Update Raspbian using apt
  • Run sudo raspi-config to:
    • Change password of user pi
    • Change hostname
    • Set localisation options (locale, timezone etc.)
  • Create my own user and give him sudo rights
  • Harden SSH server config (different port and no root login)
  • Enforce password request when sudoing (for user pi, see /etc/sudo/sudoers.d/010_pi-nopasswd, change NOPASSWD to PASSWD)
  • Install ufw and allow SSH on the chosen port

It's important to test certain changes (firewall, SSH config changes) first by keeping the current terminal session and logging in a second time. Otherwise, you might lock yourself out.

Setting Up an External Drive

As mentioned in the introduction, I want to keep the data on an external drive connected via USB3. Personally, I bought an SSD and put it in an enclosure. The first step is to plug the drive into the USB3 port of the Raspberry Pi. The USB3 ports are in the middle with blue inside.

Find out the device name

Next, you need to find out the device name for the disk. It usually starts with /dev/sd<letter>. If it is the first one it is most likely /dev/sda. To find out, execute sudo fdisk -l to get a listing of all devices.

Create a partition table

First, you need to create a partition table (if none exists yet) and partition on the disk. The steps here assume a single partition. Execute sudo fdisk /dev/<deviceName> to enter the dialogue-driven program to manage the disk. Then, do the following:

  1. Create a new empty GPT partition table (press G)
  2. Create a new partition (press N, and press enter for the following questions, i.e., use the defaults)
  3. Save the changes (press W)

The partition is identified by /dev/<deviceName>1.

Create a filesystem for the partition

Now you can create a filesystem for this partition. I suggest to use a Linux filesystem such as ext4 (further reading about Linux filesystems). Execute sudo mkfs.ext4 /dev/<deviceName>1 -L <label> and wait until it is finished.

Mount the partition

Now you can test to mount the partition. First, create a directory where the partition should be mounted to. Common places are in /mnt or /media (that's a personal choice): sudo mkdir /mnt/mydisk. Then, try to mount it manually: sudo mount /dev/<deviceName>1 /mnt/mydisk. If it succeeded, you can navigate to the folder and start using your disk. You can also verify it by executing mount -l which outputs a list of all mounts. To unmount, use sudo umount and add the directory or device name.

Automatically mount a disk on boot

To automatically mount a disk on boot, an entry in the fstab file is required. First, find out the PARTUUID of the partition:

sudo blkid

Then, edit the fstab file (sudo nano /etc/fstab) and add the following entry (adjust options as needed):

PARTUUID=<partUUID> /mnt/<dir>    ext4    defaults,auto,rw,nofail,noatime    0  2

Now, reboot the Raspberry Pi and the drive should already be mounted. The official Raspberry Pi Documentation also has a page about external storage.

fstab entry options

At the beginning I also had user as an option to allow users to mount. However, this implies noexec which prevents binaries from being executed on this filesystem. This caused a problem with Gitea because the commit hooks of repositories couldn't be executed. You can of course add exec as well, but since I don't need users to mount I just removed user instead.

At first I thought everything works fine, until I moved the MariaDB data directory to this external disk (see below) and rebooted. MariaDB wouldn't start and eventually timed out. Through a coincidence (when my disk would start unmounting randomly and having I/O errors) I found out that there is a problem with UAS support on the Raspberry Pi 4 causing slow speeds. It's not quite clear to me currently whether this is an issue with the enclosures or the Raspberry Pi.

It turned out that the speed was actually really slow (~20 MB/s for sequential write). I had only tested the enclosure when attached to my Mac. Following the steps to enable quirks mode for the disk fixed this issue. While the speeds are now higher (~210 MB/s) they are not as high as they could be with UAS (~430 MB/s). But it resolved the problem with MariaDB (and other services requiring the mounted disk).

There are some additional resources with a list of known adapters that work, and a benchmarking script to benchmark the drive (with the adapter).

If you simply would like to test the sequential write and read speeds you can use the following commands:

# write
time dd if=/dev/zero bs=1024k of=tstfile count=1024 2>&1
# read
time dd if=tstfile bs=2048k of=/dev/null count=8192 2>&1

Moving MariaDB data directory to external storage

With using the external disk I thought it makes sense to store pretty much everything (besides the system) on the external storage. Somewhere I also came across a comment about extending the life of the Micro SD card if the database is not on there, but I don't know how valid this is. I assume it could be due to a lot of writes.

Moving the MariaDB data directory is quite simple:

  1. Stop the service:

    sudo systemctl stop mariadb
    
  2. Copy the data directory:

    sudo cp -R -p /var/lib/mysql /mnt/mydisk/
    
  3. Change datadir under [mysqld] in /etc/mysql/mariadb.conf.d/50-server.conf to the new location

  4. Start the service again:

    sudo systemctl start mariadb
    

If everything goes well (verify with sudo systemctl status mariadb) you can remove the old data directory.

Ensure MariaDB starts after disk is mounted

When you reboot it is possible that MariaDB won't start if the external disk has not been mounted yet at the time MariaDB starts. Even if it did, there is no guarantee that it works for every system startup.

To address this you can make the MariaDB service depend on the mount service (a service for the fstab mounts is generated).

Warning

The service file you see shown at the top of the output of systemctl status gets overwritten on package upgrades. Don't edit it directly.

Create an override file for the MariaDB service. The required directory probably does not exist yet:

sudo mkdir /etc/systemd/system/mariadb.service.d

Create the file mount.conf in this directory with the [Unit] section. Add RequiresMountsFor=/mnt/mydisk.

Note

The corresponding dependencies (After and Requires) for RequiresMountsFor will automatically be generated.

The resulting file should look like this:

/etc/systemd/system/mariadb.service.d/mount.conf
[Unit]
RequiresMountsFor=/mnt/mydisk

Reload the systemd daemon:

sudo systemctl daemon-reload

Now, reboot the system and MariaDB should be active. You can verify this using systemctl:

sudo systemctl status mariadb

Pi-Hole

In terms of Pi-Hole there is not much to document. The installation and setup is very simple. Depending on your router you might need to delegate the DHCP server to Pi-Hole. I had to do this because the router I used first did not allow to set a DNS server for DHCP clients. It only allowed to set global DNS servers which means that if Pi-Hole is unavailable it cannot fall back to another DNS server (like your provider's DNS server).

Change Pi-Hole web interface server port and hostname

By default, Pi-Hole runs a lighttpd server on port 80. If you want to change this, add the following line to /etc/lighttpd/external.conf:

/etc/lighttpd/lighttpd.conf
server.port := 8080

Changing the hostname

If you also want to make Pi-Hole available under a different hostname (e.g., through the use of a reverse proxy), there is another change you need to do in order for the automatic redirect to the admin interface to work. Add the following line to external.conf:

setenv.add-environment = ("virtual_host" => "pihole.domain.tld")

Then restart the lighttpd service using systemctl:

sudo systemctl restart lighttpd

Prior versions of Pi-Hole could not handle using a different port and/or hostname on the admin site. My pull request addressed these problems and is available with Pi-hole v5+.

Custom hostnames inside network

Starting with Pi-hole v5 there is an option called Local DNS Records that lets you do this easily using the admin interface.

The alternative described in the following paragraph is left for transparency.

I'll get to this later in another post about the reverse proxy but if you want to have custom hosts in your network, the easiest option I find is to edit the hosts file (/etc/hosts). Add an entry there and execute pihole restartdns.

Now a dig custom.host.name should return the IP address of your server.

Updates to this blog post

  • 24.05.2020: Updated Pi-hole sections with changes introduced in Pi-hole v5.
  • 22.10.2024: Improved section ensuring the MariaDB service starts after the disk is mounted: Custom unit file so that changes don't get overwritten on package upgrades.

Did this post help you? Say Thank You by buying me a coffee

Comments

Comments are currently not supported. For the time being, please send me an email.