How to Harden an Ubuntu Server in 2026

The moment you spin up a fresh Ubuntu server, it’s under attack. Within minutes, automated scanners probe your infrastructure for default credentials, unpatched services, and misconfigurations. If you’re tasked with deploying production servers—whether on-premises, in AWS, Azure, or any other cloud platform—you need to harden your Ubuntu server properly from day one. This isn’t optional security theater; it’s foundational operational hygiene that separates mature infrastructure from compromised systems.

In 2026, hardening has evolved. The threat landscape has expanded beyond password brute-forcing and unpatched vulnerabilities to include supply chain attacks, containerized workloads, and increasingly sophisticated adversaries. The good news? Ubuntu’s security tooling has matured alongside these threats. This guide walks you through the practical, battle-tested steps to harden an Ubuntu server in production environments—from kernel hardening to application-level security controls.

The Current Ubuntu Security Landscape

Before diving into hardening steps, understand what you’re protecting against. Ubuntu 22.04 LTS (currently the enterprise standard) and Ubuntu 24.04 LTS (the latest stable release) ship with different security baselines than their predecessors. AppArmor is enabled by default (not SELinux), and systemd handles most security-critical services.

The NIST Cybersecurity Framework and CIS Benchmarks provide standardized hardening guidance, but they often feel disconnected from real operational needs. Your hardening strategy should balance:

  • Security posture — reducing attack surface
  • Operational overhead — automation to avoid manual configuration drift
  • Performance impact — some hardening incurs measurable cost
  • Compliance requirements — whether you need PCI-DSS, HIPAA, SOC 2, etc.

This guide focuses on practical, immediately deployable hardening that most infrastructure teams should implement regardless of compliance mandates.

Step 1: Patch Everything, Immediately

This sounds obvious, but I’ll say it anyway: update your system before any other hardening step.

sudo apt update
sudo apt upgrade -y
sudo apt autoremove

Check what kernel version you’re running and whether a restart is needed:

uname -r
sudo needrestart -r a

The -r a flag tells needrestart to automatically handle restarts. In 2026, Ubuntu’s automatic security updates are reliable enough for most production workloads, but verify this in your environment.

Configure unattended security updates so your systems stay patched between your maintenance windows:

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

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

// Enable automatic restarts if required
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";

// Include security updates from Ubuntu security advisories
Unattended-Upgrade::Package-Blacklist {};

For critical production systems, consider staged rollouts: harden a canary instance, validate patches, then apply to your fleet. Ansible or Terraform can automate this at scale.

Step 2: Disable Unnecessary Services and Network Interfaces

Every running service expands your attack surface. Audit what’s actually running:

sudo systemctl list-units --type=service --state=running
sudo ss -tlnp

The ss command shows all listening ports and their associated processes. Disable anything you don’t need. Common candidates for removal in production:

  • Avahi (mDNS discovery): sudo systemctl disable avahi-daemon
  • CUPS (printing service): sudo systemctl disable cups
  • Bluetooth: sudo systemctl disable bluetooth
  • IMAP/POP services: Only needed if you’re running mail servers

Don’t just disable—actually remove if you’re certain you won’t need it:

sudo apt remove avahi-daemon cups bluetooth -y

If you’re running a server that doesn’t need IPv6, consider disabling it (though this is becoming less necessary as IPv6 becomes standard). Most modern deployments benefit from keeping IPv6 enabled. Instead, focus on what’s actually listening:

# Verify nothing is unexpectedly listening on port 22 (SSH) or other services
sudo netstat -tlnp | grep LISTEN

Step 3: SSH Hardening

SSH is your primary attack vector. Secure it ruthlessly.

Generate a Strong Host Key (If Not Already Present)

# Check existing keys
sudo ls -la /etc/ssh/ssh_host_*

Modern Ubuntu generates strong Ed25519 keys during installation. If you’re retrofitting, you can generate additional strong keys:

sudo ssh-keygen -A

Harden SSH Configuration

Edit /etc/ssh/sshd_config:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
sudo nano /etc/ssh/sshd_config

Apply these critical changes:

# Disable password authentication entirely
PasswordAuthentication no
PubkeyAuthentication yes

# Disable root login
PermitRootLogin no

# Disable empty passwords
PermitEmptyPasswords no

# Restrict to protocol 2
Protocol 2

# Use only strong key exchange algorithms
KexAlgorithms curve25519-sha256,[email protected]
Ciphers [email protected],[email protected]
MACs [email protected],[email protected]

# Limit authentication attempts
MaxAuthTries 3

# Disable X11 forwarding unless you specifically need it
X11Forwarding no

# Set client alive interval to disconnect hung sessions
ClientAliveInterval 300
ClientAliveCountMax 2

# Reduce login grace time
LoginGraceTime 30

# Limit concurrent connections
MaxStartups 10:30:60

# Disable user environment override
PermitUserEnvironment no

# Only allow specific users if possible
AllowUsers deploy ubuntu

Validate the configuration:

sudo sshd -t

Only restart SSH after confirming the syntax is correct:

sudo systemctl restart ssh

Important: Keep your original terminal session open until you verify SSH login works. Never disconnect and risk locking yourself out.

Implement Public Key Authentication Only

On your workstation (not the server), generate a strong keypair if you haven’t already:

ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/id_server

Copy the public key to the server:

ssh-copy-id -i ~/.ssh/id_server.pub ubuntu@your-server-ip

Configure your local SSH config (~/.ssh/config) for convenience:

Host production-server
    HostName 192.0.2.100
    User ubuntu
    IdentityFile ~/.ssh/id_server
    AddKeysToAgent yes
    IdentitiesOnly yes

Step 4: Configure the Firewall

Ubuntu includes UFW (Uncomplicated Firewall), a wrapper around iptables. Enable it:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Check your rules:

sudo ufw status verbose

If you’re running application-specific services, add them explicitly:

sudo ufw allow 3000/tcp    # Node.js app
sudo ufw allow 5432/tcp    # PostgreSQL (if accessible externally—usually not recommended)

Never block outbound SSH entirely—you’ll need to manage the system somehow. Ensure at least port 22 is accessible from your trusted networks.

For cloud deployments (AWS, Azure, GCP), remember that security groups or network ACLs provide an additional layer before reaching UFW. UFW is still valuable for defense-in-depth.

Step 5: Enable and Configure SELinux or Harden AppArmor

Ubuntu ships with AppArmor by default (not SELinux). AppArmor is effective and less verbose than SELinux.

Check that AppArmor is running:

sudo systemctl status apparmor
sudo aa-status

AppArmor profiles ship for common services. Ensure they’re in enforcing mode (not complain mode):

sudo aa-enforce /etc/apparmor.d/usr.sbin.sshd
sudo aa-enforce /etc/apparmor.d/usr.sbin.mysqld    # if running MySQL

If you want to develop custom AppArmor profiles for your applications, the process is similar to SELinux but simpler. For most infrastructure, the default profiles are sufficient.

Step 6: Harden the Kernel

Modern Linux kernels expose dangerous settings by default. Adjust /etc/sysctl.conf to close these gaps:

sudo nano /etc/sysctl.conf

Add or modify these kernel parameters:

# IP forwarding (disable if not needed)
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0

# Disable source packet routing
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0

# Enable SYN cookies for SYN flood protection
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 4096

# Log suspicious packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# Disable ICMP redirects
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1

# Restrict kernel module loading
kernel.modules_disabled = 1

# Restrict access to kernel logs
kernel.dmesg_restrict = 1

# Restrict ptrace for additional process isolation
kernel.yama.ptrace_scope = 2

# Restrict access to kptr in /proc
kernel.kptr_restrict = 2

# Restrict access to kernel pointers
kernel.perf_event_paranoid = 3

# Restrict unprivileged user namespaces (breaks Docker if enabled—choose carefully)
# kernel.unprivileged_userns_clone = 0

# Restrict unprivileged eBPF
kernel.unprivileged_bpf_disabled = 1
kernel.bpf_stats_enabled = 0

Apply the changes:

sudo sysctl -p

Verify they took effect:

sudo sysctl -a | grep kernel.dmesg_restrict

Step 7: File System Hardening

Mount filesystems with restrictive permissions:

# Check current mounts
mount | grep -E 'ext4|xfs|btrfs'

Edit /etc/fstab to add security options:

# Find your root and other partitions
sudo blkid

# Edit /etc/fstab
sudo nano /etc/fstab

Add or modify entries with these flags:

# For /tmp (create if not present, or modify existing entry)
tmpfs /tmp tmpfs defaults,nosuid,nodev,noexec,relatime,mode=1777 0 0

# For /var/tmp
tmpfs /var/tmp tmpfs defaults,nosuid,nodev,noexec,relatime,mode=1777 0 0

# For /dev/shm
tmpfs /dev/shm tmpfs defaults,nosuid,nodev,noexec,relatime,mode=1777 0 0

Remount to apply:

sudo mount -o remount,nosuid,nodev,noexec /tmp
sudo mount -o remount,nosuid,nodev,noexec /var/tmp
sudo mount -o remount,nosuid,nodev,noexec /dev/shm

These flags prevent execution of binaries from temporary filesystems—a common attack vector for deploying malware.

Step 8: User and Permission Hardening

Enforce Strong Password Policies

Install and configure PAM (Pluggable Authentication Modules):

sudo apt install libpam-pwquality
sudo nano /etc/security/pwquality.conf

Configure password requirements:

minlen = 14
dcredit = -1
ucredit = -1
ocredit = -1
lcredit = -1
maxrepeat = 3
difok = 4
usercheck = 1
enforce_for_root

Disable Unnecessary User Accounts

List all users:

cut -d: -f1 /etc/passwd

Disable accounts you don’t need:

sudo usermod -L username    # Lock the account
sudo usermod -s /usr/sbin/nologin username    # Disable login shell

Configure sudo Properly

Edit /etc/sudoers using visudo (never edit directly):

sudo visudo

Ensure users requiring elevated privileges are in the sudo group, and consider adding this line to log all sudo commands:

Defaults use_pty
Defaults logfile="/var/log/sudo.log"

Step 9: Implement Audit Logging

The auditd daemon captures detailed system events. Install it:

sudo apt install auditd audispd-plugins
sudo systemctl enable auditd
sudo systemctl start auditd

Add audit rules for critical files:

sudo nano /etc/audit/rules.d/audit.rules

Example audit rules:

# Monitor SSH configuration changes
-w /etc/ssh/sshd_config -p wa -k sshd_config_changes

# Monitor system calls
-a always,exit -F arch=b64 -S execve -F uid=0 -k root_commands

# Monitor sudo usage
-w /etc/sudoers -p wa -k sudoers_changes
-w /etc/sudoers.d/ -p wa -k sudoers_changes

Load rules and verify:

sudo augenrules --load
sudo auditctl -l

Query audit logs:

sudo ausearch -k sshd_config_changes

For centralized logging, forward audit events to a SIEM or logging platform.

Step 10: Enable Automatic Security Updates and Monitoring

Configure unattended security updates (covered earlier), but add monitoring. Install and enable apt-listchanges to see what’s being updated:

sudo apt install apt-listchanges

Set up systemd timer notifications or integrate with your monitoring platform (Datadog and similar services can track patch compliance across your infrastructure).

Create a simple monitoring script to verify hardening is maintained:

#!/bin/bash
# verify_hardening.sh

echo "Checking SSH configuration..."
sudo sshd -T | grep -E "PasswordAuthentication|PermitRootLogin|X11Forwarding"

echo "Checking firewall status..."
sudo ufw status | grep Status

echo "Checking for listening services..."
sudo ss -tlnp | wc -l

echo "Checking for unpatched packages..."
sudo apt list --upgradable 2>/dev/null | wc -l

Run this script regularly (e.g., via cron) and alert if settings drift.

Hardening Automation with Infrastructure as Code

Manual hardening doesn’t scale. Automate using Ansible, Terraform, or cloud-init:

Cloud-Init Example

If deploying on AWS or Azure, use user data to automate initial hardening:

#!/bin/bash
apt-get update
apt-get install -y unattended-upgrades auditd

# Configure SSH
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
systemctl restart ssh

# Enable firewall
ufw default deny incoming
ufw allow ssh
ufw enable

Ansible Playbook Snippet

---
- name: Harden Ubuntu Server
  hosts: all
  become: yes

  tasks:
    - name: Update all packages
      apt:
        update_cache: yes
        upgrade: dist

    - name: Install security tools
      apt:
        name:
          - unattended-upgrades
          - auditd
          - fail2ban
        state: present

    - name: Disable password SSH authentication
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^#?PasswordAuthentication'
        line: 'PasswordAuthentication no'
        validate: /usr/sbin/sshd -T -f %s
      notify: restart ssh

    - name: Enable UFW
      ufw:
        state: enabled
        default: deny
        direction: incoming

  handlers:
    - name: restart ssh
      systemd:
        name: ssh
        state: restarted

This approach ensures consistent hardening across your infrastructure and makes compliance audits straightforward.

Additional Considerations for 2026

Container Security

If running Docker or Kubernetes, harden the container runtime and host separately. Even hardened Ubuntu hosts need additional controls at the container level (seccomp profiles, network policies, image scanning).

Secrets Management

Never embed credentials in configurations. Use 1Password Teams or similar tools to manage SSH keys, API tokens, and database passwords across your team.

Regular Security Audits

Hardening is not a one-time task. Schedule regular:

  • Vulnerability scans using tools like Trivy or Qualys
  • Configuration drift checks to ensure hardening persists
  • Log reviews to detect suspicious activity
  • Penetration testing in non-production environments

Compliance Documentation

If you’re subject to compliance requirements (PCI-DSS, HIPAA, SOC 2), document which hardening steps address specific controls. The CIS Benchmarks for Ubuntu provide a mapping to common compliance frameworks.

Conclusion and Next Steps

Hardening an Ubuntu server in 2026 requires balancing comprehensive security with operational efficiency. Start with the fundamentals—patching, SSH hardening, and firewall configuration—then layer in additional controls based on your threat model and compliance needs.

Your immediate action items:

  1. Patch your system and enable automatic security updates
  2. Harden SSH by disabling password authentication and restricting root login
  3. Enable the firewall and explicitly allow only necessary ports
  4. Configure kernel hardening via sysctl
  5. Automate everything with Ansible, Terraform, or cloud-init

If you’re managing multiple servers, invest time in infrastructure-as-code tooling now. The hours spent automating hardening will return exponentially as your infrastructure scales.

Remember: hardening is a process, not a product. The threat landscape evolves constantly, and your security posture must evolve alongside it. Set calendar reminders to review and update your hardening standards quarterly. Subscribe to Ubuntu security advisories and stay engaged with the security community.

The systems you harden today may protect your organization for years. Make them count.


Affiliate Disclosure: This article may contain affiliate links. If you purchase through these links, TechChimney may earn a commission at no extra cost to you. We only recommend products we believe provide genuine value.