Linux Server Security: A Guide to Making SSH Unhackable
In 2023 someone tried to break into one of our customers' servers: 12,400 failed SSH logins within 48 hours. Not one succeeded. Why? Because we had configured SSH security correctly. In this article we explain how to harden a Linux server, which SSH settings you need to make and which tools to use. Spoiler: disabling root login is not enough.
Why Is SSH Security So Important?
SSH (Secure Shell) is the standard way to connect to Linux servers remotely. But an SSH service running with default settings is an open door for attackers.
A Real Statistic: In our SistemDC data center we detect an average of 8,500 SSH brute-force attacks a day. An unprotected server becomes a target within the first 24 hours.
SSH Hardening in 10 Steps
Step 1: Disable Root Login
Allowing direct SSH connections as the root user is the biggest security hole. First create a user with sudo privileges:
# Create a new user
adduser sistemadmin
# Grant sudo privileges
usermod -aG sudo sistemadmin
# Edit the SSH config
nano /etc/ssh/sshd_config
# Find and change this line:
PermitRootLogin no
# Restart SSH
systemctl restart sshd
Step 2: Change the SSH Port
The default port 22 is the first target for bots. Using a different port blocks 95% of automated attacks.
# /etc/ssh/sshd_config
Port 49222
# Open the new port in the firewall
ufw allow 49222/tcp
ufw delete allow 22/tcp
# Restart SSH
systemctl restart sshd
Important: Do not close your current connection until you are sure you can connect on the new port! Open a new terminal to test.
Step 3: SSH Key Authentication (Passwordless Login)
Using an SSH key instead of a password renders brute-force attacks 100% ineffective.
# On your local computer (Mac/Linux)
ssh-keygen -t ed25519 -C "admin@sistemdc.com"
# Copy the public key to the server
ssh-copy-id -i ~/.ssh/id_ed25519.pub sistemadmin@server_ip -p 49222
# Disable password login on the server
# /etc/ssh/sshd_config
PasswordAuthentication no
PubkeyAuthentication yes
systemctl restart sshd
Step 4: Installing Fail2Ban
Fail2Ban monitors failed login attempts and blocks the attacker automatically.
# Installation
apt install fail2ban
# Configuration
nano /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 49222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
# Start
systemctl enable fail2ban
systemctl start fail2ban
# To see banned IPs
fail2ban-client status sshd
Meaning: 3 failed attempts within 10 minutes (600 seconds) = a 1-hour ban.
Step 5: Two-Factor Authentication (2FA)
In addition to the SSH key, add 2FA with Google Authenticator.
# Install the Google Authenticator PAM module
apt install libpam-google-authenticator
# Run as the user (not root!)
su - sistemadmin
google-authenticator
# Answers to the questions:
# - Time-based tokens? y
# - Update .google_authenticator? y
# - Disallow multiple uses? y
# - Increase time skew? n
# - Rate limiting? y
# PAM setting
nano /etc/pam.d/sshd
# Add:
auth required pam_google_authenticator.so
# SSH config
nano /etc/ssh/sshd_config
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
systemctl restart sshd
Step 6: IP Whitelist (Specific IPs Only)
If you have a static IP, allow SSH connections only from that IP.
# IP restriction with UFW
ufw allow from 85.34.12.45 to any port 49222 proto tcp
# Deny all other connections
ufw deny 49222/tcp
# Alternative: /etc/ssh/sshd_config
AllowUsers sistemadmin@85.34.12.45
Step 7: SSH Banner and Timeout Settings
# /etc/ssh/sshd_config
# Show a banner (warning message)
Banner /etc/ssh/banner.txt
# Idle connection timeout (5 minutes)
ClientAliveInterval 300
ClientAliveCountMax 2
# Login timeout (1 minute)
LoginGraceTime 60
# Maximum auth attempts
MaxAuthTries 3
# Maximum concurrent sessions
MaxSessions 2
Step 8: SSH Protocol and Encryption
# /etc/ssh/sshd_config
# SSH Protocol 2 only (1 is insecure)
Protocol 2
# Strong encryption algorithms
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
# Strong MAC algorithms
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
# Strong Key Exchange
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
Step 9: Log Monitoring
Monitor SSH connections continuously.
# View recent SSH logins
last -a | head -20
# Failed login attempts
grep "Failed password" /var/log/auth.log | tail -50
# Live log tracking
tail -f /var/log/auth.log
# Get a daily report by installing Logwatch
apt install logwatch
logwatch --detail High --mailto admin@sistemdc.com --service sshd
Step 10: Port Knocking (Advanced)
Keep the SSH port closed by default and knock on the "secret door" before connecting.
# knockd installation
apt install knockd
# Configuration: /etc/knockd.conf
[options]
logfile = /var/log/knockd.log
[openSSH]
sequence = 7000,8000,9000
seq_timeout = 5
command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 49222 -j ACCEPT
tcpflags = syn
[closeSSH]
sequence = 9000,8000,7000
seq_timeout = 5
command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 49222 -j ACCEPT
tcpflags = syn
# Usage (from the local computer)
knock server_ip 7000 8000 9000
ssh sistemadmin@server_ip -p 49222
Security Testing: Attack Yourself
To test your configuration, simulate an attack on your own server:
# Install the SSH audit tool
pip3 install ssh-audit
# Scan the server
ssh-audit server_ip:49222
# Port scan with Nmap
nmap -p 1-65535 server_ip
# Lynis security audit
apt install lynis
lynis audit system
Default Security at SistemDC
On SistemDC servers, basic security measures are active from the initial setup:
- Root login disabled (delivered with a sudo user)
- Fail2Ban pre-installed and configured
- UFW firewall active
- Daily security updates (unattended-upgrades)
- SSH port change (optional)
- DDoS protection (at network level)
Additional Service: With the Managed Security package we offer 24/7 security monitoring, log analysis and emergency response. Prices start from 500 TL a month.
Backups and Disaster Recovery
Security measures do not provide 100% protection. Backups are a must:
# Automatic backup script
nano /usr/local/bin/backup.sh
#!/bin/bash
BACKUP_DIR="/backup/$(date +%Y%m%d)"
mkdir -p $BACKUP_DIR
# Database backup
mysqldump --all-databases > $BACKUP_DIR/databases.sql
# Web files
tar -czf $BACKUP_DIR/web.tar.gz /var/www
# SSH config
cp -r /etc/ssh $BACKUP_DIR/
# Delete backups older than 7 days
find /backup -type d -mtime +7 -exec rm -rf {} \;
# Run daily with cron
crontab -e
0 2 * * * /usr/local/bin/backup.sh
Would You Like a Server Security Analysis?
Let us analyse the security status of your current server free of charge. We will identify the vulnerabilities and report them.
Contact:
satis@sistemdc.com
Corporate WhatsApp: +90 224 334 02 42
Conclusion: Layers of Security
SSH security is not a single setting; it requires a layered approach:
- Root login disabled
- SSH key authentication
- Port change
- Fail2Ban
- 2FA (Two-factor)
- IP whitelist (if possible)
- Log monitoring
- Regular security updates
A server that applies these 10 steps is 99.98% protected against brute-force attacks. In our 14 years of experience, none of our properly configured servers has been hacked over SSH.
Note: The commands in this article have been tested on Ubuntu 24.04, Debian 12 and derivatives. Always take a backup before making changes on a production server. The security configuration should be tailored to the system and use case.