Configuring Ubuntu Server on a Raspberry Pi

I have a standard base configuration for my Raspberry Pi Ubuntu servers. These are the changes I make from the standard install.

Configuring Ubuntu Server on a Raspberry Pi

This is a list of the changes I typically make to a standard Ubuntu Server install on a Raspberry Pi (and other hardware) to get them up and running on my local network.

You should be able to ssh into the Pi as the default user from your computer, the Pi should be able to access the Internet, and you should be able to use a text editor such as nano or vi and understand what the sudo command does.


Basic Operating System configuration

Set the root password using sudo root passwd, making sure it is a secure password that you will remember.

Make sure the operating system is up to date by running sudo apt update and then sudo apt upgrade, answering [Y]es to any prompts.

If the Pi is fitted with a PoE hat with a fan, adding these lines to the file /boot/firmware/config.txt in the [pi4] or the [all] section will ensure the fan works reliably. Edit the file (as you do with all the file edits below) with sudo nano /boot/firmware/config.txt

[pi4]
max_framebuffers=2
arm_boost=1
# PHIL - ADDED FOR PI PoE Hat Fan
dtoverlay=rpi-poe
dtparam=poe_fan_temp0=50000
dtparam=poe_fan_temp1=58000
dtparam=poe_fan_temp2=64000
dtparam=poe_fan_temp3=68000

If you are using Prometheus to monitor your servers (any more than a handful and you should be!), install the prometheus-node-exporter with sudo apt install prometheus-node-exporter.

Install zsh as a shell option for users with sudo apt install zsh.

Fix unattended upgrades configuration to automatically upgrade your OS while you sleep. In /etc/apt/apt.conf.d/50unattended-upgrades uncomment (by removing the #) the line "${distro_id}:${distro_codename}-updates" and then find and change these settings:

Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";

Make sure that unattended upgrades does more housekeeping than it would normal do by adding these lines to /etc/apt/apt.conf.d/20auto-upgrades:

APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "30";

The Raspberry Pi doesn't come with an Intelligent Platform Management Interface (IPMI), so you can safely disable that with sudo systemctl disable openipmi.

If you are going to run Docker (and why wouldn't you...) then you can install it using this series of commands:

sudo apt install \
    ca-certificates \
    curl \
    gnupg \
    python3-pip\
    lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin docker-compose

Add your default user to the docker group and to www-data while you are at it:

sudo usermod -aG docker <INSERT USER NAME>
sudo usermod -aG www-data <INSERT USER_NAME>

Configure the docker daemon for json-file format logs with a maximum size to make sure they don't fill up your drive, and enable the Prometheus metrics exporter if you are using Prometheus. If you don't know your Pi's IP address then you can find it with ip address show dev eth0. Create the file /etc/docker/daemon.json with the following contents:

{
      "metrics-addr" : "<YOUR IP ADDRESS>:9323",
      "experimental" : true,
      "log-driver":  "json-file",
      "log-opts": {
        "max-size": "250m",
        "max-file": "3"
      }
}

Install chrony to keep the system clock in decent shape with sudo apt install chrony. If you have a local NTP time server (something you trust as the Pi 4 has no battery backed clock by default) then add it to /etc/chrony/chrony.conf after the ntp pools, I use one of my Synology NAS's that is setup to serve time:

pool ntp.ubuntu.com        iburst maxsources 4
pool 0.ubuntu.pool.ntp.org iburst maxsources 1
pool 1.ubuntu.pool.ntp.org iburst maxsources 1
pool 2.ubuntu.pool.ntp.org iburst maxsources 2
server nas-2.little.place

Install some handy system admin tools with sudo apt install bmon nmap network-manager.

If you are not using WiFi and Bluetooth, turn them off with sudo nmcli radio wifi off.

Install the Raspberry Pi configuration tool with sudo apt install raspi-config and then run it using sudo raspi-config and go to the Performance Options section and set the GPU memory to the smallest allowed 16 as this is a headless server and so you will not need any display memory.

Reboot the Pi, and log back in once it is up and running.

Remove the news and help sections from the message of the day that appears every time you login by running sudo chmod a-x /etc/update-motd.d/10-help-text and changing ENABLED=1 to ENABLED=0 in /etc/default/motd-news.

Create your ssh keys by running ssh-keygen.

Install oh-my-zsh for zsh by running sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" and then edit ~/.zshrc to load the following components (this is a matter of taste - you can drop macos if you don't use Mac's for example):

# Which plugins would you like to load?
# Standard plugins can be found in $ZSH/plugins/
# Custom plugins may be added to $ZSH_CUSTOM/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(z wd macos screen history history-substring-search git common-aliases zsh-syntax-highlighting docker docker-compose)

Installing Mac and PC file services

If you want to serve files to PC's and Mac's as a file server (which you almost certainly do) then sudo apt install netatalk samba. Configure Samba by editing /etc/samba/smb.conf like this:

Add these lines to the [global] section of /etc/samba/smb.conf:

[global]
# Phil added
min protocol = SMB2
vfs objects = catia fruit streams_xattr
fruit:metadata = stream
fruit:model = MacSamba
fruit:posix_rename = yes
fruit:veto_appledouble = no
fruit:wipe_intentionally_left_blank_rfork = yes
fruit:delete_empty_adfiles = yes
multicast dns register = no

Set up the [homes] section like this:

[homes]
   comment = Home Directories
   browseable = no
   read only = no
   create mask = 0700
   directory mask = 0700
   valid users = %S

Set up the [printers] section like this:

[printers]
   comment = All Printers
   browseable = no
   path = /var/tmp
   printable = yes
   guest ok = yes
   read only = yes
   create mask = 0700

[print$]
   comment = Printer Drivers
   path = /var/lib/samba/printers
   browseable = yes
   read only = yes
   guest ok = yes

Fix the Avahi configuration by changing the following parameters in /etc/avahi/avahi-daemon.conf:

[server]
domain-name=local
use-ipv4=yes
use-ipv6=yes
ratelimit-interval-usec=1000000
ratelimit-burst=1000

[wide-area]
enable-wide-area=yes

[publish]
add-service-cookie=yes
publish-hinfo=yes
publish-workstation=yes

Make sure Avahi is advertising local file and samba services by creating the following two files:

Create /etc/avahi/services/afpd.service containing:

<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
  <name replace-wildcards="yes">%h</name>
  <service>
    <type>_afpovertcp._tcp</type>
    <port>548</port>
  </service>
  <service>
    <type>_device-info._tcp</type>
    <port>0</port>
    <txt-record>model=iMac</txt-record>
  </service>
</service-group>

Create /etc/avahi/services/smb.service containing:

<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
  <name replace-wildcards="yes">%h</name>
  <service>
    <type>_smb._tcp</type>
    <port>445</port>
  </service>
  <service>
    <type>_device-info._tcp</type>
    <port>0</port>
    <txt-record>model=iMac</txt-record>
  </service>
</service-group>

Enable Mac file services by editing /etc/netatalk/afp.conf to set where home directories can be found:

[Homes]
basedir regex = /home

Fix permissions on those files with sudo chmod 644 /etc/samba/smb.conf /etc/avahi/avahi-daemon.conf /etc/avahi/services/afpd.service /etc/avahi/services/smb.service and then restart everything with sudo systemctl restart smbd netatalk nmbd avahi-daemon.

Setting up things like email and docker containers is next on the list.