{"id":172,"date":"2026-05-29T03:54:06","date_gmt":"2026-05-29T03:54:06","guid":{"rendered":"https:\/\/blog.offshorekaka.in\/?p=172"},"modified":"2026-08-27T05:43:52","modified_gmt":"2026-08-27T05:43:52","slug":"firewall-setup-for-offshore-vps","status":"publish","type":"post","link":"https:\/\/offshorekaka.in\/blog\/firewall-setup-for-offshore-vps\/","title":{"rendered":"Firewall Setup for Offshore VPS: Ports, Rules and Testing"},"content":{"rendered":"<div class=\"ok-pro-panel\">\n<p><span class=\"ok-pro-kicker\">Server Security<\/span><\/p>\n<h2>What this guide does<\/h2>\n<p>A fresh <a href=\"https:\/\/offshorekaka.in\/offshore-vps-server\/\">offshore VPS<\/a> accepts connections on every port that has something listening. Most of the time that is more than you think: a database, a mail daemon, a panel, whatever the image shipped with. This guide closes all of it down to the three ports a web server actually needs, without cutting off your own SSH session while you do it.<\/p>\n<p>The dangerous moment is <code>ufw enable<\/code>. If SSH is not allowed at that instant, the connection you are typing into dies and does not come back.<\/p>\n<div class=\"ok-pro-grid\">\n<div class=\"ok-pro-card\"><strong>Time<\/strong><span>Under 10 minutes.<\/span><\/div>\n<div class=\"ok-pro-card\"><strong>Applies to<\/strong><span>Ubuntu and Debian. RHEL notes below.<\/span><\/div>\n<div class=\"ok-pro-card\"><strong>Risk<\/strong><span>Low, if you do step 2 before step 3.<\/span><\/div>\n<\/div>\n<\/div>\n<div class=\"ok-toc\"><strong>On this page<\/strong><a href=\"#listening\">See what is exposed now<\/a><a href=\"#steps\">The four steps<\/a><a href=\"#panel\">If you run a control panel<\/a><a href=\"#rhel\">AlmaLinux and Rocky<\/a><a href=\"#trouble\">When something breaks<\/a><a href=\"#faq\">FAQ<\/a><\/div>\n<h2 id=\"listening\">See what is exposed now<\/h2>\n<p>Start by finding out what is listening, because that decides which rules you need. There is no point guessing.<\/p>\n<pre><code>ss -tulpn<\/code><\/pre>\n<figure class=\"wp-block-image size-large ok-inline-visual\"><img decoding=\"async\" src=\"https:\/\/offshorekaka.in\/blog\/wp-content\/uploads\/2026\/08\/ok-listening-ports.webp\" alt=\"Terminal output of ss showing nginx listening on ports 80 and 443 and MySQL bound to localhost only\" loading=\"lazy\" width=\"2296\" height=\"428\"><figcaption>Note the address on the left. 0.0.0.0 means the whole internet can reach it. 127.0.0.1 means only the server itself can.<\/figcaption><\/figure>\n<p>Anything bound to <code>127.0.0.1<\/code> is already safe and needs no firewall rule at all. A database bound to <code>0.0.0.0<\/code> is a problem, and the right fix is to bind it to localhost in its own config rather than to paper over it with a firewall rule.<\/p>\n<h2 id=\"steps\">The four steps<\/h2>\n<h3>Step 1: Install UFW and set the defaults<\/h3>\n<pre><code>apt install ufw -y\nufw default deny incoming\nufw default allow outgoing<\/code><\/pre>\n<p>Deny incoming, allow outgoing. That is the whole philosophy. Nothing gets in unless you name it; your server can still reach out for updates and API calls. Neither of these commands turns the firewall on, so nothing has changed yet.<\/p>\n<h3>Step 2: Allow the ports you need, SSH first<\/h3>\n<pre><code>ufw allow OpenSSH\nufw allow 80\/tcp\nufw allow 443\/tcp<\/code><\/pre>\n<p>Do SSH before anything else. <code>ufw allow OpenSSH<\/code> uses the shipped profile for port 22. If you have already moved SSH to another port, as covered in our <a href=\"https:\/\/offshorekaka.in\/blog\/ssh-hardening-for-offshore-vps\/\">SSH hardening guide<\/a>, use the number instead: <code>ufw allow 2222\/tcp<\/code>. Get this wrong and step 3 locks you out.<\/p>\n<p>Add mail ports only if this box actually handles mail. If your mail lives at Google or Zoho, port 25, 465, 587, 993 and 110 should all stay shut.<\/p>\n<h3>Step 3: Turn it on<\/h3>\n<pre><code>ufw enable<\/code><\/pre>\n<p>It will warn you that this may disrupt existing SSH connections. Read that warning rather than clicking past it. If you followed step 2, you are fine.<\/p>\n<p>Before you press enter, open a second SSH session to the same server and leave it sitting there. If the firewall does cut you off, that second session is still connected and you can run <code>ufw disable<\/code> from it.<\/p>\n<h3>Step 4: Read the rules back<\/h3>\n<pre><code>ufw status verbose<\/code><\/pre>\n<figure class=\"wp-block-image size-large ok-inline-visual\"><img decoding=\"async\" src=\"https:\/\/offshorekaka.in\/blog\/wp-content\/uploads\/2026\/08\/ok-firewall-ufw-status.webp\" alt=\"UFW status verbose output showing default deny incoming and only ports 22, 80 and 443 allowed\" loading=\"lazy\" width=\"2296\" height=\"824\"><figcaption>Three ports in, everything else denied. This is what a web server firewall should look like.<\/figcaption><\/figure>\n<p>Every line you cannot explain is a line to remove. Use <code>ufw status numbered<\/code> and then <code>ufw delete 4<\/code> to drop one by its number.<\/p>\n<h2 id=\"panel\">If you run a control panel<\/h2>\n<p>This is where people get caught out. aaPanel, CyberPanel, Webmin and cPanel all listen on their own ports, and a lot of them install their own firewall layer as well. Turning on UFW underneath one of those gives you two firewalls disagreeing with each other.<\/p>\n<ul>\n<li><strong>aaPanel<\/strong> uses a random high port set at install time, plus 888 for phpMyAdmin. Find it with <code>bt default<\/code> and allow that port, or you will lock yourself out of the panel.<\/li>\n<li><strong>cPanel and WHM<\/strong> use 2082, 2083, 2086, 2087 and 2096. cPanel servers normally run CSF rather than UFW, and running both is a bad idea. Pick one.<\/li>\n<li><strong>CyberPanel<\/strong> uses 8090.<\/li>\n<\/ul>\n<p>The safer pattern with a panel is to restrict the panel port to your own IP rather than leaving it open to the world:<\/p>\n<pre><code>ufw allow from 203.0.113.5 to any port 8888 proto tcp<\/code><\/pre>\n<h2 id=\"rhel\">AlmaLinux and Rocky<\/h2>\n<p>These use firewalld, not UFW. Same idea, different commands:<\/p>\n<pre><code>firewall-cmd --permanent --add-service=ssh\nfirewall-cmd --permanent --add-service=http\nfirewall-cmd --permanent --add-service=https\nfirewall-cmd --reload\nfirewall-cmd --list-all<\/code><\/pre>\n<p>The <code>--permanent<\/code> flag writes the rule to disk but does not apply it until the reload. Leave it off and the rule disappears on the next reboot, which is a very confusing thing to debug three weeks later.<\/p>\n<h2 id=\"test\">How to test<\/h2>\n<ol>\n<li>Load your website over HTTP and HTTPS.<\/li>\n<li>Open a fresh SSH session in a new window.<\/li>\n<li>From your laptop, try a port that should now be closed: <code>nc -zv your-server-ip 3306<\/code>. It should time out or refuse.<\/li>\n<li>Run <code>ufw status verbose<\/code> and read every line.<\/li>\n<li>If you run a panel, log in to it once to confirm the port is still reachable.<\/li>\n<\/ol>\n<h2 id=\"trouble\">When something breaks<\/h2>\n<table>\n<thead>\n<tr>\n<th>What you see<\/th>\n<th>Why<\/th>\n<th>Fix<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>SSH dies the moment you enable UFW<\/td>\n<td>SSH was never allowed, or it is on a custom port<\/td>\n<td>Use the provider web console, run <code>ufw disable<\/code>, allow the right port, enable again<\/td>\n<\/tr>\n<tr>\n<td>Website unreachable but SSH works<\/td>\n<td>80 and 443 not allowed<\/td>\n<td><code>ufw allow 80\/tcp<\/code> and <code>ufw allow 443\/tcp<\/code><\/td>\n<\/tr>\n<tr>\n<td>Panel login stopped working<\/td>\n<td>The panel port is not in the rules<\/td>\n<td>Find the port with <code>bt default<\/code> or your panel docs and allow it<\/td>\n<\/tr>\n<tr>\n<td>Rules vanish after a reboot<\/td>\n<td>firewalld used without <code>--permanent<\/code><\/td>\n<td>Re-add with <code>--permanent<\/code>, then <code>--reload<\/code><\/td>\n<\/tr>\n<tr>\n<td>Site still reachable on a port you blocked<\/td>\n<td>Cloudflare or another proxy is in front, or Docker wrote its own iptables rules<\/td>\n<td>Test the origin IP directly, and check <code>iptables -L DOCKER<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"checklist\">Checklist<\/h2>\n<ul>\n<li>You know what was listening before you started.<\/li>\n<li>Defaults set to deny incoming, allow outgoing.<\/li>\n<li>SSH allowed on the correct port, before enabling.<\/li>\n<li>A second SSH session open as a safety net.<\/li>\n<li>Only 80 and 443 open beyond SSH, unless you have a documented reason.<\/li>\n<li>Panel port restricted to your own IP rather than open to everyone.<\/li>\n<li>Rules read back and every line understood.<\/li>\n<\/ul>\n<div class=\"ok-cta-box\">\n<p><strong>Want a VPS where the firewall is yours to run?<\/strong><\/p>\n<p>OffshoreKaka VPS servers come with full root access and a panel console, so a firewall mistake is a two minute fix rather than a support ticket.<\/p>\n<p><a class=\"btn ok-cta-link\" href=\"https:\/\/offshorekaka.in\/offshore-vps-server\/\">See the VPS plans<\/a><\/p>\n<\/div>\n<h2 id=\"faq\">FAQ<\/h2>\n<h3>Do I need a firewall if I am behind Cloudflare?<\/h3>\n<p>Yes, and arguably more so. Cloudflare only protects traffic that goes through Cloudflare. Anyone who learns your origin IP can hit the server directly and skip it entirely. A firewall that only allows Cloudflare IP ranges on ports 80 and 443 closes that hole. Our <a href=\"https:\/\/offshorekaka.in\/blog\/cloudflare-dns-setup-for-offshore-hosting\/\">Cloudflare DNS guide<\/a> covers the setup side.<\/p>\n<h3>UFW or CSF?<\/h3>\n<p>UFW if you are on a plain Ubuntu or Debian VPS and want something you can read at a glance. CSF if you are on cPanel, since it is what that ecosystem expects and it brings login failure blocking with it. Do not run both.<\/p>\n<h3>Should I block whole countries?<\/h3>\n<p>Rarely worth it. It is easy to get around with a VPN, it blocks real customers, and the rule lists get big enough to slow the firewall down. Blocking specific abusive IP ranges after you see them in your logs works far better.<\/p>\n<h3>Does a firewall help my search ranking?<\/h3>\n<p>No. It keeps the site up and uncompromised, and a hacked site absolutely does lose rankings, so there is an indirect connection. But no search engine gives you credit for having one.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Three ports in, everything else denied. The order matters, because getting it wrong locks you out of your own server.<\/p>\n","protected":false},"author":1,"featured_media":1015,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-172","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-server-security"],"_links":{"self":[{"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/posts\/172","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/comments?post=172"}],"version-history":[{"count":5,"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/posts\/172\/revisions"}],"predecessor-version":[{"id":1010,"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/posts\/172\/revisions\/1010"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/media\/1015"}],"wp:attachment":[{"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/media?parent=172"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/categories?post=172"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/tags?post=172"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}