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 -y
sudo shutdown -r now
sudo raspi-config
16
and press ENTER — this frees up some memory that would be
dedicated to the GPU (graphics) (default is 64)mkdir .ssh
chmod 700 .
chmod 700 .ssh
cd .ssh
touch authorized_keys
chmod 0600 authorized_keys
sensible-editor authorized_keys
ssh-agent
)sudoedit /etc/ssh/sshd_config
PasswordAuthentication no
PasswordAuthentication yes
linesPermitRootLogin no
PermitRootLogin
and
values other than no
sudo sh -c 'sshd -t -f /etc/ssh/sshd_config; echo $?'
— 0 should be
emitted and there should be no error messagessudo systemctl restart sshd
pi
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,,," newadmin
sudo adduser newadmin sudo
sudo adduser newadmin adm
sudo adduser newadmin staff
pi
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/.ssh
sudo chmod 700 /local-home/newadmin
newadmin
(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)pi
pi
) 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
and mutt
(no longer required for Bullseye) packages are
recommended. lvm2
is the only method described in this article for setting up
the storage. (The mutt
package allows you to read the local email messages
created by smartmontools
default configuration). (as of Bullseye,
smartmontools no longer sends mail by default)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/aliases
root: newadmin
(obviously substituting the name of your admin
user for newadmin
)sudo newaliases
Execute 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 sda
sudo 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/sda
msdos
partition, I recommend using
mklabel gpt
mkpart primary 1 -1
quit
sudo 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 vg1
sudo mkswap /dev/vg1/swap
sudoedit /etc/fstab
/dev/vg1/swap none swap sw 0 0
sudo swapon -a
sudo 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-swapfile
sudo systemctl disable dphys-swapfile
sudo rm -i /var/swap
sudo apt remove -y --purge dphys-swapfile
sudo 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/var
sudo mkfs.ext4 -E lazy_itable_init=0,lazy_journal_init=0 /dev/vg1/var
Execute 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/fstab
Add 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 show
eth0
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 OpenSSH
ens3
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 = true
sudoedit /etc/apt/apt.conf.d/50unattended-upgrades
origin=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 /root
Now 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 restic
Save 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. ↩︎