Ubuntu Security Hardening Guide

Khimananda Oli 7 min read Virtualization
Ubuntu Security Hardening Guide

By Khimananda Oli | Last reviewed: August 2026

Deploying a fresh Ubuntu instance without immediate hardening exposes your infrastructure to automated scanners and credential stuffing attacks within minutes. This Ubuntu Security Hardening Guide distills fifteen years of production experience into a repeatable checklist that balances strict defense-in-depth with operational reality. Before you install application dependencies or configure web servers, apply these foundational controls to establish a secure baseline that supports both performance and audit readiness.

Defense-in-Depth LayersNetwork EdgeUFW Default Deny • Fail2Ban • VPC/Subnet IsolationHost AccessSSH Key-Only • No Root Login • MFA • AuditDKernel & OSSysctl Hardening • AppArmor • Unattended UpgradesApplicationLeast Privilege • Secrets Manager • SAST/DAST
Layered security model referenced throughout this Ubuntu Security Hardening Guide

How do I harden SSH access on Ubuntu 24.04?

SSH is the primary attack vector for any internet-facing Linux server. In my work across AWS EC2 instances and on-prem deployments in Nepal, misconfigured SSH remains the most common finding during security assessments. The goal is to eliminate password brute-force possibilities entirely while maintaining reliable administrative access.

Disable root login and password authentication

Edit /etc/ssh/sshd_config and set the following directives. Never edit this file directly in production without a backup or out-of-band console access:

<!-- /etc/ssh/sshd_config -->
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers deployer admin
Protocol 2

After editing, validate the configuration syntax before restarting the daemon to avoid locking yourself out:

sudo sshd -t && sudo systemctl reload sshd

Restrict SSH to specific users and keys

The AllowUsers directive acts as an explicit whitelist. Combine this with per-user authorized_keys stored in /home/<user>/.ssh/authorized_keys with permissions set to 600. For teams managing multiple engineers, consider using SSH certificate authorities or centralized key management instead of distributing individual public keys manually.

  • Generate ED25519 keys locally: ssh-keygen -t ed25519 -C "[email protected]"
  • Copy securely: ssh-copy-id -i ~/.ssh/id_ed25519.pub deployer@server
  • Audit existing keys quarterly and revoke access immediately upon team member departure

How should I configure UFW firewall rules for production?

Uncomplicated Firewall (UFW) wraps nftables with a syntax that reduces human error. A common mistake I see in audits is leaving port 22 open to 0.0.0.0/0 on cloud instances where security groups already restrict access. Defense-in-depth means both layers should enforce least privilege independently.

Establish default-deny policy first

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw logging on low

Add explicit allow rules with source restrictions

# SSH only from bastion or office IP
sudo ufw allow from 203.0.113.50/32 to any port 22 proto tcp comment 'Admin SSH'

# HTTPS for public traffic
sudo ufw allow 443/tcp comment 'Web HTTPS'

# Internal monitoring agent
sudo ufw allow from 10.0.0.0/8 to any port 9100 proto tcp comment 'Node Exporter'

Enable the firewall only after verifying your current session will not be terminated:

sudo ufw enable

For environments requiring more granular packet inspection or NAT rules, refer to the comparison in our nftables versus iptables guide. UFW suffices for 90% of web application servers, but database nodes and internal services often benefit from direct nftables rulesets managed via Infrastructure as Code.

UFW Packet Evaluation FlowIncoming PacketMatch Allow Rule?(Source + Port + Protocol)YESNOACCEPT & LogDROP (Default Deny)Pass to ApplicationSilent Discardufw status verbose | grep ALLOW → Verify rules quarterly
Packet evaluation sequence for UFW default-deny firewall configuration

What kernel parameters matter most for Ubuntu server hardening?

Kernel-level hardening prevents entire classes of exploits including SYN floods, IP spoofing, and privilege escalation via core dumps. These settings belong in /etc/sysctl.d/99-hardening.conf so they persist across upgrades and can be version-controlled alongside your Ansible playbooks.

# /etc/sysctl.d/99-hardening.conf
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
kernel.core_uses_pid = 1
kernel.kptr_restrict = 2
fs.suid_dumpable = 0

Apply immediately without reboot:

sudo sysctl --system
ParameterPurposeRisk if Disabled
tcp_syncookiesMitigates SYN flood DoS attacksServer becomes unresponsive under volumetric attack
rp_filterReverse path filtering blocks spoofed packetsAccepts traffic claiming to originate from internal IPs
accept_redirectsIgnores ICMP redirect messagesAttacker reroutes traffic through malicious gateway
kptr_restrictHides kernel memory addresses from unprivileged usersExposes KASLR bypass information for exploit chaining
suid_dumpablePrevents core dumps of privileged processesSensitive credentials leaked to disk in crash artifacts

How do I automate security patching without breaking production?

Manual patching fails at scale. I have audited systems running kernels three years out of date because "we'll update during the next maintenance window" never happened. Unattended-upgrades handles security patches automatically while giving you control over timing and rollback capability.

Configure unattended-upgrades for security-only updates

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

Edit /etc/apt/apt.conf.d/50unattended-upgrades:

Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";
Unattended-Upgrade::Mail "[email protected]";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";

For SOC 2 or ISO 27001 compliance, maintain evidence of patch cadence. Configure logging to ship to your centralized stack as described in our Loki and Grafana log aggregation guide. Auditors will request proof that critical CVEs were remediated within your SLA; automated logs satisfy this requirement without manual spreadsheet tracking.

Should I use AppArmor or SELinux on Ubuntu?

Ubuntu ships with AppArmor enabled by default. Unless your organization mandates SELinux for regulatory reasons, stay with AppArmor. The learning curve is gentler, profiles exist for most common daemons, and debugging denials requires less specialized knowledge. In practice, I have seen teams disable mandatory access control entirely because SELinux complexity exceeded their capacity — a worse outcome than using AppArmor effectively.

Verify AppArmor status and enforce profiles:

sudo aa-status
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx

Create custom profiles incrementally using aa-logprof after observing denials in /var/log/syslog. Start in complain mode (aa-complain) for new applications, promote to enforce only after validating functionality in staging. This approach prevents production outages while still achieving meaningful confinement.

AppArmor vs SELinux Decision MatrixAppArmor (Recommended)✓ Default on Ubuntu 24.04 LTS✓ Path-based profile model✓ Lower operational overhead✓ Pre-built profiles for nginx, mysql✓ Faster incident diagnosisBest for: Web apps, SMBs, DevOps teamsSELinux✗ Not default on Ubuntu✗ Label-based MAC model✗ Steeper learning curve✓ Required by some federal standards✓ Finer-grained object controlBest for: Government, high-assurance MLSvs
Decision framework for choosing mandatory access control in Ubuntu hardening

Final Steps for Sustainable Ubuntu Security Hardening

Hardening is not a one-time event but a continuous process embedded in your deployment pipeline. Codify every step in this Ubuntu Security Hardening Guide as Ansible roles or Terraform modules so new instances inherit the same baseline without manual intervention. Schedule quarterly reviews of SSH keys, firewall rules, and kernel parameters against updated CIS benchmarks. Monitor compliance drift with tools like OpenSCAP or Wazuh, and integrate findings into your existing observability stack.

If your team needs help implementing these controls at scale or preparing for SOC 2 / ISO 27001 audits on Ubuntu infrastructure, reach out to discuss your specific environment. I work with organizations across Nepal and globally to build systems that are secure by default, observable by design, and audit-ready from day one.

Frequently Asked Questions

Update all packages and enable automatic security updates using unattended-upgrades to patch known vulnerabilities immediately after installation.

Edit /etc/ssh/sshd_config, set PermitRootLogin to no, then restart sshd. Always configure SSH key authentication for a non-root user before disabling root access to prevent lockout.

UFW remains the standard frontend for netfilter on Ubuntu. Configure default deny policies and explicitly allow only required ports like 22, 80, and 443 before enabling the firewall.

Yes, this guide maps configurations to CIS Ubuntu Linux 24.04 LTS Benchmark v1.0 controls, providing specific remediation commands for each scoring requirement.

Audit quarterly or after major package upgrades, as system updates can reset configuration files or introduce new services requiring additional hardening measures.

Yes, use community roles like dev-sec.hardening or write custom playbooks targeting sshd, ufw, sysctl, and auditd configurations for consistent deployment across fleets.

Enable ASLR, disable IP forwarding, restrict core dumps, and set tcp_syncookies via sysctl.conf to mitigate network-based attacks and memory exploitation attempts.

Yes, AppArmor loads automatically and enforces profiles for installed services. Verify status with aa-status and create custom profiles for unconfined applications handling sensitive data.

Run OpenSCAP or lynis audits against CIS benchmarks to generate compliance reports identifying misconfigurations, missing patches, or weak permissions requiring remediation.

Absolutely. Blacklist cramfs, freevxfs, jffs2, hfs, and squashfs in /etc/modprobe.d if unused to reduce kernel attack surface per CIS recommendations.

Configure rsyslog to forward logs remotely, enable auditd with rules for privileged commands, and retain auth.log for at least ninety days to support incident investigation.

Minimal impact when properly tuned. Excessive audit rules or aggressive AppArmor profiles may cause latency, so test thoroughly in staging before production deployment.

Mount /dev/shm with noexec,nosuid,nodev options in fstab to prevent execution of malicious binaries in temporary shared memory segments used by attackers.

Snaps run sandboxed with AppArmor confinement by default, offering better isolation than traditional deb packages for untrusted or frequently updated applications.

Legacy applications expecting unrestricted /tmp access or raw socket permissions typically fail; review application requirements and adjust AppArmor or systemd sandboxing accordingly.