Emma Larsson
VPS Technical LeadEmma Larsson is a lead systems developer and virtualization specialist with a decade of expertise in kernel configurations and hypervisor scaling.
When you spin up your first virtual private server, you gain root access and complete control over your hosting environment. That control is empowering — but it also means the responsibility for securing the server falls entirely on your shoulders. Unlike managed shared hosting, where your provider handles firewall rules, malware scanning, and patch management, an unmanaged VPS arrives as a blank slate. Default configurations on most Linux distributions prioritize ease of use, not security, and automated attack scripts begin probing new IP addresses within minutes of a server coming online. The hardening steps detailed in this guide are drawn from our team's collective experience managing thousands of VPS instances at HostingCaptain, where we have observed that a properly hardened server endures fewer intrusion attempts, maintains better uptime, and protects sensitive customer data far more effectively than a default installation left untouched after provisioning. Whether you are running a personal blog on a budget droplet or deploying a high-traffic e-commerce storefront, the checklist that follows will walk you through every essential layer of defense every VPS owner should implement before exposing services to the public internet.
Before diving into configuration files and SSH commands, it is worth understanding what separates a hardened VPS from a vulnerable one. Attackers do not typically target specific servers with elaborate custom exploits. Instead, they cast wide nets using automated scanners that check for open default ports, weak passwords, outdated software packages with known CVEs, and misconfigured services that leak information. Every hardening measure you implement closes one more door that these scanners rely on. If you are new to virtual private servers entirely, our VPS hosting guide covers the fundamentals of how virtualization works, how resources are allocated, and what you should expect from different plan tiers before proceeding with the hardening steps below.
Secure Shell, or SSH, is the primary method by which you and any potential attacker will attempt to connect to your VPS. Out of the box, most Linux distributions ship with SSH configured to accept password-based authentication on port 22 for the root user — a combination that automated brute-force bots exploit relentlessly. According to threat intelligence data aggregated across HostingCaptain's fleet in early 2026, a freshly provisioned VPS with default SSH settings typically receives between 800 and 3,000 unauthorized login attempts within the first 24 hours of operation. Hardening SSH is therefore not optional; it is the single most impactful change you can make to reduce your attack surface immediately after provisioning. The three adjustments outlined below should be completed before you install any additional software or expose application ports to the internet.
Password-based authentication is the weakest link in most SSH configurations. No matter how complex you make your credentials, they remain susceptible to brute-force guessing, credential stuffing from third-party data breaches, and shoulder-surfing. SSH key pairs solve this problem by using asymmetric cryptography: your private key stays on your local machine, while the public key sits on the server. Even if an attacker intercepts the authentication handshake, they cannot derive your private key from the public half. To implement key-based authentication, generate an Ed25519 key pair on your local workstation using ssh-keygen -t ed25519 -C "[email protected]", then copy the public key to the server with ssh-copy-id user@your-server-ip. Once you have verified that key-based login works, edit /etc/ssh/sshd_config and set PasswordAuthentication no. Restart the SSH daemon and test the connection again from a new terminal window before closing your existing session — locking yourself out of your own server is a surprisingly common mistake even among experienced administrators.
Moving SSH off the standard port 22 does not constitute a security measure by itself, because port scans will still discover the open service within seconds. However, it dramatically reduces the volume of automated login attempts your server must process, which preserves CPU cycles, reduces log noise, and makes it easier to spot targeted attack patterns among the background chatter. Choose a port number above 1024 — something in the 2000–65000 range that does not conflict with known services. Update the Port directive in /etc/ssh/sshd_config, adjust your firewall rules accordingly, and remember to append the -p flag to all future SSH connections. This is also an excellent moment to consider whether your SSH client supports connection multiplexing, which can speed up repeated sessions once the new port is configured.
Logging in directly as root means that an attacker who compromises your SSH credentials immediately gains unrestricted access to the entire filesystem. Create a dedicated non-root user account with sudo privileges instead, and set PermitRootLogin no in the SSH daemon configuration. This forces any administrative action to pass through sudo, which provides an audit trail and adds a deliberate step between a compromised user account and full system control. Combine this with AllowUsers or AllowGroups directives to restrict which accounts can authenticate via SSH at all. For environments with multiple administrators, consider pairing each individual with their own key pair and user account rather than sharing credentials — this makes revocation straightforward when team members change roles.
A default-allow firewall policy is effectively no firewall at all. The correct posture for a VPS is default-deny: block all inbound traffic except for the specific ports and protocols your applications require, and restrict outbound traffic where appropriate to limit data exfiltration channels if a service is ever compromised. The three most common firewall management tools on Linux are UFW (Uncomplicated Firewall), iptables, and firewalld. Each serves the same fundamental purpose but differs in syntax, default zone behavior, and how rules persist across reboots. For beginners managing a single VPS, UFW offers the gentlest learning curve while still providing the granularity needed for a production server. For administrators comfortable with direct netfilter rule syntax or those managing fleet-wide configurations with configuration management tools like Ansible, iptables or nftables may provide more flexibility.
Begin by enabling UFW and setting the defaults: ufw default deny incoming and ufw default allow outgoing. Then explicitly allow only the services you need — for a typical web server this means ufw allow 80/tcp, ufw allow 443/tcp, and your custom SSH port with ufw allow 2200/tcp. If you use any control panels, database administration tools, or monitoring agents, open those ports as well, but resist the temptation to add broad port ranges just to avoid future configuration work. Enable rate limiting on the SSH port with ufw limit 2200/tcp to automatically throttle repeated connection attempts from a single IP address. Before activating the firewall with ufw enable, review your rule set with ufw status verbose and confirm that your current SSH session will not be terminated by the new rules.
If your distribution uses firewalld by default — common on RHEL, CentOS Stream, AlmaLinux, and Rocky Linux — you will work with zones and services rather than raw rules. The firewall-cmd utility allows you to assign network interfaces to zones such as public, internal, or dmz, each with its own rule set. For containerized environments using Docker or Podman, be aware that these tools manipulate iptables rules directly and can bypass UFW entirely. In such cases, you must either configure Docker to respect UFW rules by setting iptables to false in the Docker daemon configuration and manually managing rules, or adopt a network policy approach using the container orchestration layer. Regardless of which firewall tool you select, always make the rules persistent — UFW handles this automatically, but raw iptables rules require the iptables-persistent or netfilter-persistent package to survive a reboot. If you eventually outgrow your VPS, our article on deciding when a dedicated server upgrade makes sense explains how firewall complexity scales with infrastructure size.
Even the most carefully configured firewall cannot protect against vulnerabilities in the software you intentionally expose to the internet. The Common Vulnerabilities and Exposures database tracked over 29,000 new CVEs in 2024 alone, and the window between public disclosure and active exploitation continues to shrink — sometimes measured in hours rather than days. Two complementary tools address this reality: unattended-upgrades ensures your packages receive security patches without manual intervention, and Fail2Ban monitors log files for suspicious activity patterns and dynamically blocks offending IP addresses at the firewall level. Together they create an automated safety net that catches both known software flaws and active intrusion attempts.
On Debian and Ubuntu systems, install the unattended-upgrades package and edit /etc/apt/apt.conf.d/50unattended-upgrades to enable the security repository while optionally leaving other update sources disabled. The key configuration block should include "${distro_id}:${distro_codename}-security"; and you should set Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; and Unattended-Upgrade::Remove-New-Unused-Dependencies "true"; to prevent old kernel images from filling up the boot partition over time. Schedule the updates via /etc/apt/apt.conf.d/20auto-upgrades with a daily cadence, and configure email notifications through Unattended-Upgrade::Mail so you receive a report whenever packages are changed. For RHEL-based distributions, the equivalent tool is dnf-automatic, which offers similar staging and notification capabilities. Keep in mind that automatic updates should be limited to security patches — full system upgrades can introduce breaking changes to application stacks and should remain a deliberate, tested process.
Fail2Ban operates by parsing log files for failed authentication attempts and, after a configurable threshold is crossed, issuing firewall rules to temporarily ban the source IP address. The default jail configurations cover SSH, but you should extend protection to every service that accepts authentication — including web application login pages, mail servers, FTP daemons, and database ports if they are network-accessible. Create a local override file at /etc/fail2ban/jail.local rather than editing the shipped jail.conf directly, because distribution updates can overwrite the latter. Set your bantime to at least 3600 seconds (one hour) and increase it progressively for repeat offenders using the findtime and maxretry parameters. A practical starting configuration is maxretry = 3 within a findtime = 600 second window, with a bantime = 3600. Monitor /var/log/fail2ban.log for the first week to tune these values — overly aggressive thresholds can lock out legitimate users behind NAT gateways or corporate VPNs, while overly lenient settings defeat the purpose of the tool.
Every network-facing daemon running on your VPS represents a potential entry point. The principle of least privilege applies not just to user accounts but also to running processes: if a service is not strictly required for your application to function, it should be stopped and disabled from starting at boot. This section covers how to audit running services, strip away the ones you do not need, and then lock down the web server that most VPS deployments ultimately serve — whether that is Nginx, Apache, or a combination of both acting as a reverse proxy and application server.
Start by listing all listening ports with ss -tulnp and all enabled systemd units with systemctl list-unit-files --state=enabled. You will likely find services such as Avahi (mDNS), CUPS (printing), and Bluetooth daemons running on a server that will never need them. Disable each unnecessary service using systemctl disable --now servicename. Pay particular attention to network filesystem daemons like NFS and Samba, remote desktop protocols like VNC, and any database listeners bound to 0.0.0.0 instead of 127.0.0.1. After pruning, run a full port scan against your server from an external host — using a tool like nmap — to verify that only the intended ports remain accessible. This external perspective often reveals services you overlooked during the internal audit, such as control panel agents or cloud-init management daemons that listen on unexpected interfaces.
Web servers leak information by default. Nginx and Apache both include verbose server tokens in HTTP response headers that advertise the exact software version, operating system, and sometimes loaded modules — a gift to attackers scanning for version-specific exploits. Disable these tokens by setting server_tokens off; in Nginx or ServerTokens Prod and ServerSignature Off in Apache. Next, implement security-relevant HTTP response headers across all virtual hosts: X-Content-Type-Options: nosniff, X-Frame-Options: DENY (or SAMEORIGIN if your application legitimately uses frames), X-XSS-Protection: 1; mode=block, and Referrer-Policy: strict-origin-when-cross-origin. For TLS configuration, use the Mozilla SSL Configuration Generator to produce a modern intermediate compatibility profile, which will disable deprecated protocols like TLS 1.0 and 1.1, remove weak cipher suites, and enable features like OCSP stapling. Always test your final configuration with the Qualys SSL Labs server test to confirm you achieve at least an A grade before declaring the web server hardened.
If you operate an e-commerce store on your VPS, the stakes for web server security are even higher because you process payment information and manage customer accounts. Our guide on choosing a VPS for e-commerce explains the additional compliance requirements and performance considerations that online stores face, including PCI DSS obligations that directly influence your TLS and logging configurations.
A hardened perimeter means little if an attacker who gains access to the application layer can walk directly into an unsecured database or read sensitive configuration files. Database hardening and filesystem permission management form the inner layers of a defense-in-depth strategy. Even if a web application vulnerability allows arbitrary file reads, properly restricted permissions should prevent the attacker from accessing SSH private keys, database credentials stored in environment files, or the database data directory itself. This section addresses MySQL and MariaDB as the most commonly deployed relational databases on VPS instances, though the principles translate directly to PostgreSQL as well.
Immediately after installing MySQL or MariaDB, run the mysql_secure_installation script if your distribution provides it. This interactive wizard walks you through setting a root password, removing anonymous users, disabling remote root login, dropping the test database, and reloading privilege tables. For manual hardening, verify that the root account uses auth_socket or a strong password and that no user accounts exist without passwords by querying SELECT User, Host, plugin FROM mysql.user;. Restrict the database server to listen only on localhost by setting bind-address = 127.0.0.1 in my.cnf — unless your application architecture genuinely requires remote database connections, in which case tunnel all traffic through SSH or a WireGuard VPN rather than exposing the MySQL port to the public internet. Apply the principle of least privilege to application database users: grant only the specific permissions each application needs (SELECT, INSERT, UPDATE, DELETE) on its own database, never ALL PRIVILEGES, and certainly never GRANT OPTION.
Incorrect file permissions are among the most common findings in VPS security audits. Configuration files containing secrets — API keys, database passwords, SMTP credentials — must be readable only by the user and group that need them. Use chmod 600 for files that should be readable only by their owner, chmod 640 for files shared with a specific group, and chmod 750 for directories. The web server's document root should be owned by a user other than the web server process itself, with group read access granted only where necessary. Set the default umask to 027 in /etc/profile and /etc/login.defs so that new files are created without world-readable permissions by default. Pay special attention to SSH authorized_keys files, SSL certificate private keys, and any .env files used by application frameworks — a world-readable .env file in a web-accessible directory is essentially a welcome mat for data thieves. For a broader perspective on when the complexity of VPS management outweighs its benefits compared to alternatives, see our discussion of upgrading to VPS for blogs where we weigh performance gains against administrative overhead across different hosting tiers.
Hardening reduces the probability of a breach, but it cannot reduce it to zero. A mature security posture accepts that compromise is possible and prepares for it with automated backups, runtime protection via a web application firewall, and intrusion detection systems that alert you when something anomalous occurs. These three layers operate on different timelines — backups let you recover from disaster within hours, a WAF blocks attacks in real time, and IDS tools help you understand whether a breach has already happened so you can contain the damage before it spreads. For business-critical VPS deployments, skipping any one of these layers creates an unacceptable single point of failure.
A backup stored on the same physical disk as the live data is not a backup — it is a copy that disappears alongside the original when the drive fails or the server is compromised. Automate daily database dumps and file-level backups using tools like rsync, rclone, or borgbackup, and push the resulting archives to an off-server destination. Cloud object storage services like AWS S3, Backblaze B2, and Wasabi offer cheap, durable storage with lifecycle policies that can automatically delete archives older than your desired retention window. For databases, use mysqldump or mariabackup with the --single-transaction flag to produce consistent snapshots without locking tables. Encrypt all backup archives before they leave the server — gpg with a strong passphrase or a tool like restic that handles encryption natively — because a cloud bucket configured with overly permissive access controls is a data breach waiting to happen. Test your restoration procedure at least once per quarter. A backup you have never restored is a theory, not a recovery plan.
ModSecurity operates as a module within Apache or Nginx (via the libmodsecurity connector) and inspects HTTP traffic against the OWASP Core Rule Set, which contains signatures for SQL injection, cross-site scripting, local file inclusion, remote code execution, and dozens of other attack categories. Installing ModSecurity with the CRS in anomaly-scoring mode — where multiple low-severity rule matches can combine to trigger a block — produces far fewer false positives than the older default-deny approach that plagued earlier ModSecurity deployments. After installation, run in detection-only mode with SecRuleEngine DetectionOnly for at least one week while you monitor the audit log at /var/log/modsec_audit.log. Whitelist any legitimate application behavior that triggers false positives by writing rule exclusions, then switch to SecRuleEngine On. Keep the CRS updated regularly through the package manager or by pulling the latest release from the OWASP GitHub repository, because attack techniques evolve and the rule set receives frequent updates to counter new exploitation patterns.
File integrity monitoring provides a tripwire that alerts you when critical system binaries, configuration files, or web application source code are modified without authorization. AIDE (Advanced Intrusion Detection Environment) builds a cryptographic checksum database of specified files and directories, which you can then compare against the current state of the filesystem to detect changes. Schedule a daily AIDE check via cron and configure it to email you the report, focusing on directories such as /bin, /sbin, /usr/bin, /etc, and your web application paths. OSSEC offers a more comprehensive host-based intrusion detection system that combines file integrity monitoring with log analysis, rootkit detection, and active response capabilities that can dynamically block IP addresses. Its client-server architecture also makes it suitable for monitoring multiple VPS instances from a central management console. Both tools generate some noise upon initial deployment as they learn your system's baseline state, so allocate time to review and tune the rules during the first two weeks of operation before relying on them for production alerting.
The Linux kernel exposes hundreds of tunable parameters through the sysctl interface, many of which directly affect network stack behavior and system security boundaries. Applying a well-tested set of kernel hardening parameters is a low-effort, high-impact step that protects against entire classes of network-based attacks without requiring additional daemons or ongoing maintenance. These parameters live in /etc/sysctl.conf or files under /etc/sysctl.d/ and take effect immediately when applied with sysctl -p, persisting across reboots automatically. The following collection represents a conservative baseline suitable for most VPS deployments — they strengthen the kernel's resistance to common attack vectors without breaking normal application behavior.
Begin by enabling TCP SYN cookie protection to defend against SYN flood attacks: net.ipv4.tcp_syncookies = 1. Disable IP source routing, which can allow attackers to specify the route packets take and bypass firewall rules: net.ipv4.conf.all.accept_source_route = 0 and net.ipv6.conf.all.accept_source_route = 0. Prevent the kernel from accepting ICMP redirects — messages that can alter your routing table maliciously — with net.ipv4.conf.all.accept_redirects = 0 and net.ipv6.conf.all.accept_redirects = 0. Enable reverse path filtering to drop packets that arrive on an interface different from the one the kernel would use to reply, a common characteristic of IP spoofing attempts: net.ipv4.conf.all.rp_filter = 1. Disable the magic SysRq key combination unless you have a specific debugging need, because on a remote server it offers no benefit and a theoretical risk: kernel.sysrq = 0.
Restrict the kernel's tendency to log potentially sensitive memory addresses to the system log by setting kernel.kptr_restrict = 2 and prevent unprivileged users from viewing kernel logs with kernel.dmesg_restrict = 1. These two parameters close information disclosure channels that attackers can use during reconnaissance after gaining a foothold as a low-privilege user. Enable Address Space Layout Randomization at its strongest setting with kernel.randomize_va_space = 2, which makes it significantly harder for exploit code to predict memory addresses. Finally, restrict the ptrace system call — which allows one process to inspect and modify another — to processes owned by the same user or with the CAP_SYS_PTRACE capability: kernel.yama.ptrace_scope = 1. This prevents a compromised application from using ptrace to steal credentials from other processes running under different user accounts. After applying all changes, run sysctl -p and verify each parameter with sysctl parametername to confirm the values took effect correctly.
This guide covers the practical decision points — pricing, performance, and when it makes sense for your situation — based on current 2026 data.
Pricing varies by provider and plan tier; see the cost breakdown section above for current ranges and what's actually included at each price point.
Look closely at uptime guarantees, renewal pricing (not just the first-year discount), and how responsive support actually is — all covered in detail in this article.
Emma Larsson is a lead systems developer and virtualization specialist with a decade of expertise in kernel configurations and hypervisor scaling.







