Raspberry Pi as a Server

This has Been Superseded

Please use Raspberry Pi OS (32-bit) Lite for server instead.


In this case I use a Model B+ but any model should work.

Not using Wireless

While we could use wireless, for basic infrastructure I prefer the stability and reliability of a wired connection.

Minimal SD Card with /var on External Hard Drive

In the use-case for which I write this article I have chosen to go with a small (4 GB) SD card for root and put swap and /var on an external hard drive. The SD Card holds the OS and software, while the external drive (which is faster and has many more write-cycles) handles all the large and/or frequently changing data. By doing this we keep wear on the SD Card to a minimum in addition to separating working data from binaries and static (package) data.

Why? Small Footprint Ideal for Low Demands

I use this as a bare metal provisioning and configuration server (using Ansible) that has no dependencies on other hosts, for the case where I need to bring up bare metal and virtual machine infrastructure (or recover from failure). This is for tens of hosts not hundreds.

Since this is a low demand environment the small size, low electricity use, fanless operation, and low price of the Pi make it ideal.

In future articles I will also detail using the same server 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 isolated 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.


Obtain Base Image for RPi SD Card

Option 1: Use a Prebuilt Image

For this guide you can use a raspshorian -lite or -swap-lite image from Armshorian: Available Images

A Raspberry Pi OS (32-bit) Lite image should work as well, with some modification to the guide (which is will be published here at some point).

Option2: Build a Custom Image

NB: These instructions expect Debian Buster or Ubuntu Xenial. If you are using another distribution your results may vary, as per the -armshorian-gen README-.

We use armshorian-gen to generate a more minimal (and stock Debian-like) image than the official images from Raspberry Pi Foundation.

Get armshorian-gen

git clone https://github.com/cshoredaniel/armshorian-gen

Build image

If you have a DHCP server the default build will be sufficient. Otherwise you should configure the network in the build configuration.

An example configuration which includes network configuration could be:

# Only use APT_PROXY if you have configured apt-cacher-ng as per the README, or
# otherwise have a proxy for APT
export APT_PROXY="${APT_PROXY:-}"

export ENABLE_SSH=1

# Require public key authentication (disable password authentication)

# Set the SSH public key for the first user (Default: rcshore)
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCYts/KmJ2B46+8lBvr+YHHz7bpWzjtNRNiYKsvEU/XtPEy8+pXGmzb/Xw+908ew5CyQ63FqUZm7AN6QIyVt9MyxZt7zkJOTyUhAw7X78dNuO0UQx7F6o5wsT1POCPxtegDIYDAIAbupfHEVtTAgGFOOz1VeOI6hR0y8Hnv+XDpIsX8KDkuKQNZr6Db4cF7OWFWIaXsSlGbs3VV5mxF4yqHD1kwNR/KxSmGPBw/aSROHWZqg9s77R97hsnaXXQNdQ/o8hc10LuR9Jp4LKp6pApoPfNYjy921V8STwoeNbPDEGo561MoZEGJhhmEzMR0S2PTsBNjJyZGQ1wsoL9FDWtB example-key@example.com

# Only build CLI images — we want the -lite image
export STAGE_LIST="raspshorian-stage0 raspshorian-stage1 raspshorian-stage2 raspshorian-stage3"

# (Optional) Configure the network (default is to use dhcp)
export INTERFACES_FILE_eth0="auto eth0
allow-hotplug eth0
#iface eth0 inet dhcp
#iface eth0 inet6 dhcp

iface eth0 inet static
  dns-search example.com
  dns-domain example.com

iface eth0 inet6 static
  address fd38:2477:022a:3::2/64
  dns-nameserver fd38:2477:022a:3::1
  dns-search example.com
  dns-domain example.com
export INTERFACES_FILES="eth0"

# Set the hostname
export HOSTNAME=example-host

# Optional: Make the serial console the primary console instead of the HDMI
# video console
export HEADLESS=1

# Optional: Set the locales to generate (Default: en_CA.UTF-8 UTF-8)
export LOCALE_GEN_DEFAULT="en_CA ISO-8859-1, en_CA.UTF-8 UTF-8, en_GB ISO-8859-1, en_GB.ISO-8859-15 ISO-8859-15, en_GB.UTF-8 UTF-8, en_US ISO-8859-1, en_US.ISO-8859-15 ISO-8859-15, en_US.UTF-8 UTF-8"
# Optional: Set the default locale (Default: en_CA.UTF-8)

# Name of the first (admin, id 1000) user
export FIRST_USER_NAME=rcshore

# Default password for first (admin, id 1000) user
export FIRST_USER_PASSWORD=raspshorian-default

# Default base name for image files
export IMG_NAME=example-host
  1. Place a config such as the above in a file named config in the armshorian-gen directory.
  2. Execute touch raspshorian-stage2/SKIP_IMAGES. (That will skip building the -minimal image which we are not using).
  3. Execute ./build-raspshorian.sh.
  4. Wait and watch.
  5. Assuming no network connectivity issues you should now have a file named image_YYYY-MM-DD-example-host-lite.zip (where ‘example-host’ is the IMG_NAME you selected above and YYYY-MM-DD is the numerical year-month-day the image was generated) in the deploy directory.

Write the Image to SD card

The Easy Way

  1. Download Etcher.
  2. Execute Etcher
    • On Linux extract the ZIP and execute the .AppImage binary
    • On Windows install Etcher and launch it.
    • On MacOS extract the dmg file and execute Etcher.
  3. Select your image.
  4. Make sure you select the correct drive to flash.
  5. Flash the image.
  6. Assuming the image flashes correctly you can now boot your Pi with the SD card you just created.

The Hard Way

Only use this method if you really know what you are doing.

  1. cd deploy
  2. unzip image_YYYY-MM-DD-example-host-lite.zip
  3. Insert your microSD card into a card reader attached to your device (using a microSD to SD adapter if all you have is an SD card reader).
  4. Determine the name of the device associated with you card reader (for a built-in card reader this is usually /dev/mmcblk0; for a USB attached card reader it is commonly /dev/sdb (but verify using dmesg).
  5. Copy the image to you SD card using a command such as sudo dd if=YYYY-MM-DD-example-host-lite.zip of=/dev/mmcblk0 bs=1M conv=fsync oflag=sync status=progress.
  6. Wait while your image is copied.
  7. When you once again have a command prompt your image has been written to the microSD card.
Ensure Data Transfer Complete and Remove SD Card
  1. sync
  2. sudo eject /dev/mmcblk0 (don’t worry if it complains).
  3. Once you have a command prompt you can remove the SD card.

Optional: Configure the SD Card to use /var and swap on External Drive

NB: If you follow these instructions, then before you can boot your Pi it will require the external drive USB be plugged in and the drive powered on.

  1. Make sure your SD card is unmounted (check the output of the mount command) but inserted and detected.

  2. Plug in your external drive and determine it’s device name (see above; the following instruction will use /dev/sdc).

  3. cd /tmp

  4. mkdir -p src dst

  5. sudo mount /dev/mmcblk0p2 src

  6. Make sure your external drive is partitioned with an appropriately sized partition for linux-swap (rule of thumb is double the amount of RAM), and a second partition for ext4.

  7. sudo mkswap /dev/sdc1

  8. sudo mkfs.ext4 /dev/sdc2

  9. sudo mount /dev/sdc2 dst

  10. sudo rsync -arHAXx --info=progress2 src/var/ dst/

  11. sudo blkid

  12. Copy the PARTUUID of /dev/sdc1 for pasting into /etc/fstab

  13. sudoedit src/etc/fstab

  14. If there is already a line mount swap, delete it.

  15. Add a line such as:

    PARTUUID=aef38-35820-01 none  swap  sw  0 0

    where aef38-35820-2332 is the UUID you copied above.

  16. Save and exit

  17. sudo blkid

  18. Copy the PARTUUID of /dev/sdc2 for pasting into /etc/fstab

  19. sudoedit src/etc/fstab

  20. Add a line such as:

    PARTUUID=aef38-35820-02 /var  ext4  defaults,relatime 1 1
  21. Save and exit

  22. sudo rm -rf src/var/*

  23. sync

  24. sudo umount dst

  25. sudo umount src

  26. sudo eject /dev/sdc

Boot the Pi and Perform Initial Configuration

Boot the Pi for the First Time (with this image)

  1. Boot the Pi.
  2. The root partition will be resized and the Pi will reboot.
  3. Once the Pi boots, you can log in.

Initial Configuration

Initial Steps if Using a Downloaded Prebuilt Image
  1. Login (username: rcshore, password: raspshorian-default)
  2. Configure your keyboard (if not using headless): sudo dpkg-reconfigure keyboard-configuration
  3. Configure your locale (language etc): sudo dpkg-reconfigure locales
  4. passwd : Change the password for rcshore
  5. Configure the timezone: sudo dpkg-reconfigure tzdata
  6. sudo hostnamectl set-hostname new_hostname : Set the intended hostname for this server.
Initial Steps if Using DHCP
  1. passwd : Change the password for the FIRST_USER_NAME you specified when building the image (rcshore if using a prebuilt image).
  2. ip addr : find the IP address and make sure you set up a DNS entry to point to this IP (this is router-specific, and you should either set a static lease so that the server always gets the same address, or ensure the router sets the DNS entry to the IP it gave via DHCP to your hostname).
Initial Steps if Using a Static IP With Image You Built
  1. passwd : Change the password for the FIRST_USER_NAME you specified when building the image.
  2. Use the IP address you specified and make sure you set up a DNS entry to point to this IP (in this cast the DNS name local part should be the value of HOSTNAME from you config when building the image).
Next Steps if Using a Prebuilt Image
  1. If you want to use public key authentication for SSH (recommended), then you need to
    1. scp yourkey.pub rcshore@<hostname>: (substituting as appropriate)
    2. ssh rcshore@<hostname>
    3. mkdir -p .ssh
    4. chmod 700 .ssh
    5. mv yourkey.pub .ssh/authorized_keys
    6. chmod 600 .ssh/authorized_keys
  2. To disable password authentication for SSH (and thus require public key authentication):
    1. sudoedit /etc/ssh/sshd_config
    2. Ensure one line has PasswordAuthentication no and that any other PasswordAuthentication lines are commented out.
    3. Ensure there are no lines with PubkeyAuthentication no.
    4. Restart ssh: systemctl restart sshd
Next Steps if Using Swap on an External Drive
  1. sudo systemctl stop dphys-swapfile
  2. sudo systemctl disable dphys-swapfile
  3. sudo rm -f /var/swap
  4. sudo apt remove --purge dphys-swapfile

Install & Configure the Desired Services

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.