---
title: "OpenWrt 裝 Tailscale：防火牆 zone、subnet router 與 exit node"
description: "在 OpenWrt 路由器上安裝官方 feed 的 tailscale 與 luci-app-tailscale-community 套件，建立 tailscale0 專用防火牆 zone（masquerade 與 MSS clamping 的 UCI 寫法），並說明 --snat-subnet-routes=false 的意義與當 subnet router、exit node 的完整設定和最小權限 grants"
---

> Documentation Index
> Fetch the complete documentation index at: https://tailscale.tw/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenWrt 裝 Tailscale：防火牆 zone、subnet router 與 exit node

把 Tailscale 裝在 OpenWrt 路由器上，整條區網的裝置（印表機、IP Cam、NAS、IoT）就能一次進 tailnet，也能讓路由器當 [Subnet Router](/features/subnet-router/) 或 [Exit Node](/features/exit-node/)，出門在外照樣連回家。這篇講官方 feed 的套件、防火牆 zone 的設定，以及兩個最常見的角色怎麼落地。

> 本文依 2026 年 10 月的 Tailscale 官方文件與 OpenWrt 官方 wiki 整理，以 Tailscale v1.104、OpenWrt 25.12.5（2026 年 7 月 1 日發佈）為準；OpenWrt 25.12 官方 feed 的 `tailscale` 套件版本為 1.102.3。本文未在實機刷機與安裝，屬文件整理。

## 套件：官方 feed 的 tailscale 與 luci-app-tailscale-community

OpenWrt 25.12 起，套件管理從 **opkg** 換成 **apk**（Alpine Package Keeper），安裝指令也跟著改：

```bash
apk update
apk add tailscale
```

舊的 `opkg update && opkg install tailscale` 在 25.12 上已不適用。官方有 [opkg 到 apk 的對照表](https://openwrt.org/docs/guide-user/additional-software/opkg-to-apk-cheatsheet)可參考。

兩個套件的現況（依 [openwrt/packages](https://github.com/openwrt/packages) 的 `openwrt-25.12` 分支、[openwrt/luci](https://github.com/openwrt/luci) 的 `openwrt-25.12` 分支，以及 downloads.openwrt.org 25.12.5 的套件索引核對）：

- **`tailscale`**：官方 feed 收錄，25.12 的版本是 **1.102.3-r1**（上游穩定版此時已是 v1.104，feed 版本會落後幾個版本）。它把 `tailscaled` 與 `tailscale` 指令一起裝到 `/usr/sbin`，並附 `/etc/config/tailscale` 設定檔與 procd 啟動腳本。套件的設定檔預設 `fw_mode 'nftables'`——也就是說，官方套件預設就讓 tailscaled 用 **nftables** 管理防火牆規則，與 OpenWrt 22.03 起預設的 fw4/nftables 一致。
- **`luci-app-tailscale-community`**：**確實存在於官方 feed**，而且是 **25.12 起才收錄**（24.10 分支查不到）。它提供 LuCI 網頁介面來查看狀態、設定節點與 daemon，維護者是 Tokisaki-Galaxy（上游為 [luci-app-tailscale-community](https://github.com/tokisaki-galaxy/luci-app-tailscale-community)），並附繁中（`luci-i18n-tailscale-community-zh-tw`）與簡中翻譯套件。想用圖形介面就加裝：

  ```bash
  apk add luci-app-tailscale-community
  ```

想純指令操作，只裝 `tailscale` 就夠了；本文接下來的設定都以指令為主。

## 防火牆：給 tailscale0 專用 zone

Tailscale 建立自己的網路介面 `tailscale0`，但 OpenWrt 的防火牆（fw4）不會自動知道它，所以要在防火牆裡替它開一個**專用 zone**，否則 tailnet 的流量會被擋。官方 wiki 的步驟（LuCI 與 UCI 兩種寫法）如下。

### 建立 unmanaged 介面

先替 `tailscale0` 建立一個 unmanaged 介面（名稱就叫 `tailscale`），讓防火牆有東西可以認。UCI 寫法：

```bash
uci set network.tailscale=interface
uci set network.tailscale.proto='none'
uci set network.tailscale.device='tailscale0'
uci commit network
```

對應 LuCI：**Network → Interfaces → Add new interface**，Protocol 選 **Unmanaged**、Device 選 **tailscale0**。官方 wiki 另外建議在該介面的 DHCP 設定裡按 **Set up DHCP Server** 再勾 **Ignore interface**（只為了在 dnsmasq 註冊這個介面、不實際發 DHCP），這一步主要影響 MagicDNS，見後文。

### 建立 firewall zone

接著建立 zone。關鍵選項（依 fw4 的 [firewall 設定文件](https://openwrt.org/docs/guide-user/firewall/firewall_configuration)）：

```bash
uci add firewall zone
uci set firewall.@zone[-1].name='tailscale'
uci set firewall.@zone[-1].network='tailscale'
uci set firewall.@zone[-1].input='ACCEPT'
uci set firewall.@zone[-1].output='ACCEPT'
uci set firewall.@zone[-1].masq='1'
uci set firewall.@zone[-1].mtu_fix='1'
uci commit firewall
```

各選項的意義：

- **`input ACCEPT`／`output ACCEPT`**：允許 tailnet 的裝置連到路由器本身（例如 SSH、LuCI），也允許路由器主動連出去。想鎖緊一點，可以把 `input` 改成 `REJECT` 再另外開放特定埠。
- **`masq '1'`**：對從這個 zone 出去的流量做 **masquerade**（來源位址轉譯）。這讓 tailnet 來的封包轉進區網時，區網裝置看到的來源是路由器的區網 IP，回程封包才會走對。可以用 `masq_src` 把轉譯範圍限縮到特定來源網段（例如只對 `100.64.0.0/10` 做）。
- **`mtu_fix '1'`**：開啟 **MSS clamping**。WireGuard 的封包比一般以太網略大，不做 MSS clamping 的話，某些 MTU 較小的連線（例如 PPPoE）會出現「小封包正常、大封包卡住」的症狀。官方 wiki 明確建議開啟。
- **`forward` 不用設**：zone 的 forward 政策只在同一個 zone 內有多個介面時才有作用；這裡的 `tailscale` zone 只涵蓋 `tailscale0` 一個介面，跨 zone 的放行由下一節的 forwarding 規則決定，所以官方 wiki 範例也把它留預設。

對應 LuCI：**Network → Firewall → Zones → Add**，Name 填 `tailscale`，Input／Output 設 ACCEPT，勾 **Masquerading** 與 **MSS Clamping**，Covered networks 選 `tailscale`，Forward 留預設。

### forwarding：讓流量進出

zone 只是「分類」，實際放行要看 forwarding。依照角色加：

**當 subnet router**（tailnet → 區網）：

```bash
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='tailscale'
uci set firewall.@forwarding[-1].dest='lan'
uci commit firewall
```

**當 exit node**（tailnet → 網際網路，要讓對外流量從這台出去）：

```bash
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='tailscale'
uci set firewall.@forwarding[-1].dest='wan'
uci commit firewall
```

**要讓區網裝置反過來連 tailnet 或走遠端 exit node**（區網 → tailnet），再補一條 `src='lan'`、`dest='tailscale'`：

```bash
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='lan'
uci set firewall.@forwarding[-1].dest='tailscale'
uci commit firewall
```

改完統一重載：

```bash
/etc/init.d/firewall reload
```

forwarding 是單向的，要雙向就各寫一條（`src`／`dest` 對調）。注意 `fw4 reload` 會印出解析結果，看到錯誤要先處理。

## 為什麼不要用舊教學的 --netfilter-mode=off

網路上的舊教學常要人加 `--netfilter-mode=off`，現在這不但不需要，反而該避免。

先講它做什麼。Tailscale 在 Linux 上會自己維護一套 netfilter 規則（放行 tailnet 流量、擋掉沒走 `tailscale0` 的 CGNAT 流量等）。`--netfilter-mode` 控制這個行為，有三個值（依官方 [netfilter modes](https://tailscale.com/kb/1593/netfilter-modes) 文件與 v1.104 原始碼）：

| 值         | 行為                                                                                      |
| ---------- | ----------------------------------------------------------------------------------------- |
| `on`       | **預設**。Tailscale 建立並管理自己的規則（nftables 用獨立 table、掛在高優先權的 hook 上） |
| `nodivert` | 建立規則但不啟用，由你自己決定何時把流量導進去                                            |
| `off`      | **完全不建立、不管理任何防火牆規則**，全部要你自己寫                                      |

官方文件對 `off` 的態度很明確：**「通常沒有好理由把 netfilter mode 設成 off」**，只有 `nodivert` 也滿足不了的特殊需求才該用；設成 `off` 之後，原本 Tailscale 會自動建立的規則（包括放行 tailnet 流量的規則）都得你手動補齊。原始碼裡，除了 Synology 特例預設 `off`，其他平台預設都是 `on`。

舊教學為什麼這麼寫？OpenWrt 22.03 起就改用 fw4/nftables（fw3/iptables 是 21.02 以前的事），但 22.03 當時收錄的 tailscale 套件還不支援 nftables（Tailscale 到 v1.48 才加入 nftables 支援），無法自動設定防火牆規則，導致 tailscaled 初始化失敗、流量轉發異常。所以官方 wiki 的 Troubleshooting 才叫人加 `--netfilter-mode=off`，關掉 Tailscale 的 netfilter 管理、自己手動放行；官方 wiki 也記載這個問題在後續套件版本已修正，**OpenWrt 23.0.5 之後不再需要這一步**。現在官方套件預設就設 `TS_DEBUG_FIREWALL_MODE=nftables`（見 `/etc/config/tailscale` 的 `fw_mode` 選項），Tailscale 走 nftables、由 fw4 的 zone 統一管理，就沒有關掉它的理由了。

所以：**別加 `--netfilter-mode=off`**。照前一節建好 zone 與 forwarding，讓 Tailscale 維持預設的 `on`，防火牆交給 fw4 管就好。

## --snat-subnet-routes=false 的意義

`--snat-subnet-routes` 控制 Tailscale 要不要對「轉往 subnet route 的流量」做來源位址轉譯（SNAT）。預設是 `true`：區網裝置看到的是 Subnet Router 本身的位址，回程自然走得回來。

官方 OpenWrt wiki 建議在路由器上加 `--snat-subnet-routes=false`，理由和前一節的 firewall zone 相扣：**zone 已經開了 masquerade**，fw4 會在封包轉進區網時做 NAT；如果 Tailscale 也做 SNAT，就變成兩層 NAT（雙重 NAT），既多餘、除錯時也容易搞混。關掉 Tailscale 的 SNAT，讓 fw4 的 masquerade 統一處理，是 OpenWrt 上比較乾淨的組合。

要留意的點：

- **這不表示會保留真實來源 IP**。只要 zone 的 `masq` 還開著，區網裝置看到的來源仍然是路由器的區網 IP。想要區網裝置看到 tailnet 對端真正的 `100.x.y.z` 位址，除了 `--snat-subnet-routes=false`，還要把 zone 的 `masq` 關掉，並替區網加一條回程路由，把 `100.64.0.0/10` 指向路由器。完整說明見 [Subnet Router 的 SNAT 一節](/features/subnet-router/#snat來源-ip-的問題)。
- **和 exit node 衝突**。同一台裝置同時當 exit node、又關掉 SNAT，可能造成上游丟包，官方建議把兩種角色拆開。見[同篇的提醒](/features/subnet-router/#snat來源-ip-的問題)。
- 這個旗標**只有 Linux 支援**（OpenWrt 是 Linux，沒問題）。

## 當 subnet router

把路由器所在的區網廣告進 tailnet，其他裝置就能存取區網內沒裝 Tailscale 的設備。假設區網是 `192.168.1.0/24`：

```bash
tailscale set --advertise-routes=192.168.1.0/24 --snat-subnet-routes=false
tailscale up
```

OpenWrt 的核心預設已開啟 IP forwarding，不必像一般 Linux 那樣改 `/etc/sysctl.conf`（要確認的話：`sysctl net.ipv4.ip_forward` 應為 `1`）。接著到 [Admin console](https://console.tailscale.com/admin/machines) 找到這台路由器，進 **Edit route settings** 核准網段，並建議替它 **Disable key expiry**（或改用 tag，見下文），路由器要常開。

區網網段不是 `192.168.1.0/24` 就換成你自己的。觀念與其他平台（`--accept-routes`、路由核准、用戶端設定）見 [Subnet Router](/features/subnet-router/)。

## 當 exit node

讓所有上網流量都從這台路由器出去：

```bash
tailscale set --advertise-exit-node
tailscale up
```

依官方文件，`--advertise-exit-node` 用 `tailscale set` 下完，要再跑一次 `tailscale up` 才生效。接著在 Admin console 核准，其他裝置就能把它選為 exit node。詳情見 [Exit Node](/features/exit-node/)。

> 同一台要兼當 subnet router 和 exit node 可以（保持 SNAT 預設開啟即可），但別再配 `--snat-subnet-routes=false`（見上一節的衝突提醒）。想要「關 SNAT 的 subnet router」又同時要 exit node，官方建議拆到兩台裝置。

## 存取規則與 autoApprovers

預設 policy 下，tailnet 裡所有人都能用你核准的 subnet router 和 exit node。要收緊，先替路由器打 tag（tagged 裝置預設金鑰不過期，也方便在 policy 裡指定）：

```bash
tailscale up --advertise-tags=tag:openwrt
```

`--advertise-tags` 是 `tailscale up` 的旗標（`tailscale set` 沒有這個選項）。打 tag 必須以該 tag 的 owner 身分重新認證才會生效：如果裝置已經用其他使用者登入，加上 `--force-reauth` 強制重新認證，或用帶 tag 的 auth key 登入；tag 也必須先在 policy 的 `tagOwners` 授權給你，否則會被拒絕。

然後在 tailnet policy file 裡寫最小權限。假設網段是 `192.168.1.0/24`：

```json
{
  "tagOwners": {
    "tag:openwrt": ["autogroup:admin"]
  },
  "autoApprovers": {
    "routes": {
      "192.168.1.0/24": ["tag:openwrt"]
    },
    "exitNode": ["tag:openwrt"]
  },
  "grants": [
    {
      "src": ["autogroup:member"],
      "dst": ["192.168.1.0/24"],
      "ip": ["tcp:631"]
    },
    {
      "src": ["autogroup:member"],
      "dst": ["autogroup:internet"],
      "ip": ["*"],
      "via": ["tag:openwrt"]
    }
  ]
}
```

說明：

- 第一條 grant 放行「經由這台路由器連到區網網段」的印表機（subnet router）：`ip` 用 `"tcp:631"` 只開放 IPP 列印埠。想開放整個網段所有埠，就把 `ip` 改成 `["*"]`。
- 第二條放行「經由這台路由器上網」（exit node）。目的地要寫 **`autogroup:internet`**（不是裝置 IP），`via` 指定只能走打上 `tag:openwrt` 的出口。`via` 只接受 tag。
- `autoApprovers` 讓這台 tag 裝置廣告的網段與 exit node 自動核准，不用每次去後台點；它只在**第一次廣告**時生效，改 policy 不會回頭核准既有未核准的路由。

`grants` 與 `autoApprovers` 的完整語法見 [ACL / Grants 入門](/admin/acl-grants/)、[Tags 與 auth key](/admin/tags-auth-keys/)，以及 [Subnet Router](/features/subnet-router/) 和 [Exit Node](/features/exit-node/) 各自的「存取規則」一節。

## DNS 與 MagicDNS

路由器預設會吃 Tailscale 的 DNS 設定（`--accept-dns`），而 OpenWrt 上沒有一般的 DNS 管理程式，Tailscale 會**直接覆寫 `/etc/resolv.conf`**，和負責區網 DNS 的 dnsmasq 打架。路由器自己只是閘道、不需要當 tailnet 的 DNS client，所以關掉它：

```bash
tailscale set --accept-dns=false
/etc/init.d/tailscale restart
```

重啟讓設定立即生效（官方 wiki 也建議這一步）。想要讓區網裝置也能用 MagicDNS 名稱（`*.ts.net`）解析 tailnet 裡的主機，官方 wiki 的建議是把 Tailscale 的 resolver 加進 dnsmasq，而不是讓路由器吃 MagicDNS：

```bash
uci add_list dhcp.@dnsmasq[0].server='/ts.net/100.100.100.100'
uci commit dhcp
/etc/init.d/dnsmasq restart
```

這樣區網裝置查 `*.ts.net` 時會轉給 `100.100.100.100`（MagicDNS），其他查詢照走原本的 DNS。詳細背景見官方 [Why is resolv.conf being overwritten?](https://tailscale.com/docs/reference/faq/dns-resolv-conf)。

## 小結

| 步驟                  | 做什麼                                                                                                      |
| --------------------- | ----------------------------------------------------------------------------------------------------------- |
| `apk add tailscale`   | 裝官方 feed 套件（25.12 為 1.102.3；套件預設用 nftables）                                                   |
| unmanaged 介面 + zone | `tailscale0` 專屬 zone：`masq '1'`、`mtu_fix '1'`、input/output ACCEPT                                      |
| forwarding            | subnet router 加 `tailscale → lan`；exit node 加 `tailscale → wan`                                          |
| 廣告路由              | `tailscale set --advertise-routes=... --snat-subnet-routes=false`（避免雙重 NAT）或 `--advertise-exit-node` |
| 收尾                  | 關 MagicDNS（`--accept-dns=false`）、打 tag、核准路由或設 autoApprovers                                     |

最容易踩的三個坑：忘了建 firewall zone（tailnet 流量被擋）、沿襲舊教學加 `--netfilter-mode=off`（在 23.0.5 之後既多餘又更容易出錯）、`--snat-subnet-routes=false` 配 exit node（會衝突）。顧好這三個，路由器當 subnet router／exit node 就穩了。

## 延伸

- 路由器之外的其他平台：華碩機型走 [Asuswrt-Merlin + Entware](/platforms/asus-merlin/)，Docker 環境則見 [Docker 官方映像檔](/platforms/docker/)。
- subnet router 與 exit node 的完整觀念、`--accept-routes` 與效能調校（[UDP GRO](/performance/udp-gro-forwarding/)、[BBR](/performance/bbr/)），見 [Subnet Router](/features/subnet-router/) 與 [Exit Node](/features/exit-node/)。
- 直連還是走 DERP 中繼，影響路由器當出口時的延遲，見[直連與 DERP](/troubleshooting/direct-vs-derp/)。

## 參考資料

- [Tailscale（OpenWrt 官方 wiki）](https://openwrt.org/docs/guide-user/services/vpn/tailscale/start)
- [Firewall configuration /etc/config/firewall（OpenWrt 官方 wiki）](https://openwrt.org/docs/guide-user/firewall/firewall_configuration)
- [opkg 到 apk 對照表（OpenWrt 官方 wiki）](https://openwrt.org/docs/guide-user/additional-software/opkg-to-apk-cheatsheet)
- [openwrt/packages 的 tailscale 套件（openwrt-25.12 分支）](https://github.com/openwrt/packages/tree/openwrt-25.12/net/tailscale)
- [openwrt/luci 的 luci-app-tailscale-community（openwrt-25.12 分支）](https://github.com/openwrt/luci/tree/openwrt-25.12/applications/luci-app-tailscale-community)
- [luci-app-tailscale-community（上游，Tokisaki-Galaxy）](https://github.com/tokisaki-galaxy/luci-app-tailscale-community)
- [Tailscale netfilter modes（官方）](https://tailscale.com/kb/1593/netfilter-modes)
- [Firewall mode in tailscaled（官方）](https://tailscale.com/docs/features/firewall-mode)
- [Subnet routers（官方）](https://tailscale.com/kb/1019/subnets)
- [Exit nodes（官方）](https://tailscale.com/kb/1103/exit-nodes)
- [Why is resolv.conf being overwritten?（官方）](https://tailscale.com/docs/reference/faq/dns-resolv-conf)
- [Subnet Router：存取整個區網內沒裝 Tailscale 的設備](/features/subnet-router/)
- [Exit Node：讓所有流量經由指定裝置出去](/features/exit-node/)

Source: https://tailscale.tw/platforms/openwrt/index.mdx
