Initial Security Configuration on Ubuntu/Debian
Securing your Ubuntu or Debian server immediately after deployment is critical to protect against unauthorized access, malware, and cyber attacks. This comprehensive guide walks you through essential security hardening steps that every system administrator should implement on new Ubuntu and Debian servers, establishing a robust security foundation for your infrastructure.
Table of Contents
- Prerequisites
- Understanding Server Security Fundamentals
- Step 1: Update System Packages
- Step 2: Create a Non-Root Administrative User
- Step 3: Configure SSH Key Authentication
- Step 4: Harden SSH Configuration
- Step 5: Configure UFW Firewall
- Step 6: Install and Configure Fail2Ban
- Step 7: Set Up Automatic Security Updates
- Step 8: Configure Timezone and NTP
- Step 9: Disable Unnecessary Services
- Step 10: Implement Additional Security Measures
- Verification
- Troubleshooting
- Best Practices
- Conclusion
- Additional Resources
Prerequisites
Before beginning the security configuration process, ensure you have:
- Fresh installation of Ubuntu (20.04 LTS, 22.04 LTS, or 24.04 LTS) or Debian (11 Bullseye or 12 Bookworm)
- Root access or user with sudo privileges
- SSH access to the server
- Server IP address or hostname
- Basic understanding of Linux command line
- Access to server console (via hosting provider panel) in case of lockout
- At least 1GB RAM and 10GB disk space available
Understanding Server Security Fundamentals
Server security operates on the principle of defense in depth, implementing multiple layers of protection to safeguard your infrastructure. The initial security configuration focuses on:
Key security principles:
- Principle of Least Privilege: Users and processes should have only the minimum permissions necessary
- Defense in Depth: Multiple security layers protect against various attack vectors
- Fail Secure: Systems should default to secure states when failures occur
- Separation of Duties: Administrative tasks should be distributed to prevent abuse
- Regular Updates: Software must be kept current to patch vulnerabilities
Common attack vectors addressed in this guide:
- Brute-force SSH attacks
- Unauthorized root access
- Unpatched software vulnerabilities
- Open unnecessary ports and services
- Privilege escalation exploits
Step 1: Update System Packages
The first and most critical step is updating all system packages to patch known vulnerabilities.
# Update package repository cache
sudo apt update
# Upgrade all installed packages
sudo apt upgrade -y
# Perform distribution upgrade (updates kernel and core packages)
sudo apt dist-upgrade -y
# Remove unnecessary packages
sudo apt autoremove -y
# Clean package cache
sudo apt clean
Why this matters: Software vendors regularly release security patches for discovered vulnerabilities. Running outdated software exposes your server to known exploits that attackers actively scan for. The dist-upgrade command ensures kernel updates are applied, which often contain critical security fixes.
Verify kernel version:
# Check current kernel version
uname -r
# List available kernels
dpkg --list | grep linux-image
If a new kernel was installed, reboot the server:
# Reboot system to load new kernel
sudo reboot
After reboot, reconnect and verify the kernel version:
# Confirm new kernel is running
uname -r
Step 2: Create a Non-Root Administrative User
Running operations as root is dangerous because every command executes with unlimited privileges. Create a dedicated administrative user with sudo access.
# Create new user (replace 'adminuser' with your preferred username)
sudo adduser adminuser
You'll be prompted to set a password and optional user information. Choose a strong password with uppercase, lowercase, numbers, and special characters.
# Add user to sudo group for administrative privileges
sudo usermod -aG sudo adminuser
# Verify user group membership
groups adminuser
Why use sudo instead of root:
- Accountability: Commands are logged with the user who executed them
- Reduced risk: Mistakes are less catastrophic with sudo prompts
- Fine-grained control: Sudo can be configured for specific command permissions
- Audit trail: /var/log/auth.log records all sudo usage
Test sudo access:
# Switch to new user
su - adminuser
# Test sudo privileges
sudo whoami
# Should output: root
# Verify sudo group membership
id adminuser
Step 3: Configure SSH Key Authentication
SSH key authentication is significantly more secure than password authentication and should be set up before disabling password logins.
Generate SSH Key Pair (on your local machine)
If you haven't already created an SSH key pair:
# Generate Ed25519 key (recommended for modern systems)
ssh-keygen -t ed25519 -C "[email protected]"
# Or generate RSA 4096-bit key (for compatibility)
ssh-keygen -t rsa -b 4096 -C "[email protected]"
Accept the default file location (~/.ssh/id_ed25519 or ~/.ssh/id_rsa) and set a strong passphrase.
Copy Public Key to Server
# Copy public key to your new administrative user
ssh-copy-id adminuser@your_server_ip
# If ssh-copy-id is unavailable, use this method:
cat ~/.ssh/id_ed25519.pub | ssh adminuser@your_server_ip "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
Verify Key Authentication
# Test connection with new user using key authentication
ssh adminuser@your_server_ip
# You should connect without entering the server password
# (only your key passphrase if you set one)
Important: Keep this SSH session open while testing to avoid lockout. Open a new terminal window for the next steps.
Set Proper Permissions on Server
Ensure correct permissions on SSH directories and files:
# On the server, as your administrative user
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
# Verify permissions
ls -la ~/.ssh/
# Should show:
# drwx------ for .ssh directory
# -rw------- for authorized_keys file
Step 4: Harden SSH Configuration
Modify SSH daemon configuration to implement security best practices.
# Backup original SSH configuration
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup.$(date +%Y%m%d)
# Edit SSH configuration
sudo nano /etc/ssh/sshd_config
Apply these security hardening settings:
# Disable root login via SSH
PermitRootLogin no
# Disable password authentication (only after key auth is working!)
PasswordAuthentication no
# Disable empty passwords
PermitEmptyPasswords no
# Disable challenge-response authentication
ChallengeResponseAuthentication no
# Disable PAM authentication (if using key-only auth)
UsePAM no
# Allow only specific users (optional)
AllowUsers adminuser
# Disable X11 forwarding if not needed
X11Forwarding no
# Set maximum authentication attempts
MaxAuthTries 3
# Reduce login grace time
LoginGraceTime 30
# Use strong key exchange algorithms
KexAlgorithms curve25519-sha256,[email protected],diffie-hellman-group-exchange-sha256
# Use strong ciphers
Ciphers [email protected],[email protected],[email protected],aes256-ctr,aes192-ctr,aes128-ctr
# Use strong MAC algorithms
MACs [email protected],[email protected],hmac-sha2-512,hmac-sha2-256
# Disable host-based authentication
HostbasedAuthentication no
# Disable rhosts authentication
IgnoreRhosts yes
# Enable strict mode
StrictModes yes
# Disable unused authentication methods
PubkeyAuthentication yes
GSSAPIAuthentication no
KerberosAuthentication no
Critical warning: Before disabling password authentication, verify SSH key authentication works correctly in a separate terminal session.
Test SSH configuration syntax:
# Verify configuration has no syntax errors
sudo sshd -t
# No output means configuration is valid
Restart SSH service:
# Restart SSH daemon to apply changes
sudo systemctl restart sshd
# Verify SSH service is running
sudo systemctl status sshd
Test the new configuration in a new terminal window before closing your current session:
# Connect in new terminal window
ssh adminuser@your_server_ip
# Verify connection works with key authentication
# Try connecting as root (should be denied)
ssh root@your_server_ip
# Should fail with "Permission denied"
Step 5: Configure UFW Firewall
UFW (Uncomplicated Firewall) provides an easy-to-use interface for iptables firewall configuration on Ubuntu and Debian.
# Install UFW (usually pre-installed on Ubuntu)
sudo apt install ufw -y
# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH before enabling firewall (critical to avoid lockout!)
sudo ufw allow ssh
# Or specify custom SSH port if you changed it:
# sudo ufw allow 2222/tcp
# Allow HTTP and HTTPS if running web server
sudo ufw allow http
sudo ufw allow https
# Or use port numbers:
# sudo ufw allow 80/tcp
# sudo ufw allow 443/tcp
Enable UFW:
# Enable firewall
sudo ufw enable
# Verify firewall status
sudo ufw status verbose
Expected output:
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)
443/tcp (v6) ALLOW IN Anywhere (v6)
Additional UFW commands:
# Allow specific IP address to all ports
sudo ufw allow from 203.0.113.50
# Allow specific IP to specific port
sudo ufw allow from 203.0.113.50 to any port 22
# Allow port range
sudo ufw allow 8000:8100/tcp
# Deny specific port
sudo ufw deny 23
# Delete rule by number
sudo ufw status numbered
sudo ufw delete [number]
# Reset UFW to default (removes all rules)
sudo ufw reset
# Disable UFW
sudo ufw disable
Why firewall configuration matters: Firewalls implement network-level access control, blocking unauthorized connection attempts before they reach your services. A properly configured firewall reduces your attack surface by exposing only necessary ports.
Step 6: Install and Configure Fail2Ban
Fail2Ban monitors log files and automatically bans IP addresses that show malicious behavior, such as repeated failed login attempts.
# Install Fail2Ban
sudo apt install fail2ban -y
# Copy default configuration
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# Edit local configuration
sudo nano /etc/fail2ban/jail.local
Configure SSH protection by adding or modifying:
[DEFAULT]
# Ban hosts for 1 hour (3600 seconds)
bantime = 3600
# Monitor for failed attempts over 10 minutes
findtime = 600
# Ban after 5 failed attempts
maxretry = 5
# Email notifications (optional)
destemail = [email protected]
sendername = Fail2Ban
action = %(action_mwl)s
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 7200
Start and enable Fail2Ban:
# Start Fail2Ban service
sudo systemctl start fail2ban
# Enable Fail2Ban to start on boot
sudo systemctl enable fail2ban
# Check Fail2Ban status
sudo systemctl status fail2ban
# View active jails
sudo fail2ban-client status
# View SSH jail status
sudo fail2ban-client status sshd
Fail2Ban management commands:
# Unban an IP address
sudo fail2ban-client set sshd unbanip 203.0.113.50
# View banned IPs
sudo fail2ban-client status sshd
# Test Fail2Ban regex patterns
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
# Reload Fail2Ban configuration
sudo fail2ban-client reload
Why Fail2Ban is essential: Automated brute-force attacks attempt thousands of login combinations. Fail2Ban automatically blocks these attacks by identifying patterns in log files and creating temporary firewall rules to ban offending IP addresses.
Step 7: Set Up Automatic Security Updates
Configure unattended-upgrades to automatically install critical security patches.
# Install unattended-upgrades package
sudo apt install unattended-upgrades apt-listchanges -y
# Enable automatic updates
sudo dpkg-reconfigure -plow unattended-upgrades
# Select "Yes" when prompted
Configure automatic update behavior:
# Edit unattended-upgrades configuration
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
Recommended configuration:
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
};
// Automatically remove unused dependencies
Unattended-Upgrade::Remove-Unused-Dependencies "true";
// Automatically reboot if required (use with caution)
Unattended-Upgrade::Automatic-Reboot "false";
// If automatic reboot is enabled, do it at 2 AM
Unattended-Upgrade::Automatic-Reboot-Time "02:00";
// Email notification on errors
Unattended-Upgrade::Mail "[email protected]";
Unattended-Upgrade::MailReport "on-change";
// Remove unused kernel packages
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Configure update frequency:
# Edit auto-upgrade configuration
sudo nano /etc/apt/apt.conf.d/20auto-upgrades
Set:
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";
Test automatic updates:
# Manually run unattended-upgrades in debug mode
sudo unattended-upgrades --debug --dry-run
# View update logs
sudo cat /var/log/unattended-upgrades/unattended-upgrades.log
Step 8: Configure Timezone and NTP
Correct time configuration is crucial for logging, scheduled tasks, and security certificates.
# Check current timezone
timedatectl
# List available timezones
timedatectl list-timezones
# Set timezone (example: UTC)
sudo timedatectl set-timezone UTC
# Or set to specific location
sudo timedatectl set-timezone America/New_York
Configure NTP time synchronization:
# Enable NTP synchronization
sudo timedatectl set-ntp on
# Verify time synchronization status
timedatectl status
# Check systemd-timesyncd service
sudo systemctl status systemd-timesyncd
# View time synchronization details
timedatectl show-timesync --all
Alternative: Install and configure chrony (more accurate):
# Install chrony
sudo apt install chrony -y
# Edit chrony configuration
sudo nano /etc/chrony/chrony.conf
# Verify chrony is running
sudo systemctl status chrony
# Check synchronization sources
chronyc sources
# View tracking information
chronyc tracking
Step 9: Disable Unnecessary Services
Reduce attack surface by disabling services you don't need.
# List all running services
sudo systemctl list-units --type=service --state=running
# List enabled services
sudo systemctl list-unit-files --type=service --state=enabled
Common services to consider disabling:
# Disable Bluetooth (if not needed on server)
sudo systemctl disable bluetooth.service
sudo systemctl stop bluetooth.service
# Disable CUPS printing service
sudo systemctl disable cups.service
sudo systemctl stop cups.service
# Disable Avahi daemon (unless using mDNS)
sudo systemctl disable avahi-daemon.service
sudo systemctl stop avahi-daemon.service
# Disable ModemManager (not needed on servers)
sudo systemctl disable ModemManager.service
sudo systemctl stop ModemManager.service
Remove unnecessary packages:
# Remove snapd if not using snap packages
sudo apt purge snapd -y
# Remove unneeded packages and dependencies
sudo apt autoremove -y
# List installed packages by size
dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -n
Disable unnecessary network protocols:
# Disable IPv6 if not used (edit /etc/sysctl.conf)
sudo nano /etc/sysctl.conf
# Add these lines:
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
# Apply changes
sudo sysctl -p
Step 10: Implement Additional Security Measures
Configure System Limits
# Edit limits configuration
sudo nano /etc/security/limits.conf
# Add resource limits:
* soft nofile 65536
* hard nofile 65536
* soft nproc 32768
* hard nproc 32768
Enable Process Accounting
# Install accounting tools
sudo apt install acct -y
# Start accounting service
sudo systemctl start acct
sudo systemctl enable acct
# View accounting statistics
sudo sa
sudo lastcomm
Configure Shared Memory Security
# Edit fstab to secure shared memory
sudo nano /etc/fstab
# Add this line:
tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0
# Remount with new options
sudo mount -o remount /run/shm
Disable Core Dumps
# Edit limits configuration
sudo nano /etc/security/limits.conf
# Add:
* hard core 0
# Disable SUID core dumps
sudo nano /etc/sysctl.conf
# Add:
fs.suid_dumpable = 0
# Apply changes
sudo sysctl -p
Configure Audit Logging
# Install auditd
sudo apt install auditd audispd-plugins -y
# Start and enable auditd
sudo systemctl start auditd
sudo systemctl enable auditd
# View audit logs
sudo ausearch -m USER_LOGIN
sudo ausearch -m USER_AUTH
Set Up AppArmor (Ubuntu) or SELinux (if available)
# Check AppArmor status (Ubuntu/Debian default)
sudo apparmor_status
# Install AppArmor utilities
sudo apt install apparmor-utils -y
# Set profile to enforce mode
sudo aa-enforce /etc/apparmor.d/*
# View AppArmor profiles
sudo aa-status
Verification
After completing all security configurations, verify everything is working correctly.
Verify SSH Security
# Test SSH connection with your admin user
ssh adminuser@your_server_ip
# Verify root login is disabled
ssh root@your_server_ip
# Should be denied
# Check SSH configuration
sudo sshd -t
Verify Firewall Status
# Check UFW status
sudo ufw status verbose
# Verify iptables rules
sudo iptables -L -n -v
# Check IPv6 rules
sudo ip6tables -L -n -v
Verify Fail2Ban Operation
# Check Fail2Ban status
sudo systemctl status fail2ban
# View active jails
sudo fail2ban-client status
# Check SSH jail
sudo fail2ban-client status sshd
Verify Automatic Updates
# Check unattended-upgrades status
sudo systemctl status unattended-upgrades
# View recent update logs
sudo tail -f /var/log/unattended-upgrades/unattended-upgrades.log
Security Audit
# Check for open ports
sudo ss -tulnp
# List running services
sudo systemctl list-units --type=service --state=running
# View recent authentication logs
sudo tail -f /var/log/auth.log
# Check for failed login attempts
sudo grep "Failed password" /var/log/auth.log | tail -20
# View last logins
sudo last -a | head -20
# Check system resource usage
top
htop
Troubleshooting
Locked Out of SSH
Problem: Cannot connect via SSH after configuration changes.
Solution:
- Access server via hosting provider's console/VNC
- Check SSH service status:
sudo systemctl status sshd
- Review SSH configuration for errors:
sudo sshd -t
- Temporarily enable password authentication if needed:
sudo nano /etc/ssh/sshd_config
# Change: PasswordAuthentication yes
sudo systemctl restart sshd
- Check firewall rules:
sudo ufw status
sudo ufw allow 22/tcp
UFW Blocking Legitimate Connections
Problem: Cannot access services after enabling UFW.
Solution:
# View current rules
sudo ufw status numbered
# Add missing rules
sudo ufw allow [port]/tcp
# Delete problematic rules
sudo ufw delete [rule_number]
# Temporarily disable for troubleshooting
sudo ufw disable
# Re-enable after fixing
sudo ufw enable
Fail2Ban Banning Your IP
Problem: Your own IP address gets banned by Fail2Ban.
Solution:
# Check if your IP is banned
sudo fail2ban-client status sshd
# Unban your IP
sudo fail2ban-client set sshd unbanip YOUR_IP_ADDRESS
# Add your IP to whitelist (edit jail.local)
sudo nano /etc/fail2ban/jail.local
# Add under [DEFAULT]:
ignoreip = 127.0.0.1/8 ::1 YOUR_IP_ADDRESS
# Restart Fail2Ban
sudo systemctl restart fail2ban
Automatic Updates Breaking System
Problem: Automatic updates caused service disruption.
Solution:
# Disable automatic updates temporarily
sudo systemctl stop unattended-upgrades
sudo systemctl disable unattended-upgrades
# Review what was updated
sudo cat /var/log/unattended-upgrades/unattended-upgrades.log
# Roll back specific package
sudo apt install package_name=previous_version
# Re-enable with more conservative settings
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
Time Synchronization Issues
Problem: Server time is incorrect.
Solution:
# Check time sync status
timedatectl status
# Restart time sync service
sudo systemctl restart systemd-timesyncd
# Manually sync time
sudo ntpdate pool.ntp.org
# Or use timedatectl
sudo timedatectl set-ntp false
sudo timedatectl set-ntp true
Best Practices
Security Recommendations
- Regular security audits: Run monthly security checks and vulnerability scans
- Least privilege principle: Grant minimum necessary permissions
- Defense in depth: Implement multiple security layers
- Monitoring: Set up logging and alerting for security events
- Documentation: Keep records of all security configurations
- Backup strategy: Implement regular backups before making changes
- Update schedule: Keep systems patched with latest security updates
- Access control: Limit SSH access to specific IP addresses when possible
- Strong authentication: Use SSH keys with passphrases and consider 2FA
- Regular password rotation: Change passwords quarterly for password-enabled accounts
Maintenance Schedule
Daily:
- Monitor authentication logs for suspicious activity
- Review Fail2Ban banned IPs
- Check system resource usage
Weekly:
- Review installed packages and remove unnecessary ones
- Check for available security updates
- Audit user accounts and permissions
Monthly:
- Review firewall rules and update as needed
- Rotate logs and clean old data
- Test backup restoration procedures
- Run security vulnerability scans
- Review and update documentation
Quarterly:
- Rotate passwords and SSH keys
- Update security configurations based on new threats
- Review and test disaster recovery procedures
Configuration Management
# Backup important configuration files
sudo tar -czf /root/config-backup-$(date +%Y%m%d).tar.gz \
/etc/ssh/sshd_config \
/etc/ufw \
/etc/fail2ban \
/etc/security/limits.conf \
/etc/sysctl.conf \
/etc/apt/apt.conf.d
Monitoring Commands
# Create alias for quick security checks
echo "alias security-check='sudo ss -tulnp; sudo ufw status; sudo fail2ban-client status; sudo journalctl -u sshd -n 50'" >> ~/.bashrc
source ~/.bashrc
# Run comprehensive security check
security-check
Conclusion
You've now implemented a comprehensive security foundation for your Ubuntu or Debian server. These initial security configurations significantly reduce your server's vulnerability to common attacks and establish a solid baseline for further hardening.
Key achievements:
- System packages updated to latest versions
- Non-root administrative user created with sudo access
- SSH hardened with key authentication and secure configuration
- Firewall configured to allow only necessary traffic
- Fail2Ban protecting against brute-force attacks
- Automatic security updates enabled
- Unnecessary services disabled
- Additional security measures implemented
Next steps:
- Install and configure application-specific security measures
- Set up monitoring and alerting systems
- Implement backup solutions
- Configure additional access controls as needed
- Regular security audits and updates
Remember that security is an ongoing process, not a one-time configuration. Stay informed about new vulnerabilities, regularly review logs, and keep your systems updated.
Additional Resources
- Ubuntu Security Guide
- Debian Security Information
- CIS Ubuntu Linux Benchmark
- [NIST Security Configuration Guides](https://nv d.nist.gov/ncp/repository)
- OpenSSH Security Best Practices
- UFW Documentation
- Fail2Ban Official Documentation
Related Guides
- How to Connect to Your Server via SSH
- How to Change the Default SSH Port
- Linux Server Hardening: Complete Guide
- Fail2Ban Configuration for Brute Force Protection
- How to Configure Users and Permissions on Linux
- SSH Key Management: Generation and Best Practices


