Ubuntu LTS Security Hardening Guide: Complete Server Setup for Beginners
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! π‘οΈβ¨
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! π