Ubuntu 20.04 Security Features Worth Using
Ubuntu 20.04 ships with several built-in security features that are installed by default but often left at their out-of-box settings. Understanding what is available and how to configure it properly can significantly strengthen your server's security posture without the need for additional software. Many administrators overlook these tools or enable them without fully understanding their capabilities, which means servers are not getting the protection they could have.
This guide covers the most useful security features that come with Ubuntu 20.04, practical steps to enable and configure them, and what each tool actually does to protect your system. If you are setting up a new server or reviewing an existing one, these features should be part of your baseline configuration.
UFW: The Uncomplicated Firewall
UFW is the default firewall configuration tool on Ubuntu. It acts as a wrapper around iptables, providing a simpler command-line interface while handling the underlying netfilter rules. On a new Ubuntu installation, UFW is present but disabled. Enabling it correctly is one of the first things you should do on any Ubuntu server, though you need to ensure SSH access is allowed before turning the firewall on to avoid locking yourself out.
The default policy for incoming connections is deny, which is the correct setting for a server. Only explicitly allowed ports will accept connections. The default policy for outgoing connections is allow, which means the server can make outbound connections freely.
# Allow SSH before enabling the firewall
sudo ufw allow 22/tcp
# Enable the firewall
sudo ufw enable
# Check the status and current rules
sudo ufw status verbose
If you are connecting via SSH, make sure you allow the SSH port first. If you use a non-standard SSH port, adjust the rule accordingly. For a detailed walkthrough of UFW configuration including common service rules, the guide on how to configure UFW firewall on Ubuntu covers practical examples for web servers, databases, and more.
Allowing Common Services
Once UFW is enabled, you need to add rules for the services you actually need running. Here are common examples:
# Allow web traffic (HTTP and HTTPS)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Allow SSH on a non-standard port (e.g., 2222)
sudo ufw allow 2222/tcp
# Allow only a specific IP to access a port (useful for database servers)
sudo ufw allow from 192.168.1.100 to any port 3306
# Deny a specific port
sudo ufw deny 3306
UFW supports both TCP and UDP rules. Most web traffic uses TCP, while DNS queries may use either protocol depending on your configuration.
Application Profiles
Some packages ship with UFW application profiles that make it easier to open the correct ports:
# List available application profiles
sudo ufw app list
# Allow an application profile
sudo ufw allow 'Nginx Full'
Application profiles are useful because they often include comments explaining what each profile does. You can view the details of any profile before applying it.
AppArmor: Mandatory Access Control
AppArmor is a security module built into the Ubuntu kernel that restricts what processes can do, regardless of what the standard Linux user permissions allow. By default, Ubuntu 20.04 ships with AppArmor profiles for common services, including Nginx, Apache, MySQL, and many other packages. These profiles limit the files, capabilities, and network access that each service can use.
The difference between traditional Unix permissions and AppArmor's mandatory access control is important. A process running as root with standard permissions can read and write almost anything on the system. With AppArmor enforcing a profile, that same process is restricted to only the files, directories, and capabilities defined in its profile, even if it runs as root.
Checking AppArmor Status
AppArmor runs in one of three modes. Enforce mode actively blocks violations. Complain mode logs violations without blocking them, which is useful for testing new profiles. Disabled mode means AppArmor is not running for that profile.
# Check AppArmor status
sudo aa-status
Typical output on an Ubuntu 20.04 server with Nginx and MySQL installed looks like this:
apparmor module is loaded.
9 profiles are in enforce mode.
/usr/sbin/nginx
/usr/sbin/mysqld
/usr/bin/screen
...
2 profiles are in complain mode.
/usr/lib/NetworkManager/nm-dhcp-client.action
/usr/lib/NetworkManager/nm-dhcp-client.sh
0 profiles are in disabled mode.
If a service is behaving unexpectedly, it is worth checking AppArmor denial logs to see if the security module is blocking a legitimate operation.
sudo dmesg | grep -i apparmor | tail -20
If AppArmor is blocking a legitimate operation, you can investigate by temporarily setting the profile to complain mode while you examine the issue. However, running security-relevant services permanently in complain mode reduces your protection, so resolve the underlying issue promptly.
Automatic Security Updates
Ubuntu 20.04 can install security updates automatically without requiring user intervention. This functionality is provided by the unattended-upgrades package, which is installed by default on Ubuntu Server but may not be enabled.
sudo apt install unattended-upgrades
sudo dpkg-reconfigure unattended-upgrades
The dpkg-reconfigure command opens an interactive prompt where you can enable or disable automatic updates. For headless servers or automated setups, you can also enable it directly through the configuration.
Configuring Automatic Updates
The configuration file at /etc/apt/apt.conf.d/50unattended-upgrades controls which updates are applied automatically. The default configuration applies security updates automatically, which is appropriate for most servers. You can extend this to other update types, but automatic installation of major version upgrades or kernel updates may cause unexpected behaviour in some environments.
# Check what automatic updates are configured
cat /etc/apt/apt.conf.d/50unattended-upgrades
Automatic updates are appropriate for most servers, but do not enable them without monitoring. Configure email notifications so you know when updates are applied and can investigate if anything goes wrong.
Unattended-Upgrade::Mail "[email protected]";
If you are managing multiple servers, consider centralising log collection so you have visibility across your infrastructure. Combining automatic updates with a monitoring solution means you get both the speed of automated patching and the awareness needed to catch problems early.
Securing SSH
SSH is the primary access point for most Ubuntu servers, and its configuration is one of the most impactful security decisions you can make. The SSH daemon configuration file is at /etc/ssh/sshd_config. The default configuration on Ubuntu 20.04 allows password authentication, which is a common target for brute-force attacks.
Before making changes to SSH configuration, ensure you have a way to access the server if your changes cause a problem. Keeping an active session open while testing changes is a sensible precaution.
Key-Based Authentication
The most important change is disabling password authentication and switching to key-based authentication. SSH keys are far more resistant to brute-force attacks than passwords.
# On your local machine, generate an SSH key pair
ssh-keygen -t ed25519
# Copy the public key to your server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server
Test that key-based login works in a new terminal before making any changes to the SSH configuration.
Hardening the SSH Configuration
Once key-based authentication is confirmed working, edit the SSH configuration file:
sudo nano /etc/ssh/sshd_config
Apply these settings:
# Disable password authentication (use key-based auth only)
PasswordAuthentication no
# Disable root login
PermitRootLogin no
# Change the default port (reduces automated scanning)
Port 2222
# Limit the users who can SSH in
AllowUsers deploy admin
# Disable empty passwords
PermitEmptyPasswords no
# Maximum authentication attempts
MaxAuthTries 3
# Client alive interval to detect inactive connections
ClientAliveInterval 300
ClientAliveCountMax 2
After making changes, test the configuration and restart the SSH daemon:
sudo sshd -t
sudo systemctl restart sshd
The sshd -t command checks the configuration file for syntax errors before restarting. This prevents you from locking yourself out due to a configuration mistake. For additional SSH hardening techniques including fail2ban configuration, the guide on Fail2Ban SSH and HTTP protection setup covers how to automatically block repeated login attempts.
PAM: Pluggable Authentication Modules
Ubuntu 20.04 uses PAM for authentication configuration. PAM controls how users authenticate, how many failed login attempts are allowed before lockout, and password complexity requirements. The pam_faillock module provides account lockout functionality, which helps protect against brute-force login attempts.
Configuring Account Lockout
Account lockout temporarily disables a user account after a set number of failed authentication attempts. This makes brute-force attacks significantly more difficult.
# Edit the common-auth file
sudo nano /etc/pam.d/common-auth
Add these lines before the standard auth modules:
auth required pam_faillock.so preauth audit deny=5 unlock_time=900
auth requisite pam_faillock.so failux
auth sufficient pam_faillock.so success
This configuration locks an account for 15 minutes (900 seconds) after 5 failed login attempts. Adjust these values based on your security requirements and how legitimate users might need to retry.
Managing Locked Accounts
If an account becomes locked and you need to unlock it manually:
# Unlock a locked account
sudo pam_faillock --user username --reset
Replace username with the actual account name that needs unlocking.
System Audit with auditd
The auditd package provides detailed logging of system calls and file access. It is useful for security auditing, compliance requirements, and for investigating suspicious activity after an incident. While it adds some overhead, the detailed logs it produces are invaluable when trying to understand what happened during a security incident.
sudo apt install auditd
sudo systemctl enable auditd
sudo systemctl start auditd
Creating Audit Rules
Configure which files and directories to monitor by adding rules to the audit rules file:
sudo nano /etc/audit/rules.d/audit.rules
Here are practical rules to consider:
# Monitor /etc/shadow for changes (password file)
-w /etc/shadow -p wa -k shadow_changes
# Monitor SSH configuration
-w /etc/ssh/sshd_config -p wa -k sshd_config_changes
# Monitor /var/log for changes
-w /var/log/ -p wa -k log_changes
# Monitor the passwd file
-w /etc/passwd -p wa -k passwd_changes
After adding rules, load them:
sudo auditctl -R /etc/audit/rules.d/audit.rules
To make these rules persistent across reboots, ensure they are saved in the rules file, as the auditctl command only loads rules for the current session.
Querying Audit Logs
Use ausearch to query the audit log for specific events:
# Find all events related to /etc/shadow
sudo ausearch -k shadow_changes
# Find failed authentication attempts
sudo ausearch -m USER_AUTH -i
# Search for events from a specific user
sudo ausearch -ua 1000 -i
Regularly reviewing audit logs, or configuring a log management solution to alert on specific events, helps you catch suspicious activity early.
Hardening the Linux Kernel
The Linux kernel itself has security settings that can be tuned through sysctl. These settings control how the kernel handles networking, memory, and system calls. The linux-hardened package applies a sensible set of security-focused sysctl settings automatically:
sudo apt install linux-hardened
Review the settings it applies and adjust if needed for your specific environment:
# Restrict access to kernel messages (prevents info leakage)
kernel.dmesg_restrict = 1
# Hide kernel pointers (makes exploitation harder)
kernel.kptr_restrict = 2
# Restrict ptrace usage (limits process inspection)
kernel.yama.ptrace_scope = 1
# Enable source address validation (helps prevent spoofing)
net.ipv4.conf.all.rp_filter = 1
# Disable source routing (security improvement)
net.ipv4.conf.all.accept_source_route = 0
These kernel parameters affect how the operating system handles various security-relevant scenarios. The linux-hardened package applies a reasonable baseline, but you may need to adjust some settings depending on your specific networking requirements. For a more comprehensive hardening checklist, the Ubuntu server hardening checklist covers additional steps beyond the default configuration.
Putting It Together
Each of these features addresses a different aspect of server security. UFW controls network access. AppArmor restricts what applications can do. Automatic updates keep your packages current. SSH hardening reduces the attack surface of remote access. PAM adds account lockout protection. auditd provides visibility into what is happening on the system. Kernel hardening improves the baseline security of the operating system itself.
None of these tools alone provides complete security, but together they create layered protection that makes your server significantly more resilient. Review each feature, apply what makes sense for your setup, and revisit the configuration as your server's role changes over time.