Security
SSH hardening with ed25519 keys, UFW firewall rules, fail2ban brute-force protection on systemd, open-files limit, disable Bluetooth and Wi-Fi radios.
What does "hardening" actually mean for a little computer in your living room? Closing doors, mostly. Your Pi is about to be reachable from the internet, and before you take that step you'll want to lock SSH down to keys only, tighten the SSH daemon, turn on a firewall, add brute-force protection, bump the open-files limit, and switch off the radios you don't need. Nothing exotic, all standard Debian hygiene, applied in the right order.
Disable password SSH login
You already set up an Ed25519 key in Remote access. Time to turn off password logins entirely so only someone holding the private key can reach the Pi.
Test your key before locking passwords out
Before touching anything, open a second SSH session in a new terminal window and confirm it logs in without asking for password [A]. Leave that second session open while you make the changes, if something goes sideways, you still have a working shell to undo it. Seriously. You don't want to learn this the hard way.
-
Instead of editing the main
sshd_config(which gets rewritten on package updates), drop a small override file into thesshd_config.d/directory, that's the modern Debian way:sudo nano /etc/ssh/sshd_config.d/raspibolt.confFirst time with
nano? Paste the content, then pressCtrl-Oto save,Enterto confirm the filename, andCtrl-Xto exit. -
Paste the following. The cipher-suite lines look like alphabet soup, but they're really just a curated list of modern algorithms, copy them as-is and move on:
# RaspiBolt SSH hardening PermitRootLogin no PasswordAuthentication no KbdInteractiveAuthentication no ChallengeResponseAuthentication no LoginGraceTime 30 MaxAuthTries 3 # Modern key exchange, ciphers, and MACs only KexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group18-sha512,diffie-hellman-group16-sha512 Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com -
Sanity-check the config before restarting the daemon, this catches typos that would otherwise lock you out:
sudo sshd -tNo output means the file is valid.
-
Restart the SSH daemon and log out:
sudo systemctl restart ssh exit -
Open a fresh SSH session. You should land in a shell using your key; password [A] should no longer be accepted.
Back up your SSH keys
If you lose your private key, recovery means attaching a keyboard
and screen to the Pi. Keep a copy of ~/.ssh/id_ed25519 somewhere
safe, an encrypted USB stick, or a password manager that supports
file attachments.
Main takeaway: only your private key can reach the Pi over SSH now, passwords are off the table.
Firewall (ufw)
The Uncomplicated Firewall (ufw) is Debian's friendly front-end
to iptables. For now it only needs to allow SSH, every service
you add later will open its own port when the time comes.
-
Install
ufw:sudo apt install ufwIf you see
ERROR: Couldn't determine iptables version, reboot the Pi once after installingufwand carry on. -
Set default policies, allow SSH with rate limiting, turn off logging, and bring the firewall up, all in one go:
sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw limit ssh sudo ufw logging off sudo ufw enableufw limit sshblocks any IP making six or more connection attempts within 30 seconds, a first layer of brute-force defence on top of whatfail2bandoes below. -
Make sure
ufwcomes up at boot, and check the active rules:sudo systemctl enable ufw sudo ufw status verboseExpected output:
Status: active Default: deny (incoming), allow (outgoing), disabled (routed) To Action From -- ------ ---- 22/tcp (SSH) LIMIT IN Anywhere 22/tcp (SSH (v6)) LIMIT IN Anywhere (v6)
If you ever lock yourself out (wrong SSH port, busted config), attach a keyboard and screen to the Pi, log in locally, and fix the rules. Not fun, but always possible.
Main takeaway: nothing reaches the Pi from the network except rate-limited SSH, every other port stays shut by default.
Brute-force protection (fail2ban)
fail2ban is a watchful little daemon that tails the SSH log and
bans IP addresses that rack up failed logins. On Trixie there's a
wrinkle: rsyslog is no longer installed by default, so fail2ban
has to read authentication events straight from the systemd journal.
Sounds fiddly, but it's two extra pieces and you're done.
-
Install
fail2banand the Python bindings for the systemd journal:sudo apt install fail2ban python3-systemd -
Create a local configuration that uses the journal backend:
sudo nano /etc/fail2ban/jail.localPaste:
[DEFAULT] backend = systemd bantime = 10m findtime = 10m maxretry = 5 [sshd] enabled = true -
Restart
fail2banand confirm the SSH jail is running:sudo systemctl restart fail2ban sudo fail2ban-client status sshdExpected output:
Status for the jail: sshd |- Filter | |- Currently failed: 0 | |- Total failed: 0 | `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd `- Actions |- Currently banned: 0 |- Total banned: 0 `- Banned IP list:
Why not the default backend?
Stock Debian fail2ban assumes rsyslog is writing /var/log/auth.log.
On Trixie it isn't, skip the two changes above and fail2ban will
run happily, read an empty log, and ban precisely nobody.
Main takeaway: any IP that fumbles five logins gets a ten-minute timeout, automatically, in the background, forever.
Raise the open-files limit
Under heavy load, or a deliberate flood, bitcoind and LND open a
lot of TCP connections at once. The default file-handle limit is far
too low for that and throws too many open files errors.
-
Create
/etc/security/limits.d/90-limits.conf:sudo nano /etc/security/limits.d/90-limits.confPaste:
* soft nofile 128000 * hard nofile 128000 root soft nofile 128000 root hard nofile 128000 -
Make sure PAM actually applies those limits on login. Open each of these files and add a
pam_limits.soline, right before any trailing comment:sudo nano /etc/pam.d/common-session sudo nano /etc/pam.d/common-session-noninteractiveAdd:
session required pam_limits.so
The new limits kick in at the next login.
Disable Bluetooth and Wi-Fi
A node dedicated to Bitcoin has no use for Bluetooth, and if you're connected over Ethernet, no use for Wi-Fi either. Turning off the radios you aren't using removes another slice of attack surface.
-
Edit the firmware configuration:
sudo nano /boot/firmware/config.txt -
Disable Bluetooth by adding this line at the end of the file:
dtoverlay=disable-bt -
If the Pi is connected by Ethernet cable, also disable Wi-Fi:
dtoverlay=disable-wifi
Save and exit. The radios stay off from the next reboot onward.

