SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-09-11

CGNAT 後方如何用 VPS 反向通道轉送連接埠

CGNAT 沒有公開 IP,連接埠轉送因此失效。使用便宜 VPS 執行 frp,讓家用主機主動建立通道,並在公開端以正式憑證終止 HTTPS。

CGNAT 後方的連接埠轉送為何沒有作用

在 CGNAT(電信業者級網路位址轉譯)後方,路由器的 WAN 位址會與其他用戶共用。因此,沒有任何公開 IP 位址專屬於你,也就沒有可供轉送的連接埠。反向通道可以解決這個問題:由低價 VPS 持有公開 IP 位址,家用主機主動連線至 VPS,外部請求再沿著家用主機已建立的連線返回。你可以繼續使用現有硬體,只需租用 ISP 不會提供給你的項目,也就是可路由的位址。

以下每個命令都標示其執行所在的機器。這需要兩台機器:具備公開 IP 位址的 VPS,以及執行你要存取之服務的家用主機。

如何判斷自己是否確實位於 CGNAT 後方

開啟路由器的管理頁面,查看它顯示的 WAN 位址。接著向網際網路查詢外部看到的位址。

# on the home box
curl -4 -s https://ifconfig.me; echo

如果兩個位址相同,表示你擁有公開 IP,無須進行以下操作。轉送連接埠後即可停止閱讀。如果路由器的 WAN 位址位於 100.64.0.0/10 內,表示你位於 CGNAT 後方。該區段是 RFC 6598 保留的共用位址空間,正是為此用途保留。有些 ISP 會改在 WAN 端配置 10.0.0.0/8,情況相同,只是使用不同的名稱。

租用任何服務前,先確認一件事。許多使用 CGNAT 的 ISP 會提供實際的 IPv6 前綴。如果家中的主機具有全域 IPv6 位址,你可以在該位址上開放防火牆,完全略過通道。只要訪客位於僅支援 IPv4 的網路上,這種方式就會失效;因此大多數人最後仍會使用本節的方法。

VPS 反向通道的運作方式:從內部向外撥號

CGNAT 與一般家用路由器都會封鎖未經請求的入站連線。企業防火牆也是如此。但它們不會封鎖出站連線,因為每個瀏覽器與更新用戶端都會持續建立出站連線。NAT 裝置偵測到出站 TCP 連線時,會為該連線建立對映,然後允許同一連線上的回傳流量。外部的任何裝置都無法主動連線到家中的主機。因此由家中的主機主動建立連線,再由通道沿著同一連線反向傳回流量。

這就是完整的運作機制。家中的主機透過某個連接埠連線到 VPS,並保持連線開啟。VPS 接收公開請求,再透過現有連線將請求傳送回家中的主機。整個過程都不需要嘗試連線到家中的 IP 位址,因此也不需要家用網路允許入站連線。

這會帶來兩個結果,而且都很實用。DNS 記錄會指向 VPS,而不是家中的網路。公開位址現在是 VPS 的位址,因此觀察者透過 IP 查詢所取得的資訊,會指向租用的伺服器,而不是家用網路。

建置方式有 3 種

  1. ssh -R:兩端都已安裝,適合單一服務或臨時示範。不提供儀表板,也沒有實質的重新連線機制。
  2. frp:小型 Go 伺服器(frps)與相應的用戶端(frpc)。適合將多個服務置於同一個主機名稱後方的長期部署。本指南主要介紹這種方式。
  3. 網狀 VPN:Tailscale,或自行執行的 WireGuard 伺服器。適合讓自有裝置彼此私下連線,而不是將服務發布到公開網際網路。

如果你的目標是讓自有裝置私下存取,請選擇網狀 VPN。Tailscale Serve 與 Funnel 說明如何將服務發布到 tailnet 外部;同一台 VPS 上自行託管的 WireGuard VPN 則提供相同的架構,且連線路徑中不需要第三方協調伺服器。閱讀其中一篇後即可略過本頁其餘內容。以下內容都假設你要使用任何人都能載入的公開 HTTPS 主機名稱。

快速版本:使用 ssh -R 為單一服務建立通道

假設家中主機在 127.0.0.1:3000 上執行應用程式,而且您已能透過 SSH 存取 VPS。

# on the home box
ssh -N \
  -o ExitOnForwardFailure=yes \
  -o ServerAliveInterval=30 \
  -o ServerAliveCountMax=3 \
  -R 127.0.0.1:8080:127.0.0.1:3000 \
  tunnel@vps.example.com

-R 127.0.0.1:8080:127.0.0.1:3000 會指示 VPS 的 sshd 在自身的 127.0.0.1:8080 上監聽,並將該處收到的內容轉送至家中主機的 127.0.0.1:3000-N 表示不執行 shell。兩個 ServerAlive 選項會讓 ssh 在約 90 秒內偵測到連線中斷,避免持續等待已不存在的連線。

接下來是最容易造成混淆的部分。該監聽器位於 loopback,因此從其他位置連線至 curl http://vps.example.com:8080 都會失敗。sshd 預設使用 GatewayPorts no,表示遠端轉送只會繫結至 loopback 介面。不要以設定 GatewayPorts yes 的方式處理。讓轉送維持在 loopback,並在前方配置 nginx,如下方的 frp 設定相同;如此公開連接埠會是具備憑證的 443,而通道連接埠不會直接暴露在網際網路上。如果不確定目前有哪些項目正在監聽,以及各自使用哪個介面,請參閱Linux 連接埠與監聽器簡介,花 10 分鐘即可了解。

如果 VPS 上的連接埠已被占用,ssh 會輸出以下訊息;ExitOnForwardFailure=yes 會讓它直接放棄,而不是在沒有可用通道的情況下繼續連線:

Warning: remote port forwarding failed for listen port 8080

常見原因是先前的工作階段中斷,但 sshd 尚未察覺。請在 VPS 的 /etc/ssh/sshd_config 中設定 ClientAliveInterval 30ClientAliveCountMax 3,讓已中斷的工作階段能被清理並釋放連接埠。使用 Restart=always 將整個命令包裝成 systemd unit,並搭配專用金鑰;或使用 autossh。若需要轉送多個服務,請停在這裡,改用 frp。

在 VPS 上安裝 frp,並固定使用指定 tag

frp 以靜態 Go 二進位檔發布,Ubuntu 或 Debian 的套件庫中沒有提供,因此您必須自行下載 release 並驗證。請固定版本。v0.52.0 變更了設定格式,之後選項名稱也曾移動,因此過時的教學會提供二進位檔無法辨識的鍵。此指南使用於 2026 年 8 月 14 日發布的 v0.71.0

# on the VPS
FRP_VERSION=0.71.0
ARCH=amd64   # use arm64 if `uname -m` prints aarch64
cd /tmp
curl -fsSLO "https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_${ARCH}.tar.gz"
curl -fsSLO "https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_sha256_checksums.txt"
sha256sum --check --ignore-missing frp_sha256_checksums.txt

sha256sum 應只輸出一行:

frp_0.71.0_linux_amd64.tar.gz: OK

之所以需要 --ignore-missing,是因為 checksum 檔案涵蓋全部 eighteen 個 release 資產,而您只下載了其中一個。若沒有該旗標,sha256sum 會將其餘 seventeen 個檔案回報為遺失,並以非零狀態結束。這看起來像是驗證失敗,但實際上沒有任何問題。

# on the VPS
tar xzf "frp_${FRP_VERSION}_linux_${ARCH}.tar.gz"
sudo install -m 755 "frp_${FRP_VERSION}_linux_${ARCH}/frps" /usr/local/bin/frps
sudo useradd --system --no-create-home --shell /usr/sbin/nologin frp
sudo install -d -m 750 -o root -g frp /etc/frp
frps --version

frps --version 會輸出 0.71.0。只有 frps 應安裝在 VPS 上。frpc 應安裝在家中的主機上。將兩個二進位檔都安裝到所有主機,會導致有人不慎在家中執行 tunnel server。

VPS 設定:token、強制 TLS、loopback 監聽器

先產生 token。這是 tunnel 與任何對 VPS 執行連接埠掃描者之間唯一的防線。

# on the VPS
openssl rand -base64 32

將該值寫入 /etc/frp/frps.toml

bindAddr = "0.0.0.0"
bindPort = 7000

# Every listener frp creates for a proxy, including the HTTP vhost, stays on loopback.
proxyBindAddr = "127.0.0.1"
vhostHTTPPort = 8080

auth.method = "token"
auth.token = "PASTE_THE_OPENSSL_OUTPUT_HERE"

transport.tls.force = true

webServer.addr = "127.0.0.1"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "PASTE_A_SECOND_SECRET_HERE"

log.level = "info"

其中 4 行負責安全性,因此逐一說明。

auth.token 必須與用戶端上的 auth.token 相符。若未設定,frps 會接受任何找到 7000 埠的用戶端。該用戶端接著可以透過你的 VPS 與憑證發布任意內容。

transport.tls.force = true 會拒絕所有不是 TLS(transport layer security)的控制連線。自 v0.50.0 起,用戶端預設已啟用 TLS,因此實際上不會增加任何負擔,也能避免舊版或手動製作的用戶端未通知你便以明文連線。

proxyBindAddr = "127.0.0.1" 是多數指南遺漏的設定,也是這套配置可以長時間執行的原因。它會將 frp 代表 proxy 開啟的所有監聽器,包括 HTTP vhost 以及用戶端要求的任何 remotePort,移至 loopback 介面。網際網路完全無法連到這些監聽器。唯一公開的入口是 443 上的 nginx,而該服務由你設定與控管。

webServer.addr = "127.0.0.1" 會讓 dashboard 不監聽公開介面。dashboard 完整列出你的私有服務及其流量,且只由一組 HTTP basic auth 密碼保護,因此不應放在 0.0.0.0

設定檔案擁有者,避免 token 可供所有使用者讀取,然後在啟動任何服務前檢查語法:

# on the VPS
sudo chown root:frp /etc/frp/frps.toml
sudo chmod 640 /etc/frp/frps.toml
sudo -u frp frps verify -c /etc/frp/frps.toml

有效檔案會輸出:

frps: the configuration file /etc/frp/frps.toml syntax is ok

補充一項格式資訊,可以避免你浪費 1 小時。frp 會依副檔名選擇解析器,支援 .toml.yaml.yml.json。舊版 .ini 檔案仍可透過舊版轉換路徑載入,但 INI 已被棄用,新的選項只記載於 TOML 文件。如果教學使用 [common] 區段與 server_addr = x.x.x.x,表示其內容早於 v0.52.0,且其中的鍵名稱不會符合你剛安裝的 binary。

以非特權服務執行 frps

bindPort 是 7000,而 vhostHTTPPort 是 8080。兩者都高於 1024,因此 frps 不需要 root,也不需要 CAP_NET_BIND_SERVICE。因此不要將 vhost 設在連接埠 80,改由 nginx 接手。

建立 /etc/systemd/system/frps.service

[Unit]
Description=frp reverse tunnel server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=frp
Group=frp
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
Restart=on-failure
RestartSec=5s
LimitNOFILE=65535
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true

[Install]
WantedBy=multi-user.target
# on the VPS
sudo systemctl daemon-reload
sudo systemctl enable --now frps
sudo journalctl -u frps -n 20 --no-pager

日誌應顯示兩個監聽器;位址比連接埠更重要:

frps tcp listen on 0.0.0.0:7000
http service listen on 127.0.0.1:8080

ProtectSystem=strict 會讓此服務使用的整個檔案系統變成唯讀。frps 可以正常運作,因為其日誌預設會輸出至標準輸出,而 journald 會擷取這些內容。若將 log.to 設為檔案路徑,服務會因無法寫入該檔案而失敗,除非加入相符的 ReadWritePaths= 設定行,因此請保留預設值。

防火牆:只開放一個連接埠,不要開放連接埠範圍

# on the VPS
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 7000/tcp
sudo ufw enable
sudo ufw status numbered

共有四條規則,其中一條只用於憑證續期。22 是 SSH。80 會重新導向至 443,並回應 ACME(自動憑證管理環境)挑戰。443 提供所有透過 tunnel 的應用程式。7000 是 frp 控制連接埠,也是 client 唯一需要連線的連接埠。

有些指南會要求開放類似 sudo ufw allow 20000:30000/tcp 的連接埠範圍。這類設定適用於另一種架構,也就是每項服務各自使用一個公開 TCP 連接埠。這裡不需要這樣做,因為所有流量都會進入 443,再由 frp 依 hostname 進行路由。若日後確實需要一個公開 TCP 連接埠,請將 proxyBindAddr 還原為 0.0.0.0,並加入限制,讓 client 只能使用你指定的連接埠:

allowPorts = [
  { start = 20000, end = 20010 }
]
maxPortsPerClient = 5

多數供應商也會在控制面板中提供 network firewall,這與主機上的 ufw 分開運作。在 sudo ufw status 中看似正確的規則若仍然逾時,通常是被該 firewall 封鎖。VPS 實際需要的 ufw 規則會說明本節所採用的 default-deny 設定。

在 VPS 上使用正式憑證終止 HTTPS

home.example.com 的 A 紀錄指向 VPS 的公有 IP。不要指向家中的網路。家中網路沒有可供指向的位址,這正是你要解決的問題。

# on the VPS
sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx

先以純粹的 port 80 區塊建立 /etc/nginx/sites-available/home.example.com,讓 certbot 有相符的 server_name 可供使用:

server {
    listen 80;
    listen [::]:80;
    server_name home.example.com;
    location / { return 404; }
}
# on the VPS
sudo ln -s /etc/nginx/sites-available/home.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot certonly --nginx -d home.example.com

檔案剖析成功時,nginx -t 會輸出 nginx: configuration file /etc/nginx/nginx.conf test is successful。每次 reload 前都要執行。reload 失敗時,nginx 會繼續使用舊設定,因此錯誤的修改看起來會像是修改沒有生效。

WebSocket upgrade 需要在 http 層級設定一個 map。將它放在 /etc/nginx/conf.d/upgrade.conf

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

現在以正式設定取代網站檔案:

server {
    listen 80;
    listen [::]:80;
    server_name home.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name home.example.com;

    ssl_certificate     /etc/letsencrypt/live/home.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/home.example.com/privkey.pem;

    client_max_body_size 512m;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        $connection_upgrade;
        proxy_read_timeout 3600s;
    }
}

此處 proxy_set_header Host $host; 不可省略。frp 的 HTTP vhost 會依據 Host 標頭進行路由,並將其與用戶端設定中的 customDomains 清單比對。省略該標頭時,nginx 會傳送 Host: 127.0.0.1,frp 找不到該名稱的代理設定,因此訪客會從 frp 收到簡單的 404,而不是應用程式提供的頁面。nginx 反向代理區塊的每一行說明介紹其他標頭的用途。

# on the VPS
sudo nginx -t && sudo systemctl reload nginx
sudo certbot renew --dry-run

這項試執行可確認九十天後的續期流程能夠正常運作;屆時你不會在旁監看。它需要能連線到 port 80,這就是設定 ufw 規則的原因。

家端:以非特權服務執行 frpc

在家用主機上安裝 frpc。安裝方式必須與安裝 frps 完全相同,使用相同版本並執行相同的 checksum 驗證步驟。接著建立相同的 frp 使用者與 /etc/frp 目錄。寫入 /etc/frp/frpc.toml

serverAddr = "vps.example.com"
serverPort = 7000

auth.method = "token"
auth.token = "PASTE_THE_SAME_TOKEN_HERE"

transport.tls.enable = true
loginFailExit = false

proxies = [
  { name = "home-app", type = "http", localIP = "127.0.0.1", localPort = 3000, customDomains = ["home.example.com"] }
]

此檔案中的鍵值順序很重要,原因不只是格式習慣。TOML 會將表格標頭之後的所有鍵值指派給該表格,因此像 serverAddr 這類頂層設定若寫在 proxy 表格標頭下方,就會悄悄變成 proxy 設定,並被 frp 忽略。以上述方式將 proxy 清單寫成 inline array,可避免這個問題:每個頂層鍵值都能明確維持在頂層。

type = "http" 會將此 proxy 經由 vhost listener 轉送,而不是為它占用專用的公開 TCP 埠。因此防火牆只需維持 4 條規則。customDomains 必須包含 nginx 在 Host header 中轉送的主機名稱,因此應填入 home.example.com,不能填 VPS 的 IP 位址。

loginFailExit = false 的重要性比表面上更高。預設值是 true,因此 frpc 第一次登入失敗時就會結束。在 ISP 連線尚未建立前就完成開機的家用主機上,這會讓服務停止,直到你注意到問題為止。將其設為 false,讓 frpc 持續重試,直到 VPS 回應。

寫入 /etc/systemd/system/frpc.service

[Unit]
Description=frp reverse tunnel client
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=frp
Group=frp
ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.toml
Restart=always
RestartSec=10s
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true

[Install]
WantedBy=multi-user.target
# on the home box
sudo chown root:frp /etc/frp/frpc.toml
sudo chmod 640 /etc/frp/frpc.toml
sudo -u frp frpc verify -c /etc/frp/frpc.toml
sudo systemctl daemon-reload
sudo systemctl enable --now frpc
sudo journalctl -u frpc -n 20 --no-pager

成功連線的 client 會記錄 run id:

login to server success, get run id [3a1f9c2b7d4e5f60]

在瀏覽器中開啟 https://home.example.com,應該會看到家中 127.0.0.1:3000 上執行的應用程式。client 上的 Restart=always 是刻意這樣設定的:家用連線可能中斷,而服務應在中斷後自動恢復。

讓儀表板不暴露在公開介面

使用 webServer.addr = "127.0.0.1" 後,儀表板只會在 VPS 本機回應。請透過本機轉送從筆電存取,不要開放連接埠:

# on your laptop
ssh -N -L 7500:127.0.0.1:7500 you@vps.example.com

開啟 http://127.0.0.1:7500,並使用 frps.toml 中的 webServer.userwebServer.password 登入。此頁面會列出每個已連線的用戶端,以及各個代理的流量計數器,因此能最快確認「家中的主機目前是否仍已連線」。關閉 SSH 工作階段後,儀表板就會再次無法存取。

隧道不會執行的工作

請將本節閱讀兩次,因為這是最容易造成損害的地方。隧道會讓私有服務可從公開網際網路連線,但不會驗證連線者的身分。https://home.example.com 解析成功後,掃描器會在數天內找到它;無論你是否告知他人這個名稱,結果都一樣。憑證透明度日誌會公開你申請憑證時使用的每個主機名稱,因此 certbot 成功的當下,該名稱就已公開。

你公開的任何服務都必須自行提供驗證機制。如果應用程式具備真正的登入功能與速率限制,就可以。如果它只使用一組共用密碼,或完全沒有登入功能,請在 VPS 上於其前方部署具驗證功能的代理伺服器。[在應用程式前方配置 protect-apps-with-oauth2-proxy|oauth2-proxy] 是常見做法;它可插入 nginx 與 frp vhost 之間,無須修改隧道的任一端。

frps.toml 中的 token 只會保護隧道,不會保護應用程式。它能阻止陌生人在你的 VPS 上註冊自己的代理伺服器,但無法處理針對你刻意公開之主機名稱、抵達 443 的請求。

請養成兩個習慣。第一,編輯兩個檔案並重新啟動兩項服務,以輪替 token,因為 token 不會自行過期。第二,讓 frp 保持最新版本:這個 binary 是對外公開的入口,而 v0.71.0 的版本說明列出一個可由 client 傳送錯誤值觸發的 server panic。這類錯誤應透過修補來處理,而不是自行推測其原因。

錯誤情況與實際顯示的字串

用戶端完全無法連線。 journalctl -u frpc 會重複顯示 connect to server error:,接著發生撥號逾時。沒有任何流量抵達 7000 埠。先檢查 VPS 上的 ufw,再檢查控制面板中的供應商網路防火牆,最後使用 getent hosts vps.example.com 確認名稱解析是否正確。

token 錯誤。 用戶端會直接顯示明確的錯誤訊息:

login to the server failed: token in login doesn't match token from configuration

再次複製 token。結尾換行,或未加引號的 shell 字串中有一個展開結果為空的 $,幾乎都會造成這些問題。因此,TOML 檔案中的 openssl rand -base64 32 輸出必須放在引號內。

tunnel 已建立,但瀏覽器收到空白的 404。 frpc 已記錄登入成功,dashboard 也列出 proxy,但頁面回傳 404,且沒有應用程式的任何樣式。這表示 frp 找不到符合此 Host 標頭的 proxy。直接在 VPS 上測試 virtual host,繞過 nginx 與 TLS:

# on the VPS
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: home.example.com' http://127.0.0.1:8080/

該命令回傳 404,表示 customDomains 設定錯誤。其他任何狀態碼都表示請求未從 nginx 取得正確的 Host

nginx 回傳 502。 nginx 正在回應,但 frp 沒有回應。VPS 上的 sudo ss -lntp | grep 8080 應顯示 frps 正在監聽 127.0.0.1:8080。輸出為空表示 frps 已停止,或 vhostHTTPPort 未在 frps.toml 中設定。

應用程式認為所有訪客都來自本機。 應用程式對每個請求記錄 127.0.0.1。frp 會設定 X-Forwarded-For,nginx 會將資訊附加至其中,因此真實的用戶端位址會位於該標頭。請設定應用程式信任此標頭。若應用程式依 IP 位址進行速率限制,切勿略過此設定,因為目前網際網路上的所有訪客都共用同一個限制額度。

長時間請求在 60 秒時中斷。 上傳或串流回應會在中途停止。這是 nginx 的預設 proxy_read_timeout,不是 tunnel 的問題。上方的設定區塊會將其提高至 3600s。client_max_body_size 是對應的上傳大小限制;其預設值為 1 MB,較大的 request body 會遭拒並回傳 413。

一切正常運作,但路由器重新開機後失效。 frpc unit 中的 Restart=always 加上 loginFailExit = false 可處理此情況。使用 sudo systemctl is-enabled frpc 確認,其輸出必須為 enabled

FAQ

如何判斷自己是否位於 CGNAT 後方?

比較路由器管理頁面上的 WAN 位址與同一網路內 curl -4 -s https://ifconfig.me 回報的位址。如果兩者不同,且路由器的 WAN 位址位於 100.64.0.0/10 內,表示 ISP 正在使用 carrier-grade NAT。該範圍是 RFC 6598 共用位址空間,專門用於此目的。有些 ISP 會改在 WAN 端使用 10.0.0.0/8,這代表相同情況。如果兩個位址相同,表示你擁有公有 IP,只要轉送連接埠即可完成設定。

反向通道需要網域名稱嗎?

需要。本節說明的 HTTPS 設定需要網域名稱。憑證會核發給主機名稱,而 frp 的 HTTP vhost 會依據 Host 標頭路由請求,因此兩端必須使用一致的名稱。編號連接埠上的原始 TCP 代理可以直接使用 VPS 的裸 IP,不需要網域名稱;但這樣沒有憑證,也沒有主機名稱路由,因此一個公開連接埠只能提供一項服務。

在公開 VPS 上執行 frp 是否安全?

只要僅公開控制連接埠並啟用驗證,就能安全執行。將 auth.token 設為隨機值,並在兩端使用相同設定;在伺服器上設定 transport.tls.force = true。接著設定 proxyBindAddr = "127.0.0.1",避免 frp 為代理開啟的任何連接埠直接面向網際網路,並讓 dashboard 保持在 webServer.addr = "127.0.0.1",透過 SSH local forward 存取。發布新版時更新 binary,因為該程序會監聽你的公開位址。

為什麼沒有人能連線到我轉送的 ssh -R 連接埠?

sshd 預設使用 GatewayPorts no,因此 remote forward 只會繫結至 VPS 的 loopback 介面。在 VPS 本機執行的 curl 可以運作,但從其他位置執行的 curl 會逾時。正確做法是讓 forward 保持在 loopback 上,並在前方使用 nginx 監聽 443。設定 GatewayPorts yes 會公開沒有憑證且沒有 TLS 的原始連接埠,造成的安全性問題比它解決的問題更嚴重。

我應該使用 frp,還是 Tailscale 或 WireGuard 等 mesh VPN?

如果只有自己的裝置需要存取,請使用 mesh VPN,因為這樣不會公開任何服務,也不會提供可供他人掃描的公開主機名稱。如果需要任何瀏覽器都能載入的公開 HTTPS 位址,例如 webhook 接收端,或要分享給不會安裝 VPN client 的使用者,請使用 frp。兩者可以在同一台 VPS 上並存,使用不同連接埠,各自處理不同工作。

#frp#cgnat#nat#tunnel#reverse-proxy