2. Customizing Raspbian


These Raspberry Pi topics are outdated. Be sure to check more current sources. I’m keeping this information here for reference and hope to update it during 2021.

The Raspbian operating system is the official OS for the Raspberry Pi, and arguably, the best supported. More important for my purposes is the fact that it is based on Debian Linux, my OS of choice for over 20 years now. These pages summarize the steps that I take to customize a freshly-installed raspbian image to my liking, over-riding many of the annoying and insecure defaults.

These steps are all performed using the command line, avoiding menu-driven configuration programs or editors to allow scripting. You may, of course, use an editor to make the changes shown below as you see fit. This isn’t really meant to be a hand-hold tutorial, so you’ll want to change the steps shown here to suit your preferred configuration method. In particular, I use command-line edits using the sed editor that you might wish to make using your preferred text editor.

I use these steps to create a master image, which I copy to disk, then burn a copy to microSD whenever doing a new install on a Raspberry Pi.

Eventually, I plan to convert all of these steps into Ansible playbooks to completely automate my configuration process, including keeping running devices up to my baseline configuration. Most of these steps apply to any other debian-based distribution, so can be used on non-Raspberry Pi computers.

2.1. Update installed packages

Update the installation cache from the raspbian repository:

sudo apt update

Update installed packages to the latest version:

sudo apt -y dist-upgrade

2.2. Install preferred packages

I like to install a variety of packages to customize or enhance the default configuration:

sudo apt -y install \
fail2ban \
openssh-server \
openssh-client \
tmux \
byobu \
molly-guard \
unattended-upgrades \
python-pip \
virtualenv \
virtualenv-clone \
virtualenvwrapper \
libraspberrypi-dev \
git \
zsh \
vim \
slay \
lsof \
traceroute \
iperf \
iftop \
nmap \
lynx \
curl \
htop \
locales \
localepurge \
deborphan \
exfat-fuse \
exfat-utils \
fbi \
dcfldd \
durep \
ufw \
time \
transmission-cli \
uprecords-cgi \
uptimed \
ssmtp \
mailutils \

Some of these are already installed, but I specify them here to keep track across raspbian versions. Non-raspbian debian-based distributions may not include some by default, so I specify them here. The apt installation tools are smart enough to identify those already installed and simply skip them.

Here’s a breakdown of these packages:

2.2.1. Security & system hardening

  • fail2ban: block access on repeated access attempts.

  • openssh-server: ssh server programs

  • openssh-client: ssh client and support programs

  • unattended-upgrades automated installation of security updates

  • molly-guard: require entering hostname to reboot via ssh

  • nmap: network port scanning and testing

  • ufw: simple firewall based on iptables

2.2.2. Development tools

  • git: source code version control

  • libraspberrypi-dev: raspberry pi development libraries

  • python-pip: pip installer for python libraries

  • python-dev: python development libraries

  • virtualenv: python virtual enviornment manager

  • virtualenv-clone: clone virtual python installation

  • virtualenvwrapper:

2.2.3. System configuration & maintenance

  • slay: kill all programs associated with a user

  • htop: console-based system monitor

  • locales: manage locales

  • localepurge: remove cache files for unused locales

  • deborphan: remove unused installation packages

  • exfat-fuse: filesystem support for exfat

  • exfat-utils: support programs for exfat filesystem

  • lsof: view open files and network connections

  • iperf: network performance monitor

  • rpi-update: update rpi firmware to bleeding edge

  • traceroute: trace netwnork path to destination

  • dcfldd: enhanced disk imager support multiple concurrent writes

  • uprecords-cgi: view system uptime milestones

  • uptimed: track system uptime

  • iftop: monitor network interface

  • time: time program execution and resources

  • ssmtp: simple, secure ssmtp mail server

2.2.4. Preferred applications & tools

  • vim: enhanced vi-like editor

  • zsh: enhanced shell

  • byobu: terminal multiplexer

  • tmux: terminal multiplexer

  • fbi: display images on framebuffer (for splash screens)

  • durep: console-based disk utilization mapper

  • lynx: command-line web browser

  • curl: work with web pages from the command-line

  • transmission-cli: command-line bittorrent client

  • mailutils: send and read email at the command-line

2.3. Localization

Raspbian ships configured for a GB user, including locale, timezone and keyboard settings. These are the steps I use to set it up for my US-based setup.

2.3.1. Configure timezone

Set the timezone to US/Eastern:

sudo rm /etc/localtime
sudo ln -s /usr/share/zoneinfo/US/Eastern /etc/localtime
echo "US/Eastern" | sudo tee -a /etc/timezone
sudo dpkg-reconfigure -f noninteractive tzdata

2.3.2. Configure locales

Remove unneeded default GB locales and generate US.UTF-8 locales:

sudo apt -y install localepurge
sudo sed -ri -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen
sudo sed -ri -e 's/en_GB.UTF-8 UTF-8/# en_GB.UTF-8 UTF-8/' /etc/locale.gen
echo 'LANG="en_US.UTF-8"' | sudo tee -a /etc/default/locale
sudo dpkg-reconfigure --frontend=noninteractive locales
sudo LANG=en_US.UTF-8 && update-locale

2.3.3. Set keyboard type to US

Install console configuration utility:

sudo apt -y install console-data

Edit or replace /etc/default/keyboard with:

# Consult the keyboard(5) manual page.



Update console data:

sudo dpkg-reconfigure --frontend=noninteractive console-data

2.4. Improve console readability and appearance

Set console font to something readable at 1080p.

Install inconsolata console font:

apt install -y fonts-inconsolata

Edit /etc/default/console-setup:

# Consult the console-setup(5) manual page.



# The following is an example how to use a braille font
# FONT='lat9w-08.psf.gz brl-8x8.psf'

2.5. Change system-wide default editor

One of the best decisions I made early-on in my Linux learning was to learn the vim editor. While there’s nothing wrong with the default nano editor, I find it a bit ironic that an editor that emulates WordStar of old is considered more user friendly. Feel free to skip this step if you’re more comfortable with a different editor.

Set default system-wide editor to vim:

apt install -y vim
sudo update-alternatives --set editor /usr/bin/vim.basic

2.6. Change hostname

Let’s face it: typing “raspberrypi” repeatedly gets tedious fast. And once you’ve got more than one Raspberry Pi running, you need to differentiate between them. Renaming your Pi by changing the hostname is the easiest way to fix this:

# change localhost reference in /etc/hosts
sudo sed -i "s/*raspberrypi\t<newhostname>/g" /etc/hosts
# change system hostname file
sudo sed -i "s/raspberrypi/<newhostname>/g" /etc/hostname
# change system mailname file (if present)
sudo sed -i "s/raspberrypi/<newhostname>/g" /etc/mailname

Replace all occurrences of <newhostname> with your chosen hostname without the angle brackets.

2.7. Test changes

At this point, you’ve done a lot of system tweaking. Although not absolutely necessary, rebooting at this point and testing your changes is a good idea. Notably, the hostname should be changed before proceeding with some of the following steps. Be sure to connect using the new hostname before proceeding.

2.8. Configuring wifi

There are multiple ways to configure wifi on raspbian. The most flexible for my usual headless configuration is through editing the /etc/wpa/wpa_supplicant.conf file. The advantages of this approach include:

  • Support for configuring country-specific wifi parameters.

  • Support for seamlessly connecting to multiple networks (SSIDs) without reconfiguration.

  • Support for prioritization of SSID connections when multiple are available.

  • Support for encrypted pre-shared keys (passwords) in the configuration file.

2.8.1. Country-specific configuration

Wifi networks operate on unlicensed frequency bands, meaning anybody can use them. However, this does not mean there aren’t restrictions. The specific frequencies available vary from jurisdiction to jurisdiction, as do rules for maximum output power. To avoid possible legal consequences and be a good neighbor in general, set the country= parameter:


2.8.2. SSID configuration

You can configure your wpa_supplicant.conf file to support roaming between multiple networks (each identified by a unique SSID) and attach automatically whenever one is in range. This is done by adding a network= stanza to the configuration. At minimum, each stanza must contain the following lines:

  • ssid= identifies the “service set identifier” (SSID) or name of your wifi network. The ssid should be specified in quotes.

  • psk= identifies the “pre-shared key” (PSK) or password associated with the SSID. The psk should be specified in quotes.

Here’s a simple example:


2.8.3. Pre-shared key encryption

Note that the psk is stored in unencrypted, clear-text in the configuration file. Although access to the file is restricted, there is always a chance someone might stumble across this information. It is good practice to encrypt passwords stored on disk. The wpa_passphrase command can be used to generate an encrypted psk given your SSID and PSK:

$ wpa_passphrase MySSID mypassphrase

Note that the encrypted psk is listed without quotes, whereas the clear-text version is enclosed in quotes. You could simply paste these lines verbatim into your wpa_supplicant.conf file. However, after testing, removal of the clear-text #psk= line is recommended.

2.8.4. Open network configuration

If you are connecting to an open wifi network such as a hotel, you’ll need to add an open network clause:



Please be sure to follow the recommended security hardening steps in this document when connecting to any network you don’t explicitly control!

2.8.5. Identifying the network

Assigning an id_str= line is optional, but can be useful to differentiate between wireless networks within /etc/network/interfaces. If no id_str is specified, it defaults to default.

2.8.6. Assigning network priority

Each network can be assigned a priority= parameter. If multiple networks are available, those with the highest priority will be selected. If two networks have the same priority, the one with the strongest signal will be selected. Unless specified, priority is set to 0.

I use this feature when doing testing. I may have a testing wifi network, or a cellular hotspot running that I want to connect to if available, but otherwise default to whatever’s available locally.

2.8.7. Putting it all together

Here’s an example of a complete /etc/wpa_supplicant/wpa_supplicant.conf supporting multiple networks, each with unique SSIDs and priorities:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev

    #psk="HomePassphrase" <- REMOVE AFTER TESTING

    #psk="HostspotPassprhase" <- REMOVE AFTER TESTING




  • proto=WPA2

  • key_mgmt=WPA-PSK

  • pairwise=CCMP

  • group=CCMP

2.9. Configure ssmtp for sending email

ssmtp is described in the debian repositories as “A secure, effective and simple way of getting mail off a system to your

mail hub”. It has just enough smarts to pass local mail off to your main email relay, and nothing more. It doesn’t handle incoming mail at all, so security concerns are minimized. I like to use it to send admin notification emails and the like.

Configure ssmtp:

sed -i "s/root=.*/root=<[email protected]>/g" /etc/ssmtp/ssmtp.conf
sed -i "s/hostname=.*/hostname=<hostname>/g" /etc/ssmtp/ssmtp.conf
sed -i "s/mailhub=.*/mailhub=<your.mail.domain>/g" /etc/ssmtp/ssmtp.conf
sed -i "s/rewriteDomain=.*$/rewriteDomain=<your.domain>/g" /etc/ssmtp/ssmtp.conf
sed -i "s/usetls=.*$//g" /etc/ssmtp/ssmtp.conf
sed -i "$ i usetls=yes" /etc/ssmtp/ssmtp.conf
sed -i "s/usestarttls=.*$//g" /etc/ssmtp/ssmtp.conf
sed -i "$ i usestarttls=yes" /etc/ssmtp/ssmtp.conf
sed -i "s/authuser=.*$//g" /etc/ssmtp/ssmtp.conf
sed -i "$ i authuser=<yourname>" /etc/ssmtp/ssmtp.conf
sed -i "s/authpass=.*$//g" /etc/ssmtp/ssmtp.conf
sed -i "$ i authpass=<yourpassword>" /etc/ssmtp/ssmtp.conf

2.10. Configure uptimed for tracking system uptime

uptimed tracks your system uptime, and optionally sends you notification emails when milestones or records are hit. This can be useful for tracking your system availability and generally bragging about system stability. Here’s an example of the output it generates:

% uprecords
     #               Uptime | System                                     Boot up
->   1    43 days, 11:03:00 | Linux 4.9.35-v7+          Wed Sep 20 02:38:48 2017
     2    18 days, 05:41:20 | Linux 4.9.35-v7+          Thu Aug 31 12:35:57 2017
     3     1 day , 06:44:25 | Linux 4.9.35-v7+          Mon Sep 18 18:17:14 2017
NewRec    25 days, 05:21:39 | since                     Sun Oct  8 08:20:08 2017
    up    62 days, 23:28:45 | since                     Thu Aug 31 12:35:57 2017
  down     0 days, 01:37:06 | since                     Thu Aug 31 12:35:57 2017
   %up               99.893 | since                     Thu Aug 31 12:35:57 2017

Configure uptimed:

sed -i "s/EMAIL=.*/EMAIL=<[email protected]>/g" /etc/uptimed.conf
sed -i "s/SEND_EMAIL=.*/SEND_EMAIL=1/g" /etc/uptimed.conf

2.11. Install versacrypt

Versacrypt provides robust, cross-platform file encryption.

Install versacrypt:

wget https://launchpad.net/veracrypt/trunk/1.19/+download/veracrypt-1.19-raspbian-setup.tar.bz2
bunzip2 veracrypt-1.19-raspbian-setup.tar.bz2
tar -xpvf veracrypt-1.19-raspbian-setup.tar
chmod +x ./veracrypt-1.19-setup-console-armv7
sudo ./veracrypt-1.19-setup-console-armv7

2.12. Install syncthing

syncthing provides cross-platform, peer-to-peer file synchornization much like dropbox, but without the need to store data on 3rd party servers. It’s great for file synchronization that “just works” once configured. I use it for:

  • Editing the source files for these pages on my non-Linux laptop using the Sublime Text editor for ease of formatting. Often times, I’m editing files when completely disconnected from the Internet.

  • When I’m back in network range, syncthing syncs the source files over to my raspberry pi where I generate the html pages. I currently do this manually, but plan to automate the detection of changes and triggering the build.

  • When connected to the Internet, syncthing synchronizes the generated static html pages to my cloud-hosted server where they are served using nginx for speedy rendering. (This is what you are viewing now.)

Install syncthing peer-to-peer file synchronization:

wget -O - https://syncthing.net/release-key.txt | sudo apt-key add -
echo "deb http://apt.syncthing.net/ syncthing release" | sudo tee -a /etc/apt/sources.list.d/syncthing-release.list
sudo apt update
sudo apt -y install syncthing

While it is possible to configure the syncthing configuration web page service to listen on a network-facing port, this is generally not a good idea, especially if your Raspberrry Pi is going to be moved around on different networks. Instead, access the webpage listening to a local-only (localhost) port on the Raspberry Pi using the port tunneling feature of ssh. On your computer, access the Raspberry Pi using:

ssh -L 8000:localhost:8384 hostname

This will connect to your Raspberry Pi via ssh and create a tunnel mapping port 8000 on your computer to port 8384 (the syncthing configuration page) listening to port 8384 on the Raspberry Pi. Acces the configuration webpage by opening a browser on your computer and opening http:://localhost:8000. You will need to login to the Raspberry Pi using ssh in this manner to administer syncthing.

2.13. Hardening the system

The Raspberry Pi foundation made some unfortunate decisions regarding security that pose unacceptable risks for any system that might be exposed to the outside world. Most notably, they configured the system to automatically login as the default pi user with the password raspberry on every new install. To make things worse, they gave the pi user root-level access via the sudo command without even entering a password. As a result, any Rasperry Pi exposed to the Internet is quickly identified and compromised with the default settings. While they made enabling ssh a separate step and inserted cautions, these measures are woefully inadequate.

2.13.1. Harden ssh server configuration

The first set of steps involve hardening the ssh server configuration on our Raspberry Pi. Regenerate ssh host keys

Host keys uniquely identify the computer (host) you are connecting to. This provides mutual protection to both you and the host you’re logging into as ssh uses keys to verify both the user and the target host. If one or the other is changed, ssh will detect this and reject the connection (if using user keys), or issue warnings (if using host keys).

Regenerate ssh host keys for our newly-updated Raspberry Pi:

sudo rm -v /etc/ssh/ssh_host_*
sudo dpkg-reconfigure openssh-server


This should be done after renaming and rebooting the host

If you have previously connected to your Raspberry Pi via ssh, the host keys have changed. On your next connection attempt, you will probably see a scary message like this:

% ssh [email protected]
The ECDSA host key for dietpi has changed,
and the key for the corresponding IP address X.X.X.X
has a different value. This could either mean that
DNS SPOOFING is happening or the IP address for the host
and its host key have changed at the same time.
Offending key for IP in /Users/yourname/.ssh/known_hosts:24
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
Please contact your system administrator.
Add correct host key in /Users/yourname/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /Users/yourname/.ssh/known_hosts:50
ECDSA host key for dietpi has changed and you have requested strict checking.
Host key verification failed.

This is ssh letting you know that the host keys changed, which is a good thing. To get rid of this message, do the following:

ssh-keygen -R X.X.X.X

If you receive similar warnings about the hostname, try:

ssh-keygen -R <hostname> Create a non-default user account

There are reportedly some programs that depend on the pi user to run, although I’ve yet to encounter any after several years of using the Raspberry Pi. Just to be cautious, I create a non-default user account with the same access rights as the pi user, then simply disable the pi account in case I do find I need it later.

Create a non-default user account for system access:

sudo adduser --gecos "Your Name,,," <yourname>
for NAME in $(groups pi| cut -f 1-3 -d " " --complement); do sudo adduser <yourname> $NAME; done
sudo usermod -a -G sudo <yourname>

Replace all instances of <yourname> with your chosen single-word username without angle brackets. Always select a strong password. Create system ssh user group

By default, openssh is configured to allow any user with a valid username and password access. If you connect any system to the Internet, you’ll quickly find your system bombarded by automated login attempts using a bewildering array of usernames and passwords culled from lists of defaults and common passwords. Rather than take the chance that an installed program or careless user uses a weak password, I prefer to restrict ssh access to only those users I explicitly permit access. This is done by creating a system sshusers group:

sudo addgroup --system sshusers

Only users added explicitly to the sshusers group will be permitted access. Add the newly-created non-default user to ssh user group:

sudo adduser <yourname> sshusers Harden the ssh server

Finally, configure ssh to enforce these restrictions:

  • Permit only members of the sshusers group access via ssh.

  • Allow root access only using key-based access. (Note: disable all root access by setting to ‘no’)

  • Permit access from our local network using passwords.

  • Require keys if accessing from anywhere else.

Edit /etc/ssh/sshd_config to include:

# restrict ssh access to specific users
AllowGroups sshusers
# allow root access only with ssh keys
# unless needed, disable completely with 'no'
PermitRootLogin without-password

# permit password from rfc1918 local addresses
# edit to match your local network
Match Address,,,
 PasswordAuthentication yes
# global option no password auth (keys only)
PasswordAuthentication no

Change the IP range specified in the Match Address line to match your network(s). Remember that you will only be able to connect using password authentication when both you and the Raspberry Pi are on specified network address ranges.


Add detail on changing to non-default port Restart and test hardened ssh configuration


It is easy to lock yourself out of your system if you are using ssh for access. If you make a mistake during configuration, you might be prevented from logging in again. Keep your initial ssh login open in a separate window or session while testing your new account. If you make a mistake, you are still logged in as the default pi user and can fix things.

Restart the ssh service:

sudo systemctl restart ssh

Test your new account by logging in via ssh and confirming that you can gain root access using sudo. If this doesn’t work, you can make fixes using your pi user connection (if you didn’t close it). Only close your pi user session after testing this step. Defang the pi user account

Once you are certain your new account is fully functional and that you won’t lock yourself out, defang the pi user account. If we ever need the account, we can re-enable it.

Change the pi user password:

passwd pi

Lock and expire the pi user account:

passwd —lock pi
usermod —expiredate 1 pi

Remove the pi user from the sudo group:

sudo deluser pi sudo

Comment out the pi user from the sudoers configuration file:

sudo sed -ri -e 's/pi ALL=(ALL) NOPASSWD: ALL/# pi ALL=(ALL) NOPASSWD: ALL/' /etc/sudoers.d/010_pi-nopasswd Add public keys to ssh authorized_keys


If you move the Raspberry Pi to a network not listed in the Match Address stanza in /etc/ssh/sshd_config, you will only be able to log in with ssh using keys listed in your user’s ~/.ssh/authorized_keys file on the target (Raspberry Pi) system. Be sure to copy over your public key (typically ~/.ssh/id_rsa.pub) to the Raspberry Pi before attempting to connect using it!

Connect to the Raspberry Pi using your user account and set up public key authentication for your user. You should be logged in using the account you will be using for remote access at this point.

Verify that your ~/.ssh folder exists:

ls -ld ~/.ssh
drwx------ 3 yourname yourname 4096 Oct 18 13:03 /home/yourname/.ssh

Note the drwx------ permissions. This indicates that .ssh is a directory (d) with read, write and execute permissions for the user (yourname) and no permissions for others. See man chmod for more details on file permissions. These permissions must be set correctly for ssh access.


Incorrect setting of ~/.ssh` directory permissions can prevent access using public keys.

If ~/.ssh doesn’t exist, create it and limit access to your user only:

mkdir ~/.ssh # create the directory
chmod go-rwx ~/.ssh # remove read, write and execute for group and others

Next, we need to create the ~/.ssh/authorized_keys file if it doesn’t exist. ssh stores public keys for authorized access in this file. Without your public key in this file, you will not be able to use key-based authentication to access the Raspberry Pi. If password authentication is not enabled for the network you are connecting from, you can be locked out.

Verify ~/.ssh/authorized_keys does not exist:

ls -l ~/.ssh/authorized_keys
ls: cannot access '/home/yourname/.ssh/authorized_keys': No such file or directory

If the file does not exist, create it and set secure access permissions:

touch ~/.ssh/authorized_keys
ls -l ~/.ssh/authorized_keys
-rw-r--r-- 1 yourname yourname 0 Oct 20 15:41 /home/yourname/.ssh/authorized_keys
chmod go-rwx authorized_keys
ls -l ~/.ssh/authorized_keys
-rw------- 1 yourname yourname 0 Oct 20 15:41 /home/yourname/.ssh/authorized_keys


Incorrect setting of ~/.ssh/authorized_keys file permissions can prevent access using public keys.


Add detail on copying public keys.

Append the contents of your public key (usually ~/.ssh/id_rsa.pub) on the computer that you will be using to connect to the Raspberry Pi from to the ~/.ssh/authorized_keys file on the Raspberry Pi you will be connecting to. Append (do not overwrite) the contents of your public key file (with the .pub extension) to ~/.ssh/authorized_keys:

cat >> ~/.ssh/authorized_keys


Be sure to copy over the public key file, not your private key. By default, public keys have the .pub file extension.

If connecting using the openssh client (recommended), you can specify the -v option multiple times to get additional troubleshooting detail. There is a lot of information, but you’ll usually find the cause of any problems in the output if you read carefully:

ssh -vvv <yourname>@<yourhost>

2.13.2. Bonus Tip: Don’t use login names for email

You should avoid giving a potential attacker more information than necessary to access your system. A popular method of finding user login names is to scrape the web for email accounts. I’ve seen email account names that I created over a decade ago and long-since abandoned used in automated login attempts, which implies someone is taking the trouble to associate a stock of email accounts with my domain and automating the access attempts against my system. Fortunately, my login usernames and email account names are entirely different. By restricting ssh access to only users explicitly listed in my sshusers group as described above, I’ve eliminated these accounts as a threat.

If you are setting up your own email server, in addition to a host of other methods to secure the system that you can find elsewhere, set up email-only accounts that are not used for anything but email access, and be sure not to include these in your sshusers group.

2.14. Contact and feedback

You can find me on Reddit where I lurk in many of the raspberry pi-related subreddits. You can email me directly at projects@ttlexceeded.com