{"slug":"firewall-mode-in-tailscaled","title":"Firewall mode in tailscaled","tags":["tailscale"],"agent_summary":"Last validated: Dec 29, 2025","trigger_phrases":[],"runnable":false,"markdown":"\r\n# Firewall mode in tailscaled\r\n\r\nLast validated: Dec 29, 2025\r\n\r\nFirewall mode for [tailscaled](https://tailscale.com/docs/reference/tailscaled) refers to a router's selection among two firewall utilities,\r\n`iptables` and `nftables`, to manipulate firewalls (using [netfilter](https://tailscale.com/docs/reference/netfilter-modes)). This applies to Linux devices only. Up until Tailscale v1.48.0, Tailscale relied only on `iptables` to set firewall rules. As `nftables` is increasingly popular for its performance benefits, we added support to use `nftables` to manage Tailscale's firewall rules from the `nftables` Netlink API.\r\n\r\nOur way of manipulating firewall rules through `iptables` is by using the `iptables` binary. When Tailscale is running in `iptables` firewall mode, there must be a compatible `iptables` binary in the system `PATH`. On the other hand, we manipulate `nftables` through the `nftables` Netlink API, so it doesn't depend on the `nft` binary.\r\n\r\nThe use of `nftables` doesn't work in Tailscale when the Netlink API is disabled for [userspace networking mode](https://tailscale.com/docs/concepts/userspace-networking), which is not a common scenario.\r\n\r\n## [How to set the firewall mode](https://tailscale.com/docs/features/firewall-mode\\#how-to-set-the-firewall-mode)\r\n\r\nUsing the `TS_DEBUG_FIREWALL_MODE` environment variable to set the firewall mode is a temporary measure. Its use is subject to change and should not be considered as permanently supported.\r\n\r\nTailscale has a work-in-progress feature to detect whether the host system is currently using `iptables` or `nftables`\r\nso that it will also use the same firewall interface. It is possible to opt-in to this detection by setting the `TS_DEBUG_FIREWALL_MODE`\r\nenvironment variable to `auto`. It is also possible to explicitly test the specific firewall modes by setting `TS_DEBUG_FIREWALL_MODE`\r\nto one of the values below.\r\n\r\n| Value | Description |\r\n| --- | --- |\r\n| `auto` | A [heuristic](https://tailscale.com/docs/features/firewall-mode#heuristic) is used to decide between `iptables` and `nftables`. |\r\n| `iptables` | `iptables` is used. |\r\n| `nftables` | `nftables` is used. |\r\n| No value set | The default of `iptables` is used. |\r\n\r\nWhen using the `TS_DEBUG_FIREWALL_MODE` environment variable, set it in `/etc/default/tailscaled`.\r\n\r\n## [Firewall mode heuristic](https://tailscale.com/docs/features/firewall-mode\\#firewall-mode-heuristic)\r\n\r\nWhen `TS_DEBUG_FIREWALL_MODE` is set to `auto`, Tailscale will detect the firewall mode that other software on the system\r\nis already using. Tailscale will prefer `nftables` over `iptables` in the event that both are in use at the same time.\r\nWhen neither the `iptables` binary nor the `nftables` Netlink API are available, Tailscale will fall back to a degraded\r\noperation that may result in reduced performance or increased CPU usage. Packet filtering for traffic in and out of\r\nTailscale is always performed by packet filtering internal to Tailscale itself, so this configuration does not affect the\r\nsecurity of a Tailscale node or tailnet.\r\n\r\n## [Examples](https://tailscale.com/docs/features/firewall-mode\\#examples)\r\n\r\nTo set `iptables` as the firewall mode (this is the default if you don't set `TS_DEBUG_FIREWALL_MODE`):\r\n\r\n```shell\r\nTS_DEBUG_FIREWALL_MODE=iptables\r\n```\r\n\r\nTo set `nftables` as the firewall mode:\r\n\r\n```shell\r\nTS_DEBUG_FIREWALL_MODE=nftables\r\n```\r\n\r\nTo let Tailscale use the [heuristic](https://tailscale.com/docs/features/firewall-mode#heuristic) to set the firewall mode:\r\n\r\n```shell\r\nTS_DEBUG_FIREWALL_MODE=auto\r\n```\r\n\r\n## [How to verify it's working](https://tailscale.com/docs/features/firewall-mode\\#how-to-verify-its-working)\r\n\r\nIf you are running Tailscale outside of a container, you can verify the firewall mode by viewing the\r\n`tailscaled` log output via `journalctl`:\r\n\r\n```shell\r\njournalctl -ru tailscaled\r\n```\r\n\r\nIf you are running Tailscale inside a container, the way to view logs depends on the containerization\r\ntechnology being used.\r\n\r\nThe log should have three lines that start with `router:`, with the first line showing the rule count.\r\nThe second line shows the reason a firewall mode was chosen, and the third line shows the firewall\r\nmode currently in effect.\r\n\r\nThe log looks like the following when the `TS_DEBUG_FIREWALL_MODE` environment variable specifies\r\n`nftables`:\r\n\r\n```shell\r\nrouter: router: nftables rule count: 0, iptables rule count: 0\r\nrouter: router: envknob TS_DEBUG_FIREWALL_MODE=nftables set\r\nrouter: router: using nftables\r\n```\r\n\r\nSimilar output is shown when the `TS_DEBUG_FIREWALL_MODE` environment variable specifies `iptables`.\r\n\r\nWhen the firewall mode selection heuristic is used, the output looks like:\r\n\r\n```shell\r\nrouter: router: nftables rule count: 0, iptables rule count: 0\r\nrouter: router: nftables is available\r\nrouter: router: using nftables\r\n```\r\n\r\nThe possible reasons (shown in line 2 of the example output) are:\r\n\r\n- `iptables is available`\r\n- `iptables is currently in use`\r\n- `nftables is available`\r\n- `nftables is currently in use`\r\n\r\nWhen neither `iptables` or `nftables` is supported, `tailscaled` silently chooses `iptables`, and\r\ncreates a runner that doesn't do anything. This is a scenario that usually only advanced users\r\nexperience, when they don't need Tailscale to configure the firewall rules and they prefer to do it\r\nthemselves.\r\n\r\n![Project Logo](https://cdn.brandfetch.io/tailscale.com/fallback/lettermark/theme/dark/h/256/w/256/icon?c=1bfwsmEH20zzEfSNTed)\r\n\r\nAsk AI\r\n\r\nreCAPTCHA\r\n\r\nRecaptcha requires verification.\r\n\r\nprotected by **reCAPTCHA**\r\n","html":"<h1>Firewall mode in tailscaled</h1>\n<p>Last validated: Dec 29, 2025</p>\n<p>Firewall mode for <a href=\"https://tailscale.com/docs/reference/tailscaled\">tailscaled</a> refers to a router's selection among two firewall utilities,\r\n<code>iptables</code> and <code>nftables</code>, to manipulate firewalls (using <a href=\"https://tailscale.com/docs/reference/netfilter-modes\">netfilter</a>). This applies to Linux devices only. Up until Tailscale v1.48.0, Tailscale relied only on <code>iptables</code> to set firewall rules. As <code>nftables</code> is increasingly popular for its performance benefits, we added support to use <code>nftables</code> to manage Tailscale's firewall rules from the <code>nftables</code> Netlink API.</p>\n<p>Our way of manipulating firewall rules through <code>iptables</code> is by using the <code>iptables</code> binary. When Tailscale is running in <code>iptables</code> firewall mode, there must be a compatible <code>iptables</code> binary in the system <code>PATH</code>. On the other hand, we manipulate <code>nftables</code> through the <code>nftables</code> Netlink API, so it doesn't depend on the <code>nft</code> binary.</p>\n<p>The use of <code>nftables</code> doesn't work in Tailscale when the Netlink API is disabled for <a href=\"https://tailscale.com/docs/concepts/userspace-networking\">userspace networking mode</a>, which is not a common scenario.</p>\n<h2><a href=\"https://tailscale.com/docs/features/firewall-mode#how-to-set-the-firewall-mode\">How to set the firewall mode</a></h2>\n<p>Using the <code>TS_DEBUG_FIREWALL_MODE</code> environment variable to set the firewall mode is a temporary measure. Its use is subject to change and should not be considered as permanently supported.</p>\n<p>Tailscale has a work-in-progress feature to detect whether the host system is currently using <code>iptables</code> or <code>nftables</code>\r\nso that it will also use the same firewall interface. It is possible to opt-in to this detection by setting the <code>TS_DEBUG_FIREWALL_MODE</code>\r\nenvironment variable to <code>auto</code>. It is also possible to explicitly test the specific firewall modes by setting <code>TS_DEBUG_FIREWALL_MODE</code>\r\nto one of the values below.</p>\n<p>| Value | Description |\r\n| --- | --- |\r\n| <code>auto</code> | A <a href=\"https://tailscale.com/docs/features/firewall-mode#heuristic\">heuristic</a> is used to decide between <code>iptables</code> and <code>nftables</code>. |\r\n| <code>iptables</code> | <code>iptables</code> is used. |\r\n| <code>nftables</code> | <code>nftables</code> is used. |\r\n| No value set | The default of <code>iptables</code> is used. |</p>\n<p>When using the <code>TS_DEBUG_FIREWALL_MODE</code> environment variable, set it in <code>/etc/default/tailscaled</code>.</p>\n<h2><a href=\"https://tailscale.com/docs/features/firewall-mode#firewall-mode-heuristic\">Firewall mode heuristic</a></h2>\n<p>When <code>TS_DEBUG_FIREWALL_MODE</code> is set to <code>auto</code>, Tailscale will detect the firewall mode that other software on the system\r\nis already using. Tailscale will prefer <code>nftables</code> over <code>iptables</code> in the event that both are in use at the same time.\r\nWhen neither the <code>iptables</code> binary nor the <code>nftables</code> Netlink API are available, Tailscale will fall back to a degraded\r\noperation that may result in reduced performance or increased CPU usage. Packet filtering for traffic in and out of\r\nTailscale is always performed by packet filtering internal to Tailscale itself, so this configuration does not affect the\r\nsecurity of a Tailscale node or tailnet.</p>\n<h2><a href=\"https://tailscale.com/docs/features/firewall-mode#examples\">Examples</a></h2>\n<p>To set <code>iptables</code> as the firewall mode (this is the default if you don't set <code>TS_DEBUG_FIREWALL_MODE</code>):</p>\n<pre><code class=\"language-shell\">TS_DEBUG_FIREWALL_MODE=iptables\n</code></pre>\n<p>To set <code>nftables</code> as the firewall mode:</p>\n<pre><code class=\"language-shell\">TS_DEBUG_FIREWALL_MODE=nftables\n</code></pre>\n<p>To let Tailscale use the <a href=\"https://tailscale.com/docs/features/firewall-mode#heuristic\">heuristic</a> to set the firewall mode:</p>\n<pre><code class=\"language-shell\">TS_DEBUG_FIREWALL_MODE=auto\n</code></pre>\n<h2><a href=\"https://tailscale.com/docs/features/firewall-mode#how-to-verify-its-working\">How to verify it's working</a></h2>\n<p>If you are running Tailscale outside of a container, you can verify the firewall mode by viewing the\r\n<code>tailscaled</code> log output via <code>journalctl</code>:</p>\n<pre><code class=\"language-shell\">journalctl -ru tailscaled\n</code></pre>\n<p>If you are running Tailscale inside a container, the way to view logs depends on the containerization\r\ntechnology being used.</p>\n<p>The log should have three lines that start with <code>router:</code>, with the first line showing the rule count.\r\nThe second line shows the reason a firewall mode was chosen, and the third line shows the firewall\r\nmode currently in effect.</p>\n<p>The log looks like the following when the <code>TS_DEBUG_FIREWALL_MODE</code> environment variable specifies\r\n<code>nftables</code>:</p>\n<pre><code class=\"language-shell\">router: router: nftables rule count: 0, iptables rule count: 0\r\nrouter: router: envknob TS_DEBUG_FIREWALL_MODE=nftables set\r\nrouter: router: using nftables\n</code></pre>\n<p>Similar output is shown when the <code>TS_DEBUG_FIREWALL_MODE</code> environment variable specifies <code>iptables</code>.</p>\n<p>When the firewall mode selection heuristic is used, the output looks like:</p>\n<pre><code class=\"language-shell\">router: router: nftables rule count: 0, iptables rule count: 0\r\nrouter: router: nftables is available\r\nrouter: router: using nftables\n</code></pre>\n<p>The possible reasons (shown in line 2 of the example output) are:</p>\n<ul>\n<li><code>iptables is available</code></li>\n<li><code>iptables is currently in use</code></li>\n<li><code>nftables is available</code></li>\n<li><code>nftables is currently in use</code></li>\n</ul>\n<p>When neither <code>iptables</code> or <code>nftables</code> is supported, <code>tailscaled</code> silently chooses <code>iptables</code>, and\r\ncreates a runner that doesn't do anything. This is a scenario that usually only advanced users\r\nexperience, when they don't need Tailscale to configure the firewall rules and they prefer to do it\r\nthemselves.</p>\n<p><img src=\"https://cdn.brandfetch.io/tailscale.com/fallback/lettermark/theme/dark/h/256/w/256/icon?c=1bfwsmEH20zzEfSNTed\" alt=\"Project Logo\"></p>\n<p>Ask AI</p>\n<p>reCAPTCHA</p>\n<p>Recaptcha requires verification.</p>\n<p>protected by <strong>reCAPTCHA</strong></p>\n"}