Skip to content

Raspberry Pi OS Trixie Security Hardening 2026

Secure a Raspberry Pi by reducing exposed services, requiring strong administration, applying updates, limiting each application, monitoring failures, and proving recovery. Start with the five high-value controls below; add TPM, encrypted storage, or immutable images only when the threat model requires them.

Quick answer: Raspberry Pi vulnerabilities

Begin with the running system rather than a generic vulnerability list: update Raspberry Pi OS, inventory listening services, replace password-only SSH with tested keys, restrict network exposure, and verify backups. A TPM can protect keys and boot policy, but it does not replace patching or least privilege.

Five essential settings

Priority Action Verify
1 Install updates and reboot when required apt list --upgradable; systemctl --failed
2 Require an administrator password and unique accounts sudo -k; sudo true
3 Use SSH keys; test them before disabling passwords New independent SSH session succeeds
4 Remove unused listeners and allow only required firewall paths sudo ss -lntup; sudo ufw status verbose
5 Automate security updates and backups; test restoration Timer/log review and documented restore result

Raspberry Pi OS 6.2 disables passwordless sudo by default on new installations. Upgraded systems can retain their prior behavior, so verify rather than assume. Before changing remote access, keep the current session open and prepare Ethernet, USB Gadget Mode, or a local console.

Define the threat model

Answer these first:

  • Is the device reachable only on a trusted LAN, through a VPN, or from the public internet?
  • Can an attacker remove storage or access GPIO/USB?
  • Which data and credentials matter?
  • Must the Pi boot unattended?
  • How quickly must service be restored?
  • Who installs updates and approves configuration changes?
  • Where are backups and recovery credentials stored?

A private hobby dashboard, public kiosk, and industrial appliance need different controls. Installing every security package does not create a coherent design.

Record a baseline

Create a directory readable only by the current user:

install -d -m 0700 "$HOME/security-baseline"

{
  date --iso-8601=seconds
  cat /proc/device-tree/model
  cat /etc/os-release
  uname -a
  id
  sudo -l
  sudo ss -lntup
  systemctl --failed
  systemctl list-unit-files --state=enabled
  vcgencmd get_throttled
} > "$HOME/security-baseline/system.txt"

This output can contain usernames, addresses, and service details. Do not publish it without review.

Check recent warnings and authentication activity:

1
2
3
journalctl -b -p warning --no-pager
sudo journalctl -u ssh --since today --no-pager
last -a | head -30

Update Raspberry Pi OS

1
2
3
4
sudo apt update
apt list --upgradable
sudo apt full-upgrade
sudo reboot

After reconnecting:

1
2
3
4
systemctl --failed
journalctl -b -p warning --no-pager
sudo ss -lntup
vcgencmd get_throttled

Do not combine a major OS migration with security-policy changes in one untested maintenance window. For Bookworm-to-Trixie planning, use the migration guide.

Require sudo authentication

Test whether the current user is prompted:

sudo -k
sudo true

Inspect effective sudo policy:

sudo -l
sudo grep -RnsE 'NOPASSWD|PASSWD' /etc/sudoers /etc/sudoers.d/

Edit sudo configuration only with visudo, which checks syntax:

sudo visudo
sudo visudo -f /etc/sudoers.d/automation

For automation, grant a dedicated service account only the exact commands required. Avoid broad NOPASSWD: ALL. File permissions for sudo drop-ins should be owned by root and not writable by ordinary users.

Use unique accounts

List interactive accounts and groups:

getent passwd | awk -F: '$7 !~ /(nologin|false)$/ {print $1, $6, $7}'
getent group sudo

Create a named administrator when multiple people operate the Pi:

sudo adduser <admin-name>
sudo usermod -aG sudo <admin-name>

Log in as that user and verify sudo before removing anyone from the admin group. Service processes should use dedicated system accounts without interactive shells where possible.

Lock an unused account rather than deleting it immediately:

sudo passwd --lock <unused-user>
sudo usermod --expiredate 1 <unused-user>

Confirm no files, timers, cron jobs, or services depend on it before deletion.

Harden SSH without locking yourself out

1. Install a client key

On the client computer:

1
2
3
ssh-keygen -t ed25519
ssh-copy-id <user>@<pi-address>
ssh <user>@<pi-address>

Open a second independent session and verify key authentication. Keep the original session connected.

2. Audit effective server settings

sudo sshd -T | grep -E \
  '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|allowusers|maxauthtries) '

Package updates may change supported algorithms and defaults. Do not paste a fixed cipher/MAC list from an old guide unless a compatibility policy requires it and current sshd supports it.

3. Use a drop-in

Create /etc/ssh/sshd_config.d/20-hardening.conf:

1
2
3
4
5
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
MaxAuthTries 3

Add AllowUsers <user> only after inventorying every legitimate SSH account and automation identity.

Validate before reload:

1
2
3
4
sudo sshd -t
sudo systemctl reload ssh
sudo sshd -T | grep -E \
  '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|maxauthtries) '

Test a third new connection. If it fails, use the still-open original session to restore the drop-in.

Changing port 22 reduces background log noise but is not a substitute for key authentication, firewall policy, or updates.

Inventory network exposure

1
2
3
sudo ss -lntup
ip -brief address
systemctl --type=service --state=running

For every listener, document:

  • owning process/service
  • interface (127.0.0.1, LAN, VPN, or all addresses)
  • port/protocol
  • required clients
  • authentication and encryption
  • update owner

Bind admin dashboards to localhost or a private VPN when possible. Do not expose SSH, VNC, databases, Docker APIs, or management interfaces directly to the public internet without a specific design.

Disable an unused service safely

Inspect the service and reverse dependencies:

1
2
3
systemctl status example.service
systemctl cat example.service
systemctl list-dependencies --reverse example.service

Disable only when the hardware and application do not require it:

1
2
3
sudo systemctl disable --now example.service
sudo ss -lntup
systemctl --failed

Record rollback:

sudo systemctl enable --now example.service

Configure UFW around required access

Install UFW:

sudo apt update
sudo apt install ufw

Before enabling it remotely, allow the current SSH path. For LAN-only SSH, replace the example subnet with the actual management subnet:

1
2
3
4
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 192.168.1.0/24 to any port 22 proto tcp
sudo ufw show added

Enable while the recovery session remains available:

sudo ufw enable
sudo ufw status verbose

Open a new SSH session and test required application ports from an allowed and, where possible, denied client. Do not blindly allow ports based on an application tutorial; expose only the interface and client range required.

Docker and other container/network frameworks can create packet-filter rules that interact with UFW. Verify the actual path from another machine rather than assuming ufw status describes every effective rule.

Add login-rate protection where useful

Fail2ban can respond to repeated failures, but key-only SSH and limited network reach are stronger primary controls.

sudo apt install fail2ban
sudo fail2ban-client status

Create local jail overrides under /etc/fail2ban/jail.d/; do not edit packaged defaults. Confirm the journal/backend and actual SSH log entries before enabling a jail, then test from a disposable client without banning the only admin address.

Enable automatic security updates

sudo apt install unattended-upgrades apt-listchanges
sudo dpkg-reconfigure -plow unattended-upgrades

Inspect timers and dry-run diagnostics:

1
2
3
systemctl list-timers 'apt-*'
sudo unattended-upgrade --dry-run --debug
sudo journalctl -u unattended-upgrades --since '7 days ago' --no-pager

Automatic reboot may be inappropriate for a production service. Define maintenance windows, health checks, rollback, and notification instead of copying a universal reboot time.

Protect secrets and permissions

Find potentially unsafe private-key permissions in known application paths rather than crawling pseudo-filesystems blindly:

find "$HOME/.ssh" /etc/ssh -xdev -type f -printf '%m %u:%g %p\n'

Typical SSH permissions:

chmod 700 "$HOME/.ssh"
chmod 600 "$HOME/.ssh/authorized_keys"

For services:

  • use systemd EnvironmentFile= with root-owned restrictive permissions, or a dedicated secret store
  • never commit .env, API keys, recovery keys, or private certificates
  • avoid secrets on command lines, which may appear in process lists and histories
  • rotate a secret immediately if it was published
  • grant service accounts access only to their own data

Check repository history as well as the current file when removing an accidentally committed secret.

Constrain custom systemd services

Inspect the unit and its security score:

systemctl cat my-app.service
systemd-analyze security my-app.service

Options to evaluate in a test environment include:

1
2
3
4
5
6
7
8
9
[Service]
User=my-app
Group=my-app
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/my-app
CapabilityBoundingSet=

Do not paste the entire block into every service. A GPIO, camera, network, or storage application may need specific devices, capabilities, home paths, or writable directories. Add one constraint, test normal operation and restart/recovery, then continue.

Logging and detection

Keep useful logs bounded rather than disabling them:

1
2
3
journalctl --disk-usage
sudo journalctl --verify
sudo journalctl -p warning --since '24 hours ago' --no-pager

Review:

  • failed SSH authentication and unexpected successful logins
  • new listeners and enabled services
  • repeated sudo failures
  • package/update failures
  • kernel storage, power, and network warnings
  • backup failures
  • unexpected account/group changes

For important remote devices, forward logs to another trusted system so evidence survives device loss or storage failure. Avoid sending secrets contained in application logs.

Backups and recovery

Back up data, service configuration, infrastructure definitions, and recovery material with different access controls. Follow the automated backup guide.

A recovery drill should prove:

  1. A clean Raspberry Pi OS image can be prepared.
  2. Network and SSH access can be restored safely.
  3. Application data and configuration restore correctly.
  4. DNS/certificates/secrets can be rotated.
  5. Required service health checks pass.
  6. Recovery time meets the objective.

Do not store the only backup or encryption recovery key on the Raspberry Pi it protects.

Physical and hardware-backed security

If storage removal, boot tampering, or device identity is in scope, compare:

  • enclosure and port access controls
  • LUKS2 encryption for removable data
  • signed/secure boot for boot-code authentication
  • dm-verity for immutable root integrity
  • external TPM 2.0 for keys, PCR policies, and attestation

Start with the Raspberry Pi 5 TPM 2.0 security guide. These controls add update and recovery complexity and do not replace ordinary OS hardening.

Monthly review checklist

  • OS and packages updated
  • Failed units and update logs reviewed
  • Listening ports compared with baseline
  • Users, sudoers, SSH keys, and service credentials reviewed
  • Firewall rules and remote-access path tested
  • Backup completed and sample restore passed
  • Disk space, storage errors, temperature, and undervoltage checked
  • Expiring certificates/domains reviewed
  • Incident contacts and recovery instructions still valid

Incident response

If compromise is suspected:

  1. Preserve volatile and log evidence when safe and authorized.
  2. Isolate the device from untrusted networks.
  3. Rotate credentials from a known-clean system.
  4. Identify affected accounts, services, data, and time range.
  5. Rebuild from trusted media rather than assuming package cleanup removes persistence.
  6. Restore verified data and configuration.
  7. patch the initial access path and monitor for recurrence.

Do not use the suspected Raspberry Pi to change the only copies of important passwords or signing keys.

Changes to avoid copying blindly

  • Fixed cipher/MAC lists from old OpenSSH guides
  • Disabling SSH passwords before testing keys
  • Enabling UFW remotely without allowing the current path
  • Exposing management ports to 0.0.0.0/0
  • Broad passwordless sudo
  • Disabling logs to reduce SD writes
  • Running every application as root
  • Automatic unattended reboots without service recovery
  • Installing security scanners from untrusted scripts
  • Claiming compliance from a checklist or TPM
  • Programming secure-boot OTP during an initial test

FAQ

Is Raspberry Pi OS secure by default?

It provides reasonable defaults for general use, but your accounts, exposed services, applications, secrets, update policy, physical access, and recovery determine the deployed risk.

Should I change the SSH port?

It may reduce background scan noise, but it does not replace key authentication, limited network reach, firewall policy, or updates.

Should SSH password authentication be disabled?

Yes when every required user and automation path has a tested key and a recovery route exists. Do not disable it during an unverified remote-only session.

Do I need fail2ban with SSH keys?

Not always. Restricting SSH to a LAN/VPN and using keys is more important. Fail2ban can provide additional rate response where logs and ban testing are reliable.

Does a TPM make Raspberry Pi secure?

No. It can protect keys and enforce measured policies, but OS vulnerabilities, exposed services, physical access, recovery, and application authorization still need controls.

How often should the Pi be rebuilt?

There is no universal interval. Rebuild after confirmed compromise, an untrusted base image, or when the current OS cannot be supported safely. Otherwise maintain updates, monitoring, backups, and reproducible configuration.