{"id":3571,"date":"2025-12-28T15:14:57","date_gmt":"2025-12-28T12:14:57","guid":{"rendered":"https:\/\/www.dchost.com\/blog\/vps-security-hardening-checklist-sshd_config-fail2ban-auto-updates-and-no-root-ssh\/"},"modified":"2025-12-28T15:14:57","modified_gmt":"2025-12-28T12:14:57","slug":"vps-security-hardening-checklist-sshd_config-fail2ban-auto-updates-and-no-root-ssh","status":"publish","type":"post","link":"https:\/\/www.dchost.com\/blog\/en\/vps-security-hardening-checklist-sshd_config-fail2ban-auto-updates-and-no-root-ssh\/","title":{"rendered":"VPS Security Hardening Checklist: sshd_config, Fail2ban, Auto Updates and No-Root SSH"},"content":{"rendered":"<div class=\"dchost-blog-content-wrapper\"><p>If you are running a <a href=\"https:\/\/www.dchost.com\/vps\">VPS<\/a>, SSH is usually the main door into your server. That also makes it the primary target for bots and attackers scanning the internet 24\/7. A default install might work for quick tests, but for anything that handles real users, payments or internal data, you need a deliberate hardening checklist. In this guide, we will walk through the concrete steps we use at dchost.com when preparing Linux VPS servers: tightening <strong>sshd_config<\/strong>, configuring <strong>Fail2ban<\/strong>, enabling <strong>automatic security updates<\/strong>, and <strong>disabling direct root login<\/strong> \u2013 without locking yourself out.<\/p>\n<p>The goal is not to turn you into a full-time security engineer. Instead, we will give you a practical, repeatable process you can apply on every new VPS or <a href=\"https:\/\/www.dchost.com\/dedicated-server\">dedicated server<\/a>. We will explain the &#8220;why&#8221; of each setting in simple terms, and then show you the exact configuration snippets. Apply these steps once, document them, and then reuse the same checklist across all your environments \u2013 whether you are hosting on a single VPS, multiple VPSs, or even colocated servers in a data center.<\/p>\n<div id=\"toc_container\" class=\"toc_transparent no_bullets\"><p class=\"toc_title\">\u0130&ccedil;indekiler<\/p><ul class=\"toc_list\"><li><a href=\"#A_Practical_VPS_Security_Hardening_Checklist\"><span class=\"toc_number toc_depth_1\">1<\/span> A Practical VPS Security Hardening Checklist<\/a><\/li><li><a href=\"#1_Create_a_Non-Root_Sudo_User\"><span class=\"toc_number toc_depth_1\">2<\/span> 1. Create a Non-Root Sudo User<\/a><ul><li><a href=\"#Step_1_Create_the_user\"><span class=\"toc_number toc_depth_2\">2.1<\/span> Step 1: Create the user<\/a><\/li><li><a href=\"#Step_2_Add_the_user_to_the_sudo_group\"><span class=\"toc_number toc_depth_2\">2.2<\/span> Step 2: Add the user to the sudo group<\/a><\/li><li><a href=\"#Step_3_Set_up_SSH_keys_for_the_new_user\"><span class=\"toc_number toc_depth_2\">2.3<\/span> Step 3: Set up SSH keys for the new user<\/a><\/li><\/ul><\/li><li><a href=\"#2_Harden_SSH_with_sshd_config\"><span class=\"toc_number toc_depth_1\">3<\/span> 2. Harden SSH with sshd_config<\/a><ul><li><a href=\"#Step_1_Back_up_your_current_sshd_config\"><span class=\"toc_number toc_depth_2\">3.1<\/span> Step 1: Back up your current sshd_config<\/a><\/li><li><a href=\"#Step_2_Optional_Change_the_SSH_port\"><span class=\"toc_number toc_depth_2\">3.2<\/span> Step 2: Optional \u2013 Change the SSH port<\/a><\/li><li><a href=\"#Step_3_Disable_SSH_protocol_1_if_still_present\"><span class=\"toc_number toc_depth_2\">3.3<\/span> Step 3: Disable SSH protocol 1 (if still present)<\/a><\/li><li><a href=\"#Step_4_Restrict_which_users_can_log_in_via_SSH\"><span class=\"toc_number toc_depth_2\">3.4<\/span> Step 4: Restrict which users can log in via SSH<\/a><\/li><li><a href=\"#Step_5_Force_key-based_authentication_and_disable_passwords\"><span class=\"toc_number toc_depth_2\">3.5<\/span> Step 5: Force key-based authentication and disable passwords<\/a><\/li><li><a href=\"#Step_6_Disable_root_login_preparation\"><span class=\"toc_number toc_depth_2\">3.6<\/span> Step 6: Disable root login (preparation)<\/a><\/li><li><a href=\"#Step_7_Other_useful_hardening_options\"><span class=\"toc_number toc_depth_2\">3.7<\/span> Step 7: Other useful hardening options<\/a><\/li><li><a href=\"#Step_8_Validate_and_reload_SSH\"><span class=\"toc_number toc_depth_2\">3.8<\/span> Step 8: Validate and reload SSH<\/a><\/li><\/ul><\/li><li><a href=\"#3_Stop_BruteForce_Attacks_with_Fail2ban\"><span class=\"toc_number toc_depth_1\">4<\/span> 3. Stop Brute\u2011Force Attacks with Fail2ban<\/a><ul><li><a href=\"#Step_1_Install_Fail2ban\"><span class=\"toc_number toc_depth_2\">4.1<\/span> Step 1: Install Fail2ban<\/a><\/li><li><a href=\"#Step_2_Create_a_local_configuration\"><span class=\"toc_number toc_depth_2\">4.2<\/span> Step 2: Create a local configuration<\/a><\/li><li><a href=\"#Step_3_Whitelist_your_office_or_VPN_IPs\"><span class=\"toc_number toc_depth_2\">4.3<\/span> Step 3: Whitelist your office or VPN IPs<\/a><\/li><li><a href=\"#Step_4_Restart_Fail2ban_and_verify_jails\"><span class=\"toc_number toc_depth_2\">4.4<\/span> Step 4: Restart Fail2ban and verify jails<\/a><\/li><li><a href=\"#Step_5_Tune_ban_policies_over_time\"><span class=\"toc_number toc_depth_2\">4.5<\/span> Step 5: Tune ban policies over time<\/a><\/li><\/ul><\/li><li><a href=\"#4_Enable_Automatic_Security_Updates\"><span class=\"toc_number toc_depth_1\">5<\/span> 4. Enable Automatic Security Updates<\/a><ul><li><a href=\"#Automatic_security_updates_on_UbuntuDebian\"><span class=\"toc_number toc_depth_2\">5.1<\/span> Automatic security updates on Ubuntu\/Debian<\/a><\/li><li><a href=\"#Automatic_security_updates_on_AlmaLinux_Rocky_RHEL\"><span class=\"toc_number toc_depth_2\">5.2<\/span> Automatic security updates on AlmaLinux \/ Rocky \/ RHEL<\/a><\/li><li><a href=\"#Balancing_automation_and_stability\"><span class=\"toc_number toc_depth_2\">5.3<\/span> Balancing automation and stability<\/a><\/li><\/ul><\/li><li><a href=\"#5_Safely_Disable_Direct_Root_Login\"><span class=\"toc_number toc_depth_1\">6<\/span> 5. Safely Disable Direct Root Login<\/a><ul><li><a href=\"#Why_disabling_root_login_matters\"><span class=\"toc_number toc_depth_2\">6.1<\/span> Why disabling root login matters<\/a><\/li><li><a href=\"#Step_1_Confirm_your_sudo_user_works_perfectly\"><span class=\"toc_number toc_depth_2\">6.2<\/span> Step 1: Confirm your sudo user works perfectly<\/a><\/li><li><a href=\"#Step_2_Edit_sshd_config_to_disable_root_login\"><span class=\"toc_number toc_depth_2\">6.3<\/span> Step 2: Edit sshd_config to disable root login<\/a><\/li><li><a href=\"#Step_3_Test_configuration_and_reload\"><span class=\"toc_number toc_depth_2\">6.4<\/span> Step 3: Test configuration and reload<\/a><\/li><li><a href=\"#Step_4_Adjust_your_operational_habits\"><span class=\"toc_number toc_depth_2\">6.5<\/span> Step 4: Adjust your operational habits<\/a><\/li><\/ul><\/li><li><a href=\"#6_Extra_Layers_Firewall_Monitoring_and_Infrastructure_Choices\"><span class=\"toc_number toc_depth_1\">7<\/span> 6. Extra Layers: Firewall, Monitoring and Infrastructure Choices<\/a><ul><li><a href=\"#Add_a_host-based_firewall\"><span class=\"toc_number toc_depth_2\">7.1<\/span> Add a host-based firewall<\/a><\/li><li><a href=\"#Set_up_basic_monitoring_and_alerts\"><span class=\"toc_number toc_depth_2\">7.2<\/span> Set up basic monitoring and alerts<\/a><\/li><li><a href=\"#Choose_infrastructure_that_supports_security\"><span class=\"toc_number toc_depth_2\">7.3<\/span> Choose infrastructure that supports security<\/a><\/li><\/ul><\/li><li><a href=\"#Putting_It_All_Together_Your_Reusable_VPS_Hardening_Checklist\"><span class=\"toc_number toc_depth_1\">8<\/span> Putting It All Together: Your Reusable VPS Hardening Checklist<\/a><\/li><\/ul><\/div>\n<h2><span id=\"A_Practical_VPS_Security_Hardening_Checklist\">A Practical VPS Security Hardening Checklist<\/span><\/h2>\n<p>Before we dive into file edits and commands, it helps to see the big picture. For most Linux VPS setups, a minimal but strong SSH-focused hardening checklist looks like this:<\/p>\n<ul>\n<li>Create a non-root user with sudo access.<\/li>\n<li>Harden the SSH service via <strong>\/etc\/ssh\/sshd_config<\/strong>.<\/li>\n<li>Install and configure <strong>Fail2ban<\/strong> to block brute-force attempts.<\/li>\n<li>Enable <strong>automatic security updates<\/strong> for the OS.<\/li>\n<li>Disable direct <strong>root<\/strong> SSH logins once everything is tested.<\/li>\n<li>Add a firewall and monitoring on top (we will point to deeper guides for these).<\/li>\n<\/ul>\n<p>We will assume a typical Linux VPS (Ubuntu\/Debian or AlmaLinux\/Rocky\/RHEL family). If your distribution uses slightly different package names, the concepts stay the same.<\/p>\n<h2><span id=\"1_Create_a_Non-Root_Sudo_User\">1. Create a Non-Root Sudo User<\/span><\/h2>\n<p>Hardening SSH properly is much easier when you stop logging in as <strong>root<\/strong> directly. Root has unlimited powers; a single mistake or stolen credential can be catastrophic. A safer pattern is:<\/p>\n<ul>\n<li>Log in as a regular user.<\/li>\n<li>Use <strong>sudo<\/strong> to run administrative commands when needed.<\/li>\n<\/ul>\n<h3><span id=\"Step_1_Create_the_user\">Step 1: Create the user<\/span><\/h3>\n<p>While you still have root access (console or SSH), create a new user. Replace <code>deploy<\/code> with a username that makes sense for you:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># Ubuntu \/ Debian \/ AlmaLinux \/ Rocky \/ RHEL (as root)\nadduser deploy\n# or on some distros\nuseradd -m -s \/bin\/bash deploy\npasswd deploy\n<\/code><\/pre>\n<p>Choose a strong password even if you plan to disable password logins later. It is your short-term safety net while setting up SSH keys.<\/p>\n<h3><span id=\"Step_2_Add_the_user_to_the_sudo_group\">Step 2: Add the user to the sudo group<\/span><\/h3>\n<p>On many distributions, members of the <code>sudo<\/code> or <code>wheel<\/code> group can run administrative commands via <code>sudo<\/code>:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># Ubuntu \/ Debian\nusermod -aG sudo deploy\n\n# AlmaLinux \/ Rocky \/ RHEL\nusermod -aG wheel deploy\n<\/code><\/pre>\n<p>Test that sudo works:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">su - deploy\nsudo id\n<\/code><\/pre>\n<p>You should be prompted for the deploy user&#8217;s password, and then see an output containing <code>uid=0(root)<\/code> when <code>sudo id<\/code> runs successfully.<\/p>\n<h3><span id=\"Step_3_Set_up_SSH_keys_for_the_new_user\">Step 3: Set up SSH keys for the new user<\/span><\/h3>\n<p>Password-based logins are one of the easiest ways for bots to brute-force access. SSH keys are far more resilient. From your local machine:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># Generate a key pair if you don't have one yet\nssh-keygen -t ed25519 -C &quot;yourname@laptop&quot;\n\n# Copy the public key to the server for the deploy user\nssh-copy-id deploy@your-server-ip\n<\/code><\/pre>\n<p>If <code>ssh-copy-id<\/code> is not available, you can manually paste your public key into <code>\/home\/deploy\/.ssh\/authorized_keys<\/code> and set permissions:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">mkdir -p \/home\/deploy\/.ssh\nchmod 700 \/home\/deploy\/.ssh\nnano \/home\/deploy\/.ssh\/authorized_keys  # paste your public key\nchmod 600 \/home\/deploy\/.ssh\/authorized_keys\nchown -R deploy:deploy \/home\/deploy\/.ssh\n<\/code><\/pre>\n<p>If you plan to share access with teammates, we strongly recommend setting up a structured key workflow instead of sharing one key. You can find a detailed, step\u2011by\u2011step process in our guide on <a href=\"https:\/\/www.dchost.com\/blog\/en\/ssh-anahtar-yonetimi-ve-yetki-paylasimi-kucuk-ekipler-icin-guvenli-vps-erisimi\/\">SSH key management and access sharing on a VPS<\/a>.<\/p>\n<h2><span id=\"2_Harden_SSH_with_sshd_config\">2. Harden SSH with sshd_config<\/span><\/h2>\n<p>With a non-root user ready and SSH keys in place, the next step is to lock down the SSH daemon itself. This is done via <strong>\/etc\/ssh\/sshd_config<\/strong>. Before you change anything, always keep one active SSH session open so you can fix mistakes if you misconfigure something.<\/p>\n<h3><span id=\"Step_1_Back_up_your_current_sshd_config\">Step 1: Back up your current sshd_config<\/span><\/h3>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">cp \/etc\/ssh\/sshd_config \/etc\/ssh\/sshd_config.backup\n<\/code><\/pre>\n<p>If something goes wrong, you can revert quickly.<\/p>\n<h3><span id=\"Step_2_Optional_Change_the_SSH_port\">Step 2: Optional \u2013 Change the SSH port<\/span><\/h3>\n<p>Security professionals sometimes argue about this, but changing the SSH port <strong>does reduce noise<\/strong> from automated bots. It is not a primary defense, but it makes your logs much cleaner. For example, change the port to <code>2222<\/code>:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">Port 2222\n<\/code><\/pre>\n<p>Remember to:<\/p>\n<ul>\n<li>Open the new port in your firewall (we will link to a firewall guide later).<\/li>\n<li>Update your SSH command, e.g. <code>ssh -p 2222 deploy@your-server-ip<\/code>.<\/li>\n<\/ul>\n<h3><span id=\"Step_3_Disable_SSH_protocol_1_if_still_present\">Step 3: Disable SSH protocol 1 (if still present)<\/span><\/h3>\n<p>Modern systems default to protocol 2, but it is good to be explicit:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">Protocol 2\n<\/code><\/pre>\n<h3><span id=\"Step_4_Restrict_which_users_can_log_in_via_SSH\">Step 4: Restrict which users can log in via SSH<\/span><\/h3>\n<p>Limit SSH access to your trusted users only. Add this near the end of <code>sshd_config<\/code>:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">AllowUsers deploy\n<\/code><\/pre>\n<p>If you have multiple users, separate them with spaces:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">AllowUsers deploy opsuser backup\n<\/code><\/pre>\n<h3><span id=\"Step_5_Force_key-based_authentication_and_disable_passwords\">Step 5: Force key-based authentication and disable passwords<\/span><\/h3>\n<p>Once you are certain your SSH key login works, disable password authentication to stop brute-force attempts from being effective:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">PasswordAuthentication no\nChallengeResponseAuthentication no\nUsePAM yes\n<\/code><\/pre>\n<p><strong>Important:<\/strong> Only do this after you have successfully logged in as your non-root user with an SSH key in a separate terminal.<\/p>\n<h3><span id=\"Step_6_Disable_root_login_preparation\">Step 6: Disable root login (preparation)<\/span><\/h3>\n<p>We will fully disable root login in a later section, but it is helpful to set the correct line now:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">PermitRootLogin no\n<\/code><\/pre>\n<p>Again, do not restart SSH until you have tested your non-root user thoroughly.<\/p>\n<h3><span id=\"Step_7_Other_useful_hardening_options\">Step 7: Other useful hardening options<\/span><\/h3>\n<p>Here are some commonly used sshd_config settings that improve security and reduce attack surface:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># Limit authentication attempts\nMaxAuthTries 3\n\n# Disconnect idle sessions (in seconds)\nClientAliveInterval 300\nClientAliveCountMax 2\n\n# Optional: Only allow specific key types\nPubkeyAcceptedKeyTypes ssh-ed25519,ssh-rsa\n<\/code><\/pre>\n<h3><span id=\"Step_8_Validate_and_reload_SSH\">Step 8: Validate and reload SSH<\/span><\/h3>\n<p>Before reloading, run a configuration test:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sshd -t\n<\/code><\/pre>\n<p>If there is no output, your config is syntactically valid. Then reload the SSH daemon:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">systemctl reload sshd   # Ubuntu \/ Debian \/ many distros\n# or\nsystemctl reload ssh    # Some distros use this name\n<\/code><\/pre>\n<p>Open a new terminal window and verify you can log in as <code>deploy<\/code> with your SSH key. Only after that should you close old sessions.<\/p>\n<p>If you want a broader, layered view of SSH and OS hardening, we also recommend our article <a href=\"https:\/\/www.dchost.com\/blog\/en\/vps-sunucu-guvenligi-nasil-saglanir-kapiyi-acik-birakmadan-yasamanin-sirri\/\">The Calm, No\u2011Drama Guide: How to Secure a VPS Server<\/a>, where we connect SSH security to firewalls, backups and monitoring.<\/p>\n<h2><span id=\"3_Stop_BruteForce_Attacks_with_Fail2ban\">3. Stop Brute\u2011Force Attacks with Fail2ban<\/span><\/h2>\n<p>Even with good sshd_config settings, bots will still try to connect and guess credentials. <strong>Fail2ban<\/strong> reads your logs and automatically bans IP addresses that show suspicious patterns, such as many failed SSH logins in a short period.<\/p>\n<h3><span id=\"Step_1_Install_Fail2ban\">Step 1: Install Fail2ban<\/span><\/h3>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># Ubuntu \/ Debian\napt update\napt install fail2ban\n\n# AlmaLinux \/ Rocky \/ RHEL\nyum install epel-release -y\nyum install fail2ban -y\n<\/code><\/pre>\n<p>Enable and start the service:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">systemctl enable fail2ban\nsystemctl start fail2ban\n<\/code><\/pre>\n<h3><span id=\"Step_2_Create_a_local_configuration\">Step 2: Create a local configuration<\/span><\/h3>\n<p>Never edit <code>\/etc\/fail2ban\/jail.conf<\/code> directly. Instead, create <code>\/etc\/fail2ban\/jail.local<\/code> (which overrides defaults):<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">nano \/etc\/fail2ban\/jail.local\n<\/code><\/pre>\n<p>A good starting configuration for SSH might look like this:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">[DEFAULT]\n# Where to ban (iptables, nftables, firewalld, etc.)\nbanaction = iptables-multiport\nbantime = 1h        # 1 hour\nfindtime = 10m      # Look at 10-minute windows\nmaxretry = 3        # 3 failed attempts before ban\n\n[sshd]\nenabled  = true\nport     = ssh\nlogpath  = \/var\/log\/auth.log\nbackend  = systemd\n<\/code><\/pre>\n<p>On RHEL-based systems, you might use a different log path such as <code>\/var\/log\/secure<\/code>:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">logpath  = \/var\/log\/secure\n<\/code><\/pre>\n<h3><span id=\"Step_3_Whitelist_your_office_or_VPN_IPs\">Step 3: Whitelist your office or VPN IPs<\/span><\/h3>\n<p>To avoid accidentally blocking yourself or your team, add trusted IPs to the <code>ignoreip<\/code> directive:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">[DEFAULT]\nignoreip = 127.0.0.1\/8 192.0.2.10 203.0.113.0\/24\n<\/code><\/pre>\n<p>Replace the example IPs with your real office VPN ranges or home IP addresses.<\/p>\n<h3><span id=\"Step_4_Restart_Fail2ban_and_verify_jails\">Step 4: Restart Fail2ban and verify jails<\/span><\/h3>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">systemctl restart fail2ban\nfail2ban-client status\nfail2ban-client status sshd\n<\/code><\/pre>\n<p>The output should show the <code>sshd<\/code> jail as enabled and list any banned IPs once attacks start hitting your server.<\/p>\n<h3><span id=\"Step_5_Tune_ban_policies_over_time\">Step 5: Tune ban policies over time<\/span><\/h3>\n<p>Fail2ban is not a &#8220;set it and forget it&#8221; tool. In the first days, watch your logs and jails:<\/p>\n<ul>\n<li>If legitimate users get banned often, loosen <code>maxretry<\/code> or shorten <code>bantime<\/code>.<\/li>\n<li>If you see thousands of attempts from the same country or range, consider longer bans (e.g., 24h or even permanent) and additional firewall rules.<\/li>\n<\/ul>\n<p>Fail2ban can protect more than just SSH, such as web panel logins or web applications. For example, in another article we show how to combine Nginx rate limiting and Fail2ban to protect WordPress logins from bots. If that is relevant to you, check out our guide on <a href=\"https:\/\/www.dchost.com\/blog\/en\/nginx-rate-limiting-ve-fail2ban-ile-wp%e2%80%91login-php-ve-xml%e2%80%91rpc-brute%e2%80%91force-saldirilarini-nasil-saksiya-alirsin\/\">stopping wp-login.php and XML\u2011RPC brute\u2011force attacks with Fail2ban<\/a>.<\/p>\n<h2><span id=\"4_Enable_Automatic_Security_Updates\">4. Enable Automatic Security Updates<\/span><\/h2>\n<p>SSH and Fail2ban reduce the chance of someone getting in, but you also need to keep the underlying operating system patched. Many critical vulnerabilities (kernel, OpenSSH, glibc, etc.) are fixed via security updates. If you forget to apply them, your server may remain vulnerable for months.<\/p>\n<p>There are two main patterns:<\/p>\n<ul>\n<li><strong>Automatic security updates<\/strong> for OS packages.<\/li>\n<li><strong>Manual or controlled updates<\/strong> for application-level changes (e.g., major PHP or database upgrades).<\/li>\n<\/ul>\n<h3><span id=\"Automatic_security_updates_on_UbuntuDebian\">Automatic security updates on Ubuntu\/Debian<\/span><\/h3>\n<p>Install the <code>unattended-upgrades<\/code> package:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">apt update\napt install unattended-upgrades apt-listchanges\n<\/code><\/pre>\n<p>Enable it:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">dpkg-reconfigure --priority=low unattended-upgrades\n<\/code><\/pre>\n<p>This wizard creates or updates <code>\/etc\/apt\/apt.conf.d\/50unattended-upgrades<\/code>. Inside, ensure that security repositories are enabled, for example:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">Unattended-Upgrade::Origins-Pattern {\n  &quot;origin=Ubuntu,codename=${distro_codename},label=Ubuntu-Security&quot;;\n};\n<\/code><\/pre>\n<p>You can also configure:<\/p>\n<ul>\n<li>Email notifications when updates are applied.<\/li>\n<li>Automatic removal of unused dependencies.<\/li>\n<li>Automatic reboots if a kernel update requires it (use with care on production systems).<\/li>\n<\/ul>\n<h3><span id=\"Automatic_security_updates_on_AlmaLinux_Rocky_RHEL\">Automatic security updates on AlmaLinux \/ Rocky \/ RHEL<\/span><\/h3>\n<p>On these distributions, use <code>dnf-automatic<\/code> (or <code>yum-cron<\/code> on older releases).<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">yum install dnf-automatic -y\n<\/code><\/pre>\n<p>Edit the configuration file:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">nano \/etc\/dnf\/automatic.conf\n<\/code><\/pre>\n<p>Key options to review:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">apply_updates = yes\nupgrade_type = security\nemit_via = email\n<\/code><\/pre>\n<p>Enable the timer to run periodically:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">systemctl enable --now dnf-automatic.timer\n<\/code><\/pre>\n<p>You can check its status with:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">systemctl list-timers *dnf-automatic*\n<\/code><\/pre>\n<h3><span id=\"Balancing_automation_and_stability\">Balancing automation and stability<\/span><\/h3>\n<p>On critical production systems, you may not want every single update applied automatically without any testing. Here is a balanced approach we often recommend:<\/p>\n<ul>\n<li>Enable fully automatic <strong>security<\/strong> updates for the OS.<\/li>\n<li>For application stack (e.g., web server, database), apply updates on a staging server first.<\/li>\n<li>Use monitoring to detect issues after updates (e.g., HTTP checks, log alerts).<\/li>\n<li>Always pair updates with a solid backup strategy so you can roll back if needed.<\/li>\n<\/ul>\n<p>If you are still building your backup strategy, our guide on how to <a href=\"https:\/\/www.dchost.com\/blog\/en\/3-2-1-yedekleme-stratejisi-neden-ise-yariyor-cpanel-plesk-ve-vpste-otomatik-yedekleri-nasil-kurarsin\/\">apply the 3\u20112\u20111 backup strategy on your VPS<\/a> shows how to automate reliable, off\u2011site backups.<\/p>\n<h2><span id=\"5_Safely_Disable_Direct_Root_Login\">5. Safely Disable Direct Root Login<\/span><\/h2>\n<p>With a non-root sudo user, hardened sshd_config, Fail2ban and security updates in place, you can now remove one of the biggest risks: direct root SSH logins.<\/p>\n<h3><span id=\"Why_disabling_root_login_matters\">Why disabling root login matters<\/span><\/h3>\n<p>Root is a known username. Attackers know it exists and will try to guess its password. Even if you are using keys, disabling direct root login gives you:<\/p>\n<ul>\n<li>An extra step for attackers (they must compromise a non-root account first).<\/li>\n<li>Better auditability (sudo logs show which user ran which command).<\/li>\n<li>A strong protection against accidental destructive commands while logged in as root.<\/li>\n<\/ul>\n<h3><span id=\"Step_1_Confirm_your_sudo_user_works_perfectly\">Step 1: Confirm your sudo user works perfectly<\/span><\/h3>\n<p>Before touching root login, double-check from your local machine:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">ssh deploy@your-server-ip\nsudo -l\nsudo systemctl status sshd\n<\/code><\/pre>\n<p>You should be able to use <code>sudo<\/code> without problems. If this fails, fix it now \u2013 do not proceed.<\/p>\n<h3><span id=\"Step_2_Edit_sshd_config_to_disable_root_login\">Step 2: Edit sshd_config to disable root login<\/span><\/h3>\n<p>Open the SSH configuration:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo nano \/etc\/ssh\/sshd_config\n<\/code><\/pre>\n<p>Find the <code>PermitRootLogin<\/code> line and set it to:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">PermitRootLogin no\n<\/code><\/pre>\n<p>Make sure you do <strong>not<\/strong> have conflicting lines (e.g., one commented and one active). There should be exactly one active <code>PermitRootLogin no<\/code> entry.<\/p>\n<h3><span id=\"Step_3_Test_configuration_and_reload\">Step 3: Test configuration and reload<\/span><\/h3>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo sshd -t\nsudo systemctl reload sshd\n<\/code><\/pre>\n<p>Now, try logging in as root from a new terminal:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">ssh root@your-server-ip\n<\/code><\/pre>\n<p>You should see a &#8220;Permission denied&#8221; type error. Logging in as <code>deploy<\/code> with your key should still work. From now on, you will escalate privileges via <code>sudo<\/code> only.<\/p>\n<h3><span id=\"Step_4_Adjust_your_operational_habits\">Step 4: Adjust your operational habits<\/span><\/h3>\n<p>After disabling root SSH, make sure your operational workflows follow these principles:<\/p>\n<ul>\n<li>Do not share the same SSH key among multiple humans; give each person their own user or their own key.<\/li>\n<li>Use sudo for all administrative tasks and review <code>\/var\/log\/auth.log<\/code> (or <code>\/var\/log\/secure<\/code>) regularly.<\/li>\n<li>If you use automation (Ansible, scripts, CI\/CD), update them to connect as the non-root user and use sudo where required.<\/li>\n<\/ul>\n<p>If you are designing a more advanced SSH architecture (e.g., SSH CA, FIDO2 keys, bastion host), our deep\u2011dive article on <a href=\"https:\/\/www.dchost.com\/blog\/en\/vpste-ssh-guvenligi-nasil-saglamlasir-fido2-anahtarlari-ssh-ca-ve-rotasyonun-sicacik-yolculugu\/\">VPS SSH hardening with FIDO2 keys and SSH CA<\/a> walks through production\u2011grade patterns we see in real projects.<\/p>\n<h2><span id=\"6_Extra_Layers_Firewall_Monitoring_and_Infrastructure_Choices\">6. Extra Layers: Firewall, Monitoring and Infrastructure Choices<\/span><\/h2>\n<p>The four pillars we covered so far (sshd_config, Fail2ban, automatic updates and no-root SSH) dramatically improve your VPS security posture. To complete the picture, you should also add a firewall and basic monitoring.<\/p>\n<h3><span id=\"Add_a_host-based_firewall\">Add a host-based firewall<\/span><\/h3>\n<p>A firewall enforces which ports on your VPS are reachable from the internet. Even if you have cloud-level security, we strongly recommend a host firewall as a second layer:<\/p>\n<ul>\n<li><strong>UFW<\/strong> for simple, human-friendly rules on Ubuntu\/Debian.<\/li>\n<li><strong>firewalld<\/strong> on many RHEL-based systems.<\/li>\n<li><strong>iptables<\/strong> or <strong>nftables<\/strong> for advanced setups.<\/li>\n<\/ul>\n<p>At minimum:<\/p>\n<ul>\n<li>Allow your SSH port (e.g., 2222).<\/li>\n<li>Allow HTTP\/HTTPS (80\/443) if you are running a web server.<\/li>\n<li>Deny everything else by default.<\/li>\n<\/ul>\n<p>For a full tutorial with examples, see our guide on how to <a href=\"https:\/\/www.dchost.com\/blog\/en\/vps-sunucularda-guvenlik-duvari-yapilandirma-ufw-firewalld-ve-iptables\/\">configure a firewall on your VPS with ufw, firewalld or iptables<\/a>.<\/p>\n<h3><span id=\"Set_up_basic_monitoring_and_alerts\">Set up basic monitoring and alerts<\/span><\/h3>\n<p>Security is not just about preventing incidents; it is also about detecting them quickly. Monitoring helps you notice:<\/p>\n<ul>\n<li>SSH login anomalies (sudden logins from unusual IPs).<\/li>\n<li>Resource spikes that may indicate abuse or malware.<\/li>\n<li>Services going down after an automatic update.<\/li>\n<\/ul>\n<p>We like combining metrics, logs and uptime checks. A good starting point is our article on how to <a href=\"https:\/\/www.dchost.com\/blog\/en\/vps-izleme-ve-alarm-kurulumu-prometheus-grafana-ve-uptime-kuma-ile-baslangic\/\">set up VPS monitoring and alerts with Prometheus, Grafana and Uptime Kuma<\/a>.<\/p>\n<h3><span id=\"Choose_infrastructure_that_supports_security\">Choose infrastructure that supports security<\/span><\/h3>\n<p>All of these best practices work best when your underlying infrastructure is reliable and transparent. At dchost.com, we run VPS, dedicated servers and colocation in professional data centers with attention to:<\/p>\n<ul>\n<li>Consistent, stable kernel and OS images for your VPS installs.<\/li>\n<li>Clear network policies that play nicely with host-based firewalls and Fail2ban.<\/li>\n<li>Options for dedicated servers or colocation when you need stricter isolation or custom security hardware.<\/li>\n<\/ul>\n<p>If you outgrow a single VPS, you can easily scale to multiple VPS nodes, a dedicated server, or even colocate your own hardware in our data centers while keeping the same hardening checklist.<\/p>\n<h2><span id=\"Putting_It_All_Together_Your_Reusable_VPS_Hardening_Checklist\">Putting It All Together: Your Reusable VPS Hardening Checklist<\/span><\/h2>\n<p>Security hardening does not have to be a one\u2011off, stressful project. Once you convert it into a checklist, you can apply it calmly to every new VPS, dedicated server or environment you deploy. Here is a concise version of the process we covered:<\/p>\n<ol>\n<li><strong>Create a non-root sudo user<\/strong> and set up SSH keys for that user.<\/li>\n<li><strong>Harden sshd_config<\/strong>: restrict users, prefer keys, reduce auth attempts, optionally change the port, and prepare <code>PermitRootLogin no<\/code>.<\/li>\n<li><strong>Install and configure Fail2ban<\/strong> to automatically block brute-force attacks on SSH (and later, on other exposed services).<\/li>\n<li><strong>Enable automatic security updates<\/strong> for your Linux distribution so critical patches are applied even if you are busy.<\/li>\n<li><strong>Disable direct root SSH login<\/strong> once you are confident your non-root user and sudo setup work correctly.<\/li>\n<li><strong>Add a firewall and monitoring<\/strong> on top to build a layered defense.<\/li>\n<\/ol>\n<p>Document these steps in your internal runbooks and apply them every time you deploy a new VPS at dchost.com, spin up a fresh node for a cluster, or prepare a dedicated server. Over time, you can extend the checklist with items like HTTP security headers, WAF rules, log retention and database hardening; our blog already covers many of these topics, such as <a href=\"https:\/\/www.dchost.com\/blog\/en\/http-guvenlik-basliklari-rehberi-hsts-csp-x-frame-options-ve-referrer-policy-dogru-nasil-kurulur\/\">HTTP security headers done right<\/a> and <a href=\"https:\/\/www.dchost.com\/blog\/en\/vps-sunucu-guvenligi-pratik-olceklenebilir-ve-dogrulanabilir-yaklasimlar\/\">step\u2011by\u2011step VPS security hardening for real\u2011world threats<\/a>.<\/p>\n<p>If you want help choosing the right VPS or dedicated server size for your workload and then applying this hardening checklist from day one, our team at dchost.com is here to guide you. Start with a clean VPS, follow the steps above, and you will be running on a significantly more secure foundation than most servers on the internet.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>If you are running a VPS, SSH is usually the main door into your server. That also makes it the primary target for bots and attackers scanning the internet 24\/7. A default install might work for quick tests, but for anything that handles real users, payments or internal data, you need a deliberate hardening checklist. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3572,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-3571","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-teknoloji"],"_links":{"self":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/3571","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/comments?post=3571"}],"version-history":[{"count":0,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/3571\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media\/3572"}],"wp:attachment":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media?parent=3571"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/categories?post=3571"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/tags?post=3571"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}