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
- Set up monitoring alerts (email notifications for security events)
- Configure log shipping to a central logging server
- Implement SIEM (Security Information and Event Management) if managing multiple servers
- 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! 🔒