Preparing USB

Note: We can boot RPi from USB if we are using RPi 3B+ or newer.

Run Raspberry Pi Imager

Choose OS-Lite and select USB flash drive from storage

Press Ctrl+Shift+X for more advanced settings. Here we can configure the following items:

  • Hostname
  • SSH (standard username: pi)
  • Wifi SSID and password
  • Locales (Timezone and Keyboard layout)

First boot

Plug in USB drive and power into RPi. The RPi will boot up and do first boot configuration, which then will connect to SSID previously configured.

Boot sequence will be completed around 5 mins. You can try ping to the [hostname].local configured

ping pi04.local -4

Subsequent steps will require RPi to be connected via ssh or directly with keyboard + monitor + mouse

Core Software Installation

First update

# Download latest package information from pre-configured sources
# Sources: /etc/apt/sources.list + /etc/apt/sources.list.d/
# And then run upgrade, bypass prompt
sudo apt update && sudo apt -y upgrade

This will take some time, so it’s a good time for coffee

Unattended Reset

# Use super user (elevated) rights
# Write watchdog config into /boot/config.txt
# Reboot RPi afterwards

sudo sed -i '$ a \
dtparam=watchdog=on' /boot/config.txt

sudo reboot -h now

After restart, run the following

# Download latest package information from pre-configured sources
sudo apt update

# Install Watchdog service
sudo apt install watchdog

# Configure the watchdog service
# 15 seconds timeout
sudo sed -i '$ a \
watchdog-device = /dev/watchdog \
watchdog-timeout = 15 \
max-load-1 = 24' /etc/watchdog.conf

# Enable service and run without restarting pi
sudo systemctl enable --now watchdog

# Check watchdog service status
sudo systemctl status watchdog

User account

Now is a good time to create new user account and disable standard account

# Add new user
# New password prompt will be available
sudo adduser [username]

# Add new user into admin group
sudo gpasswd -a [username] adm

# Add new user into superuser group
sudo gpasswd -a [username] sudo

# Check if both adm and sudo group is indeed committed
sudo groups [username]

# It is a good idea to test using SSH before proceeding to next step

# Reset root password
# Choose something long and keep this safe
sudo passwd root

# Disable standard pi account
sudo passwd --lock pi

Log2Ram (if using SD Card)

# For Log2Ram to work best, rsync is recommended to be installed
sudo apt update
sudo apt install rsync

# make directory for download
mkdir download
cd download

# Get archive of the latest code from GitHub
# Extract the archive then run the install script
wget https://github.com/azlux/log2ram/archive/master.tar.gz -O log2ram.tar.gz
tar xf log2ram.tar.gz
cd log2ram-master
sudo ./install.sh

# After next boot, /var/log will exist in RAM

# Configure Log2Ram
sudo nano /etc/log2ram.conf

# Change the SIZE option and change to SIZE=80M (or 128M if there's a lot of logs expected)
# Change the PATH_DISK if needed PATH_DISK="/var/log;/home/[username]/log"

# If there are changes in configuration, reboot is needed
sudo reboot

ZeroTier

# Configure GPG for ZeroTier
# Download ZeroTier binary and install
curl -s 'https://raw.githubusercontent.com/zerotier/ZeroTierOne/master/doc/contact%40zerotier.com.gpg' | gpg --import && \
if z=$(curl -s 'https://install.zerotier.com/' | gpg); then echo "$z" | sudo bash; fi

# Replace ################ with network ID
# Can be found from https://my.zerotier.com/
sudo zerotier-cli join ################

# After running the CLI above, we'll need to approve the Pi from web portal
# The following sections will refer to the Managed IP available from ZeroTier central

SSH hardening

SSH Key instead of password

Now is a good time to complete SSH keypair configuration for password-less SSH authentication

SSH port number

We can also change port number for SSH as per needed

# Edit config file for ssh service
sudo nano /etc/ssh/sshd_config


# Commit the changes by restarting ssh service
sudo service ssh restart

SSH user authorization

We can specify which user accounts are allowed to access SSH

# Edit config file for ssh service
sudo nano /etc/ssh/sshd_config

# Under authentication, enter the following value
# Multiple users can be configured with comma without spaces
AllowUsers [username],[user2]


# Commit the changes by restarting ssh service
sudo service ssh restart

Unattended Upgrades

# Install unattended-upgrades
sudo apt install -y unattended-upgrades

# Testing installation
# In the output, we're interested in seeing if there's any error
sudo unattended-upgrade -d -v --dry-run

# Enabling unattended-upgrades
# Click YES on the warning page
# Configuration can be found at /etc/apt/apt.conf.d/ folder
sudo dpkg-reconfigure --priority=low unattended-upgrades

# Change from Debian to RPi distro
# ---
# Change "origin=Debian,codename=${distro_codename},label=Debian"; into
# "origin=Raspbian,codename=${distro_codename},label=Raspbian";
# Change "origin=Debian,codename=${distro_codename},label=Debian-Security"; into
# "origin=Raspberry Pi Foundation,codename=${distro_codename},label=Raspberry Pi Foundation";
sudo sed -i 's/origin=Debian,codename=${distro_codename},label=Debian/origin=Raspbian,codename=${distro_codename},label=Raspbian/g' /etc/apt/apt.conf.d/50unattended-upgrades
sudo sed -i 's/origin=Debian,codename=${distro_codename},label=Debian-Security/origin=Raspberry Pi Foundation,codename=${distro_codename},label=Raspberry Pi Foundation/g' /etc/apt/apt.conf.d/50unattended-upgrades

Sudo without password

sudo visudo

# Add at the end of the line
[username] ALL=(ALL)    NOPASSWD:ALL

Turn off unused services

Use the following command to check currently running services

systemctl --type=service --state=active

We can deactivate unused services from this list. Example as per below

  • Avahi (avahi-daemon.service)
  • Bluetooth (bluetooth.service)

To deactivate, use the following command

sudo systemctl disable [servicename] --now

Firewall

Install

# Get network status
netstat -an

# Install ufw
sudo apt install ufw

Default configuration

By default, ufw will deny all incoming connection. We’ll need to configure allow rule to accept connection.

sudo ufw allow 22/tcp comment "Basebuild - SSH"
sudo ufw allow http/tcp comment "Basebuild - HTTP"
sudo ufw allow https/tcp comment "Basebuild - HTTPS"

sudo ufw allow 9993/udp comment "Basebuild - Zerotier"
sudo ufw allow proto udp from any port 9993 comment "Basebuild - Zerotier"

sudo ufw allow proto udp from any to any port 32768:65535 comment "Ephemeral"

Firewall with ZeroTier

Run the following and note down listening ports. This will be different for each ZeroTier node

sudo netstat -lp --numeric-ports --numeric-hosts | grep zero

Enable Firewall

sudo ufw enable
sudo ufw status

UFW issue with docker

Docker by default will bypass ufw. We’ll need to change default configuration for ufw:

Read more here

NetworkManager issue with docker

sudo nano /etc/udev/rules.d/85-nm-unmanaged.rules


# Include the following line
# Virtual Ethernet device pair. Often used to communicate with a peer interface
# in another net namespace and managed by libvirt, Docker or the like.
ENV{INTERFACE}=="veth*", ENV{NM_UNMANAGED}="1"

Fail2ban

# Install fail2ban
sudo apt install fail2ban -y

# Configure fail2ban
sudo nano /etc/fail2ban/jail.local

# Insert the following
[DEFAULT]
bantime = 1h
banaction = ufw

[sshd]
enabled = true

# Save then enable
sudo systemctl enable --now fail2ban

# Restart sshd
sudo systemctl restart sshd

Secondary WiFi

sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

# Add another network = {} section below

Last modified: 10 May 2023