[{"data":1,"prerenderedAt":29},["ShallowReactive",2],{"doc-en-secure-linux-vps-2026":3},{"path":4,"slug":5,"title":6,"description":7,"category":8,"subcategory":9,"icon":10,"date":11,"author":12,"order":13,"image":14,"tags":15,"keywords":20,"docGroup":26,"docGroupIcon":26,"link_fr":27,"bodyHtml":28},"\u002Fdocs\u002Fen\u002Fvps\u002Fvps-linux\u002Fsecure-linux-vps-2026","secure-linux-vps-2026","How to Secure Your Linux VPS (2026 Guide)","Secure your Winheberg Linux VPS, system updates, SSH key authentication, firewall, and CrowdSec, whatever your distribution.","vps","vps-linux","tabler:file-text","2026-07-24","Winheberg",2,"\u002Fstatics\u002Fimages\u002Fdocs\u002Fen\u002Fvps-linux\u002Fsecure-linux-vps-2026.webp",[8,16,17,18,19],"security","ssh","crowdsec","firewall",[21,22,23,24,25],"secure linux vps","ed25519 ssh key","ufw firewalld iptables","crowdsec vps","vps security guide 2026","","\u002Fdocs\u002Fvps-linux\u002Fsecuriser-vps-linux-2026","\u003Ch2>Context\u003C\u002Fh2>\n\u003Cp>You just rented a \u003Cstrong>Linux VPS\u003C\u002Fstrong> at Winheberg and want to secure it properly? Good news, a few simple steps are enough to block the vast majority of automated attacks targeting servers exposed on the Internet.\u003C\u002Fp>\n\u003Cp>This step-by-step guide is designed for beginners. Every command is explained, and you&#39;ll understand why each step matters. It covers every distribution we offer, namely Debian 11\u002F12\u002F13, Ubuntu 23.10\u002F24.04\u002F25.04, AlmaLinux 9\u002F10, Rocky Linux 9\u002F10, Fedora 41\u002F42, and Alpine Linux 3.22.\u003C\u002Fp>\n\u003Ch2>Why secure your Linux VPS?\u003C\u002Fh2>\n\u003Cp>As soon as a VPS goes online, it becomes a target. Thousands of bots constantly scan the Internet looking for misconfigured servers. Within just a few hours, your server can face several types of attacks.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>SSH brute-force attempts\u003C\u002Fstrong>, where bots try thousands of passwords\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Port scans\u003C\u002Fstrong> to detect vulnerable services\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Exploits of vulnerabilities\u003C\u002Fstrong> in outdated software\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>A compromised VPS can be used to send spam, mine cryptocurrency, or take part in DDoS attacks, often without you even noticing.\u003C\u002Fp>\n\u003Cdiv class=\"markdown-alert markdown-alert-important\">\u003Cspan class=\"alert-icon\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\u003Cpath d=\"M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z\"\u002F>\u003Cpath d=\"M12 8v4\"\u002F>\u003Cpath d=\"M12 16h.01\"\u002F>\u003C\u002Fsvg>\u003C\u002Fspan>\u003Cdiv class=\"markdown-alert-body\">\u003Cp>Follow this guide as soon as you first connect to your VPS, before even installing your services on it.\u003C\u002Fp>\n\u003C\u002Fdiv>\u003C\u002Fdiv>\n\u003Ch2>Prerequisites\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>An active \u003Cstrong>Linux VPS\u003C\u002Fstrong> at Winheberg\u003C\u002Fli>\n\u003Cli>Root SSH access to your server\u003C\u002Fli>\n\u003Cli>A local PC to generate an SSH key pair\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2>1. Update the system\u003C\u002Fh2>\n\u003Cp>The very first step is to update all installed packages. This fixes known security vulnerabilities and gives you the latest stable versions of your software.\u003C\u002Fp>\n\u003Ch3>Connect to your VPS via SSH\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-bash\">ssh root@YOUR_VPS_IP\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cdiv class=\"markdown-alert markdown-alert-note\">\u003Cspan class=\"alert-icon\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cline x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"\u002F>\u003Cline x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"\u002F>\u003C\u002Fsvg>\u003C\u002Fspan>\u003Cdiv class=\"markdown-alert-body\">\u003Cp>Your server&#39;s IP address was sent to you in the delivery email when you ordered, or is available in the IP Address section of your client area. Replace \u003Ccode>YOUR_VPS_IP\u003C\u002Fcode> with that address (for example \u003Ccode>ssh root@82.153.202.xx\u003C\u002Fcode>).\u003C\u002Fp>\n\u003C\u002Fdiv>\u003C\u002Fdiv>\n\u003Ch3>Run the update\u003C\u002Fh3>\n\u003Cdiv class=\"md-tabs\" data-md-tabs>\u003Cdiv class=\"md-tabs__nav\" role=\"tablist\">\u003Cbutton type=\"button\" role=\"tab\" class=\"md-tabs__btn md-tabs__btn--active\" data-md-tab=\"0\" aria-selected=\"true\">Debian and Ubuntu\u003C\u002Fbutton>\u003Cbutton type=\"button\" role=\"tab\" class=\"md-tabs__btn\" data-md-tab=\"1\" aria-selected=\"false\">AlmaLinux, Rocky Linux, and Fedora\u003C\u002Fbutton>\u003Cbutton type=\"button\" role=\"tab\" class=\"md-tabs__btn\" data-md-tab=\"2\" aria-selected=\"false\">Alpine Linux\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cdiv class=\"md-tabs__body\">\u003Cdiv role=\"tabpanel\" class=\"md-tab__panel md-tab__panel--active\" data-md-panel=\"0\">\u003Cpre>\u003Ccode class=\"language-bash\">apt update &amp;&amp; apt dist-upgrade -y\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cdiv class=\"markdown-alert markdown-alert-tip\">\u003Cspan class=\"alert-icon\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"M12 16v-4\"\u002F>\u003Cpath d=\"M12 8h.01\"\u002F>\u003C\u002Fsvg>\u003C\u002Fspan>\u003Cdiv class=\"markdown-alert-body\">\u003Cp>Why \u003Ccode>dist-upgrade\u003C\u002Fcode> and not \u003Ccode>upgrade\u003C\u002Fcode>? The \u003Ccode>apt upgrade\u003C\u002Fcode> command can hold back certain critical updates (particularly Linux kernel updates or packages with new dependencies). \u003Ccode>apt dist-upgrade\u003C\u002Fcode> (or its equivalent \u003Ccode>apt full-upgrade\u003C\u002Fcode>) is more thorough and applies every security update without exception. It&#39;s the recommended command for a server.\u003C\u002Fp>\n\u003C\u002Fdiv>\u003C\u002Fdiv>\n\u003C\u002Fdiv>\u003Cdiv role=\"tabpanel\" class=\"md-tab__panel\" data-md-panel=\"1\" hidden>\u003Cpre>\u003Ccode class=\"language-bash\">dnf upgrade --refresh -y\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The \u003Ccode>--refresh\u003C\u002Fcode> option forces a refresh of repository metadata before applying updates, to make sure nothing is missed.\u003C\u002Fp>\n\u003C\u002Fdiv>\u003Cdiv role=\"tabpanel\" class=\"md-tab__panel\" data-md-panel=\"2\" hidden>\u003Cpre>\u003Ccode class=\"language-bash\">apk update &amp;&amp; apk upgrade\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>\n\u003Cdiv class=\"markdown-alert markdown-alert-tip\">\u003Cspan class=\"alert-icon\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"M12 16v-4\"\u002F>\u003Cpath d=\"M12 8h.01\"\u002F>\u003C\u002Fsvg>\u003C\u002Fspan>\u003Cdiv class=\"markdown-alert-body\">\u003Cp>Get into the habit of running this command every week to keep your VPS up to date.\u003C\u002Fp>\n\u003C\u002Fdiv>\u003C\u002Fdiv>\n\u003Ch2>2. Secure SSH access\u003C\u002Fh2>\n\u003Cp>SSH is your VPS&#39;s main entry point. It&#39;s also the number one target for attacks. Here are the best practices to apply.\u003C\u002Fp>\n\u003Ch3>❌ Why changing the SSH port is pointless\u003C\u002Fh3>\n\u003Cp>Many tutorials recommend changing the default SSH port (22) to another port (for example 2222). That&#39;s a false good idea.\u003C\u002Fp>\n\u003Cp>This is security through obscurity, you&#39;re hiding the service instead of actually protecting it. A modern scanner like \u003Ccode>nmap\u003C\u002Fcode> or \u003Ccode>masscan\u003C\u002Fcode> will find your new port within seconds. In the end, this change mostly complicates your administration (you need to specify the port on every connection), breaks certain tools that assume port 22 by default, and gives you a false sense of security.\u003C\u002Fp>\n\u003Cp>Keep port 22 and apply the real protections below instead.\u003C\u002Fp>\n\u003Ch3>2.1 Set up SSH key authentication\u003C\u002Fh3>\n\u003Cp>Key-based authentication is much safer than a password. A private key is nearly impossible to guess through brute force, unlike a password, which can be attacked for days on end.\u003C\u002Fp>\n\u003Cdiv class=\"markdown-alert markdown-alert-note\">\u003Cspan class=\"alert-icon\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cline x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"\u002F>\u003Cline x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"\u002F>\u003C\u002Fsvg>\u003C\u002Fspan>\u003Cdiv class=\"markdown-alert-body\">\u003Cp>&quot;Nearly impossible&quot; with today&#39;s computers. With the rise of quantum computing, some classical cryptographic algorithms (like RSA) may become vulnerable in the future. That&#39;s why \u003Cstrong>Ed25519\u003C\u002Fstrong> keys (used in this guide) are recommended today, more robust and already better prepared for the post-quantum era.\u003C\u002Fp>\n\u003C\u002Fdiv>\u003C\u002Fdiv>\n\u003Cp>This step is identical regardless of your VPS&#39;s distribution, since it mostly happens on your local PC.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>On your local PC\u003C\u002Fstrong> (not on the VPS), generate a key pair.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">ssh-keygen -t ed25519 -C &quot;your_email@example.com&quot;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Press Enter to accept the default location, then set a passphrase (a password protecting the key).\u003C\u002Fp>\n\u003Cp>Then copy the public key to your VPS.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">ssh-copy-id root@YOUR_VPS_IP\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Test the connection.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">ssh root@YOUR_VPS_IP\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>If you connect without being asked for a password (just the key&#39;s passphrase), everything works.\u003C\u002Fp>\n\u003Ch3>2.2 Disable password login\u003C\u002Fh3>\n\u003Cp>Now that key-based login works, disable password login to permanently block brute-force attacks.\u003C\u002Fp>\n\u003Cp>Open the SSH configuration file, identical across every distribution.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">nano \u002Fetc\u002Fssh\u002Fsshd_config\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Edit (or add) the following lines.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>PermitRootLogin prohibit-password\nPasswordAuthentication no\nPubkeyAuthentication yes\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The \u003Ccode>PermitRootLogin prohibit-password\u003C\u002Fcode> option allows root only via SSH key, never via password. \u003Ccode>PasswordAuthentication no\u003C\u002Fcode> completely disables password authentication, and \u003Ccode>PubkeyAuthentication yes\u003C\u002Fcode> allows key-based login.\u003C\u002Fp>\n\u003Cp>Save (\u003Ccode>Ctrl+O\u003C\u002Fcode>, Enter, \u003Ccode>Ctrl+X\u003C\u002Fcode>), then restart the SSH service. The service name differs depending on the distribution.\u003C\u002Fp>\n\u003Cdiv class=\"md-tabs\" data-md-tabs>\u003Cdiv class=\"md-tabs__nav\" role=\"tablist\">\u003Cbutton type=\"button\" role=\"tab\" class=\"md-tabs__btn md-tabs__btn--active\" data-md-tab=\"0\" aria-selected=\"true\">Debian and Ubuntu\u003C\u002Fbutton>\u003Cbutton type=\"button\" role=\"tab\" class=\"md-tabs__btn\" data-md-tab=\"1\" aria-selected=\"false\">AlmaLinux, Rocky Linux, and Fedora\u003C\u002Fbutton>\u003Cbutton type=\"button\" role=\"tab\" class=\"md-tabs__btn\" data-md-tab=\"2\" aria-selected=\"false\">Alpine Linux\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cdiv class=\"md-tabs__body\">\u003Cdiv role=\"tabpanel\" class=\"md-tab__panel md-tab__panel--active\" data-md-panel=\"0\">\u003Cpre>\u003Ccode class=\"language-bash\">systemctl restart ssh\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\u003Cdiv role=\"tabpanel\" class=\"md-tab__panel\" data-md-panel=\"1\" hidden>\u003Cpre>\u003Ccode class=\"language-bash\">systemctl restart sshd\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\u003Cdiv role=\"tabpanel\" class=\"md-tab__panel\" data-md-panel=\"2\" hidden>\u003Cpre>\u003Ccode class=\"language-bash\">rc-service sshd restart\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>\n\u003Cdiv class=\"markdown-alert markdown-alert-warning\">\u003Cspan class=\"alert-icon\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\u003Cpath d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"\u002F>\u003Cline x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"\u002F>\u003Cline x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"\u002F>\u003C\u002Fsvg>\u003C\u002Fspan>\u003Cdiv class=\"markdown-alert-body\">\u003Cp>Don&#39;t close your current session before testing the new configuration in another terminal. If something&#39;s wrong, you could end up locked out of the server.\u003C\u002Fp>\n\u003C\u002Fdiv>\u003C\u002Fdiv>\n\u003Ch2>3. Install a firewall\u003C\u002Fh2>\n\u003Cp>Which firewall to use depends on your distribution.\u003C\u002Fp>\n\u003Cdiv class=\"md-tabs\" data-md-tabs>\u003Cdiv class=\"md-tabs__nav\" role=\"tablist\">\u003Cbutton type=\"button\" role=\"tab\" class=\"md-tabs__btn md-tabs__btn--active\" data-md-tab=\"0\" aria-selected=\"true\">UFW (Debian, Ubuntu)\u003C\u002Fbutton>\u003Cbutton type=\"button\" role=\"tab\" class=\"md-tabs__btn\" data-md-tab=\"1\" aria-selected=\"false\">firewalld (AlmaLinux, Rocky, Fedora)\u003C\u002Fbutton>\u003Cbutton type=\"button\" role=\"tab\" class=\"md-tabs__btn\" data-md-tab=\"2\" aria-selected=\"false\">iptables (Alpine)\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cdiv class=\"md-tabs__body\">\u003Cdiv role=\"tabpanel\" class=\"md-tab__panel md-tab__panel--active\" data-md-panel=\"0\">\u003Cp>UFW (\u003Cem>Uncomplicated Firewall\u003C\u002Fem>) is an easy-to-use firewall that lets you only allow the necessary ports on your server.\u003C\u002Fp>\n\u003Ch3>Install UFW\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-bash\">apt install ufw -y\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Allow SSH (critical step)\u003C\u002Fh3>\n\u003Cp>\u003Cstrong>Before any other UFW command\u003C\u002Fstrong>, allow SSH. If you skip this step and enable the firewall, you&#39;ll be immediately disconnected from your VPS with no way back in.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">ufw allow OpenSSH\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Set the base rules\u003C\u002Fh3>\n\u003Cp>Now that SSH is allowed, you can block all incoming traffic by default and allow outgoing traffic.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">ufw default deny incoming\nufw default allow outgoing\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The \u003Ccode>default deny incoming\u003C\u002Fcode> rule blocks everything coming in, except the exceptions you&#39;ve defined (like SSH). The \u003Ccode>default allow outgoing\u003C\u002Fcode> rule lets your server keep communicating outward (updates, web requests, etc.).\u003C\u002Fp>\n\u003Ch3>Allow other services (if needed)\u003C\u002Fh3>\n\u003Cp>If you&#39;re hosting a website, open the HTTP and HTTPS ports.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">ufw allow 80\u002Ftcp\nufw allow 443\u002Ftcp\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Enable the firewall\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-bash\">ufw enable\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Then check that everything is in order.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">ufw status verbose\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>You should see your rules listed with \u003Ccode>active\u003C\u002Fcode> status.\u003C\u002Fp>\n\u003C\u002Fdiv>\u003Cdiv role=\"tabpanel\" class=\"md-tab__panel\" data-md-panel=\"1\" hidden>\u003Cp>firewalld is the default firewall in the Red Hat ecosystem. Unlike UFW, its default zone already blocks any incoming traffic not explicitly allowed, so there&#39;s no separate &quot;deny incoming&quot; rule to add.\u003C\u002Fp>\n\u003Ch3>Check that firewalld is active\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-bash\">systemctl status firewalld\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>On AlmaLinux, Rocky, and Fedora, firewalld is usually active by default. If it isn&#39;t, start it and enable it at boot.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">systemctl enable --now firewalld\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Allow SSH (critical step)\u003C\u002Fh3>\n\u003Cp>\u003Cstrong>Before anything else\u003C\u002Fstrong>, make sure SSH is allowed. It is by default on the \u003Ccode>public\u003C\u002Fcode> zone, but check anyway.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">firewall-cmd --permanent --add-service=ssh\nfirewall-cmd --reload\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Allow other services (if needed)\u003C\u002Fh3>\n\u003Cp>If you&#39;re hosting a website, open the HTTP and HTTPS ports.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">firewall-cmd --permanent --add-service=http\nfirewall-cmd --permanent --add-service=https\nfirewall-cmd --reload\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Check active rules\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-bash\">firewall-cmd --list-all\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>You should see the allowed services listed in the active zone.\u003C\u002Fp>\n\u003C\u002Fdiv>\u003Cdiv role=\"tabpanel\" class=\"md-tab__panel\" data-md-panel=\"2\" hidden>\u003Cp>Alpine doesn&#39;t include UFW or firewalld, so firewall protection goes through \u003Ccode>iptables\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch3>Install iptables\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-bash\">apk add iptables\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Allow loopback, established connections, and SSH (critical step)\u003C\u002Fh3>\n\u003Cp>\u003Cstrong>Before applying a default block policy\u003C\u002Fstrong>, explicitly allow SSH, or you&#39;ll end up locked out of the server.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">iptables -A INPUT -i lo -j ACCEPT\niptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT\niptables -A INPUT -p tcp --dport 22 -j ACCEPT\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Allow other services (if needed)\u003C\u002Fh3>\n\u003Cp>If you&#39;re hosting a website, open the HTTP and HTTPS ports.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">iptables -A INPUT -p tcp --dport 80 -j ACCEPT\niptables -A INPUT -p tcp --dport 443 -j ACCEPT\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Block the rest of the incoming traffic by default\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-bash\">iptables -P INPUT DROP\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Make the rules persistent\u003C\u002Fh3>\n\u003Cp>By default, iptables rules are lost on reboot.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">\u002Fetc\u002Finit.d\u002Fiptables save\nrc-update add iptables\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Check active rules\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-bash\">iptables -L INPUT -n -v --line-numbers\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>\n\u003Ch2>4. Install CrowdSec to block attacks\u003C\u002Fh2>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fwww.crowdsec.net\u002F\">CrowdSec\u003C\u002Fa> is a modern alternative to Fail2Ban. It analyzes logs in real time to detect malicious behavior (brute-force attempts, scans, etc.) and automatically blocks suspicious IPs.\u003C\u002Fp>\n\u003Cp>Its distinctive feature is that CrowdSec shares malicious IPs with a worldwide community, which lets it block attackers before they even attack your server.\u003C\u002Fp>\n\u003Cdiv class=\"markdown-alert markdown-alert-note\">\u003Cspan class=\"alert-icon\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cline x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"\u002F>\u003Cline x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"\u002F>\u003C\u002Fsvg>\u003C\u002Fspan>\u003Cdiv class=\"markdown-alert-body\">\u003Cp>On Alpine, CrowdSec doesn&#39;t have the same level of support as on other distributions. The automatic install wizard doesn&#39;t work (it assumes systemd, which Alpine doesn&#39;t have with OpenRC), and the packages are only available in the \u003Ccode>edge\u002Ftesting\u003C\u002Fcode> repository, not in the stable repos. A manual install is possible but is beyond the scope of this guide. On Alpine, the iptables firewall set up in the previous step remains your main protection.\u003C\u002Fp>\n\u003C\u002Fdiv>\u003C\u002Fdiv>\n\u003Cdiv class=\"md-tabs\" data-md-tabs>\u003Cdiv class=\"md-tabs__nav\" role=\"tablist\">\u003Cbutton type=\"button\" role=\"tab\" class=\"md-tabs__btn md-tabs__btn--active\" data-md-tab=\"0\" aria-selected=\"true\">Debian and Ubuntu\u003C\u002Fbutton>\u003Cbutton type=\"button\" role=\"tab\" class=\"md-tabs__btn\" data-md-tab=\"1\" aria-selected=\"false\">AlmaLinux, Rocky Linux, and Fedora\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cdiv class=\"md-tabs__body\">\u003Cdiv role=\"tabpanel\" class=\"md-tab__panel md-tab__panel--active\" data-md-panel=\"0\">\u003Ch3>Install CrowdSec\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-bash\">curl -s https:\u002F\u002Finstall.crowdsec.net | sh\napt install crowdsec -y\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The installer automatically detects the services to monitor (including SSH) and configures the necessary collections.\u003C\u002Fp>\n\u003Ch3>Check the installation\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-bash\">systemctl status crowdsec\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>You should see \u003Ccode>active (running)\u003C\u002Fcode> in green.\u003C\u002Fp>\n\u003Cp>To see the active detection scenarios, run the following command.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">cscli collections list\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Install the bouncer\u003C\u002Fh3>\n\u003Cp>CrowdSec detects threats, but it needs a bouncer to actively block them.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">apt install crowdsec-firewall-bouncer-iptables -y\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The bouncer registers itself automatically with CrowdSec. Then check that it&#39;s active.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">systemctl status crowdsec-firewall-bouncer\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\u003Cdiv role=\"tabpanel\" class=\"md-tab__panel\" data-md-panel=\"1\" hidden>\u003Ch3>Install CrowdSec\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-bash\">curl -s https:\u002F\u002Fpackagecloud.io\u002Finstall\u002Frepositories\u002Fcrowdsec\u002Fcrowdsec\u002Fscript.rpm.sh | bash\ndnf install crowdsec -y\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cdiv class=\"markdown-alert markdown-alert-note\">\u003Cspan class=\"alert-icon\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cline x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"\u002F>\u003Cline x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"\u002F>\u003C\u002Fsvg>\u003C\u002Fspan>\u003Cdiv class=\"markdown-alert-body\">\u003Cp>If the repository installation fails asking for \u003Ccode>pygpgme\u003C\u002Fcode>, this package is no longer packaged on recent versions of AlmaLinux and Rocky. Check the official CrowdSec documentation for the manual repository install method for your exact version.\u003C\u002Fp>\n\u003C\u002Fdiv>\u003C\u002Fdiv>\n\u003Ch3>Check the installation\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-bash\">systemctl status crowdsec\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>You should see \u003Ccode>active (running)\u003C\u002Fcode> in green.\u003C\u002Fp>\n\u003Cp>To see the active detection scenarios, run the following command.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">cscli collections list\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Install the bouncer\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-bash\">dnf install crowdsec-firewall-bouncer-iptables -y\nsystemctl enable --now crowdsec-firewall-bouncer\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Then check that it&#39;s active.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">systemctl status crowdsec-firewall-bouncer\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>\n\u003Ch3>Test and monitor CrowdSec\u003C\u002Fh3>\n\u003Cp>To list current decisions (blocked IPs), use this command.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">cscli decisions list\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>To check alerts (detected attempts), run this one.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">cscli alerts list\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cdiv class=\"markdown-alert markdown-alert-tip\">\u003Cspan class=\"alert-icon\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"M12 16v-4\"\u002F>\u003Cpath d=\"M12 8h.01\"\u002F>\u003C\u002Fsvg>\u003C\u002Fspan>\u003Cdiv class=\"markdown-alert-body\">\u003Cp>Create a free account at \u003Ca href=\"https:\u002F\u002Fapp.crowdsec.net\">app.crowdsec.net\u003C\u002Fa> to view your alerts in a web dashboard and benefit from the community blocklist, which preemptively blocks IPs flagged as malicious by other users.\u003C\u002Fp>\n\u003C\u002Fdiv>\u003C\u002Fdiv>\n\u003Ch2>Summary of good habits\u003C\u002Fh2>\n\u003Cp>After following this guide, your VPS is protected against most common attacks. To maintain this level of security over time, keep these habits in mind.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Update the system regularly\u003C\u002Fli>\n\u003Cli>Only use SSH key authentication\u003C\u002Fli>\n\u003Cli>Keep your firewall enabled and only open the ports you actually need\u003C\u002Fli>\n\u003Cli>Check the CrowdSec logs from time to time (\u003Ccode>cscli alerts list\u003C\u002Fcode>), on distributions where it&#39;s installed\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2>Need help?\u003C\u002Fh2>\n\u003Cp>If you run into an issue while securing your VPS, our team is here. Open a ticket in the \u003Cstrong>Technical\u003C\u002Fstrong> department from your client area and fill in the \u003Cstrong>Related Product\u003C\u002Fstrong> field with the VPS in question.\u003C\u002Fp>\n\u003Cp>You now have a secure Linux VPS, ready to host your projects with peace of mind 🔒\u003C\u002Fp>\n",1788993144249]