March 7, 2026

PBX Science

VoIP & PBX, Networking, DIY, Computers.

How to securely harden Ubuntu Cloud Server?

How to securely harden Ubuntu Cloud Server?



How to securely harden Ubuntu Cloud Server?

Hardening Your Ubuntu Cloud Server: A Comprehensive Security Guide

December 2025 — In an era where cloud servers face relentless attacks from automated scripts and malicious actors, securing your Ubuntu server immediately after deployment has become non-negotiable.

Recent security advisories from Ubuntu’s December 2025 updates highlight the critical importance of proper server hardening, with multiple kernel vulnerabilities requiring immediate attention across Ubuntu 22.04 LTS, 24.04 LTS, and the newer 24.10 versions.

This comprehensive guide explores essential security measures every system administrator should implement within the first hour of deploying an Ubuntu cloud server, transforming a vulnerable fresh installation into a hardened, production-ready system.


The Critical First Hour: Why Immediate Hardening Matters

Cloud servers become targets within minutes of being deployed. Automated scanning tools continuously probe IP addresses for vulnerable services, with SSH being the primary target. According to recent security research, servers on default configurations can receive hundreds of brute-force attempts within the first 24 hours of deployment.

The stakes are particularly high in late 2025, with Ubuntu releasing patches for critical vulnerabilities including recent OpenSSH security issues that could allow remote code execution through unsafe signal handling. These threats underscore why hardening cannot be postponed.

1. Root Access: To Enable or Not to Enable?

The Default Approach: Disable Root Login

The overwhelming consensus among security professionals is clear: direct root login via SSH should be disabled. Here’s why this matters and how to do it correctly.

Why Disable Root Login?

Root users possess unrestricted system control. If an attacker gains root access through a compromised password or SSH key, they have complete authority over your server. By disabling root login, you create a crucial security layer that forces administrators to use regular user accounts with sudo privileges, providing better audit trails and limiting the blast radius of compromised credentials.

Implementation Steps:

  1. Create a non-root administrative user:
# Create new user with sudo privileges
sudo adduser admin_username
sudo usermod -aG sudo admin_username
  1. Configure SSH key authentication for the new user:
# On your local machine, generate SSH key pair
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

# Copy public key to server
ssh-copy-id admin_username@your_server_ip
  1. Test the new user account before disabling root:
# In a NEW terminal session (keep current session open)
ssh admin_username@your_server_ip
sudo apt update  # Test sudo privileges
  1. Only after confirming the new user works, disable root login:
sudo nano /etc/ssh/sshd_config

Modify these lines:

PermitRootLogin no
PasswordAuthentication no  # Disable password auth entirely
PubkeyAuthentication yes
  1. Restart SSH service:
sudo systemctl restart sshd

When Root Login is Unavoidable: Hardening Strategies

In rare scenarios where root login cannot be disabled (certain legacy applications or specific cloud management requirements), implement these compensatory controls:

A. Enforce Key-Based Authentication Only

# In /etc/ssh/sshd_config
PermitRootLogin without-password
PasswordAuthentication no

B. Restrict Root Login by IP Address

Use SSH configuration to limit which IP addresses can attempt root login:

# In /etc/ssh/sshd_config
Match User root
    AllowUsers root@trusted_ip_address

C. Implement Two-Factor Authentication

Install and configure Google Authenticator for root:

sudo apt install libpam-google-authenticator
google-authenticator

Configure PAM and SSH to require both key and OTP:

# In /etc/pam.d/sshd
auth required pam_google_authenticator.so

# In /etc/ssh/sshd_config
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

D. Aggressive Logging and Monitoring

Configure auditd to track all root activities:

sudo apt install auditd
sudo auditctl -w /etc/passwd -p wa -k passwd_changes
sudo auditctl -w /etc/shadow -p wa -k shadow_changes

2. Installing and Configuring Fail2ban: Automated Defense

Fail2ban has become an essential tool in recent years, with managed hosting providers increasingly including it as a pre-configured service. This intrusion prevention system monitors log files and automatically bans IP addresses exhibiting malicious behavior.

Installation and Basic Setup

# Install Fail2ban
sudo apt update
sudo apt install fail2ban

# Start and enable service
sudo systemctl start fail2ban
sudo systemctl enable fail2ban

Creating Effective Jail Configurations

Fail2ban uses “jails” to define protection rules. Create a local configuration file:

sudo nano /etc/fail2ban/jail.local

Recommended Configuration:

[DEFAULT]
# Ban settings
bantime = 1h          # Ban duration
findtime = 10m        # Time window to track attempts
maxretry = 3          # Failed attempts before ban
destemail = admin@yourdomain.com
sendername = Fail2Ban
action = %(action_mwl)s  # Ban and send email with log

# Whitelist your trusted IPs
ignoreip = 127.0.0.1/8 ::1 your_office_ip_here

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 24h         # Longer ban for SSH attacks
findtime = 10m

# Protect against SSH brute force
[sshd-aggressive]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 2
bantime = 1w          # Week-long ban for persistent attackers
findtime = 1h

# Recidive jail for repeat offenders
[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
action = %(action_mwl)s
bantime = 1w          # One week ban
findtime = 1d         # Track bans over one day
maxretry = 3          # Three separate ban incidents

Advanced Fail2ban Features

Monitor Multiple Services:

# Protect web services
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/error.log

# Protect against bad bots
[nginx-badbots]
enabled = true
port = http,https
filter = nginx-badbots
logpath = /var/log/nginx/access.log
maxretry = 2

Managing Banned IPs

# View all banned IPs
sudo fail2ban-client status

# View specific jail status
sudo fail2ban-client status sshd

# Manually ban an IP
sudo fail2ban-client set sshd banip 192.168.1.100

# Unban an IP
sudo fail2ban-client set sshd unbanip 192.168.1.100

# Monitor Fail2ban logs in real-time
sudo tail -f /var/log/fail2ban.log

Testing Your Fail2ban Configuration

# Test configuration syntax
sudo fail2ban-client -t

# Reload configuration
sudo systemctl reload fail2ban

3. SSH Port Configuration: Security Through Defense in Depth

Understanding the Trade-offs

Arguments for Changing the Port:

  • Significantly reduces automated attack volume
  • Decreases log noise from scanning bots
  • Makes targeted attacks marginally more difficult
  • Signals to attackers that security measures are in place

Arguments Against:

  • Not true security enhancement (obscurity vs. security)
  • Can complicate legitimate access
  • Port scanning easily identifies open SSH ports
  • May violate firewall rules in restricted networks

Best Practice Recommendation: Change the Port

While not a silver bullet, changing the SSH port combined with other measures creates meaningful friction for attackers. Many administrators report 90% reduction in automated attacks after this simple change.

Implementation Guide

1. Choose an Appropriate Port:

# Check if your desired port is available
sudo netstat -tlnp | grep :2222

# Or use ss command
sudo ss -tlnp | grep :2222

Choose a port between 1024-65535 that isn’t used. Avoid common alternative SSH ports like 2222 or 2200 which attackers also scan.

2. Modify SSH Configuration:

sudo nano /etc/ssh/sshd_config

Change or uncomment the Port line:

Port 4422  # Your chosen port

3. Update Firewall Rules:

For UFW (Ubuntu Firewall):

# Allow new SSH port
sudo ufw allow 4422/tcp

# Enable UFW if not already enabled
sudo ufw enable

# After confirming new port works, remove old rule
sudo ufw delete allow 22/tcp

For iptables:

# Allow new port
sudo iptables -A INPUT -p tcp --dport 4422 -j ACCEPT

# Save rules
sudo iptables-save | sudo tee /etc/iptables/rules.v4

4. Update Fail2ban Configuration:

sudo nano /etc/fail2ban/jail.local

Update the port in your SSH jail:

[sshd]
port = 4422

5. Restart Services:

# Test configuration first
sudo sshd -t

# If no errors, restart
sudo systemctl restart sshd
sudo systemctl restart fail2ban

6. Test Before Logging Out:

# In a NEW terminal window (keep current session open)
ssh -p 4422 username@your_server_ip

Complete SSH Hardening Configuration

Beyond port changes, implement these critical SSH hardening measures:

sudo nano /etc/ssh/sshd_config

Recommended Current Settings:

# Protocol and Addressing
Port 4422
Protocol 2
AddressFamily inet          # Use IPv4 only unless IPv6 needed
ListenAddress 0.0.0.0      # Or specify your server IP

# Authentication
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no
UsePAM yes

# Limit login attempts
MaxAuthTries 3
MaxSessions 2
LoginGraceTime 30s

# Security hardening
PermitEmptyPasswords no
X11Forwarding no           # Disable unless specifically needed
PermitUserEnvironment no
AllowAgentForwarding no
AllowTcpForwarding no
GatewayPorts no

# Cryptography (strong algorithms only)
Ciphers [email protected],[email protected],[email protected]
MACs [email protected],[email protected],[email protected]
KexAlgorithms [email protected],diffie-hellman-group-exchange-sha256

# Connection timeouts
ClientAliveInterval 300
ClientAliveCountMax 2

# Logging
SyslogFacility AUTH
LogLevel VERBOSE

# User restrictions (whitelist approach)
AllowUsers admin_username another_user

4. Disk Snapshots and Backup Strategies

Regular backups are your last line of defense against data loss from attacks, human error, or system failures. Cloud providers offer various snapshot mechanisms.

Cloud Provider Snapshot Tools

AWS EC2:

# Using AWS CLI to create snapshot
aws ec2 create-snapshot \
    --volume-id vol-1234567890abcdef0 \
    --description "Daily backup $(date +%Y-%m-%d)"

# Automate with AWS Backup service (preferred method)

Google Cloud:

# Create snapshot
gcloud compute disks snapshot DISK_NAME \
    --snapshot-names=snapshot-$(date +%Y%m%d) \
    --zone=us-central1-a

# Create snapshot schedule (automated)
gcloud compute resource-policies create snapshot-schedule daily-backup \
    --max-retention-days=7 \
    --on-source-disk-delete=keep-auto-snapshots \
    --daily-schedule \
    --start-time=02:00 \
    --storage-location=us

Azure:

# Create snapshot
az snapshot create \
    --resource-group myResourceGroup \
    --source myDisk \
    --name mySnapshot

Automated Backup Script

Create a comprehensive backup solution:

sudo nano /usr/local/bin/backup-server.sh
#!/bin/bash

# Configuration
BACKUP_DIR="/var/backups"
RETENTION_DAYS=7
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/backup.log"

# Create backup directory
mkdir -p $BACKUP_DIR

# Function to log messages
log_message() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}

log_message "Starting backup process..."

# Backup system configuration
log_message "Backing up system configuration..."
tar -czf $BACKUP_DIR/etc-backup-$DATE.tar.gz /etc/ 2>/dev/null

# Backup user home directories (excluding large files)
log_message "Backing up home directories..."
tar -czf $BACKUP_DIR/home-backup-$DATE.tar.gz \
    --exclude='*/.[Cc]ache/*' \
    --exclude='*/.local/share/Trash/*' \
    /home/ 2>/dev/null

# Backup important application data
log_message "Backing up application data..."
tar -czf $BACKUP_DIR/var-backup-$DATE.tar.gz \
    /var/www/ \
    /var/log/ 2>/dev/null

# Database backup (if applicable)
if command -v mysql &> /dev/null; then
    log_message "Backing up MySQL databases..."
    mysqldump --all-databases --single-transaction \
        | gzip > $BACKUP_DIR/mysql-backup-$DATE.sql.gz
fi

# Remove old backups
log_message "Removing backups older than $RETENTION_DAYS days..."
find $BACKUP_DIR -name "*-backup-*.tar.gz" -mtime +$RETENTION_DAYS -delete
find $BACKUP_DIR -name "*-backup-*.sql.gz" -mtime +$RETENTION_DAYS -delete

# Sync to remote location (optional)
# rsync -avz $BACKUP_DIR/ remote_server:/backup/location/

log_message "Backup process completed successfully"

Make script executable and schedule:

sudo chmod +x /usr/local/bin/backup-server.sh

# Add to crontab for daily 2 AM execution
sudo crontab -e
# Add: 0 2 * * * /usr/local/bin/backup-server.sh

Application-Level Backup Tools

For Database-Heavy Applications:

# PostgreSQL backup
pg_dump dbname | gzip > /var/backups/postgres-$(date +%Y%m%d).sql.gz

# MongoDB backup
mongodump --out=/var/backups/mongodb-$(date +%Y%m%d)

Using rsnapshot for Incremental Backups:

sudo apt install rsnapshot
sudo nano /etc/rsnapshot.conf

5. Minimizing Service Exposure: The Principle of Least Privilege

Every running service is a potential attack vector. Identifying and disabling unnecessary services dramatically reduces your attack surface.

Auditing Running Services

# List all running services
sudo systemctl list-units --type=service --state=running

# View listening ports and their services
sudo netstat -tulpn
# Or with ss (more modern)
sudo ss -tulpn

# More detailed port information
sudo lsof -i -P -n | grep LISTEN

Identifying Unnecessary Services

Common services to evaluate:

  • avahi-daemon: Automatic network discovery (rarely needed on servers)
  • cups: Printing service (almost never needed on cloud servers)
  • bluetooth: Wireless connectivity (unnecessary on virtual servers)
  • ModemManager: Modem management (not needed on cloud instances)

Disabling Unnecessary Services

# Disable and stop service
sudo systemctl stop avahi-daemon
sudo systemctl disable avahi-daemon
sudo systemctl mask avahi-daemon  # Prevents accidental re-enabling

# Repeat for other unnecessary services
sudo systemctl stop cups
sudo systemctl disable cups
sudo systemctl mask cups

sudo systemctl stop bluetooth
sudo systemctl disable bluetooth

Closing Unused Ports with UFW

Ubuntu’s Uncomplicated Firewall provides straightforward port management:

# Check UFW status
sudo ufw status verbose

# Default policies (deny all incoming, allow outgoing)
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow only necessary services
sudo ufw allow 4422/tcp  # SSH (custom port)
sudo ufw allow 80/tcp    # HTTP
sudo ufw allow 443/tcp   # HTTPS

# Enable UFW
sudo ufw enable

# View numbered rules for easier management
sudo ufw status numbered

# Delete a specific rule by number
sudo ufw delete [number]

Advanced Firewall Configuration

Rate Limiting SSH Connections:

# Limit SSH connection attempts
sudo ufw limit 4422/tcp

Allowing Specific IP Ranges:

# Allow SSH only from office network
sudo ufw allow from 203.0.113.0/24 to any port 4422

Logging Configuration:

# Enable firewall logging
sudo ufw logging on

# Set log level
sudo ufw logging medium  # off, low, medium, high, full

Network Service Security Checklist

Create a systematic approach to service management:

# Audit script
sudo nano /usr/local/bin/security-audit.sh
#!/bin/bash

echo "=== Security Audit Report ==="
echo "Date: $(date)"
echo ""

echo "=== Listening Ports ==="
sudo ss -tulpn | grep LISTEN
echo ""

echo "=== Running Services ==="
sudo systemctl list-units --type=service --state=running --no-pager
echo ""

echo "=== Firewall Status ==="
sudo ufw status verbose
echo ""

echo "=== Failed Login Attempts (Last 24 hours) ==="
sudo grep "Failed password" /var/log/auth.log | grep "$(date +%b\ %d)"
echo ""

echo "=== Fail2ban Status ==="
sudo fail2ban-client status

6. System Updates: Your First and Continuous Defense

Keeping your system updated addresses known vulnerabilities before they can be exploited. With Ubuntu releasing critical kernel patches throughout 2025 and into early 2026, this cannot be overlooked.

Manual Update Process

# Update package lists
sudo apt update

# Show available upgrades
apt list --upgradable

# Upgrade all packages
sudo apt upgrade -y

# Full distribution upgrade (handles dependencies)
sudo apt full-upgrade -y

# Remove unnecessary packages
sudo apt autoremove -y
sudo apt autoclean

Automated Security Updates

Ubuntu provides unattended-upgrades for automatic security patches:

# Install unattended-upgrades
sudo apt install unattended-upgrades

# Configure automatic updates
sudo dpkg-reconfigure -plow unattended-upgrades

Configure update behavior:

sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
    "${distro_id}ESMApps:${distro_codename}-apps-security";
    "${distro_id}ESM:${distro_codename}-infra-security";
};

// Automatically reboot if required
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";

// Email notifications
Unattended-Upgrade::Mail "admin@yourdomain.com";
Unattended-Upgrade::MailReport "on-change";

// Remove unused dependencies
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";

Ubuntu Pro for Extended Security

Ubuntu Pro provides extended security maintenance:

# Check Ubuntu Pro status
sudo pro status

# Attach Ubuntu Pro subscription (free for personal use, up to 5 machines)
sudo pro attach [your-token]

# Enable ESM (Extended Security Maintenance)
sudo pro enable esm-infra
sudo pro enable esm-apps

Kernel Live Patching with Livepatch

Apply kernel security updates without rebooting:

# Enable Canonical Livepatch
sudo pro enable livepatch

# Check livepatch status
sudo pro status --all

Monitoring Security Updates

Create an update monitoring script:

sudo nano /usr/local/bin/check-updates.sh
#!/bin/bash

LOG_FILE="/var/log/update-check.log"

echo "=== Update Check $(date) ===" >> $LOG_FILE

# Check for updates
sudo apt update > /dev/null 2>&1

# Count security updates
SECURITY_UPDATES=$(apt list --upgradable 2>/dev/null | grep -i security | wc -l)

if [ $SECURITY_UPDATES -gt 0 ]; then
    echo "WARNING: $SECURITY_UPDATES security updates available!" >> $LOG_FILE
    apt list --upgradable 2>/dev/null | grep -i security >> $LOG_FILE
    
    # Send email notification (requires mailutils)
    echo "Security updates available on $(hostname)" | \
        mail -s "Security Alert: Updates Required" admin@yourdomain.com
fi

echo "" >> $LOG_FILE

Schedule daily checks:

sudo crontab -e
# Add: 0 6 * * * /usr/local/bin/check-updates.sh

Bringing It All Together: The Complete Hardening Workflow

Here’s a comprehensive checklist for immediate post-deployment hardening:

Hour One: Critical Security Setup

  1. Update the System
sudo apt update && sudo apt upgrade -y
  1. Create Administrative User
sudo adduser secadmin
sudo usermod -aG sudo secadmin
  1. Set Up SSH Keys
# On local machine
ssh-keygen -t rsa -b 4096
ssh-copy-id secadmin@server_ip
  1. Harden SSH Configuration
sudo nano /etc/ssh/sshd_config
# Apply recommended settings from Section 3
sudo systemctl restart sshd
  1. Install and Configure Fail2ban
sudo apt install fail2ban
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# Configure jails as per Section 2
sudo systemctl restart fail2ban
  1. Configure Firewall
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 4422/tcp  # Your SSH port
sudo ufw enable
  1. Disable Unnecessary Services
sudo systemctl disable avahi-daemon cups bluetooth
  1. Enable Automatic Security Updates
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

Week One: Enhanced Security

  • Review and refine Fail2ban rules based on log analysis
  • Implement backup automation
  • Set up monitoring and alerting
  • Document all configuration changes
  • Test disaster recovery procedures

Ongoing: Continuous Security Maintenance

  • Weekly: Review authentication logs and Fail2ban reports
  • Monthly: Audit user accounts and permissions
  • Quarterly: Review and update security configurations
  • Annually: Conduct comprehensive security audit

Conclusion

Hardening an Ubuntu cloud server is not a one-time task but an ongoing process. The measures outlined in this guide provide a solid foundation that transforms a vulnerable fresh installation into a resilient, production-ready system capable of withstanding common attack vectors.

Remember: security is layered. No single measure provides complete protection, but the combination of disabled root login, Fail2ban monitoring, modified SSH configuration, proper firewall rules, minimal service exposure, and consistent updates creates a formidable defense against the vast majority of attacks.

The threats evolve constantly, as evidenced by Ubuntu’s continuous security updates throughout 2025. Stay informed about security advisories, maintain your vigilance, and treat security as an integral part of system administration rather than an afterthought.

Your server’s security posture today determines whether tomorrow brings smooth operations or a crisis recovery scenario. Invest the time now to implement these hardening measures—your future self will thank you.


For the latest security updates and best practices, regularly consult Ubuntu’s security notices at ubuntu.com/security and consider subscribing to security mailing lists for your critical infrastructure.

 

Ubuntu Server Officical Download Link

 

How to securely harden Ubuntu Cloud Server?

How to securely harden Ubuntu Cloud Server?


Windows Software Alternatives in Linux


Disclaimer of pbxscience.com

PBXscience.com © All Copyrights Reserved. | Newsphere by AF themes.