Ubuntu Server Hardening Documentation: SSH Configuration, Security, and Firewall
At a glance#
- Purpose: Baseline security hardening for an Ubuntu server, covering SSH, firewall, users and auditing.
- Applies to: Ubuntu Server 20.04, 22.04 and 24.04.
- Risk: High - SSH and firewall changes can lock you out of a remote host.
- Time: 1-2 hours.
1. SSH Configuration#
Important Note Before You Make SSH Changes#
It is strongly recommended that you keep a second terminal session open while making changes to SSH configuration. This will allow you to fix any issues in case you accidentally lock yourself out from the first session.
SSH Public/Private Key Authentication#
Why Use SSH Public/Private Keys?#
Using SSH public/private keys for authentication is more secure than using a password. It also simplifies and speeds up the connection process as you no longer have to manually enter a password.
How It Works#
SSH public/private key authentication works by using a pair of cryptographic keys. One key (the public key) can only encrypt data, while the other key (the private key) can decrypt the data.
- The public key is placed on the server in the
~/.ssh/authorized_keysfile. - The private key is kept on the client machine and used to decrypt a challenge message sent by the server.
Once the public and private keys are set up, SSH uses these keys to verify the client’s identity without requiring a password. The private key must match the public key stored on the server for the connection to be established.
Goal#
- Ed25519 Public/Private SSH keys will be used.
- Private key on the client machine.
- Public key on the server.
References#
Steps#
- Create an Ed25519 SSH Key Pair on Client:
Run the following command to generate the SSH key pair on the client machine:
``bash ssh-keygen -t ed25519 ``
Follow the prompts and choose a location for saving the key and an optional passphrase. The public key will be saved as ~/.ssh/id_ed25519.pub.
- Transfer Public Key to the Server Using
ssh-copy-id:
Append the public key to the server’s authorized_keys file by running:
``bash ssh-copy-id user@server ``
- Replace
userwith your server’s username andserverwith your server’s IP or hostname. - This command ensures that the public key is copied to the
~/.ssh/authorized_keysfile on the server.
- Verify SSH Access:
Try logging into the server with:
``bash ssh user@server ``
- Ensure you can log in without being asked for a password.
2. Create SSH Group for AllowGroups#
Why?#
Creating an SSH group ensures that only members of a specified UNIX group can SSH into the server, making it easier to control access.
Steps#
- Create the
sshusersGroup:
``bash sudo groupadd sshusers ``
- Add Users to the Group:
To add a user to the group:
``bash sudo usermod -a -G sshusers user1 sudo usermod -a -G sshusers user2 ``
- Configure SSH to Use
AllowGroups:- Edit the SSH configuration file
/etc/ssh/sshd_config:
- Edit the SSH configuration file
``bash sudo nano /etc/ssh/sshd_config ``
- Add the following line to restrict SSH access to users in the
sshusersgroup:
``bash AllowGroups sshusers ``
- Restart SSH:
Restart the SSH service to apply changes:
``bash sudo systemctl restart ssh ``
3. Secure /etc/ssh/sshd_config#
Why?#
Securing the sshd_config file ensures that SSH is configured to use the most secure settings. Improper configurations can leave the system vulnerable to unauthorized access.
Steps#
- Backup the
sshd_configFile:
``bash sudo cp --archive /etc/ssh/sshd_config /etc/ssh/sshd_config-COPY-$(date +"%Y%m%d%H%M%S") ``
- Remove Comments and Edit Settings:
- Run the following to remove commented lines and make the file easier to read:
``bash sudo sed -i -r -e '/^#|^$/ d' /etc/ssh/sshd_config ``
- Edit
/etc/ssh/sshd_config:- Open the file for editing:
``bash sudo nano /etc/ssh/sshd_config ``
- Add or modify the following settings to secure the SSH configuration:
``bash # Enable strong encryption HostKey /etc/ssh/ssh_host_ed25519_key HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_ecdsa_key KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com LogLevel VERBOSE PermitRootLogin no PasswordAuthentication no ChallengeResponseAuthentication yes ``
- Restart SSH:
Restart the SSH service:
``bash sudo systemctl restart ssh ``
4. Remove Short Diffie-Hellman Keys#
Why?#
Using a key length shorter than 3072 bits makes the Diffie-Hellman key exchange vulnerable to attacks. We must remove weak keys.
Steps#
- Backup SSH Moduli:
``bash sudo cp --archive /etc/ssh/moduli /etc/ssh/moduli-COPY-$(date +"%Y%m%d%H%M%S") ``
- Remove Short Moduli:
``bash sudo awk '$5 >= 3071' /etc/ssh/moduli | sudo tee /etc/ssh/moduli.tmp sudo mv /etc/ssh/moduli.tmp /etc/ssh/moduli ``
5. Enable 2FA/MFA for SSH#
Why?#
Adding Two-Factor Authentication (2FA) increases security by requiring two factors (password and a temporary code) to log in.
Steps#
- Install
libpam-google-authenticator:
``bash sudo apt install libpam-google-authenticator ``
- Configure Google Authenticator for the User:
- Run the following command to set up Google Authenticator for the user:
``bash google-authenticator ``
- Backup
/etc/pam.d/sshd:
``bash sudo cp --archive /etc/pam.d/sshd /etc/pam.d/sshd-COPY-$(date +"%Y%m%d%H%M%S") ``
- Edit
/etc/pam.d/sshdto Enable 2FA:
Add the following line to the file:
``bash auth required pam_google_authenticator.so nullok ``
- Edit
/etc/ssh/sshd_configto Enable ChallengeResponseAuthentication:
Add or uncomment:
``bash ChallengeResponseAuthentication yes ``
- Restart SSH:
``bash sudo systemctl restart ssh ``
6. Disable Root Login Over SSH#
Objective: Prevent direct root login over SSH to secure the system.
Steps:#
- Edit the SSH configuration file
/etc/ssh/sshd_config:
``bash sudo nano /etc/ssh/sshd_config ``
- Find the following line and set it to
no:
``bash PermitRootLogin no ``
- Restart SSH service to apply changes:
``bash sudo systemctl restart ssh ``
Summary:#
Direct root login over SSH is disabled, enhancing security by requiring users to log in with a regular account and then escalate privileges.
6. Force Accounts to Use Secure Passwords#
Why?#
By enforcing strong password policies, we ensure that weak passwords are not used, protecting the system from brute-force and dictionary attacks.
Steps#
- Install
libpam-pwquality:
``bash sudo apt install libpam-pwquality ``
- Backup
/etc/pam.d/common-password:
``bash sudo cp --archive /etc/pam.d/common-password /etc/pam.d/common-password-COPY-$(date +"%Y%m%d%H%M%S") ``
- Edit
/etc/pam.d/common-password:
Modify the line starting with password requisite pam_pwquality.so:
``bash password requisite pam_pwquality.so retry=3 minlen=10 difok=3 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1 maxrepeat=3 gecoschec ``
- Verify the Changes:
Change the password for a user to check the new password policy:
``bash passwd <username> ``
7. Session Inactivity Timeout in SSH Config#
Objective: Set a session timeout to automatically disconnect idle SSH sessions.
Steps:#
- Edit the SSH configuration file
/etc/ssh/sshd_config:
``bash sudo nano /etc/ssh/sshd_config ``
- Add the following lines:
``bash ClientAliveInterval 300 ClientAliveCountMax 0 ``
ClientAliveInterval 300: The server will send a message every 300 seconds (5 minutes) to check if the client is still connected.ClientAliveCountMax 0: If no response is received, the session will be terminated after one interval.
- Restart SSH service:
``bash sudo systemctl restart ssh ``
Summary:#
SSH sessions will automatically be terminated after 5 minutes of inactivity to prevent unused sessions from staying open.
8. Automatic Security Updates and Alerts#
Why?#
To ensure the server remains updated with critical patches and security updates, reducing the risk of exploitation from known vulnerabilities.
Steps#
- Install
unattended-upgrades,apt-listchanges, andapticron:
``bash sudo apt install unattended-upgrades apt-listchanges apticron ``
- Configure
unattended-upgrades:
Create /etc/apt/apt.conf.d/51myunattended-upgrades and add:
``bash APT::Periodic::Enable "1"; APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Download-Upgradeable-Packages "1"; APT::Periodic::AutocleanInterval "7"; APT::Periodic::Unattended-Upgrade "1"; ``
- Configure
apticronfor email alerts:
Configure /etc/apticron/apticron.conf to email root for pending updates.
- Enable and Start
unattended-upgrades:
``bash sudo systemctl enable unattended-upgrades.timer sudo systemctl start unattended-upgrades.timer ``
9. Firewall with UFW (Uncomplicated Firewall)#
Why?#
To ensure only authorized traffic can access the server, limiting potential attack vectors.
Steps#
- Install UFW:
``bash sudo apt install ufw ``
- Configure UFW Rules:
- Deny all outgoing traffic by default:
``bash sudo ufw default deny outgoing ``
- Deny all incoming traffic by default:
``bash sudo ufw default deny incoming ``
- Allow incoming SSH connections:
``bash sudo ufw limit in ssh ``
- Allow Necessary Traffic:
- Allow outgoing traffic for DNS, NTP, HTTP, HTTPS, etc.
``bash sudo ufw allow out 53 sudo ufw allow out 123 sudo ufw allow out http sudo ufw allow out https sudo ufw allow out ftp ``
- Enable UFW:
``bash sudo ufw enable ``
- Check UFW Status:
``bash sudo ufw status verbose ``
Default Applications
ufw ships with some default applications. You can see them with:
sudo ufw app listAvailable applications:
AIM
Bonjour
CIFS
DNS
Deluge
IMAP
IMAPS
IPP
KTorrent
Kerberos Admin
Kerberos Full
Kerberos KDC
Kerberos Password
LDAP
LDAPS
LPD
MSN
MSN SSL
Mail submission
NFS
OpenSSH
POP3
POP3S
PeopleNearby
SMTP
SSH
Socks
Telnet
Transmission
Transparent Proxy
VNC
WWW
WWW Cache
WWW Full
WWW Secure
XMPP
Yahoo
qBittorrent
svnserveTo get details about the app, like which ports it includes, type:
sudo ufw app info [app name]sudo ufw app info DNS `` Profile: DNS Title: Internet Domain Name Server Description: Internet Domain Name Server Port: 53 ``
Custom Application
If you don't want to create rules by explicitly providing the port number(s), you can create your own application configurations. To do this, create a file in /etc/ufw/applications.d.
For example, here is what you would use for Plex:
cat /etc/ufw/applications.d/plexmediaserver[PlexMediaServer]
title=Plex Media Server description=This opens up PlexMediaServer for http (32400), upnp, and autodiscovery. ports=32469/tcp|32413/udp|1900/udp|32400/tcp|32412/udp|32410/udp|32414/udp|32400/udp
Then you can enable it like any other app:
sudo ufw allow plexmediaserver