Securing a production Linux virtual private server requires establishing layered defensive controls across remote administrative access, network packet filtering, and automated intrusion prevention. Because any public IPv4 address experiences automated vulnerability scanning and dictionary attacks within minutes of being provisioned, relying on standard operating system defaults or password authentication exposes instances to compromise. Implementing cryptographic SSH key authentication, strict UFW firewall policies, and automated Fail2ban jail rules creates a resilient defense.
The Three Pillars of Linux Host Security
A comprehensive security architecture coordinates defensive controls across three distinct operational layers:
- Cryptographic Authentication (OpenSSH): Eliminating password vulnerabilities, removing root login access, and enforcing modern public-key cryptography.
- Host Packet Filtering (UFW): Enforcing an explicit default-deny network posture so that unhardened background services cannot be accessed from public networks.
- Automated Threat Mitigation (Fail2ban): Continuously parsing authentication logs to detect suspicious activity and applying dynamic temporary firewall drops to offending IP addresses.
Step 1: Generating Ed25519 SSH Keys and User Privileges
Before modifying server configuration files, generate a modern cryptographic key pair on your local development workstation. While older RSA-2048 keys remain common, Ed25519 keys offer superior security, smaller key signatures, and immunity to common side-channel vulnerabilities:
# Generate an Ed25519 key pair on your local computer
ssh-keygen -t ed25519 -a 100 -C "admin@production-vps"
# Copy public key to the server
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@<vps_ip_address>Ensure that administrative access is handled through a non-root user account belonging to the sudo administrative group. Never permit automated deploy scripts or external developers to access the root account directly.
Step 2: OpenSSH Daemon Hardening in sshd_config
Keep your current active SSH session open in a terminal window to avoid accidental lockout during testing. Create a dedicated hardening configuration drop-in file at /etc/ssh/sshd_config.d/hardening.conf:
# Disable root login completely
PermitRootLogin no
# Enforce public key authentication only
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
# Limit authentication attempts per connection to prevent credential stuffing
MaxAuthTries 3
# Limit simultaneous unauthenticated connections to protect against connection floods
MaxStartups 10:30:60
# Terminate idle sessions automatically after 10 minutes of inactivity
ClientAliveInterval 300
ClientAliveCountMax 2
# Disable legacy and insecure features
X11Forwarding no
AllowAgentForwarding no
PermitEmptyPasswords noValidate the syntax of your configuration before reloading the SSH daemon:
sudo sshd -t
sudo systemctl reload sshdIf sshd -t returns any errors, resolve them immediately before closing your active session. With password authentication disabled, dictionary attacks targeting system user accounts are rendered ineffective.
Step 3: Configuring UFW (Uncomplicated Firewall)
The Linux kernel includes sophisticated packet filtering capabilities via iptables and nftables. UFW provides a reliable management interface to define strict ingress and egress policies.
Ensure IPv6 support is enabled in /etc/default/ufw (IPV6=yes), then establish a baseline default-deny policy:
# Set baseline security policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow administrative SSH access with rate limiting
sudo ufw limit 22/tcp comment 'Rate-limited SSH'
# Allow standard web server traffic
sudo ufw allow 80/tcp comment 'HTTP traffic'
sudo ufw allow 443/tcp comment 'HTTPS encrypted traffic'
# Enable the firewall
sudo ufw enableCheck the active rule table using sudo ufw status verbose. Verify that internal service ports—such as MySQL (3306), Redis (6379), and PostgreSQL (5432)—are not listed as open to public ingress. Inspect open sockets on the host using ss -tulpn to confirm that database engines bind only to localhost (127.0.0.1).
Step 4: Deploying Fail2ban for Dynamic Threat Mitigation
Even with password authentication disabled, botnets repeatedly attempt connections against port 22, generating unnecessary system log noise. Fail2ban monitors authentication logs in real time and automatically bans offending IP addresses via temporary firewall rules.
Install Fail2ban on Ubuntu or Debian:
sudo apt update && sudo apt install fail2ban -yCreate a customized local jail configuration in /etc/fail2ban/jail.d/sshd.local:
[sshd]
enabled = true
port = 22
logpath = %(sshd_log)s
backend = systemd
# Ban IP for 2 hours if 3 failed attempts occur within 10 minutes
maxretry = 3
findtime = 600
bantime = 7200
# Whitelist trusted office IP addresses
# ignoreip = 127.0.0.1/8 ::1 203.0.113.100Start and enable the service across system boots:
sudo systemctl restart fail2ban
sudo systemctl enable fail2banInspect active bans and banned IP statistics at any time using sudo fail2ban-client status sshd.
StreamData Protected VPS Infrastructure
Operating-system-level security achieves peak effectiveness when built on an isolated hypervisor foundation. StreamData Networks provides KVM VPS hosting with full root administrative access across 10 distinct tiers ranging from 1 GB to 128 GB RAM with RAID NVMe storage starting from Rs 149 per month. For high-intensity workloads, StreamData offers AMD Ryzen 9 9950X VPS instances (16 GB to 64 GB DDR5) and bare-metal dedicated servers from Rs 6,499 per month. All nodes in Mumbai, Noida, and Jaipur are protected by Cloudflare Magic Transit-ready and StormWall partner mitigation paths.
Provision secure virtual instances on StreamData KVM VPS, review enterprise servers on StreamData Dedicated Servers, or view network capabilities on StreamData Company.