Basic Security Defaults for ARM Linux

Summary
This page sets out a workable security baseline for an ARM Linux single-board computer used as a server, development host, or always-on service. It cuts down the obvious risks without turning the machine into something awkward to run. The main problems are familiar ones: weak authentication, unpatched software, unnecessary exposed services, and no useful access logs.
Who this is for
This is for anyone running an SBC that accepts network connections, especially boards exposed to the public internet or to networks you do not control. If the board runs SSH, web services, or network-attached storage, these defaults should not be optional.
Prerequisites
Before changing anything, make sure you have direct console access - serial, or HDMI plus keyboard - so you can recover if SSH stops working. Keep a second way in as well, such as local console, VNC, or a management network. Firewall and SSH changes do break access now and then. Save current backups first, including /etc and any critical configuration files.
Baseline security principles
Start with SSH keys rather than passwords. Passwords invite brute-force attacks; keys do not. Keep the system patched on a predictable schedule, because most real-world attacks go after known vulnerabilities that already have fixes. Expose only the services and ports you mean to run. Every open port is another place to look for trouble.
Logging matters too. If access logs are missing, intrusion detection becomes guesswork. And services should run with the least privilege they can get away with. Root is not a default setting for convenience.
Step-by-step security setup
Step 1: Generate and deploy SSH keys
Generate an ED25519 key pair on your workstation, not on the SBC:
ssh-keygen -t ed25519 -C "your-email@example.com"
# Save to default location (~/.ssh/id_ed25519)
# Set a strong passphrase (optional but recommended)
Then copy the public key to the board:
ssh-copy-id user@SBC_IP_ADDRESS
# Enter your password one last time
Test the login before you touch SSH configuration:
ssh user@SBC_IP_ADDRESS
# You should log in without a password (or with your key passphrase if you set one)
Step 2: Disable password authentication
Once key-based login works, turn off password authentication on the SBC:
sudo nano /etc/ssh/sshd_config
# Find and set these directives:
# PasswordAuthentication no
# ChallengeResponseAuthentication no
# PermitRootLogin no
# PubkeyAuthentication yes
Or use sed to edit in place:
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?ChallengeResponseAuthentication.*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
Reload SSH to apply the change:
sudo systemctl reload ssh || sudo systemctl reload sshd
Critical: keep the current SSH session open until a fresh terminal window has been used to confirm that login still works.
Step 3: Configure a firewall
For simple rule management, ufw (Uncomplicated Firewall) is the easiest route:
# Install ufw (if not already present):
sudo apt install ufw
# Default policies: deny all incoming, allow all outgoing
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH (change port if you use non-standard):
sudo ufw allow 22/tcp
# Allow additional services as needed:
# sudo ufw allow 80/tcp # HTTP
# sudo ufw allow 443/tcp # HTTPS
# Enable firewall:
sudo ufw enable
# Check status:
sudo ufw status verbose
For iptables users, the same baseline can be done by hand:
# Flush existing rules:
sudo iptables -F
# Default policies:
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT
# Allow loopback:
sudo iptables -A INPUT -i lo -j ACCEPT
# Allow established connections:
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow SSH:
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Save rules (Debian/Ubuntu):
sudo apt install iptables-persistent
sudo netfilter-persistent save
Step 4: Create a non-root user for services
Do not run applications as root unless there is no practical alternative. Create a dedicated service account instead:
# Example: create a user for a web application
sudo useradd -r -s /bin/false -d /var/www webapp
# -r: system account (no login shell, no home directory by default)
# -s /bin/false: no interactive shell
# -d /var/www: home directory (if needed for app files)
Step 5: Enable automatic security updates (optional)
On Debian, Ubuntu, or Armbian, install unattended-upgrades:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
# Select "Yes" to enable automatic security updates
Check the configuration:
cat /etc/apt/apt.conf.d/50unattended-upgrades
# Confirm security updates are enabled
Note: on production systems, test updates on a staging board first. Automatic updates are convenient, but they are not forgiving when a kernel or package behaves badly.
Step 6: Disable unused services
List the services actually running on the board:
systemctl list-units --type=service --state=running
Then disable anything you do not need:
sudo systemctl disable --now <service-name>
sudo systemctl mask <service-name> # Prevent manual or automatic start
Common candidates are avahi-daemon for mDNS, bluetooth if it is not in use, cups on boards that never print, and ModemManager when there is no cellular modem attached.
Verification checks
After the changes go in, check the configuration rather than assuming it is fine:
# List all listening ports and associated services:
ss -tulpn
# or
sudo netstat -tulpn
# Check failed systemd units:
systemctl --failed
# Check recent SSH authentication logs:
sudo journalctl -u ssh -n 50
# or
sudo grep "Accepted\|Failed" /var/log/auth.log | tail -n 20
# Verify firewall rules:
sudo ufw status verbose
# or
sudo iptables -L -v -n
# Check for rootkits (optional, install rkhunter or chkrootkit):
sudo rkhunter --check --skip-keypress
Monitoring and logging
To keep the system journal across reboots, create the persistent journal directory:
sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald
journalctl --disk-usage # Check current journal size
Set log retention in /etc/systemd/journald.conf:
[Journal]
SystemMaxUse=500M
MaxRetentionSec=1month
For failed login attempts, this is the direct check:
sudo journalctl _SYSTEMD_UNIT=ssh.service | grep "Failed password"
fail2ban is worth installing if you want repeat attackers blocked at the source:
sudo apt install fail2ban
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
Troubleshooting common issues
Locked out of SSH after disabling password authentication:
- Use the serial console or HDMI plus keyboard.
- Edit /etc/ssh/sshd_config and temporarily set PasswordAuthentication yes.
- Reload SSH: sudo systemctl reload sshd.
- Test key-based login again from your workstation. Check ~/.ssh/authorized_keys permissions, which must be 600 or 644.
Firewall blocks SSH after enabling ufw:
- If console access is available, run sudo ufw allow 22/tcp and sudo ufw reload.
- If the board is unreachable, boot from a rescue microSD card and edit the firewall rules there.
fail2ban bans your own IP address:
- Unban it with sudo fail2ban-client set sshd unbanip YOUR_IP.
- Add your IP to the ignore list in /etc/fail2ban/jail.local: ignoreip = 127.0.0.1/8 YOUR_IP/32.
Automatic updates break the system:
- Check /var/log/unattended-upgrades/ for error logs.
- Roll back the kernel or package via serial console or rescue boot.
- Disable unattended-upgrades and apply updates manually during maintenance windows.
Frequently asked questions
Q: Should I change the SSH port from 22 to something else?
A: It cuts down the noise from automated scans, but it does not change security much. SSH keys and fail2ban do the real work. If you move the port, update the firewall rules at the same time.
Q: Is fail2ban necessary if I use SSH keys?
A: Not strictly. Still, it reduces log clutter and blocks scanning bots. It also protects other exposed services, such as HTTP or FTP, if you run them.
Q: How do I allow SSH only from specific IP addresses?
A: With ufw, use sudo ufw allow from YOUR_IP to any port 22 proto tcp. With iptables, use sudo iptables -A INPUT -p tcp -s YOUR_IP --dport 22 -j ACCEPT.
Q: What should I back up before making security changes?
A: At minimum, save /etc/ssh/sshd_config, /etc/ssh/authorized_keys or ~/.ssh/authorized_keys for each user, and your firewall rules. Use sudo iptables-save > iptables-backup.txt or sudo ufw status > ufw-backup.txt.
Q: How do I test firewall rules without locking myself out?
A: Use at to schedule a firewall flush: echo "ufw disable" | at now + 5 minutes. If access fails, the firewall drops after five minutes on its own.
Q: Should I install an intrusion detection system (IDS)?
A: For home or lab systems, fail2ban plus log monitoring is usually enough. For production or high-value targets, OSSEC, Snort, or Suricata are the more serious options.
Q: How do I rotate SSH keys?
A: Create a new key pair, add the new public key to ~/.ssh/authorized_keys, test login with the new key, then remove the old key from authorized_keys.
Related guides
Author: LeMaker Documentation Team
Last updated: 2026-01-10