Debian on Raspberry Pi 4 8GB
I am a big fan of Debian. I like the philosophy and the fact it is not owned by a company. With the death of CentOS I feel it becomes even more important.
I know you can get Ubuntu Server 20.04 LTS x64 for the Pi but I want Debian.
This is run as an unofficial side project at https://raspi.debian.net/
This post covers the little niggles I encountered getting it all setup and working like I wanted ready for anything else you wanted to do with your Pi.
Download the latest image file from https://raspi.debian.net/tested-images/
Flash it onto your MicroSD card.
xzcat raspi_4.img.xz | sudo dd of=/dev/{YOUR_DEVICE} bs=64k oflag=dsync status=progress
On first boot you need to login locally. The root account has no password and is therefore not enabled for remote login via SSH.
Now before you do anything else set a password for the root account.
passwd root
Initial setup
Install sudo, add a new user, set a password and add them to the sudo.
apt install sudo
useradd -m john-doe
passwd little-death
usermod -aG sudo john-doe
Change the host name and update the hosts file.
nano /etc/hostname
rpi4-debian10
Quit and save the file.
nano /etc/hosts
Add an additional line at the bottom of the file.
127.0.1.1 rpi4-debian10
Quit and save the file. Without this entry you get an error when running apt commands.
Look up your IP address.
ip a
You can now login via SSH with your new user using the IP address you just looked up.
Once logged in you will see that the command prompt is only a $ sign. This is because the shell is /bin/sh
You can change the shell for your new user with the command.
chsh -s /bin/bash
You will be prompted for the password of the user. Once done logout of the SSH session with exit and then back in again.
Now test upgrading the system.
sudo apt update
sudo apt upgrade
Install locales. If you don’t do this you will get a warning whenever installing software.
sudo apt-get install locales-all
Static IP address issue
So I went to set a static IP as I am used to.
sudo nano /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)
# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
auto eth0
iface eth0 inet static
address 192.168.0.2
netmask 255.255.255.0
broadcast 192.168.0.255
gateway 192.168.0.1
dns-nameservers 192.168.0.4 192.168.0.6
# This is an autoconfigured IPv6 interface
iface eth0 inet6 auto
But after a reboot an ip a shows me a static and dynamic address?
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether dc:a6:32:e0:cc:dc brd ff:ff:ff:ff:ff:ff
inet 192.168.0.94/24 brd 192.168.0.255 scope global dynamic eth0
valid_lft 86386sec preferred_lft 86386sec
inet 192.168.0.2/24 brd 192.168.0.255 scope global secondary eth0
valid_lft forever preferred_lft forever
inet6 2001:8b0:1741:ec2e:dea6:32ff:fee0:ccdc/64 scope global dynamic mngtmpaddr
valid_lft 4294965554sec preferred_lft 4294965554sec
inet6 fe80::dea6:32ff:fee0:ccdc/64 scope link
valid_lft forever preferred_lft forever
3: wlan0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether dc:a6:32:e0:cc:dd brd ff:ff:ff:ff:ff:ff
The culprit was the file /etc/network/interfaces.d/eth0
Change
auto eth0
iface eth0 inet dhcp
to
auto eth0
iface eth0 inet static
I also changed the fourth line in /etc/network/interfaces from
source-directory /etc/network/interfaces.d
to
source-directory /etc/network/interfaces.d/*
Now after a reboot all was well with the output from ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether dc:a6:32:e0:cc:dc brd ff:ff:ff:ff:ff:ff
inet 192.168.0.2/24 brd 192.168.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 2001:8b0:1741:ec2e:dea6:32ff:fee0:ccdc/64 scope global dynamic mngtmpaddr
valid_lft 4294966050sec preferred_lft 4294966050sec
inet6 fe80::dea6:32ff:fee0:ccdc/64 scope link
valid_lft forever preferred_lft forever
3: wlan0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether dc:a6:32:e0:cc:dd brd ff:ff:ff:ff:ff:ff
Swap
The Debian Pi image has no swap file for whatever reason. To create a small swap file enter the following commands.
Elevate to root
sudo su
Create the file.
fallocate -l 2G /swapfile
Limit the swap file to root access only.
chmod 600 /swapfile
Mark the file as a swap file.
mkswap /swapfile
Turn the swap file on.
swapon /swapfile
Edit the fstab file.
nano /etc/fstab
Add the below line to the end of the file. This will ensure the swap file is turned on after a reboot.
/swapfile none swap sw 0 0
Reboot the server.
shutdown -r now
Check that the swap is present.
free -h
total used free shared buff/cache available
Mem: 7.6Gi 58Mi 7.5Gi 24Mi 98Mi 7.4Gi
Swap: 2.0Gi 0B 2.0Gi
Security
SSH keys
So lets make the server more secure. First thing to do is setup SSH keys and disable password access.
Enter the following command on the client PC you are connecting from. We are assuming this is running a Linux OS.
I also do this on the Pi put it is not strictly required.
ssh-keygen -t rsa
This command creates a hidden .ssh folder in your home directory. Inside this will be a file called id_rsa.pub. Copy the contents of this file and paste it into a file called authorized_keys on the Pi in the same .ssh directory.
Logout out of the SSH session on the Pi and back in again. It should login without prompting for a password.
Now edit the ssh server config file with the following command.
sudo nano /etc/ssh/sshd_config
Change the following line
#PasswordAuthentication yes
to
PasswordAuthentication no
and reload the settings.
sudo systemctl reload sshd.service
I also like to change the SSH port to something above 64000.
The first file determines what port you connect to the Pi on.
sudo nano /etc/ssh/sshd_config
The second file will change what port you connect out from the Pi if you SSH from it to something else.
sudo nano /etc/ssh/sshd_config
In both cases find the line for Port uncomment it and change the number to whatever you want.
This does mean that you will have to remember to use the -p switch when using SSH to connect to the Pi. An example would be.
ssh -p 64000 [email protected]
nftables firewall
In Debian 10 the recommended firewall is nftables rather than iptables. I think it is easier to use personally.
Install and enable.
sudo apt install nftables
sudo systemctl enable nftables.service
A selection of templates are provided at
/usr/share/doc/nftables/examples
The active configuration file is located at /etc/nftables.conf
sudo nano /etc/nftables.conf
The file will look as below.
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0;
}
chain forward {
type filter hook forward priority 0;
}
chain output {
type filter hook output priority 0;
}
}
For a basic setup copy in the version below and edit the port list as needed.
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0;
# accept any localhost traffic
iif lo accept
# accept traffic originated from us
ct state established,related accept
# activate the following line to accept common local services
tcp dport { 64000 } ct state new accept
# accept neighbour discovery otherwise IPv6 connectivity breaks.
ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept
# count and drop any other traffic
counter drop
}
}
Now start.
sudo systemctl start nftables.service
A basic probe from nmap will show nothing.
[email protected]:~$ nmap rpi4-debian10
Starting Nmap 7.80 ( https://nmap.org ) at 2020-12-13 00:17 GMT
Note: Host seems down. If it is really up, but blocking our ping probes, try -Pn
Nmap done: 1 IP address (0 hosts up) scanned in 3.03 seconds
If you expand the port range and add in the suggested switches you get the following.
[email protected]:~$ nmap -Pn -p 1-65000 rpi4-debian10
Starting Nmap 7.80 ( https://nmap.org ) at 2020-12-13 00:23 GMT
Nmap scan report for rpi4-debian10 (192.168.0.2)
Host is up (0.00035s latency).
Not shown: 64997 filtered ports
PORT STATE SERVICE
64000/tcp open unknown
Nmap done: 1 IP address (1 host up) scanned in 262.56 seconds
If you want to be able to ping the Pi change your nftables.conf file as below.
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0;
# accept any localhost traffic
iif lo accept
# accept traffic originated from us
ct state established,related accept
# activate the following line to accept common local services
tcp dport { 64000 } ct state new accept
# accept neighbour discovery otherwise IPv6 connectivity breaks.
ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept
ip protocol icmp icmp type echo-request accept
ip6 nexthdr icmpv6 icmpv6 type echo-request accept
# count and drop any other traffic
counter drop
}
}
fail2ban
It is still useful to have fail2ban even if you have setup SSH keys as it allows you to see a log of where attacks are coming from. Also it means the program is ready for you to configure when you install additional services onto your Pi that you might want to protect.
sudo apt install fail2ban
Now make copies to the two major configuration files. These are the ones we will edit as they will not be overwritten by any future upgrade of the application.
sudo cp /etc/fail2ban/fail2ban.conf /etc/fail2ban/fail2ban.local
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
By default five incorrect login attempts within ten minutes will lead to a ten minute ban.
All we need to do to enable the protection for ssh is to edit the jail.local file.
sudo nano /etc/fail2ban/jail.local
Scroll down to the sshd file and add the line enabled = true as below. If your SSH port is non standard change the port line as well.
[sshd]
enabled = true
# 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
port = 64000
logpath = %(sshd_log)s
backend = %(sshd_backend)s
Exit and save the file. Then restart fail2ban.
sudo systemctl restart fail2ban.service
You can configure fail2ban to send email alerts to you as well if desired although this requires the installation of an mta like sendmail first.
The log files you will want to look at are
/var/log/fail2ban.log
and
/var/log/auth.log
The first shows the application running.
[email protected]:/var/log$ sudo tail -f fail2ban.log
2020-12-13 20:57:50,205 fail2ban.jail [11335]: INFO Jail 'sshd' uses pyinotify {}
2020-12-13 20:57:50,213 fail2ban.jail [11335]: INFO Initiated 'pyinotify' backend
2020-12-13 20:57:50,215 fail2ban.filter [11335]: INFO maxLines: 1
2020-12-13 20:57:50,289 fail2ban.server [11335]: INFO Jail sshd is not a JournalFilter instance
2020-12-13 20:57:50,291 fail2ban.filter [11335]: INFO Added logfile: '/var/log/auth.log' (pos = 15423, hash = b7b651a6982ddc689261d6962a1ee4d735492404)
2020-12-13 20:57:50,302 fail2ban.filter [11335]: INFO encoding: UTF-8
2020-12-13 20:57:50,303 fail2ban.filter [11335]: INFO maxRetry: 5
2020-12-13 20:57:50,303 fail2ban.filter [11335]: INFO findtime: 600
2020-12-13 20:57:50,304 fail2ban.actions [11335]: INFO banTime: 600
2020-12-13 20:57:50,309 fail2ban.jail [11335]: INFO Jail 'sshd' started
The second shows login attempts. I attempted to connect from a different machine on 192.168.0.3 which does not have the required keys.
[email protected]:/var/log$ sudo tail -f auth.log
Dec 13 20:58:28 rpi4-debian10 sshd[11363]: Connection closed by authenticating user john-doe 192.168.0.3 port 35022 [preauth]
Dec 13 20:58:29 rpi4-debian10 sshd[11365]: Connection closed by authenticating user john-doe 192.168.0.3 port 35024 [preauth]
Dec 13 20:59:05 rpi4-debian10 sudo: john-doe : TTY=pts/0 ; PWD=/home/john-doe ; USER=root ; COMMAND=/usr/bin/nano /etc/fail2ban/jail.local
Dec 13 20:59:05 rpi4-debian10 sudo: pam_unix(sudo:session): session opened for user root by john-doe(uid=0)
Dec 13 20:59:49 rpi4-debian10 sudo: pam_unix(sudo:session): session closed for user root
Dec 13 21:01:39 rpi4-debian10 sudo: john-doe : TTY=pts/0 ; PWD=/var/log ; USER=root ; COMMAND=/usr/bin/tail -f fail2ban.log
Dec 13 21:01:39 rpi4-debian10 sudo: pam_unix(sudo:session): session opened for user root by john-doe(uid=0)
Dec 13 21:02:03 rpi4-debian10 sudo: pam_unix(sudo:session): session closed for user root
Dec 13 21:02:10 rpi4-debian10 sudo: john-doe : TTY=pts/0 ; PWD=/var/log ; USER=root ; COMMAND=/usr/bin/tail -f auth.log
Dec 13 21:02:10 rpi4-debian10 sudo: pam_unix(sudo:session): session opened for user root by john-doe(uid=0)
Dec 13 21:04:55 rpi4-debian10 sshd[11420]: Connection closed by authenticating user john-doe 192.168.0.3 port 35046 [preauth]
Dec 13 21:04:55 rpi4-debian10 sshd[11422]: Connection closed by authenticating user john-doe 192.168.0.3 port 35048 [preauth]
Dec 13 21:04:56 rpi4-debian10 sshd[11424]: Connection closed by authenticating user john-doe 192.168.0.3 port 35050 [preauth]
Dec 13 21:04:58 rpi4-debian10 sshd[11428]: Connection closed by authenticating user john-doe 192.168.0.3 port 35052 [preauth
You can see after several attempts the connect is shut down automatically by fail2ban.