Linux Security Best Practices

Linux Security Best Practices

Securing a Linux system does not require a security degree. Most attacks against Linux servers succeed because of a small set of preventable mistakes: weak authentication, unpatched software, unnecessary exposed services, and overly permissive access controls. Fixing these takes a few hours and blocks the vast majority of real-world threats.

The core principles

Security is not a single setting but a set of layered defences. Each layer reduces your exposure:

  1. Minimise the attack surface: run only what you need, listen only on the ports you need
  2. Least privilege: no account or process has more access than it needs
  3. Defence in depth: assume individual controls can fail; layer multiple defences
  4. Keep software current: most exploits target known, patched vulnerabilities
  5. Monitor and audit: know what your system is doing so anomalies are visible

User access

Disable direct root login

# Never log in as root. Use a regular user with sudo access.

# Create a non-root admin user (if not already done)
useradd -m -s /bin/bash colton
passwd colton
usermod -aG sudo colton          # Debian/Ubuntu
usermod -aG wheel colton         # Fedora/RHEL/Arch

# Confirm sudo works for the new user before locking root
su - colton
sudo whoami                      # should print "root"

# Lock the root account password (sudo still works)
sudo passwd -l root

# Disable root SSH login (in /etc/ssh/sshd_config)
sudo sed -i 's/^#*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sudo systemctl reload sshd

Configure sudo properly

# Only grant sudo access to users who need it
# Never add users to sudoers directly; use the sudo group

# Review who has sudo access
grep -E '^sudo|^wheel' /etc/group
sudo -l -U username

# Audit recent sudo usage
sudo grep sudo /var/log/auth.log | tail -20     # Debian/Ubuntu
sudo journalctl | grep sudo | tail -20          # systemd

# For more restricted access, use visudo to limit specific commands
sudo visudo
# Example: let colton run only systemctl restart nginx without password
# colton ALL=(ALL) NOPASSWD: /bin/systemctl restart nginx

Disable unused user accounts

# List all users with a login shell
grep -v '/nologin\|/false' /etc/passwd

# Lock an account (prevent login, keep files)
sudo usermod -L username

# Check for accounts with no password (empty password field)
sudo awk -F: '($2 == "" || $2 == "!") {print $1}' /etc/shadow

# Check for UID 0 accounts other than root
awk -F: '($3 == 0) {print $1}' /etc/passwd

SSH hardening

SSH is the most commonly attacked service on internet-facing servers. See the dedicated SSH Hardening Guide for full coverage.

# /etc/ssh/sshd_config -- key settings
PermitRootLogin no
PasswordAuthentication no        # key-based auth only
PubkeyAuthentication yes
AllowUsers colton                # whitelist specific users
MaxAuthTries 3
LoginGraceTime 20
X11Forwarding no
AllowTcpForwarding no            # unless you need port forwarding

sudo systemctl reload sshd

# Test the config before reloading
sudo sshd -t

Firewall

# Start with deny-all inbound, allow-all outbound
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow only what you need (SSH must come first)
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Enable
sudo ufw enable
sudo ufw status verbose

# Restrict SSH to your management IP only (if possible)
sudo ufw delete allow 22/tcp
sudo ufw allow from 203.0.113.5 to any port 22

Software updates

# Apply all pending updates (run after any audit)
sudo apt update && sudo apt upgrade -y              # Debian/Ubuntu
sudo dnf upgrade --refresh -y                       # Fedora/RHEL
sudo pacman -Syu                                    # Arch

# Check for security-specific updates only
sudo apt list --upgradable 2>/dev/null | grep security
sudo dnf check-update --security

# Enable automatic security updates (Debian/Ubuntu)
sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

# Enable automatic security updates (Fedora/RHEL)
sudo dnf install dnf-automatic
sudo sed -i 's/upgrade_type = default/upgrade_type = security/' /etc/dnf/automatic.conf
sudo sed -i 's/apply_updates = no/apply_updates = yes/' /etc/dnf/automatic.conf
sudo systemctl enable --now dnf-automatic.timer

Reduce the attack surface

# List all listening services
ss -tlnp

# List all installed services that start at boot
systemctl list-unit-files --type=service --state=enabled

# Disable and stop services you do not need
sudo systemctl disable --now bluetooth.service
sudo systemctl disable --now cups.service          # printing
sudo systemctl disable --now avahi-daemon.service  # mDNS/Bonjour

# Remove packages you do not use
sudo apt autoremove
sudo dpkg -l | grep -i telnet                       # find telnet packages
sudo apt purge telnet                               # remove them

File permissions audit

# Find world-writable files (anyone can modify these)
find / -not \( -path /proc -prune \) -not \( -path /sys -prune \) \
  -perm -o+w -type f 2>/dev/null

# Find SUID/SGID binaries (run with elevated privileges)
find / -not \( -path /proc -prune \) -perm /6000 -type f 2>/dev/null

# Verify SUID binaries are expected (compare against a known-good list)
find / -perm /6000 -type f 2>/dev/null | sort > /tmp/suid-$(date +%F).txt

# Check for files owned by no user
find / -nouser -o -nogroup 2>/dev/null | grep -v /proc

# Secure home directories
chmod 700 /home/username
chmod 600 /home/username/.ssh/authorized_keys

Audit logging

# Check who has logged in recently
last
lastb                              # failed login attempts

# Review authentication logs
sudo journalctl -u sshd --since "24 hours ago"
sudo tail -f /var/log/auth.log     # Debian/Ubuntu

# Enable the Linux audit daemon for detailed tracking
sudo apt install auditd
sudo systemctl enable --now auditd

# Watch for privilege escalation
sudo auditctl -w /etc/sudoers -p wa -k sudoers-changes
sudo auditctl -w /etc/passwd -p wa -k passwd-changes

# Review audit log
sudo ausearch -k sudoers-changes

File integrity monitoring

# AIDE: creates a database of file checksums and detects changes
sudo apt install aide

# Initialize the database (do this on a fresh, trusted system)
sudo aideinit
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db

# Check for changes against the stored database
sudo aide --check

# Run aide check weekly via cron
echo "0 3 * * 0 root /usr/bin/aide --check | mail -s 'AIDE report' admin@example.com" \
  | sudo tee /etc/cron.d/aide-check

Security auditing with Lynis

# Install
sudo apt install lynis              # Debian/Ubuntu
sudo dnf install lynis              # Fedora/RHEL

# Full system audit
sudo lynis audit system

# The report output:
# [WARNING]    -- should be fixed
# [SUGGESTION] -- worth investigating
# Hardening index: your score out of 100

# Audit just a specific category
sudo lynis audit system --tests-from-group authentication
sudo lynis audit system --tests-from-group networking
sudo lynis audit system --tests-from-group firewalls

# Non-interactive mode (for scripting)
sudo lynis audit system --quiet --no-colors

Checklist summary

[ ] Non-root user created, sudo configured
[ ] Root SSH login disabled
[ ] Password SSH auth disabled (key-based only)
[ ] SSH AllowUsers or AllowGroups set
[ ] Firewall enabled, default deny incoming
[ ] Only required ports open
[ ] Automatic security updates enabled
[ ] Unnecessary services disabled/removed
[ ] World-writable files reviewed
[ ] SUID/SGID files reviewed
[ ] Audit logging enabled
[ ] Lynis audit run and warnings addressed
[ ] Fail2ban installed and configured

Frequently Asked Questions

What are the most important Linux security steps for a new server?

The highest-impact steps for a new server are: disable root SSH login and use key-based authentication only; enable a firewall (ufw) with a default-deny inbound policy and only allow the ports you need; keep the system updated with security patches; create a non-root user with sudo access and do all work as that user; disable or remove services you do not need; and change the SSH port or use fail2ban to reduce automated brute-force attempts. These five steps address the vast majority of common attack vectors against internet-facing servers.

Should I log in as root on a Linux server?

No. You should create a regular user account for all daily work and use sudo for commands that require elevated privileges. Logging in directly as root means every command runs with full system access, so a typo or a compromised terminal can cause irreversible damage. It also prevents audit logs from recording which user performed a privileged action. Best practice is to disable root SSH login entirely in /etc/ssh/sshd_config (PermitRootLogin no) and allow only your regular user to connect, using key-based authentication.

How do I check if my Linux system has been compromised?

Look for unusual running processes (ps aux, top), unexpected listening ports (ss -tlnp), unfamiliar user accounts (cat /etc/passwd), recent file modifications in system directories (find /etc /bin /usr/bin -newer /tmp/ref -type f), entries in /root/.ssh/authorized_keys you did not add, and cron jobs you do not recognise (crontab -l, ls /etc/cron.*). Tools like rkhunter, chkrootkit, and AIDE can automate integrity checks. Check authentication logs (/var/log/auth.log or journalctl -u sshd) for failed login attempts and unexpected successful logins.

What is the principle of least privilege and how do I apply it on Linux?

The principle of least privilege means giving users, processes, and services only the permissions they need to do their job and nothing more. On Linux, this means: running services as dedicated non-root users (nginx runs as www-data, not root); using sudo to grant specific commands rather than full root access; setting file permissions so files are only readable by users who need them; using Linux capabilities to give a process a specific root-level ability without making it fully root; and running containers or services in isolated namespaces. Every extra permission is a potential attack surface.

What is Lynis and how do I use it?

Lynis is an open-source security auditing tool for Linux systems. It scans your system and produces a report with findings grouped by severity: warnings (things that need fixing) and suggestions (things worth considering). Install it with your package manager (apt install lynis or dnf install lynis) and run sudo lynis audit system. The report shows your hardening index score and lists specific actions you can take. Lynis does not make changes; it only reports. Run it periodically and after configuration changes to track your security posture.

How do I set up automatic security updates on Linux?

On Debian and Ubuntu, install the unattended-upgrades package (apt install unattended-upgrades) and run dpkg-reconfigure —priority=low unattended-upgrades to enable it. By default it applies only security updates automatically. On Fedora and RHEL, install dnf-automatic (dnf install dnf-automatic), configure /etc/dnf/automatic.conf to set upgrade_type = security and apply_updates = yes, then enable the timer: systemctl enable —now dnf-automatic.timer. Automatic security updates are appropriate for most servers; kernel updates still require a reboot and some administrators prefer to handle those manually.