SSH hardening · SELinux · AppArmor · fail2ban · auditd · Interactive hardening checklist.
$ sudo useradd -m -s /bin/bash saad $ sudo passwd saad $ sudo usermod -aG sudo saad # Debian/Ubuntu $ sudo usermod -aG wheel saad # RHEL/Fedora # Grant only specific commands (not full sudo): $ sudo visudo # Add: saad ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx # Lock / expire an account: $ sudo usermod -L baduser # lock $ sudo chage -E 0 baduser # expire immediately # Find accounts with no password set: $ sudo awk -F: '($2 == "") {print $1}' /etc/shadow # List all UID 0 accounts (should ONLY be root): $ awk -F: '($3==0) {print $1}' /etc/passwd
Edit /etc/ssh/sshd_config, then run sudo systemctl restart sshd. Keep a second session open before restarting.
Port 2222 # Change from default 22 PermitRootLogin no # CRITICAL — never SSH as root PasswordAuthentication no # Keys only — disable passwords PubkeyAuthentication yes AllowUsers saad deploy # Whitelist specific users only MaxAuthTries 3 LoginGraceTime 20 X11Forwarding no AllowTcpForwarding no # Disable unless you need tunnels ClientAliveInterval 300 # Disconnect idle sessions after 5 min ClientAliveCountMax 2 # Test config before restarting: $ sudo sshd -t $ sudo systemctl restart sshd
$ getenforce # Enforcing / Permissive / Disabled $ sestatus # detailed status + policy name $ sudo setenforce 0 # Permissive (logs but doesn't block) $ sudo setenforce 1 # Back to Enforcing # Permanent — edit /etc/selinux/config: SELINUX=enforcing # View denials: $ sudo ausearch -m avc -ts recent $ sudo tail -f /var/log/audit/audit.log | grep denied # Generate a policy module to allow a denied action: $ sudo ausearch -m avc -ts recent | audit2allow -M mypolicy $ sudo semodule -i mypolicy.pp # Fix file contexts: $ sudo chcon -R -t httpd_sys_content_t /var/www/mysite/ $ sudo restorecon -Rv /var/www/mysite/ # Allow httpd to make network connections: $ sudo setsebool -P httpd_can_network_connect 1
$ sudo aa-status # show all profiles and their modes $ sudo aa-complain /usr/sbin/nginx # complain mode (log, don't block) $ sudo aa-enforce /usr/sbin/nginx # enforce mode (block violations) $ sudo dmesg | grep apparmor # view denials # Reload a profile after editing: $ sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx # Auto-generate a profile for a program: $ sudo aa-genprof /usr/bin/myapp # run app, press S to scan, F to finish
$ sudo apt install fail2ban $ sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local $ sudo nano /etc/fail2ban/jail.local # Recommended jail.local settings: [DEFAULT] bantime = 1h findtime = 10m maxretry = 5 ignoreip = 127.0.0.1/8 192.168.1.0/24 # whitelist [sshd] enabled = true port = 2222 # match your SSH port $ sudo systemctl enable --now fail2ban # Monitor: $ sudo fail2ban-client status $ sudo fail2ban-client status sshd $ sudo fail2ban-client set sshd unbanip 1.2.3.4 # unban an IP $ sudo tail -f /var/log/fail2ban.log
$ sudo apt install auditd && sudo systemctl enable --now auditd # Watch critical files for changes: $ sudo auditctl -w /etc/passwd -p wa -k passwd_changes $ sudo auditctl -w /etc/sudoers -p wa -k sudoers_changes # Search audit log: $ sudo ausearch -k passwd_changes $ sudo ausearch -m USER_LOGIN -ts today $ sudo aureport --auth # authentication report $ sudo aureport --failed # all failed events
# Find SUID files (potential privilege escalation): $ find / -perm /4000 -type f 2>/dev/null # World-writable directories: $ find / -type d -perm -0002 -not -path "*/proc/*" 2>/dev/null # Recent failed login attempts: $ sudo lastb | head -20 $ sudo grep "Failed password" /var/log/auth.log | tail -20 # All listening ports: $ ss -tulnp # Unowned files (no valid user): $ find / -nouser -o -nogroup 2>/dev/null
Track your server hardening progress. Click each item to mark it done.
0 / 14 complete
Spin up a locked-down Linux droplet and apply every item on this checklist in a real environment.
Get Started →