{"id":3493,"date":"2025-12-27T17:11:37","date_gmt":"2025-12-27T14:11:37","guid":{"rendered":"https:\/\/www.dchost.com\/blog\/firewall-configuration-on-vps-servers-with-ufw-firewalld-and-iptables\/"},"modified":"2025-12-27T17:11:37","modified_gmt":"2025-12-27T14:11:37","slug":"firewall-configuration-on-vps-servers-with-ufw-firewalld-and-iptables","status":"publish","type":"post","link":"https:\/\/www.dchost.com\/blog\/en\/firewall-configuration-on-vps-servers-with-ufw-firewalld-and-iptables\/","title":{"rendered":"Firewall Configuration on VPS Servers with ufw, firewalld and iptables"},"content":{"rendered":"<div class=\"dchost-blog-content-wrapper\"><p>If you are running a <a href=\"https:\/\/www.dchost.com\/vps\">VPS<\/a>, your firewall is not a nice-to-have add\u2011on; it is one of the core layers that decides who can talk to your server and how. Whether you host a small WordPress site, a Laravel API, a game server or a full e\u2011commerce stack, a properly configured firewall often makes the difference between a noisy, constantly attacked machine and a calm, predictable environment. On Linux\u2011based VPS servers, three tools show up again and again: <strong>ufw<\/strong>, <strong>firewalld<\/strong> and <strong>iptables<\/strong>. Each solves the same problem with a slightly different philosophy and complexity level.<\/p>\n<p>In this guide, we will walk through how these tools fit together, when to use which, and how to build practical, repeatable firewall configurations for real VPS workloads. We will keep the focus on concrete rules and command examples that you can paste, tweak and apply to your own servers at dchost.com or elsewhere. By the end, you should be able to lock down a fresh VPS in minutes, avoid the most common mistakes (like locking yourself out of SSH), and extend your rules safely as your architecture grows.<\/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=\"#How_Linux_Firewalls_Really_Work_Under_the_Hood\"><span class=\"toc_number toc_depth_1\">1<\/span> How Linux Firewalls Really Work Under the Hood<\/a><ul><li><a href=\"#Netfilter_iptables_and_nftables_in_one_minute\"><span class=\"toc_number toc_depth_2\">1.1<\/span> Netfilter, iptables and nftables in one minute<\/a><\/li><li><a href=\"#Why_the_firewall_is_part_of_a_bigger_security_picture\"><span class=\"toc_number toc_depth_2\">1.2<\/span> Why the firewall is part of a bigger security picture<\/a><\/li><\/ul><\/li><li><a href=\"#Choosing_Between_ufw_firewalld_and_iptables\"><span class=\"toc_number toc_depth_1\">2<\/span> Choosing Between ufw, firewalld and iptables<\/a><ul><li><a href=\"#ufw_Simple_and_ideal_for_singlepurpose_servers\"><span class=\"toc_number toc_depth_2\">2.1<\/span> ufw: Simple and ideal for single\u2011purpose servers<\/a><\/li><li><a href=\"#firewalld_Zones_and_services_for_dynamic_environments\"><span class=\"toc_number toc_depth_2\">2.2<\/span> firewalld: Zones and services for dynamic environments<\/a><\/li><li><a href=\"#iptables_Maximum_control_and_complexity\"><span class=\"toc_number toc_depth_2\">2.3<\/span> iptables: Maximum control and complexity<\/a><\/li><li><a href=\"#Practical_rule_of_thumb\"><span class=\"toc_number toc_depth_2\">2.4<\/span> Practical rule of thumb<\/a><\/li><\/ul><\/li><li><a href=\"#Core_Firewall_Strategy_for_a_VPS\"><span class=\"toc_number toc_depth_1\">3<\/span> Core Firewall Strategy for a VPS<\/a><\/li><li><a href=\"#Configuring_ufw_on_a_VPS\"><span class=\"toc_number toc_depth_1\">4<\/span> Configuring ufw on a VPS<\/a><ul><li><a href=\"#Step_1_Install_and_check_status\"><span class=\"toc_number toc_depth_2\">4.1<\/span> Step 1: Install and check status<\/a><\/li><li><a href=\"#Step_2_Set_default_policies\"><span class=\"toc_number toc_depth_2\">4.2<\/span> Step 2: Set default policies<\/a><\/li><li><a href=\"#Step_3_Allow_SSH_before_enabling_ufw\"><span class=\"toc_number toc_depth_2\">4.3<\/span> Step 3: Allow SSH before enabling ufw<\/a><\/li><li><a href=\"#Step_4_Allow_web_traffic_and_other_services\"><span class=\"toc_number toc_depth_2\">4.4<\/span> Step 4: Allow web traffic and other services<\/a><\/li><li><a href=\"#Step_5_Enable_ufw\"><span class=\"toc_number toc_depth_2\">4.5<\/span> Step 5: Enable ufw<\/a><\/li><li><a href=\"#Step_6_Hardening_SSH_with_ufw_optional_but_recommended\"><span class=\"toc_number toc_depth_2\">4.6<\/span> Step 6: Hardening SSH with ufw (optional but recommended)<\/a><\/li><li><a href=\"#Step_7_IPv6_with_ufw\"><span class=\"toc_number toc_depth_2\">4.7<\/span> Step 7: IPv6 with ufw<\/a><\/li><\/ul><\/li><li><a href=\"#Configuring_firewalld_on_a_VPS\"><span class=\"toc_number toc_depth_1\">5<\/span> Configuring firewalld on a VPS<\/a><ul><li><a href=\"#Step_1_Confirm_firewalld_is_running\"><span class=\"toc_number toc_depth_2\">5.1<\/span> Step 1: Confirm firewalld is running<\/a><\/li><li><a href=\"#Step_2_Check_the_current_zone_and_interfaces\"><span class=\"toc_number toc_depth_2\">5.2<\/span> Step 2: Check the current zone and interfaces<\/a><\/li><li><a href=\"#Step_3_Set_default_target_and_allow_SSH\"><span class=\"toc_number toc_depth_2\">5.3<\/span> Step 3: Set default target and allow SSH<\/a><\/li><li><a href=\"#Step_4_Allow_HTTPHTTPS_and_other_services\"><span class=\"toc_number toc_depth_2\">5.4<\/span> Step 4: Allow HTTP\/HTTPS and other services<\/a><\/li><li><a href=\"#Step_5_Using_rich_rules_for_IPbased_restrictions\"><span class=\"toc_number toc_depth_2\">5.5<\/span> Step 5: Using rich rules for IP\u2011based restrictions<\/a><\/li><li><a href=\"#Step_6_Zones_for_private_interfaces\"><span class=\"toc_number toc_depth_2\">5.6<\/span> Step 6: Zones for private interfaces<\/a><\/li><\/ul><\/li><li><a href=\"#Configuring_iptables_Directly\"><span class=\"toc_number toc_depth_1\">6<\/span> Configuring iptables Directly<\/a><ul><li><a href=\"#Step_1_Basic_IPv4_rules_for_a_web_server\"><span class=\"toc_number toc_depth_2\">6.1<\/span> Step 1: Basic IPv4 rules for a web server<\/a><\/li><li><a href=\"#Step_2_Restrict_SSH_to_a_specific_IP\"><span class=\"toc_number toc_depth_2\">6.2<\/span> Step 2: Restrict SSH to a specific IP<\/a><\/li><li><a href=\"#Step_3_Persistent_iptables_rules\"><span class=\"toc_number toc_depth_2\">6.3<\/span> Step 3: Persistent iptables rules<\/a><\/li><li><a href=\"#Step_4_Dont_forget_IPv6_ip6tables\"><span class=\"toc_number toc_depth_2\">6.4<\/span> Step 4: Don\u2019t forget IPv6 (ip6tables)<\/a><\/li><\/ul><\/li><li><a href=\"#Common_RealWorld_Scenarios_and_Tips\"><span class=\"toc_number toc_depth_1\">7<\/span> Common Real\u2011World Scenarios and Tips<\/a><ul><li><a href=\"#Running_Docker_on_a_VPS_with_a_firewall\"><span class=\"toc_number toc_depth_2\">7.1<\/span> Running Docker on a VPS with a firewall<\/a><\/li><li><a href=\"#cPanel_DirectAdmin_and_other_hosting_panels\"><span class=\"toc_number toc_depth_2\">7.2<\/span> cPanel, DirectAdmin and other hosting panels<\/a><\/li><li><a href=\"#Rate_limiting_and_bruteforce_protection\"><span class=\"toc_number toc_depth_2\">7.3<\/span> Rate limiting and brute\u2011force protection<\/a><\/li><li><a href=\"#Logging_and_monitoring_your_firewall\"><span class=\"toc_number toc_depth_2\">7.4<\/span> Logging and monitoring your firewall<\/a><\/li><\/ul><\/li><li><a href=\"#Verification_Testing_and_Safe_Change_Management\"><span class=\"toc_number toc_depth_1\">8<\/span> Verification, Testing and Safe Change Management<\/a><ul><li><a href=\"#Always_test_connectivity_after_changes\"><span class=\"toc_number toc_depth_2\">8.1<\/span> Always test connectivity after changes<\/a><\/li><li><a href=\"#Keep_a_rescue_window_open\"><span class=\"toc_number toc_depth_2\">8.2<\/span> Keep a rescue window open<\/a><\/li><li><a href=\"#Document_and_version_your_firewall_rules\"><span class=\"toc_number toc_depth_2\">8.3<\/span> Document and version your firewall rules<\/a><\/li><\/ul><\/li><li><a href=\"#Bringing_It_All_Together_on_dchostcom_VPS_Servers\"><span class=\"toc_number toc_depth_1\">9<\/span> Bringing It All Together on dchost.com VPS Servers<\/a><\/li><\/ul><\/div>\n<h2><span id=\"How_Linux_Firewalls_Really_Work_Under_the_Hood\">How Linux Firewalls Really Work Under the Hood<\/span><\/h2>\n<p>Before choosing between ufw, firewalld and iptables, it helps to understand what is actually happening inside the kernel. All three are primarily front\u2011ends to the same packet\u2011filtering engine.<\/p>\n<h3><span id=\"Netfilter_iptables_and_nftables_in_one_minute\">Netfilter, iptables and nftables in one minute<\/span><\/h3>\n<p>Linux uses a subsystem called <strong>netfilter<\/strong> to inspect, filter and mangle network packets. Tools like <strong>iptables<\/strong> and the newer <strong>nftables<\/strong> are user\u2011space interfaces that load rules into netfilter. In many current distributions, even ufw and firewalld end up generating iptables or nftables rules behind the scenes.<\/p>\n<p>Key concepts you will see across all tools:<\/p>\n<ul>\n<li><strong>Tables<\/strong>: Groups of rules for different purposes (e.g. <code>filter<\/code> for allow\/deny, <code>nat<\/code> for port forwarding).<\/li>\n<li><strong>Chains<\/strong>: Ordered lists of rules applied at specific stages (e.g. <code>INPUT<\/code> for packets going into the server, <code>OUTPUT<\/code> for packets leaving, <code>FORWARD<\/code> for packets routed through).<\/li>\n<li><strong>Policies<\/strong>: Default action if a packet reaches the end of a chain (often <code>ACCEPT<\/code> or <code>DROP<\/code>).<\/li>\n<li><strong>Stateful filtering<\/strong>: Using connection tracking to allow established and related traffic, instead of manually opening reply ports.<\/li>\n<\/ul>\n<p>If these feel abstract, keep reading; we will translate them into concrete ufw, firewalld and iptables commands shortly.<\/p>\n<h3><span id=\"Why_the_firewall_is_part_of_a_bigger_security_picture\">Why the firewall is part of a bigger security picture<\/span><\/h3>\n<p>A firewall is not the only security control on a VPS. You should combine it with:<\/p>\n<ul>\n<li>Secure SSH access (keys, non\u2011root logins, possibly hardware keys).<\/li>\n<li>Up\u2011to\u2011date software and OS patches.<\/li>\n<li>HTTP security headers and TLS best practices for web apps. You can see real examples in our guide on <a href=\"https:\/\/www.dchost.com\/blog\/en\/http-guvenlik-basliklari-rehberi-hsts-csp-x-frame-options-ve-referrer-policy-dogru-nasil-kurulur\/\">how to correctly set HSTS, CSP and other HTTP security headers<\/a>.<\/li>\n<li>Application\u2011level protections (WAF, rate limiting, strong authentication).<\/li>\n<\/ul>\n<p>On a new VPS, we usually touch three areas within the first few hours: system updates, user\/SSH hardening and firewall. We covered the full first\u2011day checklist in detail in <a href=\"https:\/\/www.dchost.com\/blog\/en\/yeni-vpste-ilk-24-saat-guncelleme-guvenlik-duvari-ve-kullanici-hesaplari\/\">our article about the first 24 hours on a new VPS<\/a>; here we will dive deeper into the firewall part.<\/p>\n<h2><span id=\"Choosing_Between_ufw_firewalld_and_iptables\">Choosing Between ufw, firewalld and iptables<\/span><\/h2>\n<p>All three tools ultimately manipulate netfilter rules. The main question is how much abstraction and automation you want.<\/p>\n<h3><span id=\"ufw_Simple_and_ideal_for_singlepurpose_servers\">ufw: Simple and ideal for single\u2011purpose servers<\/span><\/h3>\n<p><strong>ufw (Uncomplicated Firewall)<\/strong> focuses on ease of use. It is common on Ubuntu and many Debian\u2011based systems. Pros:<\/p>\n<ul>\n<li>Very easy syntax for common tasks like opening ports or whitelisting IP ranges.<\/li>\n<li>Good fit for single\u2011server setups: WordPress, small APIs, game servers, panels.<\/li>\n<li>Plays nicely with tools like Fail2ban and many hosting panel scripts.<\/li>\n<\/ul>\n<p>Limitations:<\/p>\n<ul>\n<li>Less expressive than raw iptables for very complex setups.<\/li>\n<li>Less integrated with concept of network zones compared to firewalld.<\/li>\n<\/ul>\n<h3><span id=\"firewalld_Zones_and_services_for_dynamic_environments\">firewalld: Zones and services for dynamic environments<\/span><\/h3>\n<p><strong>firewalld<\/strong> is the default on many RPM\u2011based distributions (AlmaLinux, Rocky Linux, CentOS Stream, Fedora). It introduces:<\/p>\n<ul>\n<li><strong>Zones<\/strong> (public, internal, dmz, trusted, etc.), each with its own policy.<\/li>\n<li><strong>Services<\/strong> defined by name (e.g. <code>http<\/code>, <code>https<\/code>, <code>ssh<\/code>) instead of raw port numbers.<\/li>\n<li>Support for dynamic rule reloads without dropping connections.<\/li>\n<\/ul>\n<p>It is a great fit for VPS setups where you might have multiple interfaces, VLANs, or plan to expand into more complex architectures later.<\/p>\n<h3><span id=\"iptables_Maximum_control_and_complexity\">iptables: Maximum control and complexity<\/span><\/h3>\n<p><strong>iptables<\/strong> is the classic, low\u2011level interface. You talk directly in terms of tables, chains and rules. Advantages:<\/p>\n<ul>\n<li>Full control: anything netfilter can do, you can express with iptables.<\/li>\n<li>Better for advanced needs: custom NAT, load balancers, VPN gateways, or non\u2011standard protocols.<\/li>\n<\/ul>\n<p>Downsides:<\/p>\n<ul>\n<li>Steeper learning curve and easier to lock yourself out.<\/li>\n<li>Large rule sets can get hard to manage without configuration management tools.<\/li>\n<\/ul>\n<p>On modern systems, iptables may use the <strong>nf_tables<\/strong> backend internally, but from your perspective the commands look the same.<\/p>\n<h3><span id=\"Practical_rule_of_thumb\">Practical rule of thumb<\/span><\/h3>\n<ul>\n<li><strong>Just one web app, simple setup?<\/strong> Use <strong>ufw<\/strong> (Ubuntu\/Debian) or <strong>firewalld<\/strong> (Alma\/Rocky) and keep things readable.<\/li>\n<li><strong>Multiple networks, custom routing, VPN, or complex NAT?<\/strong> Consider managing core rules with <strong>iptables<\/strong>, or at least be comfortable reading generated iptables rules even if you use ufw\/firewalld as the front\u2011end.<\/li>\n<li><strong>Want to go even further?<\/strong> We have a separate deep\u2011dive on nftables for advanced users: <a href=\"https:\/\/www.dchost.com\/blog\/en\/nftables-ile-vps-guvenlik-duvari-rehberi-rate-limit-port-knocking-ve-ipv6-kurallari-nasil-tatli-tatli-kurulur\/\">our nftables firewall cookbook for VPS<\/a>.<\/li>\n<\/ul>\n<h2><span id=\"Core_Firewall_Strategy_for_a_VPS\">Core Firewall Strategy for a VPS<\/span><\/h2>\n<p>Regardless of the tool, the strategy is similar. On most customer VPS setups at dchost.com, we start from a minimal baseline:<\/p>\n<ol>\n<li><strong>Default deny incoming<\/strong>, default allow outgoing.<\/li>\n<li><strong>Explicitly allow SSH<\/strong> from trusted IPs or ranges, with optional rate limiting.<\/li>\n<li><strong>Allow only required application ports<\/strong> (e.g. 80\/443 for a web server, 22 for SSH, 25\/587\/993 for a mail server, etc.).<\/li>\n<li><strong>Enable connection tracking<\/strong> so replies to allowed connections are permitted automatically.<\/li>\n<li><strong>Support IPv6<\/strong> properly instead of forgetting it open or misconfigured.<\/li>\n<\/ol>\n<p>This zero\u2011trust style aligns nicely with what we recommend in broader VPS hardening. If you want a full checklist that also covers SSH, file permissions and web stack settings, our article <a href=\"https:\/\/www.dchost.com\/blog\/en\/vps-sunucu-guvenligi-nasil-saglanir-kapiyi-acik-birakmadan-yasamanin-sirri\/\">on securing a VPS server without drama<\/a> pairs perfectly with this firewall guide.<\/p>\n<h2><span id=\"Configuring_ufw_on_a_VPS\">Configuring ufw on a VPS<\/span><\/h2>\n<p>Let\u2019s start with ufw because it is the simplest and very common on Ubuntu VPS servers.<\/p>\n<h3><span id=\"Step_1_Install_and_check_status\">Step 1: Install and check status<\/span><\/h3>\n<p>On Ubuntu, ufw is usually installed by default:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo ufw status verbose\n<\/code><\/pre>\n<p>If it says &#8220;inactive&#8221;, that\u2019s normal on a fresh VPS. To install (if missing):<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo apt update\nsudo apt install ufw\n<\/code><\/pre>\n<h3><span id=\"Step_2_Set_default_policies\">Step 2: Set default policies<\/span><\/h3>\n<p>We recommend:<\/p>\n<ul>\n<li>Deny all incoming by default.<\/li>\n<li>Allow all outgoing by default (you can tighten this later if needed).<\/li>\n<\/ul>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo ufw default deny incoming\nsudo ufw default allow outgoing\n<\/code><\/pre>\n<h3><span id=\"Step_3_Allow_SSH_before_enabling_ufw\">Step 3: Allow SSH before enabling ufw<\/span><\/h3>\n<p>This part is critical: if you enable ufw without allowing SSH, you will lock yourself out. On most systems, SSH runs on port 22 and ufw knows the <code>OpenSSH<\/code> profile by name:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo ufw allow OpenSSH\n<\/code><\/pre>\n<p>If you have moved SSH to a custom port, for example 2222:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo ufw allow 2222\/tcp\n<\/code><\/pre>\n<h3><span id=\"Step_4_Allow_web_traffic_and_other_services\">Step 4: Allow web traffic and other services<\/span><\/h3>\n<p>For a classic HTTPS web server:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo ufw allow 80\/tcp\nsudo ufw allow 443\/tcp\n<\/code><\/pre>\n<p>For a database that must only be reachable from a specific IP (for example, an application server or your office IP):<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo ufw allow from 203.0.113.10 to any port 3306 proto tcp\n<\/code><\/pre>\n<p>This lets <code>203.0.113.10<\/code> connect to MySQL on port 3306 but blocks everyone else.<\/p>\n<h3><span id=\"Step_5_Enable_ufw\">Step 5: Enable ufw<\/span><\/h3>\n<p>Once your rules are in place:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo ufw enable\n<\/code><\/pre>\n<p>Confirm with:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo ufw status numbered\n<\/code><\/pre>\n<h3><span id=\"Step_6_Hardening_SSH_with_ufw_optional_but_recommended\">Step 6: Hardening SSH with ufw (optional but recommended)<\/span><\/h3>\n<p>For publicly reachable SSH, simple rate limiting helps against brute\u2011force attempts:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo ufw limit OpenSSH\n<\/code><\/pre>\n<p>This tells ufw to allow SSH but rate\u2011limit excessive connections from the same IP. For WordPress or PHP apps, we often combine ufw with Fail2ban and application hardening; you can see a firewall\u2011plus\u2011Fail2ban example in our <a href=\"https:\/\/www.dchost.com\/blog\/en\/wordpress-guvenlik-sertlestirme-kontrol-listesi-dosya-izinleri-salt-keys-xml-rpc-ufw-fail2ban-nasil-tatli-tatli-kurulur\/\">WordPress hardening checklist that uses ufw and Fail2ban together<\/a>.<\/p>\n<h3><span id=\"Step_7_IPv6_with_ufw\">Step 7: IPv6 with ufw<\/span><\/h3>\n<p>If your VPS has IPv6 (which we strongly recommend, especially given the ongoing IPv4 scarcity), make sure ufw is configured for it. Edit:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo nano \/etc\/ufw\/ufw.conf\n<\/code><\/pre>\n<p>Set:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">IPV6=yes\n<\/code><\/pre>\n<p>Then reload:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo ufw disable\nsudo ufw enable\n<\/code><\/pre>\n<p>From now on, your rules will apply to both IPv4 and IPv6.<\/p>\n<h2><span id=\"Configuring_firewalld_on_a_VPS\">Configuring firewalld on a VPS<\/span><\/h2>\n<p>On AlmaLinux, Rocky Linux and similar systems, <strong>firewalld<\/strong> is the preferred tool. It uses zones and services to structure rules.<\/p>\n<h3><span id=\"Step_1_Confirm_firewalld_is_running\">Step 1: Confirm firewalld is running<\/span><\/h3>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo systemctl status firewalld\n<\/code><\/pre>\n<p>If it is not active:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo systemctl enable --now firewalld\n<\/code><\/pre>\n<h3><span id=\"Step_2_Check_the_current_zone_and_interfaces\">Step 2: Check the current zone and interfaces<\/span><\/h3>\n<p>List active zones:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo firewall-cmd --get-active-zones\n<\/code><\/pre>\n<p>You will see something like:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">public\n  interfaces: eth0\n<\/code><\/pre>\n<p>The <code>public<\/code> zone is usually the default for your main interface.<\/p>\n<h3><span id=\"Step_3_Set_default_target_and_allow_SSH\">Step 3: Set default target and allow SSH<\/span><\/h3>\n<p>By default, the <code>public<\/code> zone uses a reasonably restrictive policy, but let\u2019s be explicit. To ensure we are denying by default and only allowing needed services:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo firewall-cmd --zone=public --set-target=DROP\n<\/code><\/pre>\n<p>Now, permit SSH in the public zone:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo firewall-cmd --zone=public --add-service=ssh --permanent\n<\/code><\/pre>\n<p>Reload to apply:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo firewall-cmd --reload\n<\/code><\/pre>\n<h3><span id=\"Step_4_Allow_HTTPHTTPS_and_other_services\">Step 4: Allow HTTP\/HTTPS and other services<\/span><\/h3>\n<p>Firewalld ships with service definitions for common protocols. For a web server:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo firewall-cmd --zone=public --add-service=http --permanent\nsudo firewall-cmd --zone=public --add-service=https --permanent\nsudo firewall-cmd --reload\n<\/code><\/pre>\n<p>For a custom TCP port, e.g. 8080 for an internal API:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo firewall-cmd --zone=public --add-port=8080\/tcp --permanent\nsudo firewall-cmd --reload\n<\/code><\/pre>\n<h3><span id=\"Step_5_Using_rich_rules_for_IPbased_restrictions\">Step 5: Using rich rules for IP\u2011based restrictions<\/span><\/h3>\n<p>Firewalld rich rules allow more complex matching. For example, permit MySQL only from <code>203.0.113.10<\/code>:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo firewall-cmd --zone=public --add-rich-rule='rule family=&quot;ipv4&quot; \n  source address=&quot;203.0.113.10&quot; port protocol=&quot;tcp&quot; port=&quot;3306&quot; accept' --permanent\nsudo firewall-cmd --reload\n<\/code><\/pre>\n<h3><span id=\"Step_6_Zones_for_private_interfaces\">Step 6: Zones for private interfaces<\/span><\/h3>\n<p>If your VPS has multiple interfaces (e.g. one public, one private VLAN), you can attach the private interface to a more permissive zone, such as <code>internal<\/code> or <code>trusted<\/code>:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo firewall-cmd --zone=internal --change-interface=eth1 --permanent\nsudo firewall-cmd --reload\n<\/code><\/pre>\n<p>Then allow MySQL freely inside the internal zone:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo firewall-cmd --zone=internal --add-service=mysql --permanent\nsudo firewall-cmd --reload\n<\/code><\/pre>\n<p>This kind of zoning becomes especially useful when you scale out to multiple VPSs (web, database, cache) in the same data center.<\/p>\n<h2><span id=\"Configuring_iptables_Directly\">Configuring iptables Directly<\/span><\/h2>\n<p>If you need full control, or your distribution does not ship ufw\/firewalld by default, you can configure <strong>iptables<\/strong> directly. Be extra careful: a typo can lock you out instantly.<\/p>\n<h3><span id=\"Step_1_Basic_IPv4_rules_for_a_web_server\">Step 1: Basic IPv4 rules for a web server<\/span><\/h3>\n<p>This is a minimal set for a single\u2011interface VPS that should:<\/p>\n<ul>\n<li>Allow established\/related traffic (replies to existing connections).<\/li>\n<li>Allow SSH (22), HTTP (80), HTTPS (443).<\/li>\n<li>Drop everything else inbound.<\/li>\n<\/ul>\n<p>You can test interactively:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo iptables -F\nsudo iptables -P INPUT DROP\nsudo iptables -P FORWARD DROP\nsudo iptables -P OUTPUT ACCEPT\n\n# Allow loopback\nsudo iptables -A INPUT -i lo -j ACCEPT\n\n# Allow established and related\nsudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n\n# Allow SSH\nsudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT\n\n# Allow HTTP\/HTTPS\nsudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT\nsudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT\n<\/code><\/pre>\n<p>Check the rules:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo iptables -L -n -v\n<\/code><\/pre>\n<h3><span id=\"Step_2_Restrict_SSH_to_a_specific_IP\">Step 2: Restrict SSH to a specific IP<\/span><\/h3>\n<p>If you want only one IP to reach SSH:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo iptables -A INPUT -p tcp -s 203.0.113.10 --dport 22 -j ACCEPT\n<\/code><\/pre>\n<p>and omit the more general <code>--dport 22<\/code> accept rule.<\/p>\n<h3><span id=\"Step_3_Persistent_iptables_rules\">Step 3: Persistent iptables rules<\/span><\/h3>\n<p>On many distributions, iptables rules do not survive a reboot unless you save them. On Debian\/Ubuntu, you can use <code>iptables-persistent<\/code>:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo apt install iptables-persistent\nsudo netfilter-persistent save\n<\/code><\/pre>\n<p>On RHEL\u2011like systems, you can write rules into a script (e.g. <code>\/etc\/iptables.rules<\/code>) and load them via <code>rc.local<\/code> or a systemd unit on boot. Whatever method you choose, test a reboot window when you still have out\u2011of\u2011band access (for example, the VPS console in the dchost.com panel) so you can recover if something goes wrong.<\/p>\n<h3><span id=\"Step_4_Dont_forget_IPv6_ip6tables\">Step 4: Don\u2019t forget IPv6 (ip6tables)<\/span><\/h3>\n<p>If your VPS is IPv6\u2011enabled, you must mirror your firewall philosophy for IPv6 as well, otherwise you risk having a locked\u2011down IPv4 side and a wide\u2011open IPv6 side.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">sudo ip6tables -F\nsudo ip6tables -P INPUT DROP\nsudo ip6tables -P FORWARD DROP\nsudo ip6tables -P OUTPUT ACCEPT\n\nsudo ip6tables -A INPUT -i lo -j ACCEPT\nsudo ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n\nsudo ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT\nsudo ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT\nsudo ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT\n<\/code><\/pre>\n<p>If you want a deeper IPv6 perspective, including DNS, email and hosting side considerations, we covered it in our article on <a href=\"https:\/\/www.dchost.com\/blog\/en\/vps-sunucunuzda-ipv6-kurulum-ve-yapilandirma-rehberi-2\/\">IPv6 setup and configuration for VPS servers<\/a>.<\/p>\n<h2><span id=\"Common_RealWorld_Scenarios_and_Tips\">Common Real\u2011World Scenarios and Tips<\/span><\/h2>\n<h3><span id=\"Running_Docker_on_a_VPS_with_a_firewall\">Running Docker on a VPS with a firewall<\/span><\/h3>\n<p>Docker manipulates iptables rules automatically, which can surprise you if you also manage iptables directly. A few guidelines:<\/p>\n<ul>\n<li>With ufw or firewalld, it is usually safe to let Docker manage its own NAT and forward rules while you control which ports are exposed via Docker\u2019s <code>-p<\/code> mappings.<\/li>\n<li>If you write raw iptables rules, add them in a way that coexists with Docker chains (e.g. insert your rules at appropriate positions, avoid flushing tables indiscriminately).<\/li>\n<li>Consider using a reverse proxy (Nginx, Caddy, Traefik) on the host and expose only that proxy\u2019s ports at the firewall layer.<\/li>\n<\/ul>\n<h3><span id=\"cPanel_DirectAdmin_and_other_hosting_panels\">cPanel, DirectAdmin and other hosting panels<\/span><\/h3>\n<p>Many control panels install their own firewall helpers or expect certain ports to stay open (panel ports, mail ports, FTP\/SFTP ports, etc.). When you use a panel on a VPS from dchost.com, make a list of:<\/p>\n<ul>\n<li>Panel access ports (e.g. 2083 for cPanel\u2019s HTTPS, depending on configuration).<\/li>\n<li>Mail ports if you run your own mail server (25, 465, 587, 993, 995, etc.).<\/li>\n<li>Passive FTP ranges <em>if<\/em> you still support FTP (ideally, use SFTP only).<\/li>\n<\/ul>\n<p>Then explicitly allow only those ports you actually use. If you are moving away from FTP to SFTP for security, our step\u2011by\u2011step guide <a href=\"https:\/\/www.dchost.com\/blog\/en\/ftp-yerine-sftp-kullanmanin-zamani-geldi\/\">on switching from FTP to SFTP<\/a> pairs well with tightening your firewall rules.<\/p>\n<h3><span id=\"Rate_limiting_and_bruteforce_protection\">Rate limiting and brute\u2011force protection<\/span><\/h3>\n<p>Some attacks are not just about reaching a port, but about hammering it with repeated attempts. Your firewall can help:<\/p>\n<ul>\n<li><strong>ufw<\/strong> has the <code>limit<\/code> option for basic SSH rate limiting.<\/li>\n<li><strong>iptables<\/strong> can use the <code>recent<\/code> or <code>hashlimit<\/code> modules for more advanced rules.<\/li>\n<li>You can combine firewall rules with Fail2ban to dynamically ban misbehaving IPs based on log patterns.<\/li>\n<\/ul>\n<p>For HTTP\u2011level protections (bots, abusive crawlers, API overuse), you should complement your server\u2011side firewall with proper rate limiting at the web stack or CDN level. We covered real\u2011world strategies in our article on <a href=\"https:\/\/www.dchost.com\/blog\/en\/api-ve-mikroservisler-icin-rate-limiting-stratejileri-nginx-cloudflare-ve-redis-ile-trafik-kontrolu\/\">rate limiting for APIs and microservices with Nginx and Cloudflare<\/a>.<\/p>\n<h3><span id=\"Logging_and_monitoring_your_firewall\">Logging and monitoring your firewall<\/span><\/h3>\n<p>A firewall rule that drops traffic silently is only half useful; you also want visibility. Depending on your tool:<\/p>\n<ul>\n<li><strong>ufw<\/strong> can log to <code>\/var\/log\/ufw.log<\/code> when logging is enabled (<code>sudo ufw logging on<\/code>).<\/li>\n<li><strong>firewalld<\/strong> can log via <code>firewall-cmd --set-log-denied=all<\/code> (or <code>unicast<\/code>\/<code>broadcast<\/code>), integrating with systemd journals.<\/li>\n<li><strong>iptables<\/strong> can use the <code>LOG<\/code> target to send drops to syslog.<\/li>\n<\/ul>\n<p>Once logs are flowing, integrate them into your monitoring stack. We have a dedicated playbook for this: <a href=\"https:\/\/www.dchost.com\/blog\/en\/vps-log-yonetimi-nasil-rayina-oturur-grafana-loki-promtail-ile-merkezi-loglama-tutma-sureleri-ve-alarm-kurallari\/\">VPS log management with Grafana Loki and Promtail<\/a> shows how to centralise logs and build useful alerts.<\/p>\n<h2><span id=\"Verification_Testing_and_Safe_Change_Management\">Verification, Testing and Safe Change Management<\/span><\/h2>\n<p>Any firewall change can cut off legitimate traffic as easily as it blocks attacks. A small, disciplined workflow helps keep things safe.<\/p>\n<h3><span id=\"Always_test_connectivity_after_changes\">Always test connectivity after changes<\/span><\/h3>\n<ul>\n<li>From your own machine, verify SSH and panel access after each rule change.<\/li>\n<li>Use tools like <code>curl -v<\/code> or <code>nc -vz<\/code> to test specific ports from outside.<\/li>\n<li>From the server, use <code>ss -tulpn<\/code> or <code>netstat<\/code> (if installed) to confirm which ports are actually listening.<\/li>\n<\/ul>\n<h3><span id=\"Keep_a_rescue_window_open\">Keep a rescue window open<\/span><\/h3>\n<p>When applying risky firewall changes on a production VPS:<\/p>\n<ul>\n<li>Keep an active SSH session open while you experiment in another session.<\/li>\n<li>On dchost.com VPS plans, have the console\/serial access ready in your panel in case you lock out SSH.<\/li>\n<li>Consider time\u2011limited rules first. Some admins use simple scripts that rollback to a known\u2011good ruleset if they do not confirm within N minutes.<\/li>\n<\/ul>\n<h3><span id=\"Document_and_version_your_firewall_rules\">Document and version your firewall rules<\/span><\/h3>\n<p>Once your firewall becomes more than a handful of rules, treat it like code:<\/p>\n<ul>\n<li>Store your ufw\/app profiles, firewalld zone definitions or iptables scripts in Git.<\/li>\n<li>Write comments explaining why a rule exists, not just what it does.<\/li>\n<li>Update documentation when services are added or removed; pruned firewall rules reduce attack surface.<\/li>\n<\/ul>\n<h2><span id=\"Bringing_It_All_Together_on_dchostcom_VPS_Servers\">Bringing It All Together on dchost.com VPS Servers<\/span><\/h2>\n<p>When you spin up a new VPS with us, you control the operating system, panel and stack, but the network perimeter is shared: our data center edge, DDoS protection and routing policies form the outer rings. Your <strong>firewall on the VPS<\/strong> is the inner, application\u2011aware ring you can fully own.<\/p>\n<p>A sensible progression for many customers looks like this:<\/p>\n<ol>\n<li>Start on Ubuntu or Debian with <strong>ufw<\/strong>, open only SSH and HTTP\/HTTPS, and deploy your first site.<\/li>\n<li>As you grow into multi\u2011service stacks (separate database, cache, internal APIs), adopt <strong>firewalld<\/strong> zones or more structured ufw rules.<\/li>\n<li>For advanced setups (custom VPN, internal load balancers, multi\u2011network routing), maintain a curated <strong>iptables<\/strong> (or nftables) ruleset and integrate it into your configuration management.<\/li>\n<\/ol>\n<p>Throughout that journey, you do not need to guess or reinvent everything on your own. We keep publishing practical, real\u2011world examples on our blog\u2014covering everything from firewall design and SSH hardening to performance tuning and HTTPS security\u2014so that each new VPS feels more like a repeatable pattern than a one\u2011off experiment.<\/p>\n<p>If you are planning a new project and want to align firewall design with hosting architecture (single VPS, multi\u2011VPS, or a mix of VPS and colocation), you can always start with our articles on <a href=\"https:\/\/www.dchost.com\/blog\/en\/dedicated-sunucu-mu-vps-mi-hangisi-isinize-yarar\/\">choosing between dedicated servers and VPS<\/a> and on <a href=\"https:\/\/www.dchost.com\/blog\/en\/managed-vs-unmanaged-vps-hosting-hangi-is-yuku-icin-hangisi-dogru\/\">managed vs unmanaged VPS responsibilities<\/a>, then layer this firewall guide on top.<\/p>\n<p>The important part is consistency: choose a tool (ufw, firewalld or iptables), define a minimal, documented baseline, and evolve it carefully as your VPS and applications grow. With that mindset, your firewall stops being an obscure, fragile script and becomes a predictable, trusted component of your hosting stack.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>If you are running a VPS, your firewall is not a nice-to-have add\u2011on; it is one of the core layers that decides who can talk to your server and how. Whether you host a small WordPress site, a Laravel API, a game server or a full e\u2011commerce stack, a properly configured firewall often makes the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3494,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-3493","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\/3493","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=3493"}],"version-history":[{"count":0,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/3493\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media\/3494"}],"wp:attachment":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media?parent=3493"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/categories?post=3493"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/tags?post=3493"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}