September 8, 2020 by Daniel F Dickinson19 minutes

You may find yourself in need of a 'bare metal' server. If the workload is not too demanding, a Raspberry Pi can be a good choice.
For small deployments (or home or small office use) you may find yourself in need of a ‘bare metal’ server, but not want or need the expense of an x64 machine. If the workload is not too demanding, a Raspberry Pi can be a good choice. The Pi has the benefit of being inexpensive, using little electricity and taking minimal space.
For testing and experimentation for this article a Model B+ and a Pi 2 have been used, but any model should work. With a Pi 2 may want to investigate using Ubuntu Server (32-bit), and for a Pi 3 or higher an ‘aarch64’ Linux (such as Ubuntu Server aarch64). ‘aarch64’ is the 64-bit version of Linux for ARM processors and is often a better choice (and certainly is for models with large amounts of RAM).
While we could use wireless, servers used for basic infrastructure benefit from the stability and reliability of a wired connection. In addition, on models of Pi available to the author wireless is an addon rather than builtin.
In the past the author has used this as a bare metal provisioning and configuration server (using Ansible) that has no dependencies on other hosts, for the case where there is a need to bring up bare metal and virtual machine infrastructure (or recover from failure). A similar configuration has been used to serve network booting and installs of CentOS, Debian, and Fedora and related projects (like Atomic), as well as allowing network boots of System Rescue CD. In addition, the same server can easily act as the repository server for package updates on an isolate network.
A further use of this server is to act as a Debian apt cache for isolated networks. With these capabilities all other servers on the network can be installed, provisioned, and configured from this server.
Since this is a low demand environment, the small size, minimal electricity use, fanless operation and low price of the Pi make it ideal.
This time around the Pi is being used to host a small PostgreSQL instance, due to lack of an available virtual machine host on the local network (Author’s Note: remind me not to use water-cooled heatsinks; not because of short circuits when they leak, but that with a very slow leak, they result in the CPU overheating and the CPU and/or motherboard being damaged without it being noticed until too late).
This article discusses techniques for using swap and /var on an external drive as there are times this can be useful. In particular if one has an external spinning disk or other external media which is faster and has more write cycles than an SD card, then it can make sense to move both swap and the /var directory (and maybe /tmp) to the external drive(s). This is because it will increase the speed and robustness of the system due to the fact swap and /var (and often /tmp) are written frequently. In addition, the faster swap is, the better, although you still want to avoid situations where you exceed available memory and end up where swap is thrashing and bringing the system to a crawl. (External drives help because the SD and microSD cards on which the Pi OS typically resides is almost certainly slower than any external drive).
It is assumed you aren’t planning on doing this often as, if you are, you really ought to automate your process.
NB: Raspberry Pi OS has very recently (as I tweak this page in early November 2021) switched to being based on Debian ‘Bullseye’ instead of ‘Buster’ so there are some minor changes and tweaks noted on this page to reflect that.
A Raspberry Pi OS (32-bit) lite image provides a solid base for this configuration.
If you find download speeds are slow you may wish to try the Raspberry Pi OS (32-bit) lite torrent.
Basically: put an empty file called ‘ssh’ on the ‘boot’ partition of the SD card (not boot directory in the root partition).
See:
Boot the Pi.
Once the SD card light stops flashing and is off for at least a minute, you should be able to login via SSH1.
See the links above to see how to determine the address of your Raspberry Pi so you can login.
ssh pi@<address-of-your-pi>passwd — Enter your old password, and then a better (and unique) password
for your pi (twice), following the prompts. Remember it!sudo apt update && sudo apt upgrade -ysudo shutdown -r nowsudo raspi-config16 and press ENTER — this frees up some memory that would be
dedicated to the GPU (graphics) (default is 64)mkdir .sshchmod 700 .chmod 700 .sshcd .sshtouch authorized_keyschmod 0600 authorized_keyssensible-editor authorized_keysssh-agent)sudoedit /etc/ssh/sshd_configPasswordAuthentication noPasswordAuthentication yes linesPermitRootLogin noPermitRootLogin and
values other than nosudo sh -c 'sshd -t -f /etc/ssh/sshd_config; echo $?' — 0 should be
emitted and there should be no error messagessudo systemctl restart sshdpi with a different administrative
user/local-home instead of /home means
that if there are users under /home with large dirs, that the dirs can
be mounted on a separate drive/partition. It also facilitates shrinking the
size of /home (easier to avoid /home being in use, which matters
because in order to shrink a filesystem you need to unmount it), should you
wish to reallocate the storage for another purpose.pi user, which is full root without entering the user’s password again.sudo adduser --home /local-home/newadmin --shell /bin/bash --gecos "New Admin User,,," newadminsudo adduser newadmin sudosudo adduser newadmin admsudo adduser newadmin staffpi user is a member of a number other groups
which are more relevant for desktop use, or accessing the Pi’s
electronics capabilities; is you need any of that you should add newadmin
to the those groups as well.sudo cp -r .ssh /local-home/newadmin/ — This assumes you want to use
the same SSH keypair for the newadmin as you are now using for the pi
user; you could instead follow the instructions above for the newadmin
user (to act as the newadmin user without a new login, use:
sudo su - newadmin).sudo chown -R newadmin:newadmin /local-home/newadmin/.sshsudo chmod 700 /local-home/newadminnewadmin (e.g.
ssh newadmin@<address-of-your-pi>)newadmin user, verify you can sudo (e.g.
sudo ls -al /home/pi/.ssh for which you should see pi’s authorized_key
file with additional info)pipi) by issuing:
sudo deluser --remove-home pi. If you don’t do this, you should at least
make sure the pi user and newadmin user are using different passwords and
SSH keypairs. Removing the pi user has the advantage that script-based
attacks spam you less, especially if you also change the SSH port, which makes
it easier to examine your logs for untoward behaviour.lvm2 and
smartmontools muttlvm2 is the only method described in this article for setting up
the storage. mutt package allows you to read the local email messages
created by smartmontools default configuration).ufw is required.cryptsetup or full disk encryption as it
does not have the horsepower nor crypto offload. One should therefore make sure
that any sensitive data one stores on the Pi is encrypted at the application
level (rather than at the OS level as is the case with full disk encryption).sudo apt install -y lvm2 smartmontools ufw (add mutt to that list
if pre-Bullseye)/etc/aliases to send local mail messages2 to your admin user
(e.g. newadmin)sudoedit /etc/aliasesroot: newadmin (obviously substituting the name of your admin
user for newadmin)sudo newaliasesExecute sudo apt install -y aptitude byobu etckeeper fail2ban iftop iotop-c unattended-upgrades ufw whois
If you want to start using byobu immediately, execute byobu. This has
certain advantages if you become disconnected, or need to open another
terminal session, and you know how to use it.
If you only have one USB storage device attached to the Pi, this is easy; it is
known as /dev/sda. For the purposes of this guide we will assume this is the
situation.
sudo dmesg|grep sdasudo smartctl -i /dev/sda should
correctly identify the device and show some information about it (assuming you
installed smartmontools as described above).sudo parted /dev/sdamsdos partition, I recommend using
mklabel gptmkpart primary 1 -1quitsudo pvcreate /dev/sda1 — Prepares the drive for use as a ‘physical volume’
by LVM2sudo vgcreate vg1 /dev/sda1 — Creates a volume group on physical volume
/dev/sda1 (a volume group can span multiple physical volumes) for LVM2sudo pvs will show you the physical volume statussudo vgs will show the volume group statussudo lvcreate -L 512M -n swap vg1sudo mkswap /dev/vg1/swapsudoedit /etc/fstab/dev/vg1/swap none swap sw 0 0sudo swapon -asudo dmesg and verify that there haven’t been any errors using
the swap partition.cat /proc/swaps — you should see see your new swap partition
(you will likely also see a /var/swap ‘file’ — we’ll remove that next)sudo systemctl stop dphys-swapfilesudo systemctl disable dphys-swapfilesudo rm -i /var/swapsudo apt remove -y --purge dphys-swapfilesudo apt install rsync.var partition that fits your storage and
you think is big enough. If you will be using volumes for more than just /var,
you should create your volumes so that there is space left unallocated in the
volume group. That allows you to increase the size of a volume that turns out
not to have have storage ‘on-the-fly’ (you’ll need to look for guides on using
lvresize and resize2fs to see how to achieve that; that is beyond the scope
of this article). For example, sudo lvcreate -L 20G -n var vg1.sudo mkfs.ext4 /dev/vg1/varsudo mkfs.ext4 -E lazy_itable_init=0,lazy_journal_init=0 /dev/vg1/varExecute the following commands:
sudo -sH
mount /dev/vg1/var /mnt
systemctl stop syslog.socket rsyslog
systemctl stop systemd-journal*.socket systemd-journal*.service
rsync -arHAXx --info=progress2 /var/ /mnt/
umount /mnt
mv /var /var.old
mkdir /var
mount /dev/vg1/var /var
sudoedit /etc/fstabAdd a line such as /dev/vg1/var /var ext4 defaults,relatime 1 1
Save and exit
Execute sudo mount -a. If it doesn’t succeed, you need to fix the problem
else your system will not boot.
Reboot
If you’ve done things right, df -h should show your new partition
(possibly as /dev/mapper/vg1-var) mounted on /var.
Execute sudo rm -rf /var.old
If you wish you can repeat for /tmp (with appropriate substitions)
Ideally for other mountpoints you create the logical volume and mount it (entry
in /etc/fstab then sudo mount -a) before you use the partition so that you
don’t need to copy the old contents and owner/permissions to the new
destination.
ip addr showeth0 has an ip address. If not, you need to use a
different (not eth0) interface, which will involve learning more about
Linux/Debian networking.sudo ufw allow in on eth0 from any to any app OpenSSHens3 as the
interface you need to deal with)sudo ufw enable — NB Make sure you have the right interface above else
you will be locked out from network access to the Pi and will either need to
attach a keyboard and monitor and fix things, or reinstall.sudo touch /etc/byobu/autolaunch. From now on, when you
login to a shell (e.g. via SSH) byobu will launch.touch .byobu/.always-select. This will cause
byobu to prompt to create a new session or login to an existing one, when a user
logs in and already has a running byobu session.byobu-config and choose the items they
want to have appear on their status bar in byobu.Note that we comment out the enabling of nginx fail2ban jails until after we install nginx (if we do).
Place the following in /etc/fail2ban/jail.local and execute
sudo systemctl restart fail2ban.
[DEFAULT]
# "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban
# will not ban a host which matches an address in this list. Several addresses
# can be defined using space (and/or comma) separator.
ignoreip = 127.0.0.1/8 ::1
[sshd]
# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
#mode = normal
enabled = true
[nginx-http-auth]
#enabled = true
[nginx-botsearch]
#enabled = true
# Ban attackers that try to use PHP's URL-fopen() functionality
# through GET/POST variables. - Experimental, with more than a year
# of usage in production environments.
[php-url-fopen]
#enabled = truesudoedit /etc/apt/apt.conf.d/50unattended-upgradesorigin=Debian with origin=Raspbian and label=Debian
with label=Raspbian"origin=Raspberry Pi Foundation,codename=${distro_codename},label=Raspberry Pi Foundation";’
in the Unattended-Upgrade::Origins-Pattern sectionFor this article we will use restic because it allows backing up to a variety
of remote storage types.
apt updates the binary (e.g. due to bug fix).ps e (e.g.
ps auex)To backup the main OS and OS data (e.g. /etc, most of /var, /local-home, /root)
sudo apt install -y restic
sudo -sH
`cd ~``
mkdir restic-files
cd restic-files
chmod 700 .
touch password-file
chmod 600 password-file
sensible-editor password-file
In the editor, add a strong password (e.g. 30 alphanumeric and special characters), then save and close (having a file with the password not ideal, but avoiding it is rather complicated, and out of scope for this article).
If using SFTP for backups, create a passwordless SSH keypair using:
ssh-keygen -t rsa -f restic@piserver -C restic@piserver -N ''restic@piserver.pub to your destination’s
authorized_keys file.(assuming you have configured, ~/.ssh/config so that
restic@backupserver.example.com uses the restic@piserver created above:
restic -r sftp:restic@backupserver.example.com:/path/to/repo --password-file ~/restic-files/password-file backup --one-file-system --exclude /var/cache/apt --cleanup-cache /etc /var /local-home /rootNow create a crontab entry to do this once a day:
crontab -e
Add an entry such as:
23 2 * * * restic -r sftp:restic@backupserver.example.com:/path/to/repo --password-file ~/restic-files/password-file backup --one-file-system --cleanup-cache --exclude /var/cache/apt --quiet /etc /var /local-home /root 2>&1 | logger -t resticSave and exit the editor
exit
sudo -u data-owner -s (where
data-owner is the user that ‘owns’ the data be backed up).This is basically a Debian system so the many guides for installing and configuring services on Debian (and, in many cases, Ubuntu) will be applicable.
Enjoy!
Should you choose to use the console (HDMI monitor and USB keyboard)
there are a few things you should do, using the Raspberry Pi configuration
tool: sudo raspi-config, especially configure the local keyboard,
network, and if applicable, wireless.
Repeat: For Pi on the console rather than through SSH you should configure
the keyboard layout using raspi-config before changing the password, if
your keyboard is not a standard UK keyboard, because the Pi console
keyboard layout defaults to the type used by the Raspberry Pi Foundation, a
UK non-profit organization. ↩︎
We only enable this because smartmontools automatically pulls in mail
configuration. For an internal (no public facing internet inbound access)
server, it is not recommended to send mail to public mail servers, as it
will likely be seen as spam. Further, because this article describes an
unencrypted root filesystem, I do not recommend adding the use of
authenticated SMTP in order to send mail as an email user you have on a
public mail server. That is is your email password would be stored
unencrypted on your root partition. ↩︎