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

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:

  1. Access server via hosting provider's console/VNC
  2. Check SSH service status:
sudo systemctl status sshd
  1. Review SSH configuration for errors:
sudo sshd -t
  1. Temporarily enable password authentication if needed:
sudo nano /etc/ssh/sshd_config
# Change: PasswordAuthentication yes
sudo systemctl restart sshd
  1. 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

  1. Regular security audits: Run monthly security checks and vulnerability scans
  2. Least privilege principle: Grant minimum necessary permissions
  3. Defense in depth: Implement multiple security layers
  4. Monitoring: Set up logging and alerting for security events
  5. Documentation: Keep records of all security configurations
  6. Backup strategy: Implement regular backups before making changes
  7. Update schedule: Keep systems patched with latest security updates
  8. Access control: Limit SSH access to specific IP addresses when possible
  9. Strong authentication: Use SSH keys with passphrases and consider 2FA
  10. 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

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