Post

Ubuntu LTS Security Hardening Guide: Complete Server Setup for Beginners

Step-by-step guide to setting up and hardening Ubuntu LTS server with security best practices, firewall configuration, SSH hardening, intrusion prevention, and automated security monitoring. Perfect for beginners who want enterprise-level security.

Ubuntu LTS Security Hardening Guide: Complete Server Setup

Setting up a secure Ubuntu LTS server doesn’t have to be complicated. This guide walks you through enterprise-grade security hardening step by step, explaining why each security measure matters and how it protects your server.

Whether you’re setting up a web server, development environment, or personal cloud server, these security practices will protect you from common attacks and keep your data safe.

Prerequisites

What you’ll need:

  • Fresh Ubuntu LTS installation (20.04, 22.04, or 24.04)
  • Root or sudo access
  • Internet connection
  • Basic command-line familiarity

Why start with a fresh install?

  • Clean baseline free of pre-existing vulnerabilities
  • No conflicting configurations from previous setups
  • Easier to implement security from the ground up

Automated Security Hardening Scripts

Save time and reduce errors! Copy and run these automated scripts to implement all security measures with a single command.

Master Security Hardening Script

Why use automation?

  • Consistency: Same security measures every time
  • Speed: Implement all security in minutes, not hours
  • Accuracy: No manual typos or missed steps
  • Documentation: Scripts serve as living security documentation

⚠️ Important: Review each script before running. Understand what it does and customize variables for your environment.

#!/bin/bash # Ubuntu LTS Security Hardening Master Script # Run as root or with sudo # Version: 1.0 # Author: Ubuntu Security Hardening Guide set -e # Exit on any error # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Configuration variables - MODIFY THESE FOR YOUR ENVIRONMENT NEW_USER="yourusername" # Replace with your desired username SSH_PORT="22" # Change if you want non-standard SSH port ADMIN_EMAIL="admin@yourdomain.com" # For security notifications TIMEZONE="America/New_York" # Set your timezone # Logging LOG_FILE="/var/log/ubuntu-hardening-$(date +%Y%m%d-%H%M%S).log" exec > >(tee -a "$LOG_FILE") 2>&1 echo -e "${BLUE}🔒 Ubuntu LTS Security Hardening Script${NC}" echo -e "${BLUE}=======================================${NC}" echo -e "${YELLOW}Log file: $LOG_FILE${NC}" echo -e "${YELLOW}Started at: $(date)${NC}" echo "" # Function to print status messages print_status() { echo -e "${GREEN}$1${NC}" } print_warning() { echo -e "${YELLOW}⚠️ $1${NC}" } print_error() { echo -e "${RED}$1${NC}" } # Check if running as root if [[ $EUID -ne 0 ]]; then print_error "This script must be run as root or with sudo" exit 1 fi echo -e "${BLUE}Step 1: System Updates${NC}" echo "========================" # Update system print_status "Updating package lists..." apt update print_status "Upgrading packages..." apt upgrade -y print_status "Installing security tools..." apt install -y curl wget ufw fail2ban rkhunter chkrootkit auditd unattended-upgrades apt-transport-https ca-certificates gnupg lsb-release print_status "Configuring automatic security updates..." cat > /etc/apt/apt.conf.d/50unattended-upgrades << EOF Unattended-Upgrade::Allowed-Origins { "\${distro_id}:\${distro_codename}"; "\${distro_id}:\${distro_codename}-security"; "\${distro_id}:\${distro_codename}-updates"; }; Unattended-Upgrade::Mail "$ADMIN_EMAIL"; Unattended-Upgrade::Remove-Unused-Dependencies "true"; Unattended-Upgrade::Automatic-Reboot "true"; Unattended-Upgrade::Automatic-Reboot-Time "02:00"; EOF print_status "Enabling unattended upgrades..." dpkg-reconfigure --frontend=noninteractive unattended-upgrades echo "" echo -e "${BLUE}Step 2: User Management${NC}" echo "=======================" # Create new user if it doesn't exist if id "$NEW_USER" &>/dev/null; then print_warning "User $NEW_USER already exists" else print_status "Creating new user: $NEW_USER" useradd -m -s /bin/bash "$NEW_USER" usermod -aG sudo "$NEW_USER" print_status "User created. Set password with: sudo passwd $NEW_USER" fi echo "" echo -e "${BLUE}Step 3: SSH Hardening${NC}" echo "====================" print_status "Backing up SSH configuration..." cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup.$(date +%Y%m%d_%H%M%S) print_status "Configuring SSH security..." cat >> /etc/ssh/sshd_config << EOF # Security hardening - Added by hardening script PasswordAuthentication no PermitRootLogin no Protocol 2 MaxAuthTries 3 ClientAliveInterval 300 ClientAliveCountMax 2 X11Forwarding no AllowTcpForwarding no PermitEmptyPasswords no UseDNS no EOF print_status "Restarting SSH service..." systemctl restart ssh echo "" echo -e "${BLUE}Step 4: Firewall Configuration${NC}" echo "============================" print_status "Configuring UFW firewall..." ufw --force reset print_status "Setting default policies..." ufw default deny incoming ufw default allow outgoing print_status "Allowing SSH..." ufw allow "$SSH_PORT"/tcp print_status "Enabling firewall..." ufw --force enable echo "" echo -e "${BLUE}Step 5: Fail2Ban Setup${NC}" echo "====================" print_status "Configuring Fail2Ban..." cat > /etc/fail2ban/jail.local << EOF [sshd] enabled = true port = $SSH_PORT filter = sshd logpath = /var/log/auth.log maxretry = 3 bantime = 3600 findtime = 600 [nginx-http-auth] enabled = true port = http,https filter = nginx-http-auth logpath = /var/log/nginx/error.log maxretry = 3 bantime = 3600 [nginx-noscript] enabled = true port = http,https filter = nginx-noscript logpath = /var/log/nginx/access.log maxretry = 6 bantime = 3600 EOF print_status "Enabling and starting Fail2Ban..." systemctl enable fail2ban systemctl restart fail2ban echo "" echo -e "${BLUE}Step 6: System Hardening${NC}" echo "=======================" print_status "Configuring kernel security parameters..." cat >> /etc/sysctl.conf << EOF # Security hardening - Added by hardening script net.ipv4.tcp_syncookies = 1 net.ipv4.ip_forward = 0 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.all.log_martians = 1 net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.icmp_ignore_bogus_error_responses = 1 fs.suid_dumpable = 0 kernel.dmesg_restrict = 1 vm.mmap_min_addr = 65536 EOF print_status "Applying kernel parameters..." sysctl -p print_status "Securing file permissions..." chmod 600 /etc/shadow /etc/gshadow chmod 644 /etc/passwd /etc/group echo "" echo -e "${BLUE}Step 7: Security Monitoring${NC}" echo "=========================" print_status "Enabling auditd..." systemctl enable auditd systemctl start auditd print_status "Installing logwatch..." apt install -y logwatch print_status "Configuring logwatch..." cat > /etc/cron.daily/logwatch << EOF #!/bin/bash /usr/sbin/logwatch --output mail --mailto $ADMIN_EMAIL --detail high EOF chmod +x /etc/cron.daily/logwatch echo "" echo -e "${BLUE}Step 8: Backup Configuration${NC}" echo "===========================" print_status "Installing backup tools..." apt install -y rsync duplicity print_status "Creating backup script..." cat > /usr/local/bin/ubuntu-backup.sh << 'EOF' #!/bin/bash # Ubuntu automated backup script BACKUP_DIR="/var/backups" SOURCE_DIR="/home" DATE=$(date +%Y%m%d_%H%M%S) # Create backup directory if it doesn't exist mkdir -p "$BACKUP_DIR" # Local backup rsync -avz --delete "$SOURCE_DIR" "$BACKUP_DIR/daily_$DATE" # Clean old backups (keep last 7) find "$BACKUP_DIR" -name "daily_*" -type d -mtime +7 -exec rm -rf {} + echo "Backup completed: $BACKUP_DIR/daily_$DATE" EOF chmod +x /usr/local/bin/ubuntu-backup.sh print_status "Scheduling daily backups..." echo "0 2 * * * /usr/local/bin/ubuntu-backup.sh" > /etc/cron.d/ubuntu-backup echo "" echo -e "${BLUE}Step 9: Security Validation${NC}" echo "===========================" print_status "Creating security validation script..." cat > /usr/local/bin/ubuntu-security-check.sh << 'EOF' #!/bin/bash # Ubuntu Security Validation Script echo "🔒 Ubuntu Security Check" echo "========================" # SSH Security echo "SSH Security:" if grep -q "PasswordAuthentication no" /etc/ssh/sshd_config; then echo "✅ Password authentication disabled" else echo "❌ Password authentication enabled" fi if grep -q "PermitRootLogin no" /etc/ssh/sshd_config; then echo "✅ Root login disabled" else echo "❌ Root login enabled" fi # Firewall echo -e "\nFirewall Status:" ufw status | grep -E "(Status|active)" # Fail2Ban echo -e "\nFail2Ban Status:" systemctl is-active fail2ban # Updates echo -e "\nSystem Updates:" apt list --upgradable 2>/dev/null | grep -c "upgradable" | xargs echo "packages can be upgraded" echo -e "\nSecurity check complete!" EOF chmod +x /usr/local/bin/ubuntu-security-check.sh print_status "Running initial security check..." /usr/local/bin/ubuntu-security-check.sh echo "" echo -e "${GREEN}🎉 Ubuntu Security Hardening Complete!${NC}" echo "" echo -e "${YELLOW}Next Steps:${NC}" echo "1. Set password for new user: sudo passwd $NEW_USER" echo "2. Copy SSH keys to server for the new user" echo "3. Test SSH connection with new user" echo "4. Run security check: /usr/local/bin/ubuntu-security-check.sh" echo "5. Review logs: tail -f $LOG_FILE" echo "" echo -e "${BLUE}Log saved to: $LOG_FILE${NC}" echo -e "${BLUE}Completed at: $(date)${NC}"

Individual Security Scripts

Quick SSH Key Setup Script

#!/bin/bash # Quick SSH Key Setup for Ubuntu # Run as the user who needs SSH access set -e # Colors GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' echo -e "${GREEN}🔑 SSH Key Setup for Ubuntu${NC}" echo "=============================" # Check if SSH key already exists if [ -f ~/.ssh/id_ed25519 ]; then echo -e "${YELLOW}SSH key already exists. Backup and create new one? (y/n)${NC}" read -r response if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then mv ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.backup.$(date +%Y%m%d_%H%M%S) mv ~/.ssh/id_ed25519.pub ~/.ssh/id_ed25519.pub.backup.$(date +%Y%m%d_%H%M%S) else echo "Keeping existing SSH key." exit 0 fi fi # Generate new SSH key echo "Generating Ed25519 SSH key..." ssh-keygen -t ed25519 -C "$(whoami)@$(hostname)-$(date +%Y%m%d)" -f ~/.ssh/id_ed25519 -N "" # Set correct permissions chmod 700 ~/.ssh chmod 600 ~/.ssh/id_ed25519 chmod 644 ~/.ssh/id_ed25519.pub echo -e "${GREEN}✅ SSH key generated!${NC}" echo "" echo "Public key (copy this to server's authorized_keys):" echo "==================================================" cat ~/.ssh/id_ed25519.pub echo "" echo "To copy to server, run:" echo "ssh-copy-id user@server-ip" echo "" echo "Private key location: ~/.ssh/id_ed25519" echo "Public key location: ~/.ssh/id_ed25519.pub"

Automated Firewall Setup Script

#!/bin/bash # Automated Firewall Setup for Ubuntu # Configures UFW with security best practices set -e # Colors GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' echo -e "${GREEN}🔥 Ubuntu Firewall Setup${NC}" echo "========================" # Check if running as root if [[ $EUID -ne 0 ]]; then echo -e "${RED}❌ This script must be run as root or with sudo${NC}" exit 1 fi # Backup current UFW configuration echo "Backing up current UFW configuration..." ufw status > /etc/ufw/ufw-status-backup-$(date +%Y%m%d_%H%M%S).txt # Reset UFW to defaults echo "Resetting UFW to defaults..." ufw --force reset # Set default policies echo "Setting secure default policies..." ufw default deny incoming ufw default allow outgoing # Allow essential services echo "Allowing essential services..." # SSH (with rate limiting to prevent brute force) ufw limit ssh/tcp comment 'SSH with rate limiting' # HTTP/HTTPS for web servers (uncomment if needed) # ufw allow 80/tcp comment 'HTTP' # ufw allow 443/tcp comment 'HTTPS' # DNS ufw allow out 53/udp comment 'DNS' ufw allow out 53/tcp comment 'DNS TCP' # NTP for time synchronization ufw allow out 123/udp comment 'NTP' # Enable UFW echo "Enabling UFW firewall..." ufw --force enable # Show status echo "" echo -e "${GREEN}✅ Firewall configured successfully!${NC}" echo "" echo "Current firewall status:" ufw status verbose echo "" echo -e "${YELLOW}📋 Firewall Rules Applied:${NC}" echo "- Default: Deny all incoming, allow all outgoing" echo "- SSH: Allowed with rate limiting (6 connections/minute)" echo "- DNS: Allowed for name resolution" echo "- NTP: Allowed for time synchronization" echo "" echo -e "${YELLOW}🔧 To modify rules:${NC}" echo " ufw allow 80/tcp # Allow HTTP" echo " ufw allow 443/tcp # Allow HTTPS" echo " ufw allow from 192.168.1.0/24 # Allow from specific IP range" echo " ufw reload # Apply changes"

Security Monitoring Dashboard Script

#!/bin/bash # Ubuntu Security Monitoring Dashboard # Run periodically to check system security status # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' NC='\033[0m' echo -e "${BLUE}🔒 Ubuntu Security Monitoring Dashboard${NC}" echo -e "${BLUE}=========================================${NC}" echo -e "${CYAN}Report generated: $(date)${NC}" echo "" # System Information echo -e "${PURPLE}📊 System Information${NC}" echo "======================" echo "Hostname: $(hostname)" echo "Ubuntu Version: $(lsb_release -d | cut -f2)" echo "Kernel: $(uname -r)" echo "Uptime: $(uptime -p)" echo "" # Security Status Checks echo -e "${PURPLE}🔐 Security Status${NC}" echo "===================" # SSH Security echo -e "${CYAN}SSH Configuration:${NC}" if grep -q "^PasswordAuthentication no" /etc/ssh/sshd_config; then echo -e "${GREEN}✅ Password authentication disabled${NC}" else echo -e "${RED}❌ Password authentication enabled${NC}" fi if grep -q "^PermitRootLogin no" /etc/ssh/sshd_config; then echo -e "${GREEN}✅ Root login disabled${NC}" else echo -e "${RED}❌ Root login enabled${NC}" fi # Firewall Status echo -e "\n${CYAN}Firewall Status:${NC}" if systemctl is-active --quiet ufw; then echo -e "${GREEN}✅ UFW firewall is active${NC}" ufw status | grep -E "(Status:|22|80|443)" | sed 's/^/ /' else echo -e "${RED}❌ UFW firewall is not active${NC}" fi # Fail2Ban Status echo -e "\n${CYAN}Fail2Ban Status:${NC}" if systemctl is-active --quiet fail2ban; then echo -e "${GREEN}✅ Fail2Ban is running${NC}" echo " Currently banned IPs:" fail2ban-client status sshd 2>/dev/null | grep "Currently banned" | sed 's/^/ /' || echo " None" else echo -e "${RED}❌ Fail2Ban is not running${NC}" fi # System Updates echo -e "\n${CYAN}System Updates:${NC}" UPGRADABLE=$(apt list --upgradable 2>/dev/null | grep -c "upgradable" || echo "0") if [ "$UPGRADABLE" -eq 0 ]; then echo -e "${GREEN}✅ System is up to date${NC}" else echo -e "${YELLOW}⚠️ $UPGRADABLE packages can be upgraded${NC}" fi # Security Updates SECURITY_UPDATES=$(apt list --upgradable 2>/dev/null | grep -c "security" || echo "0") if [ "$SECURITY_UPDATES" -gt 0 ]; then echo -e "${RED}🚨 $SECURITY_UPDATES security updates available${NC}" fi echo "" # Service Status echo -e "${PURPLE}🔧 Service Status${NC}" echo "=================" services=("ssh" "ufw" "fail2ban" "auditd" "unattended-upgrades") for service in "${services[@]}"; do if systemctl is-active --quiet "$service"; then echo -e "${GREEN}$service is running${NC}" else echo -e "${RED}$service is not running${NC}" fi done echo "" # Recent Security Events echo -e "${PURPLE}📋 Recent Security Events${NC}" echo "===========================" echo -e "${CYAN}Failed SSH login attempts (last 24h):${NC}" failed_attempts=$(journalctl -u ssh --since "24 hours ago" -g "Failed password" | wc -l) if [ "$failed_attempts" -gt 0 ]; then echo -e "${RED}🚨 $failed_attempts failed login attempts${NC}" else echo -e "${GREEN}✅ No failed login attempts${NC}" fi echo -e "\n${CYAN}Recent sudo usage:${NC}" sudo_log=$(journalctl -u sudo --since "24 hours ago" | wc -l) if [ "$sudo_log" -gt 0 ]; then echo -e "${BLUE}ℹ️ $sudo_log sudo commands executed${NC}" else echo -e "${YELLOW}⚠️ No sudo usage in last 24 hours${NC}" fi echo "" # Recommendations echo -e "${PURPLE}💡 Security Recommendations${NC}" echo "============================" recommendations=() # Check SSH key authentication if ! grep -q "^PasswordAuthentication no" /etc/ssh/sshd_config; then recommendations+=("Disable SSH password authentication") fi # Check firewall if ! systemctl is-active --quiet ufw; then recommendations+=("Enable UFW firewall") fi # Check Fail2Ban if ! systemctl is-active --quiet fail2ban; then recommendations+=("Install and enable Fail2Ban") fi # Check updates if [ "$SECURITY_UPDATES" -gt 0 ]; then recommendations+=("Apply security updates immediately") fi if [ ${#recommendations[@]} -eq 0 ]; then echo -e "${GREEN}✅ No immediate security actions required${NC}" else echo -e "${YELLOW}⚠️ Recommended actions:${NC}" for rec in "${recommendations[@]}"; do echo -e " • $rec" done fi echo "" echo -e "${BLUE}🔍 Dashboard complete. Run this script daily for security monitoring.${NC}" echo -e "${BLUE}💡 For detailed logs, check: journalctl -u ssh, ufw, fail2ban${NC}"

1. System Updates and Package Management

Why Update Immediately?

Security Risk: New Ubuntu installations often ship with known vulnerabilities that attackers actively exploit. Cybercriminals scan the internet for unpatched systems.

Real-World Impact: The Equifax breach (2017) exposed 147 million records partly due to unpatched Apache Struts vulnerability.

# Update package lists sudo apt update # Upgrade all packages to latest versions sudo apt upgrade -y # Install security updates only sudo apt install unattended-upgrades -y

Configure Automatic Security Updates

Why automate updates?

  • Human error prevention: Manual updates often get forgotten
  • Rapid vulnerability patching: Zero-day exploits get fixed quickly
  • Reduced attack window: Vulnerabilities patched before exploitation
# Enable automatic security updates sudo dpkg-reconfigure --priority=low unattended-upgrades # Edit the configuration file sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

Add these lines to enable automatic updates:

// Automatically upgrade packages from these sources Unattended-Upgrade::Allowed-Origins { "${distro_id}:${distro_codename}"; "${distro_id}:${distro_codename}-security"; "${distro_id}:${distro_codename}-updates"; }; // Send email notifications (optional) Unattended-Upgrade::Mail "your-email@example.com"; // Remove unused dependencies Unattended-Upgrade::Remove-Unused-Dependencies "true"; // Automatic reboot if needed Unattended-Upgrade::Automatic-Reboot "true"; Unattended-Upgrade::Automatic-Reboot-Time "02:00";

Install Essential Security Tools

# Install security and monitoring tools sudo apt install -y curl wget htop ncdu ufw fail2ban rkhunter chkrootkit auditd # Install development tools (if needed) sudo apt install -y build-essential git vim # Clean up sudo apt autoremove -y sudo apt autoclean

2. User Management and Access Control

Why Proper User Management Matters

Security Principle: Use separate user accounts for different purposes. Never use root for daily tasks.

Why not use root?

  • Accountability: Track who did what
  • Damage limitation: Compromised user ≠ full system compromise
  • Audit trails: Security monitoring can identify suspicious activity

Create a New Administrative User

# Create a new user (replace 'yourusername' with your preferred username) sudo adduser yourusername # Add user to sudo group for administrative access sudo usermod -aG sudo yourusername # Verify sudo access su - yourusername sudo whoami # Should show 'root'

Secure SSH Access

Why harden SSH?

  • Brute force protection: Default SSH allows password authentication
  • Key-based auth: Cryptographically secure vs password guessing
  • Root login prevention: Eliminates direct root access attempts
# Switch to your new user su - yourusername # Generate SSH key pair (on your LOCAL machine) ssh-keygen -t ed25519 -C "your-email@example.com" # Copy public key to server ssh-copy-id yourusername@your-server-ip # Now disable password authentication sudo nano /etc/ssh/sshd_config

Critical SSH security settings:

# Disable password authentication PasswordAuthentication no # Disable root login PermitRootLogin no # Use only secure protocols Protocol 2 # Limit authentication attempts MaxAuthTries 3 # Use secure ciphers Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com # Disable X11 forwarding (unless needed) X11Forwarding no # Set idle timeout ClientAliveInterval 300 ClientAliveCountMax 2
# Restart SSH service sudo systemctl restart ssh # Test SSH connection with key (from another terminal) ssh yourusername@your-server-ip

Configure sudo Properly

Why sudo security matters:

  • Command logging: All sudo actions are logged
  • Time limits: Password not required repeatedly
  • Access control: Specific commands can be restricted
# Edit sudoers file safely sudo visudo # Add these security settings at the end:
# Security hardening Defaults env_reset Defaults mail_badpass Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" Defaults logfile="/var/log/sudo.log" Defaults log_input,log_output Defaults requiretty # Allow members of group sudo to execute any command %sudo ALL=(ALL:ALL) ALL # Your user with passwordless sudo for specific commands (optional) yourusername ALL=(ALL) NOPASSWD: /usr/sbin/service apache2 restart, /usr/sbin/service nginx restart

3. Firewall Configuration with UFW

Why Firewalls Are Essential

Network Security 101:

  • Default deny: Block everything except explicitly allowed traffic
  • Attack surface reduction: Fewer open ports = fewer attack vectors
  • Traffic monitoring: Log suspicious connection attempts

Real-World Example: The Mirai botnet (2016) exploited IoT devices with open Telnet ports, infecting 500,000+ devices.

# Enable UFW sudo ufw enable # Allow SSH (change port if you modified SSH config) sudo ufw allow ssh sudo ufw allow 22/tcp # Allow HTTP/HTTPS for web servers sudo ufw allow 80/tcp sudo ufw allow 443/tcp # Allow specific services as needed # sudo ufw allow 3306/tcp # MySQL # sudo ufw allow 5432/tcp # PostgreSQL # Set default policies sudo ufw default deny incoming sudo ufw default allow outgoing # Check status sudo ufw status verbose

Advanced Firewall Rules

# Limit SSH connections (prevent brute force) sudo ufw limit ssh # Allow from specific IP ranges only sudo ufw allow from 192.168.1.0/24 to any port 22 # Deny specific IPs sudo ufw deny from 123.456.789.0/24 # Reload firewall sudo ufw reload

4. Intrusion Prevention with Fail2Ban

Why Fail2Ban Matters

Automated Defense:

  • Brute force prevention: Bans IPs after failed login attempts
  • DDoS mitigation: Limits connection rates
  • Log analysis: Monitors system logs for attack patterns

Effectiveness: Reduces successful brute force attacks by 99%+.

# Enable and start Fail2Ban sudo systemctl enable fail2ban sudo systemctl start fail2ban # Check status sudo systemctl status fail2ban # View banned IPs sudo fail2ban-client status sshd

Configure Fail2Ban Jails

# Edit jail configuration sudo nano /etc/fail2ban/jail.local

Add these security jails:

[sshd] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 3 bantime = 3600 [nginx-http-auth] enabled = true port = http,https filter = nginx-http-auth logpath = /var/log/nginx/error.log maxretry = 3 bantime = 3600 [nginx-noscript] enabled = true port = http,https filter = nginx-noscript logpath = /var/log/nginx/access.log maxretry = 6 bantime = 3600 [nginx-badbots] enabled = true port = http,https filter = nginx-badbots logpath = /var/log/nginx/access.log maxretry = 2 bantime = 3600 [nginx-noproxy] enabled = true port = http,https filter = nginx-noproxy logpath = /var/log/nginx/access.log maxretry = 2 bantime = 3600
# Restart Fail2Ban sudo systemctl restart fail2ban # Monitor Fail2Ban logs sudo tail -f /var/log/fail2ban.log

5. System Hardening and Security Monitoring

Kernel Security Parameters

Why harden the kernel?

  • Disable dangerous features: Prevent exploits using kernel vulnerabilities
  • Network protection: Block common network-based attacks
  • Resource limits: Prevent DoS attacks
# Edit sysctl configuration sudo nano /etc/sysctl.conf

Add these security parameters:

# Network security net.ipv4.tcp_syncookies = 1 net.ipv4.ip_forward = 0 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.all.log_martians = 1 # Disable IPv6 if not needed net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 # File system security fs.suid_dumpable = 0 kernel.dmesg_restrict = 1 # Memory protection vm.mmap_min_addr = 65536 # ICMP security net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.icmp_ignore_bogus_error_responses = 1
# Apply changes sudo sysctl -p

File Permissions Security

# Secure critical files sudo chmod 600 /etc/shadow sudo chmod 600 /etc/gshadow sudo chmod 644 /etc/passwd sudo chmod 644 /etc/group # Secure SSH directory sudo chmod 700 ~/.ssh sudo chmod 600 ~/.ssh/authorized_keys # Remove unnecessary files sudo find /home -name ".rhost" -delete sudo find /home -name ".shosts" -delete

Install and Configure Auditd

Why audit system activity?

  • Intrusion detection: Monitor file changes and system calls
  • Compliance: Meet security standards and regulations
  • Forensic analysis: Investigate security incidents
# Enable auditd sudo systemctl enable auditd sudo systemctl start auditd # Check status sudo systemctl status auditd # View audit logs sudo ausearch -m USER_LOGIN --start today

6. Security Monitoring and Alerting

Log Monitoring Setup

# Install logwatch for log analysis sudo apt install -y logwatch # Configure daily log reports sudo nano /etc/cron.daily/logwatch # Add this content: #!/bin/bash /usr/sbin/logwatch --output mail --mailto your-email@example.com --detail high

Automated Security Scanning

# Install security scanning tools sudo apt install -y lynis rkhunter chkrootkit # Run security audit sudo lynis audit system # Schedule weekly security scans echo "0 2 * * 1 /usr/sbin/lynis audit system --cronjob" | sudo tee /etc/cron.weekly/lynis-scan

Rootkit Detection

# Run rootkit checks sudo chkrootkit sudo rkhunter --check # Schedule regular scans echo "0 3 * * * /usr/bin/chkrootkit" | sudo tee /etc/cron.daily/chkrootkit echo "0 4 * * 1 /usr/bin/rkhunter --check --cronjob" | sudo tee /etc/cron.weekly/rkhunter

7. Backup and Recovery Strategy

Why Backups Matter

Data Protection:

  • Ransomware defense: Restore from clean backups
  • Accidental deletion: Recover lost files
  • System corruption: Restore from known good state

3-2-1 Rule: 3 copies, 2 media types, 1 offsite location.

Automated Backup Setup

# Install backup tools sudo apt install -y rsync duplicity # Create backup script sudo nano /usr/local/bin/backup.sh
#!/bin/bash # Automated backup script BACKUP_DIR="/var/backups" SOURCE_DIR="/home" DESTINATION="user@backup-server:/backups" DATE=$(date +%Y%m%d_%H%M%S) # Create local backup sudo rsync -avz --delete $SOURCE_DIR $BACKUP_DIR/daily_$DATE # Encrypt and send to remote server duplicity $SOURCE_DIR $DESTINATION/daily_$DATE \ --encrypt-key YOUR_GPG_KEY_ID \ --sign-key YOUR_GPG_KEY_ID # Clean old backups (keep 7 daily, 4 weekly, 12 monthly) duplicity remove-older-than 1M $DESTINATION
# Make executable and schedule sudo chmod +x /usr/local/bin/backup.sh echo "0 2 * * * /usr/local/bin/backup.sh" | sudo crontab -

8. Security Validation and Testing

Security Assessment Script

Create a comprehensive security check script:

sudo nano /usr/local/bin/security-check.sh
#!/bin/bash # Comprehensive security validation script echo "🔒 Ubuntu Security Hardening Check" echo "==================================" # Check SSH configuration echo "SSH Security:" if grep -q "PasswordAuthentication no" /etc/ssh/sshd_config; then echo "✅ Password authentication disabled" else echo "❌ Password authentication still enabled" fi if grep -q "PermitRootLogin no" /etc/ssh/sshd_config; then echo "✅ Root login disabled" else echo "❌ Root login still enabled" fi # Check firewall echo -e "\nFirewall Status:" sudo ufw status | grep -E "(Status|22|80|443)" # Check Fail2Ban echo -e "\nFail2Ban Status:" sudo fail2ban-client status sshd | grep "Currently banned" # Check system updates echo -e "\nSystem Updates:" apt list --upgradable 2>/dev/null | wc -l | xargs echo "packages can be upgraded" # Check running services echo -e "\nCritical Services:" systemctl is-active ssh && echo "✅ SSH running" || echo "❌ SSH not running" systemctl is-active ufw && echo "✅ Firewall running" || echo "❌ Firewall not running" systemctl is-active fail2ban && echo "✅ Fail2Ban running" || echo "❌ Fail2Ban not running" echo -e "\nSecurity check complete!"
# Make executable sudo chmod +x /usr/local/bin/security-check.sh # Run security check sudo /usr/local/bin/security-check.sh

9. Ongoing Security Maintenance

Daily Security Tasks

# Quick daily security check sudo /usr/local/bin/security-check.sh # Check system logs for suspicious activity sudo journalctl -p err --since today # Monitor disk usage df -h # Check for failed login attempts sudo lastb | head -10

Weekly Security Tasks

# Full system update sudo apt update && sudo apt upgrade -y # Run security scans sudo lynis audit system sudo rkhunter --check # Review user accounts sudo lastlog # Check sudo usage sudo cat /var/log/sudo.log | tail -20

Monthly Security Tasks

# Full backup verification sudo /usr/local/bin/backup.sh # Review firewall rules sudo ufw status verbose # Audit user permissions sudo find /home -type f -perm 777 # Check for world-writable files sudo find / -type f -perm 777 2>/dev/null | head -10

10. Troubleshooting Common Issues

SSH Connection Problems

# Check SSH service status sudo systemctl status ssh # Verify SSH configuration sudo sshd -t # Check listening ports sudo netstat -tlnp | grep :22 # Restart SSH service sudo systemctl restart ssh

Firewall Issues

# Check UFW status sudo ufw status # Reset firewall (CAUTION: will disconnect SSH) sudo ufw reset sudo ufw enable sudo ufw allow ssh # Check iptables rules sudo iptables -L

Fail2Ban Problems

# Check Fail2Ban status sudo fail2ban-client status # View jail status sudo fail2ban-client status sshd # Unban an IP sudo fail2ban-client set sshd unbanip 192.168.1.100 # Restart Fail2Ban sudo systemctl restart fail2ban

Conclusion

Congratulations! You’ve successfully hardened your Ubuntu LTS server with enterprise-grade security practices. Your server now has:

  • Automatic security updates
  • Secure user management with proper sudo configuration
  • Hardened SSH with key-based authentication
  • Firewall protection with UFW
  • Intrusion prevention with Fail2Ban
  • System monitoring with auditd and logging
  • Automated backups with encryption
  • Security scanning and validation

Security Mindset

Remember that security is an ongoing process, not a one-time setup. Regularly:

  • Monitor logs for suspicious activity
  • Apply updates promptly
  • Review access controls periodically
  • Test backups regularly
  • Stay informed about new threats

Next Steps

  1. Set up monitoring alerts (email notifications for security events)
  2. Configure log shipping to a central logging server
  3. Implement SIEM (Security Information and Event Management) if managing multiple servers
  4. Consider intrusion detection systems like OSSEC or Snort for advanced protection

Your Ubuntu server is now significantly more secure and ready for production use! 🛡️✨

Ubuntu LTS Security Hardening Master Script

Ready to automate everything? Copy and run this comprehensive script to implement all security measures with a single command. Perfect for consistent deployments and reducing manual errors.

#!/bin/bash # Ubuntu LTS Security Hardening Master Script # Run as root or with sudo # Version: 1.0 # Author: Ubuntu Security Hardening Guide set -e # Exit on any error # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Configuration variables - MODIFY THESE FOR YOUR ENVIRONMENT NEW_USER="yourusername" # Replace with your desired username SSH_PORT="22" # Change if you want non-standard SSH port ADMIN_EMAIL="admin@yourdomain.com" # For security notifications TIMEZONE="America/New_York" # Set your timezone # Logging LOG_FILE="/var/log/ubuntu-hardening-$(date +%Y%m%d-%H%M%S).log" exec > >(tee -a "$LOG_FILE") 2>&1 echo -e "${BLUE}🔒 Ubuntu LTS Security Hardening Script${NC}" echo -e "${BLUE}=======================================${NC}" echo -e "${YELLOW}Log file: $LOG_FILE${NC}" echo -e "${YELLOW}Started at: $(date)${NC}" echo "" # Function to print status messages print_status() { echo -e "${GREEN}$1${NC}" } print_warning() { echo -e "${YELLOW}⚠️ $1${NC}" } print_error() { echo -e "${RED}$1${NC}" } # Check if running as root if [[ $EUID -ne 0 ]]; then print_error "This script must be run as root or with sudo" exit 1 fi echo -e "${BLUE}Step 1: System Updates${NC}" echo "========================" # Update system print_status "Updating package lists..." apt update print_status "Upgrading packages..." apt upgrade -y print_status "Installing security tools..." apt install -y curl wget ufw fail2ban rkhunter chkrootkit auditd unattended-upgrades apt-transport-https ca-certificates gnupg lsb-release print_status "Configuring automatic security updates..." cat > /etc/apt/apt.conf.d/50unattended-upgrades << EOF Unattended-Upgrade::Allowed-Origins { "\${distro_id}:\${distro_codename}"; "\${distro_id}:\${distro_codename}-security"; "\${distro_id}:\${distro_codename}-updates"; }; Unattended-Upgrade::Mail "$ADMIN_EMAIL"; Unattended-Upgrade::Remove-Unused-Dependencies "true"; Unattended-Upgrade::Automatic-Reboot "true"; Unattended-Upgrade::Automatic-Reboot-Time "02:00"; EOF print_status "Enabling unattended upgrades..." dpkg-reconfigure --frontend=noninteractive unattended-upgrades echo "" echo -e "${BLUE}Step 2: User Management${NC}" echo "=======================" # Create new user if it doesn't exist if id "$NEW_USER" &>/dev/null; then print_warning "User $NEW_USER already exists" else print_status "Creating new user: $NEW_USER" useradd -m -s /bin/bash "$NEW_USER" usermod -aG sudo "$NEW_USER" print_status "User created. Set password with: sudo passwd $NEW_USER" fi echo "" echo -e "${BLUE}Step 3: SSH Hardening${NC}" echo "====================" print_status "Backing up SSH configuration..." cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup.$(date +%Y%m%d_%H%M%S) print_status "Configuring SSH security..." cat >> /etc/ssh/sshd_config << EOF # Security hardening - Added by hardening script PasswordAuthentication no PermitRootLogin no Protocol 2 MaxAuthTries 3 ClientAliveInterval 300 ClientAliveCountMax 2 X11Forwarding no AllowTcpForwarding no PermitEmptyPasswords no UseDNS no EOF print_status "Restarting SSH service..." systemctl restart ssh echo "" echo -e "${BLUE}Step 4: Firewall Configuration${NC}" echo "============================" print_status "Configuring UFW firewall..." ufw --force reset print_status "Setting default policies..." ufw default deny incoming ufw default allow outgoing print_status "Allowing SSH..." ufw allow "$SSH_PORT"/tcp print_status "Enabling firewall..." ufw --force enable echo "" echo -e "${BLUE}Step 5: Fail2Ban Setup${NC}" echo "====================" print_status "Configuring Fail2Ban..." cat > /etc/fail2ban/jail.local << EOF [sshd] enabled = true port = $SSH_PORT filter = sshd logpath = /var/log/auth.log maxretry = 3 bantime = 3600 findtime = 600 [nginx-http-auth] enabled = true port = http,https filter = nginx-http-auth logpath = /var/log/nginx/error.log maxretry = 3 bantime = 3600 [nginx-noscript] enabled = true port = http,https filter = nginx-noscript logpath = /var/log/nginx/access.log maxretry = 6 bantime = 3600 EOF print_status "Enabling and starting Fail2Ban..." systemctl enable fail2ban systemctl restart fail2ban echo "" echo -e "${BLUE}Step 6: System Hardening${NC}" echo "=======================" print_status "Configuring kernel security parameters..." cat >> /etc/sysctl.conf << EOF # Security hardening - Added by hardening script net.ipv4.tcp_syncookies = 1 net.ipv4.ip_forward = 0 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.all.log_martians = 1 net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.icmp_ignore_bogus_error_responses = 1 fs.suid_dumpable = 0 kernel.dmesg_restrict = 1 vm.mmap_min_addr = 65536 EOF print_status "Applying kernel parameters..." sysctl -p print_status "Securing file permissions..." chmod 600 /etc/shadow /etc/gshadow chmod 644 /etc/passwd /etc/group echo "" echo -e "${BLUE}Step 7: Security Monitoring${NC}" echo "=========================" print_status "Enabling auditd..." systemctl enable auditd systemctl start auditd print_status "Installing logwatch..." apt install -y logwatch print_status "Configuring logwatch..." cat > /etc/cron.daily/logwatch << EOF #!/bin/bash /usr/sbin/logwatch --output mail --mailto $ADMIN_EMAIL --detail high EOF chmod +x /etc/cron.daily/logwatch echo "" echo -e "${BLUE}Step 8: Backup Configuration${NC}" echo "===========================" print_status "Installing backup tools..." apt install -y rsync duplicity print_status "Creating backup script..." cat > /usr/local/bin/ubuntu-backup.sh << 'EOF' #!/bin/bash # Ubuntu automated backup script BACKUP_DIR="/var/backups" SOURCE_DIR="/home" DATE=$(date +%Y%m%d_%H%M%S) # Create backup directory if it doesn't exist mkdir -p "$BACKUP_DIR" # Local backup rsync -avz --delete "$SOURCE_DIR" "$BACKUP_DIR/daily_$DATE" # Clean old backups (keep last 7) find "$BACKUP_DIR" -name "daily_*" -type d -mtime +7 -exec rm -rf {} + echo "Backup completed: $BACKUP_DIR/daily_$DATE" EOF chmod +x /usr/local/bin/ubuntu-backup.sh print_status "Scheduling daily backups..." echo "0 2 * * * /usr/local/bin/ubuntu-backup.sh" > /etc/cron.d/ubuntu-backup echo "" echo -e "${BLUE}Step 9: Security Validation${NC}" echo "===========================" print_status "Creating security validation script..." cat > /usr/local/bin/ubuntu-security-check.sh << 'EOF' #!/bin/bash # Ubuntu Security Validation Script echo "🔒 Ubuntu Security Check" echo "========================" # SSH Security echo "SSH Security:" if grep -q "PasswordAuthentication no" /etc/ssh/sshd_config; then echo "✅ Password authentication disabled" else echo "❌ Password authentication enabled" fi if grep -q "PermitRootLogin no" /etc/ssh/sshd_config; then echo "✅ Root login disabled" else echo "❌ Root login enabled" fi # Firewall echo -e "\nFirewall Status:" ufw status | grep -E "(Status|active)" # Fail2Ban echo -e "\nFail2Ban Status:" systemctl is-active fail2ban # Updates echo -e "\nSystem Updates:" apt list --upgradable 2>/dev/null | grep -c "upgradable" | xargs echo "packages can be upgraded" echo -e "\nSecurity check complete!" EOF chmod +x /usr/local/bin/ubuntu-security-check.sh print_status "Running initial security check..." /usr/local/bin/ubuntu-security-check.sh echo "" echo -e "${GREEN}🎉 Ubuntu Security Hardening Complete!${NC}" echo "" echo -e "${YELLOW}Next Steps:${NC}" echo "1. Set password for new user: sudo passwd $NEW_USER" echo "2. Copy SSH keys to server for the new user" echo "3. Test SSH connection with new user" echo "4. Run security check: /usr/local/bin/ubuntu-security-check.sh" echo "5. Review logs: tail -f $LOG_FILE" echo "" echo -e "${BLUE}Log saved to: $LOG_FILE${NC}" echo -e "${BLUE}Completed at: $(date)${NC}"

Security Resources

  • Ubuntu Security Notices: https://ubuntu.com/security/notices
  • NIST Cybersecurity Framework: https://www.nist.gov/cyberframework
  • OWASP Security Guidelines: https://owasp.org/
  • Linux Security Best Practices: https://www.cisecurity.org/

Stay secure, stay vigilant! 🔒

This post is licensed under CC BY 4.0 by the author.