🔒 Ubuntu Server Hardening Guide

Securing Your Server as a Non-Root User

📋 Overview

This comprehensive guide covers essential server hardening techniques for Ubuntu Server, focusing on security measures that should be implemented as a non-root user. Server hardening is the process of securing a server by reducing its attack surface and implementing security best practices to protect against potential threats and unauthorized access.

What You'll Learn:
  • Understanding and using sudo for administrative tasks
  • Implementing SSH key authentication
  • Configuring SSH for secure remote access
  • Keeping your server updated
  • Implementing firewall policies
  • Using Fail2Ban for intrusion prevention

🛡️ Understanding Sudo: The Superuser Command

What is Sudo?

Sudo (Superuser Do) is a powerful command that allows permitted users to execute commands with elevated privileges without switching to the root user account. This approach provides an additional layer of security and accountability by making administrators more conscious of their actions and creating an audit trail of privileged operations.

💡 Key Principle: The root user is all-powerful and any mistakes made as root can be devastating and often irreversible. A single command executed incorrectly as root can destroy an entire server. Sudo forces you to think before executing privileged commands.

How Sudo Works

User enters command with sudo prefix
System prompts for user's password
Password is cached for 5 minutes
Command executes with root privileges

Common Sudo Usage Examples

Example 1: Rebooting the Server

$ reboot
Call to reboot failed: Interactive authentication required.

$ sudo reboot
[sudo] password for andrew:
Connection closed by remote host.

Example 2: Editing Configuration Files

$ nano /etc/ssh/sshd_config
[ Error writing /etc/ssh/sshd_config: Permission denied ]

$ sudo nano /etc/ssh/sshd_config
[sudo] password for andrew:
[ File opens successfully for editing ]

Example 3: Clearing Cached Password

$ sudo -k
[ Clears the cached sudo password ]
⚠️ Important: When performing administrative tasks such as installing packages, updating the system, restarting services, or editing configuration files, you must always use sudo before the command.

When to Use Sudo

Task Type Requires Sudo? Example
Installing packages ✓ Yes sudo apt install nginx
Updating packages ✓ Yes sudo apt update
Restarting services ✓ Yes sudo systemctl restart ssh
Editing system config files ✓ Yes sudo nano /etc/ssh/sshd_config
Viewing directories ✗ No ls -la
Changing your own files ✗ No nano myfile.txt

🔑 SSH Key Authentication: Passwordless Security

Understanding SSH Key Authentication

SSH key authentication is a more secure alternative to password-based authentication. It uses a public-private key pair where the private key remains on your local machine (encrypted with a passphrase) and the public key is stored on the server. This method is significantly more secure because it eliminates the risk of password brute-force attacks and provides stronger cryptographic security.

Your Local PC/Mac

🔐 Private Key (Encrypted)

Never leaves your machine

Ubuntu Server

🔓 Public Key

Stored in ~/.ssh/authorized_keys

How SSH Key Authentication Works

Client initiates SSH connection
Server sends challenge encrypted with public key
Client decrypts challenge with private key
Client sends response to server
Server verifies response and grants access
⚠️ Critical Warning: DO NOT log into your server to generate the SSH key pair! The key pair must be generated locally on your PC or Mac, not on the server. This is a fundamental security principle.

Step-by-Step Implementation Guide

  1. Verify You're on Your Local Machine

    Before proceeding, ensure you're working on your local machine, not logged into the server. Check your terminal prompt.

    $ hostname
    HP ← Local machine

    If you see your server hostname (e.g., "2404"), you're logged into the server. Type 'exit' to log out.
  2. Generate the SSH Key Pair

    Create a 4096-bit RSA key pair on your local machine. This command works identically on Linux, Mac, and Windows (Git Bash).

    $ ssh-keygen -t rsa -b 4096
    Generating public/private rsa key pair.
    Enter file in which to save the key (/home/andrew/.ssh/id_rsa):
    my_2404_server_keys ← Use underscores, no spaces

    Enter passphrase (empty for no passphrase):
    ******** ← Strong passphrase (NOT your server password)
    Enter same passphrase again:
    ********

    Your identification has been saved in /home/andrew/.ssh/my_2404_server_keys
    Your public key has been saved in /home/andrew/.ssh/my_2404_server_keys.pub
    Understanding the Passphrase: The passphrase encrypts your private key on your local machine. It is NOT the password you use to log into your server. You'll need this passphrase each time you use the private key to connect to your server.
  3. Verify Key Generation

    Check that both keys were created with correct permissions.

    $ ls -l ~/.ssh/
    -rw------- 1 andrew andrew 3389 Nov 05 10:30 my_2404_server_keys ← Private key (600)
    -rw-r--r-- 1 andrew andrew 742 Nov 05 10:30 my_2404_server_keys.pub ← Public key (644)
  4. Copy Public Key to Server

    Use ssh-copy-id to securely transfer and configure your public key on the server.

    $ ssh-copy-id -i ~/.ssh/my_2404_server_keys.pub [email protected]
    /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s)
    [email protected]'s password: ← Enter your server password (one last time)

    Number of key(s) added: 1

    Now try logging into the machine with:
    ssh '[email protected]'
    and check to make sure that only the key(s) you wanted were added.
    What Just Happened: The ssh-copy-id command connected to your server using SSH, created the necessary directories and files, added your public key to ~/.ssh/authorized_keys, and set the correct permissions automatically.
  5. Test SSH Key Authentication

    Verify that you can log in using your private key instead of a password.

    $ ssh -i ~/.ssh/my_2404_server_keys [email protected]
    Enter passphrase for key '/home/andrew/.ssh/my_2404_server_keys':
    ******** ← Enter your passphrase to unlock the private key

    Welcome to Ubuntu 24.04 LTS
    andrew@2404:~$ ← Successfully logged in!
  6. Disable Password Authentication

    Now that SSH key authentication works, disable password-based login for enhanced security.

    $ cd /etc/ssh/sshd_config.d/
    $ sudo nano 50-cloud-init.conf
    [sudo] password for andrew:

    # Find and modify the following line:
    PasswordAuthentication yes
    PasswordAuthentication no ← Change to 'no'

    # Save and exit: Ctrl+X, then Y, then Enter
  7. Restart SSH Service

    Apply the configuration changes by restarting the SSH service.

    $ sudo systemctl restart ssh
    [ SSH service restarted successfully ]
  8. Verify Password Authentication is Disabled

    Log out and test that password authentication no longer works.

    $ exit
    logout
    Connection to 192.168.1.100 closed.

    $ ssh -i ~/.ssh/my_2404_server_keys [email protected]
    Enter passphrase for key '/home/andrew/.ssh/my_2404_server_keys':
    ********
    andrew@2404:~$ ← Only key authentication works now!
⚠️ Critical Backup Reminder:
  • DO NOT lose the private key file on your PC/Mac
  • Create a backup copy on a USB stick and store it securely
  • If you lose your private key and password authentication is disabled, you will be locked out of your server
  • Keep your passphrase in a secure password manager

⚡ Server Updates: Keeping Your System Secure

Regular system updates are crucial for maintaining server security. Updates include security patches, bug fixes, and performance improvements that protect your server from known vulnerabilities and exploits.

Understanding System Update Messages

Welcome to Ubuntu 24.04 LTS
System restart required
Pending kernel upgrade
Running kernel version: 5.15.0-87-generic
Expected kernel version: 5.15.0-91-generic

When Server Restart is Required

After creating a new server instance, many hosting providers (like Vultr, DigitalOcean, AWS) automatically run package updates. If kernel updates are applied, you'll see a "System restart required" message. Here's how to handle it:

$ sudo reboot
[sudo] password for andrew:
Connection to 192.168.1.100 closed by remote host.

# Wait a minute or two for the server to reboot

$ ssh -i ~/.ssh/my_2404_server_keys [email protected]
ssh: connect to host 192.168.1.100 port 22: Connection refused
# Server still rebooting, wait a bit longer...

$ ssh -i ~/.ssh/my_2404_server_keys [email protected]
Enter passphrase for key:
Welcome to Ubuntu 24.04 LTS
andrew@2404:~$ ← Restart complete, messages cleared

Regular Update Commands

Command Purpose When to Use
sudo apt update Updates package lists from repositories Before installing or upgrading packages
sudo apt upgrade Upgrades installed packages to newer versions Weekly or when security updates available
sudo apt dist-upgrade Upgrades packages and handles dependencies For major system upgrades
sudo apt autoremove Removes unnecessary packages After upgrades to clean up
Best Practice Update Routine:
$ sudo apt update
$ sudo apt upgrade -y
$ sudo apt autoremove -y
$ sudo reboot ← Only if kernel was updated

🔥 Firewall Configuration: Closing Unused Ports

Implementing a firewall policy is one of the most crucial steps in server hardening. A properly configured firewall acts as a barrier between your server and potential threats, allowing only necessary traffic while blocking everything else.

💡 Firewall Principle: Deny all incoming traffic by default, then explicitly allow only the services and ports you need. This "default deny" approach minimizes your attack surface.

Common Ports and Services

Port Service Protocol Should Allow?
22 SSH TCP ✓ Yes (for remote access)
80 HTTP TCP ✓ If running web server
443 HTTPS TCP ✓ If running web server
3306 MySQL TCP ✗ Block (internal only)
5432 PostgreSQL TCP ✗ Block (internal only)

🛡️ Fail2Ban: Intrusion Prevention

Fail2Ban is an intrusion prevention framework that protects your server from brute-force attacks by monitoring log files and automatically blocking IP addresses that show malicious behavior, such as too many failed login attempts.

How Fail2Ban Works

Fail2Ban monitors log files (e.g., /var/log/auth.log)
Detects failed login attempts or suspicious patterns
Counts failures from each IP address
If threshold exceeded, adds firewall rule to block IP
IP remains blocked for configured ban time
After ban expires, IP is automatically unblocked
Protection Benefits:
  • Automatically blocks brute-force SSH login attempts
  • Protects web applications from DDoS and authentication attacks
  • Reduces server load from malicious traffic
  • Creates detailed logs of attack attempts
  • Configurable rules for different services

📝 Summary and Best Practices

Security Checklist

Security Measure Status Priority
Created non-root user with sudo privileges ✓ Complete Critical
Implemented SSH key authentication ✓ Complete Critical
Disabled password authentication ✓ Complete Critical
Applied system updates ✓ Complete High
Configure firewall (UFW) Pending Critical
Install and configure Fail2Ban Pending High

Key Takeaways

  1. Always use sudo for administrative tasks to maintain security and accountability
  2. SSH key authentication is mandatory - never rely solely on passwords
  3. Generate keys locally on your PC/Mac, never on the server
  4. Backup your private key securely - losing it means losing access
  5. Keep systems updated regularly to patch security vulnerabilities
  6. Implement firewall rules to minimize attack surface
  7. Use Fail2Ban to protect against brute-force attacks
⚠️ Critical Reminders:
  • Never lose your SSH private key - store it securely with backups
  • Keep your passphrase in a password manager
  • Always verify you're on your local machine before generating keys
  • Test SSH key authentication before disabling password login
  • Document your security configurations for disaster recovery

Quick Reference Commands

# Generate SSH key pair (LOCAL machine)
ssh-keygen -t rsa -b 4096

# Copy public key to server (LOCAL machine)
ssh-copy-id -i ~/.ssh/keyfile.pub user@server

# Login with SSH key (LOCAL machine)
ssh -i ~/.ssh/keyfile user@server

# Update system (ON server)
sudo apt update && sudo apt upgrade -y

# Restart SSH service (ON server)
sudo systemctl restart ssh

# Clear cached sudo password (ON server)
sudo -k

🎯 Next Steps

With SSH key authentication successfully implemented and password authentication disabled, your server is significantly more secure. The next phase of hardening will focus on configuring the firewall and implementing Fail2Ban. These steps will be completed in subsequent sections to create a comprehensive security posture for your Ubuntu server.

Remember: Security is not a one-time setup but an ongoing process. Regularly review logs, update systems, and stay informed about security best practices and emerging threats.