{"id":169190,"date":"2026-06-19T08:30:18","date_gmt":"2026-06-19T05:30:18","guid":{"rendered":"https:\/\/computingforgeeks.com\/?p=169190"},"modified":"2026-06-19T08:30:18","modified_gmt":"2026-06-19T05:30:18","slug":"configure-firewalld-opensuse-leap","status":"publish","type":"post","link":"https:\/\/computingforgeeks.com\/configure-firewalld-opensuse-leap\/","title":{"rendered":"Configure Firewalld on openSUSE Leap 16"},"content":{"rendered":"<p>A fresh openSUSE Leap 16 server is already running firewalld, and that is the first thing to verify rather than assume. Unlike many distributions where the firewall ships disabled, Leap 16 enables firewalld by default with a <code>public<\/code> zone that permits SSH and Cockpit. That default is sane, but the moment you add a database, an application port, or a second interface, you are making security decisions, and the failure mode is a port you opened for a quick test that stays open for a year. This guide shows how to configure firewalld on openSUSE Leap 16 deliberately: read the live state, open only what you need, scope rules to the sources that should reach them, and verify the result.<\/p>\n\n<p>The distinction that causes the most production incidents is runtime versus permanent rules, so that gets its own step with the exact behavior captured on a live box.<\/p>\n\n<p><em>Tested June 2026 on openSUSE Leap 16.0 with firewalld 2.1.2 active and SELinux enforcing.<\/em><\/p>\n\n<h2>Step 1: Read the live firewall state first<\/h2>\n\n<p>Before changing anything, look at what is already allowed. Here is the first Leap 16 quirk worth knowing: the informational firewall-cmd calls go through polkit, so even <code>--state<\/code> and <code>--version<\/code> fail for a normal user with an authorization error. Run them with sudo:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo firewall-cmd --state\nsudo firewall-cmd --version<\/code><\/pre>\n\n\n<p>You should see the daemon running on version 2.1.2:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>running\n2.1.2<\/code><\/pre>\n\n\n<p>Now read the default zone in full. This is the single most useful command in firewalld, because it shows exactly what is exposed:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo firewall-cmd --list-all<\/code><\/pre>\n\n\n<p>On a default Leap 16 install the <code>public<\/code> zone is active on your main interface and already permits SSH and Cockpit:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>public (default, active)\n  target: default\n  ingress-priority: 0\n  egress-priority: 0\n  icmp-block-inversion: no\n  interfaces: enp6s18\n  sources:\n  services: cockpit dhcpv6-client ssh\n  ports:\n  protocols:\n  forward: yes\n  masquerade: no\n  forward-ports:\n  source-ports:\n  icmp-blocks:\n  rich rules:<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"980\" height=\"560\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-firewalld-zone-config-opensuse-leap.png\" alt=\"firewalld list-all zone services and rich rule on openSUSE Leap 16\" class=\"wp-image-169181\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-firewalld-zone-config-opensuse-leap.png 980w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-firewalld-zone-config-opensuse-leap-300x171.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-firewalld-zone-config-opensuse-leap-768x439.png 768w\" sizes=\"auto, (max-width: 980px) 100vw, 980px\" \/><\/figure>\n\n\n<h2>Step 2: Understand zones before you touch a rule<\/h2>\n\n<p>firewalld groups rules into zones, and each network interface sits in exactly one zone. List the zones that ship with Leap 16:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo firewall-cmd --get-zones<\/code><\/pre>\n\n\n<p>Leap 16 ships the standard set plus container and virtualization zones:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>block dmz docker drop external home internal libvirt libvirt-routed nm-shared public trusted work<\/code><\/pre>\n\n\n<p>Check which zone owns your interfaces. On a box running Docker you will see two active zones, because the Docker daemon places <code>docker0<\/code> in its own zone:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo firewall-cmd --get-active-zones<\/code><\/pre>\n\n\n<p>The output names each zone and the interfaces bound to it:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>docker\n  interfaces: docker0\npublic (default)\n  interfaces: enp6s18<\/code><\/pre>\n\n\n<p>The practical rule: the zone applied to traffic is the zone of the interface it arrived on. Put your public-facing interface in <code>public<\/code> and a trusted management interface in <code>internal<\/code>, and the zone names stop being abstract.<\/p>\n\n<h2>Step 3: Open a service or a port the right way<\/h2>\n\n<p>Prefer named services over raw port numbers. A service definition carries the protocol and port together and reads clearly in an audit. Add HTTPS and reload to apply it:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo firewall-cmd --permanent --add-service=https\nsudo firewall-cmd --reload<\/code><\/pre>\n\n\n<p>Confirm the rule landed:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo firewall-cmd --list-services<\/code><\/pre>\n\n\n<p>The service now appears in the active set alongside the defaults:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>cockpit dhcpv6-client https ssh<\/code><\/pre>\n\n\n<p>When an application has no predefined service, open the port directly. This opens TCP 8080 for a custom app:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo firewall-cmd --permanent --add-port=8080\/tcp\nsudo firewall-cmd --reload\nsudo firewall-cmd --list-ports<\/code><\/pre>\n\n\n<p>The port shows in the list:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>8080\/tcp<\/code><\/pre>\n\n\n<h2>Step 4: Runtime versus permanent, the rule that bites people<\/h2>\n\n<p>Every firewall-cmd change is either runtime or permanent. A change without <code>--permanent<\/code> takes effect immediately but lives only in memory; a reload or reboot erases it. A change with <code>--permanent<\/code> is written to disk but does not apply until you reload. Confusing the two is how a rule you thought you saved vanishes after a reboot, and how a rule you thought you removed comes back.<\/p>\n\n<p>Add a runtime-only port and compare the two views. The runtime list shows it; the permanent list does not:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo firewall-cmd --add-port=9999\/tcp\nsudo firewall-cmd --list-ports\nsudo firewall-cmd --permanent --list-ports<\/code><\/pre>\n\n\n<p>Runtime carries both ports, permanent carries only the one saved earlier:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>8080\/tcp 9999\/tcp\n8080\/tcp<\/code><\/pre>\n\n\n<p>Reload, and the runtime-only port is gone, because reload re-reads the permanent configuration:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo firewall-cmd --reload\nsudo firewall-cmd --list-ports<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"980\" height=\"520\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-firewalld-runtime-permanent-opensuse-leap.png\" alt=\"firewalld runtime vs permanent ports demonstration on openSUSE Leap 16\" class=\"wp-image-169182\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-firewalld-runtime-permanent-opensuse-leap.png 980w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-firewalld-runtime-permanent-opensuse-leap-300x159.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-firewalld-runtime-permanent-opensuse-leap-768x408.png 768w\" sizes=\"auto, (max-width: 980px) 100vw, 980px\" \/><\/figure>\n\n\n<p>The safe workflow is to test a rule in runtime, confirm it does what you expect, then promote the whole runtime state to permanent in one move:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo firewall-cmd --runtime-to-permanent<\/code><\/pre>\n\n\n<h2>Step 5: Scope access with rich rules<\/h2>\n\n<p>Opening a database port to the whole internet is the kind of default that ends in a breach report. A rich rule lets you allow a service only from the network that should reach it. This permits MySQL from a single subnet and from nowhere else:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo firewall-cmd --permanent --add-rich-rule='rule family=\"ipv4\" source address=\"10.0.0.0\/24\" service name=\"mysql\" accept'\nsudo firewall-cmd --reload<\/code><\/pre>\n\n\n<p>List the rich rules to confirm the scope:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo firewall-cmd --list-rich-rules<\/code><\/pre>\n\n\n<p>The rule is now in force. Because MySQL is not opened anywhere else in the zone, the subnet in the rule is the only source that can reach it; a connection to that port from any other address matches no allow rule and is dropped:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>rule family=\"ipv4\" source address=\"10.0.0.0\/24\" service name=\"mysql\" accept<\/code><\/pre>\n\n\n<p>This is least privilege applied to the network: the port is reachable only by the hosts that have a reason to reach it.<\/p>\n\n<h2>Step 6: Block ping and trim the defaults<\/h2>\n\n<p>If policy says the host should not answer ICMP echo, block it without disabling the rest of ICMP, which carries useful path-MTU messages. Add it permanently so it survives a reboot, then reload:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo firewall-cmd --permanent --add-icmp-block=echo-request\nsudo firewall-cmd --reload\nsudo firewall-cmd --list-icmp-blocks<\/code><\/pre>\n\n\n<p>Equally, remove anything in the default zone you do not use. If a host is not a Cockpit management node, drop the Cockpit service so the port is not even listening to the firewall:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo firewall-cmd --permanent --remove-service=cockpit\nsudo firewall-cmd --reload<\/code><\/pre>\n\n\n<h2>Firewall audit checklist<\/h2>\n\n<p>Before you call the host done, run through this list. Each item is a command you have already used above, now turned into a verification.<\/p>\n\n<ol>\n<li><strong>Confirm firewalld is enabled at boot:<\/strong> <code>systemctl is-enabled firewalld<\/code> should return <code>enabled<\/code>, not just <code>active<\/code>. A firewall that does not survive a reboot is not a firewall.<\/li>\n<li><strong>Audit the open services and ports:<\/strong> <code>sudo firewall-cmd --list-all<\/code>. Every entry under <code>services<\/code> and <code>ports<\/code> must map to something actually running. If you cannot name what listens behind a rule, remove the rule.<\/li>\n<li><strong>Check the interface-to-zone mapping:<\/strong> <code>sudo firewall-cmd --get-active-zones<\/code>. A public-facing NIC must not be sitting in <code>trusted<\/code>.<\/li>\n<li><strong>Verify sensitive ports are scoped:<\/strong> <code>sudo firewall-cmd --list-rich-rules<\/code>. Database, cache, and admin ports should be source-restricted, never open to <code>0.0.0.0\/0<\/code>.<\/li>\n<li><strong>Persist the working state:<\/strong> after testing in runtime, run <code>sudo firewall-cmd --runtime-to-permanent<\/code> so a reboot keeps exactly what you verified.<\/li>\n<\/ol>\n\n<p>With the firewall scoped, the next layer is the services behind it, whether that is an <a href=\"https:\/\/computingforgeeks.com\/install-nginx-opensuse-leap\/\">nginx web server<\/a> or a Kubernetes node. The <a href=\"https:\/\/computingforgeeks.com\/opensuse-leap-initial-server-setup\/\">initial server setup and hardening<\/a> guide covers SSH and SELinux on the same host, and <a href=\"https:\/\/computingforgeeks.com\/cockpit-web-console-opensuse-leap\/\">Cockpit<\/a> can show the firewall and active services from the browser once you decide a host should be a management node.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A fresh openSUSE Leap 16 server is already running firewalld, and that is the first thing to verify rather than assume. Unlike many distributions where the firewall ships disabled, Leap 16 enables firewalld by default with a public zone that permits SSH and Cockpit. That default is sane, but the moment you add a database, &#8230; <a title=\"Configure Firewalld on openSUSE Leap 16\" class=\"read-more\" href=\"https:\/\/computingforgeeks.com\/configure-firewalld-opensuse-leap\/\" aria-label=\"Read more about Configure Firewalld on openSUSE Leap 16\">Read more<\/a><\/p>\n","protected":false},"author":13,"featured_media":169189,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[299,47,50],"tags":[282,9986,205],"cfg_series":[39887],"class_list":["post-169190","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-how-to","category-linux","category-linux-tutorials","tag-linux","tag-opensuse","tag-security","cfg_series-opensuse-leap-16"],"_links":{"self":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/169190","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/comments?post=169190"}],"version-history":[{"count":1,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/169190\/revisions"}],"predecessor-version":[{"id":169221,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/169190\/revisions\/169221"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media\/169189"}],"wp:attachment":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media?parent=169190"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/categories?post=169190"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/tags?post=169190"},{"taxonomy":"cfg_series","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/cfg_series?post=169190"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}