The Raspberry Pi is a small, inexpensive, single-board computer system that retails for about $35 USD. It is one of the simplest and most cost-effective ways of powering digital infrastructure services for a small- to medium-sized group of comrades who need secure access to various telecommunications and coordination tools. You can think of a Raspberry Pi as a small-scale equivalent of your own private “cloud” service offering, replacing the need to create accounts with Google, Microsoft, or Apple, Inc.

Hardware setup

TK-TODO

Software setup

Operating System installation

Installing Raspberry Pi OS

TK-TODO

Installing NOOBS

TK-TODO

See Raspberry Pi Foundation: Installing NOOBS for now.

Post-OS install checklist

The following tasks should be performed after every clean installation of the Operating System (such as NOOBS, Raspberry Pi OS, etc).

  1. Provide the Raspberry Pi with Internet connectivity; this is usually as simple as connecting to a Wi-Fi network (if your model Pi has a built-in Wi-Fi card), plugging in an ethernet cable attached to a modem provided by your ISP into the Raspberry Pi’s physical network port (its NIC), or inserting an external Wi-Fi device and setting up Wi-Fi via the command line.
    1. Check for successful connectivity by attempting to contact a remote server, perhaps by invoking ping 1.1.1.1 or ping 8.8.8.8 or ping 9.9.9.9. The first is Cloudflare’s public DNS resolver, the next is Google’s public DNS resolver, and the latter is the non-profit group Quad 9’s public DNS resolver, which both respond to WAN-side pings. If you receive a response, you are connected.
    2. If you do not read a reply, check that the Raspberry Pi has obtained an IP address: ip addr | grep inet. You should see at least one IP address in a routable range (such as 192.168.XXX.XXX, where XXX is a number from 1 to 254).
    3. Next, check that your local DNS resolver is configured correctly, so that you can use addresses such as google.com instead of its numeric IP address. Inspect the contents of the plain-text file at /etc/resolv.conf on your local filesystem; if in doubt, replace its contents using the following command invocation:
      echo "nameserver 9.9.9.9" > /tmp/resolv.conf && sudo cp /tmp/resolv.conf /etc/resolv.conf # Use Quad 9, a security-conscious provider.
      
      1. Finally, some network configurations will confuse the resolvconf utility, which is responsible for updating the resolv.conf file, and your changes will be automatically overwritten. To disable this, append resolvconf=NO to your system’s /etc/resolvconf.conf file.
  2. Update the installed packages.
    • For a Debian-based system, this is usually accomplished using the sudo apt update and sudo apt upgrade commands performed in sequence.
    • For a RedHat-derived system, this is usually accomplished using the sudo yum update or sudo dnf update command.
  3. Optionally, update the kernel, device firmware, and other boot code to the bleeding edge (“unstable/testing”) release. Raspberry Pi OS-based Operating Systems (such as NOOBS) supply a special utility, rpi-update, for this purpose. Invoke it with root privileges using the sudo rpi-update command. (Note that this will overwrite all customizations you may have made to your kernel, if any, replacing it with the stock release from the Raspberry Pi Foundation.)
  4. Reboot the Raspberry Pi to activate the new firmware:
    sudo shutdown -r now
    
  5. Configure locale and regional settings. Raspberry Pi OS-based Operating Systems (such as NOOBS) supply the raspi-config utility for this purpose. Invoke it with root privileges using the sudo raspi-config command.
    1. First, update the raspi-config utility itself to make sure you have the latest version.
    2. Set the correct keyboard layout, timezone, and other localization options:
      1. Localisation OptionsKeyboard
      2. Localisation OptionsTimezone
    3. Configure other Raspberry Pi system settings as desired. Recommendations:
      1. Change the default password. (By default, most Raspberry Pi OS-derived OS installations create a pi user with the password set to raspberry, as documented by the Raspberry Pi Foundation. This should be changed to a strong pass phrase and stored securely by a trusted administrator.)
      2. Disable automatic login: System OptionsBoot / Auto LoginConsole (Text console, requiring user to login.)
      3. Disable the camera interface: Interface OptionsLegacy CameraNo
      4. Disable the Raspberry Pi’s VNC server: Interface OptionsVNCNo
      5. Disable the Raspberry Pi’s SPI interface: Interface OptionsSPINo
      6. Disable the I2C interface: Interface OptionsI2CNo
      7. Disable the serial interface, both the login shell and the port itself: Interface OptionsSerialNo
      8. Disable the 1-Wire interface: Interface Options1-WireNo
      9. Disable the remote GPIO network interface: Interface OptionsRemote GPIONo
  6. Tune the filesystem:
    1. Enable automatic filesystem integrity checking, for example by invoking the following command, making sure to replace root with the correct label of your filesystem:
      sudo tune2fs -i 1m "LABEL=rootfs"
      

Consider following the above procedure with a security hardening guide relevant for your chosen Operation System. For example, as Raspberry Pi OS is a Debian-derived OS, read the Securing Debian Manual and perform the hardening steps described there to further secure the Operating System itself.

Essential security tooling installation

Once the Operating System is installed, updated, and configured, you should consider taking extra security precautions. This section describes a non-exhaustive listing of additional steps to take to further secure your installation. As mentioned earlier, refer to the Securing Debian Manual for additional recommended security hardening steps.

dm-crypt

If you did not encrypt your hard drive(s) during the Operating System installation, you can (and should?) do so as soon as possible thereafter.

TK-TODO

Tor

Tor is an anonymizing overlay network known as a mix network (or "mixnet" for short). It sits in between your application(s) and your network connection, providing an extra layer of protection between your (self-hosted) services and the public Internet. Tor is useful for privacy-enhanced communication, cryptographic naming services (through its Onion service or “hidden service” features), and firewall traversing capabilities.

See the Tor page for a further treatment of using Tor as an infrastructure provider. The remainder of this section considers Tor in the specific context of a Raspberry Pi.

Install Tor on a Raspberry Pi 1 running Debian-based GNU/Linux

The Raspberry Pi 1 (all models) have an older, ARM CPU. You can confirm this by running uname -m at a command line. The output will be something like armv6l, indicating an older ARM chip. (Newer Raspberry Pi’s, the Raspberry Pi 2 and the Raspberry Pi 3, ship with a newer ARM chip, which report armv7l when queried with uname -m). This older version of the processor requires us to build Tor packages from source.

NOTE: You can also install Tor “the easy way” by doing sudo apt install tor, but this is unlikely to provide you with a stable, officially supported version of Tor. Installing Tor this way on a Raspberry Pi 1 will mean your Tor installation will lack critical security patches. If you do not want to follow these instructions, consider acquiring a Raspberry Pi 2 or a Raspberry Pi 3, instead.

The Tor Project maintains simple instructions for building Tor from source, which work nicely on a Raspberry Pi 1. Those instructions are duplicated here in our own voice, but refer to the primary source at the linked page for the most up-to-date information.

Install Tor on a Raspberry Pi 2 or 3 running Debian-based GNU/Linux

Installing Tor on a Raspberry Pi model 2 or 3 is usually as simple as sudo apt install tor, but be certain to check the version of Tor available in your Operating System distribution’s package repositories:

sudo apt update && apt show tor | grep -i version

Compare the version of Tor available from the command output above to the latest stable versions available from the Tor project.

Alternatively, and if the repositories are too far out of date, you can also build Tor from source yourself.

Secure Shell

Raspberry Pi OS-derived systems automatically install OpenSSH. However, you should check the version (using ssh -V) and update if necessary (using sudo apt update && sudo apt install openssh-server), as well as harden the default installation to avoid known vulnerabilities.

See SSH for details.

Software installation

Once the Operating System is installed, updated, and configured, you can further customize your system by choosing purpose-specific software tools for your use case. Some examples:

You can, of course, run any software you wish on your Pi. See the Awesome Selfhosted list for quality recommendations.

Post-software installation security considerations

After you have installed a given software package, consider performing the following steps to ensure the tool does not compromise you or your comrades.

Network security

Audit listening ports

If you don’t require the use of a network-capable service, don’t run it. This keeps the number of open (listening) ports on your server to a minimum. Audit the system for listening ports on a regular basis to ensure no services are unintentionally accessible over the network.

For example, to see a listing of listening TCP and UDP ports:

ss --listening --tcp --udp

Ensure that the output of this command shows you only the output you expect to see. The following example output shows the machine is accessible over IPv4 and IPv6 at TCP port 22, and that the sshd process is listening to that port:

sudo ss --listening --tcp --numeric --processes
State      Recv-Q Send-Q                                               Local Address:Port                                                 Peer Address:Port
LISTEN     0      128                                                              *:22                                                              *:*      users:(("sshd",pid=942,fd=3))
LISTEN     0      128                                                             :::22                                                             :::*      users:(("sshd",pid=942,fd=4))

This is expected if you run an SSH server. If you do not intend to be running an SSH server, this is a concern.

Activate a firewall

Use a firewall such as iptables(8) to enable explicit filtering of inbound (or outbound) network traffic. Since software packages sometimes have insecure defaults or unexpectedly open listening sockets, a firewall can prevent you from accidentally exposing an insecure service to the network.

Remove identifying service information from banners and headers

Many network services provide details about their implementation to clients attempting to make use of those services. For instance, Web servers often identify themselves as a certain piece of software at a specific version. This information is useful to attackers and should therefore be limited or omitted.

For example, if you run the Lighttpd HTTP server, you could remove the HTTP Server header from its responses to clients with the following configuration line in your server’s /etc/lighttpd/lighttpd.conf file:

server.tag = ""

This limits the amount of information attackers can acquire about your infrastructure.

Different services will have different identifying details and will need to be configured in different ways.

By way of another example, Debian-based GNU/Linux distributions that ship with OpenSSH have an additional SSH configuration directive to remove Operating System information from the server’s SSH header. Consider adding the following to your server’s /etc/ssh/sshd_config file:

DebianBanner no

Be certain to check the specific service you are running for security hardening instructions before making that service available to a wider populace.

Host-based security precautions

Perform regular backups

Making regular, complete backups, and storing those backups at an off-site facility for an extended period of time is one of the most important disaster recovery activities you should take. Tools such as Duplicity make performing backups a lot easier, although in the simplest case you can typically simply copy a filesystem hierarchy from one disk to another. Describing backups at length is beyond the scope of the guide, but this section is nevertheless presented as a reminder not to overlook this crucial part of system maintenance and to treat it as a security precaution in its own right.

Disable logging

Most of the time, activity logging is used for debugging and troubleshooting purposes, or as a collection engine for future analytics, typically in the service of surveillance capitalism. Therefore, unless you need to debug a problem, it is recommended that you disable the logging behavior of as many running services as possible, as much as possible. You can always re-enable logs for a short time during troubleshooting efforts if you need to.

Disable login logging

Out of the box, most Operating Systems maintain various logs of user logins (both successful and unsuccessful attempts), sometimes along with a user name and/or a remote IP address of the initiator. Consider removing the logs of successful logins, but retain the unsuccessful attempt logs so that you may monitor your system for brute force password guessing attacks using software such as Fail2ban.

Note: Depending on one’s threat model, be aware that retaining logs of even unsuccessful logins may expose operational security blunders such as the (user)names of system operators. For example, if a hypothetical system administrator named Sam Smith (whose username is samsmith) has a missing or misconfigured SSH config file, executing the command ssh example.com may result in a line such as Aug 9 00:52:45 example.com sshd[15164]: input_userauth_request: invalid user samsmith [preauth] being loged to example.com’s /var/log/auth.log file. If this log entry exists when the server is compromised, the server operator can be more easily identified. Minimize this risk by religiously following good operational security guidelines, and configure your SSH client as soon as you have authentication credentials so as to automate these good opsec practices as quickly as possible.

A non-exhaustive list of the various successful login logs that you may wish to audit or nullify on your system include:

Meanwhile, a non-exhaustive list of the various unsuccessful login logs that you may wish to audit or nullify on your system include:

Replace the wtmp and lastlog files with a symbolic link to /dev/null in order to disable it:

sudo rm /var/log/wtmp* /var/log/lastlog # Remove all historical successful login logs.
sudo ln -s /dev/null /var/log/wtmp      # Put symbolic links in place of these files.
sudo ln -s /dev/null /var/log/lastlog

In addition to the filesystem locations listed above, many modern GNU/Linux systems aggregate this information in the /var/log/auth.log file. See also §4.11.3 of the Securing Debian Manual for more information about login logging, or login.defs(5) in the manual. See also Caisleán example login logging hardening configurations.

utmp file special case

The utmp file cannot be removed on GNU/Linux kernels (it will be recreated on boot), but it can be protected by removing world-readable permissions from the file:

sudo chmod o-r /var/run/utmp # Disallow access to `who(1)` and similar functions for regular users.

See logrotate § Disable current login reporting for information regarding making this change persistent across reboots.

Disable service logs

If you run a service that you cannot stop from logging, you may have a number of other options:

Shredding log files with logrotate

If you cannot create a situation where zero information is logged to disk, you can still clean up after the service’s daemon yourself by using your system’s built-in log rotation facility, which is likely the logrotate(8) utility. For each service you add that writes logs, create a file in the /etc/logrotate.d directory. That file should contain a logrotate configuration, similar to the following example:

# This is an example to show how you can use logrotate to eradicate a service's logfiles.
# See logrotate.conf(5) for a fuller explanation of these and other available directives.
/path/to/server/log.txt {
        daily
        copytruncate
        rotate 0
        size 1
        shred
        missingok
        nomail
        postrotate
                shred --remove /path/to/server/log.txt.1
        endscript
}

Restrict process privileges with systemd

When writing systemd service units, consider including the following directives in the unit’s [Service] section to harden the service unit’s execution context:

# Harden the unit's execution context.
# See systemd.exec(5) for more details about these directives.

# Deny attempts to create writable and executable memory.
MemoryDenyWriteExecute=true

# Deny access to `execve()` to help prevent exploitation of potential privilege escalation vulnerabilities.
NoNewPrivileges=true

# Restrict access to physical storage media.
# With `PrivateDevices=true`, the process can only access data through mounted filesystems
# and not by accessing the block devices (under `/dev`) that make up the disk itself.
PrivateDevices=true

# Restrict access to network interfaces.
# This should only be enabled for services that should not have access to the network.
#PrivateNetwork=true

# Protects the `/tmp` directory by giving each process its own `/tmp` hierarchy.
PrivateTmp=true

# Re-map the process's own user namespace so it is disconnected from other processes's user namespace.
PrivateUsers=true

# Makes the `/sys/fs/cgroup` directory hierarchy read-only to all processes of the unit.
ProtectControlGroups=true

# Makes the `/home`, `/root` and `/run/user` directories inaccessible and appear empty to the unit's processes.
ProtectHome=true

# Disallows the process from making modifications to loaded kernel modules.
ProtectKernelModules=true

# Disallows the process from making changes to kernel variables (such as those set via `sysctl(8)`).
ProtectKernelTunables=true

# When set to `true`, this makes the `/usr` and `/boot` directories read-only.
# When set to `full`, this additionally makes the `/etc` directory hierarchy read-only, as well.
ProtectSystem=full

# Disallows the process from changing the default Linux kernel personality. See `personality(2)` for details.
LockPersonality=true

# Disallows the process from using sockets other than UNIX domain, IPv4, and IPv6 sockets.
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6

# Disallows the process from using kernal scheduling APIs to change the CPU scheduler's settings; see `sched(7)` for deatils.
RestrictRealtime=true

AppArmor

AppArmor is a Linux kernel module that implements MAC policies via the LSM framework. ARM builds of the Raspberry Pi OS, i.e., the kernels that run on Raspberry Pi hardware, do not enable support for AppArmor by default. Therefor, to enable AppArmor on a Raspberry Pi, one must recompile their own kernel.

In many situations, it may be preferable to containerize applications using a container runtime such as Docker rather than compiling (and then maintaining) customized kernel builds. That said, see AppArmor § Enabling AppArmor on a Raspberry Pi for instructions on adding support for and enabling AppArmor enforcement on the Raspberry Pi Foundation’s Linux kernel forks.