當遠端伺服器連線全域 VPN 時,預設路由變化可能導致現有 SSH 會話中斷。如果需求只是讓部分命令或應用通過另一條網路出口,更穩妥的方式是部署一個應用層正向代理,再讓需要代理的用戶端顯式使用它。

1. 準備 Squid 設定

建立工作目錄:

mkdir -p ~/squid
cd ~/squid

儲存以下設定為 squid.conf

# 只允许可信内网与 Tailscale/CGNAT 地址。
acl localnet src 10.0.0.0/8
acl localnet src 100.64.0.0/10
acl localnet src 172.16.0.0/12
acl localnet src 192.168.0.0/16
acl localnet src fc00::/7
acl localnet src fe80::/10

acl SSL_ports port 443
acl Safe_ports port 80
acl Safe_ports port 21
acl Safe_ports port 443
acl Safe_ports port 70
acl Safe_ports port 210
acl Safe_ports port 280
acl Safe_ports port 488
acl Safe_ports port 591
acl Safe_ports port 777
acl Safe_ports port 1025-65535
acl CONNECT method CONNECT

http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow localnet
http_access deny all

http_port 3128
coredump_dir /var/spool/squid

refresh_pattern ^ftp:             1440    20%     10080
refresh_pattern ^gopher:          1440    0%      1440
refresh_pattern -i (/cgi-bin/|\?) 0       0%      0
refresh_pattern .                 0       20%     4320

這裡的關鍵不是埠,而是 http_access 的順序:

  • 先拒絕不安全的目標埠;
  • 只允許 localnet 中定義的來源;
  • 最後使用 http_access deny all 拒絕其他請求。

如果只需要一個更小的網段,應把 ACL 收緊到實際地址。例如只允許 AOI 內網時,可以使用 10.10.10.0/24,不必允許整個 10.0.0.0/8

2. 啟動 Squid 容器

MR 37 使用 Ubuntu 官方 Squid 映像,並把主機的 3129 對映到容器的 3128

docker run -d \
  --name squid \
  --restart unless-stopped \
  -e TZ=UTC \
  -p 3129:3128 \
  -v "$PWD/squid.conf:/etc/squid/squid.conf:ro" \
  ubuntu/squid:5.2-22.04_beta

如果宿主機啟用了 SELinux,可以把掛載選項改為 :Z,ro

-v "$PWD/squid.conf:/etc/squid/squid.conf:Z,ro"

日誌和快取也可以按需持久化:

掛載路徑用途
/var/log/squidSquid 日誌
/var/spool/squid磁碟快取
/etc/squid/squid.conf主設定檔
/etc/squid/conf.d/設定片段

3. 驗證容器和設定

檢查容器狀態與日誌:

docker ps --filter name=squid
docker logs --tail=100 squid

在容器內驗證設定語法:

docker exec squid squid -k parse

從允許訪問的用戶端測試 HTTP:

curl -I -x http://10.10.10.11:3129 http://example.com

測試 HTTPS:

curl -I -x http://10.10.10.11:3129 https://example.com

普通 HTTPS 訪問使用 CONNECT 隧道,不需要在 Squid 上生成自簽名憑證。用戶端與目標網站之間的 TLS 仍然保持端到端加密。

4. 設定用戶端

命令列程式通常會讀取以下環境變數:

export http_proxy=http://10.10.10.11:3129
export https_proxy=http://10.10.10.11:3129

雖然第二個變數名是 https_proxy,代理 URL 仍然使用 http://:用戶端先與 HTTP 代理協商 CONNECT,再在隧道內建立到目標網站的 TLS 連線。

需要持久儲存時,可以把環境變數加入 ~/.bashrc~/.zshrc。並非所有程式都會讀取這些變數,瀏覽器和桌面應用可能需要單獨設定。

5. 通過 Tailscale 使用

設定中允許 100.64.0.0/10,因此用戶端可以通過 Tailscale 地址訪問代理,而無需把 3129 暴露到公網:

export http_proxy=http://100.x.y.z:3129
export https_proxy=http://100.x.y.z:3129

這裡的 100.x.y.z 應替換為執行 Squid 的 Tailscale 節點地址。除了 Squid ACL,還應通過主機防火牆和 Tailscale ACL 限制訪問來源。

6. 更新設定

修改 squid.conf 後先驗證,再重新建立容器:

docker exec squid squid -k parse
docker restart squid

如果需要從本地部署到遠端伺服器,可以複製設定後通過 SSH 執行啟動命令,但指令碼中不應硬編碼使用者名稱、公網 IP 或密碼:

scp squid.conf server:~/squid/squid.conf
ssh server 'cd ~/squid && docker restart squid'

7. 安全邊界

不要在設定中使用 http_access allow all,也不要直接向公網開放代理埠。Squid 的應用層 ACL、主機防火牆和 Tailscale ACL 應形成多層限制。若需要使用者名稱和密碼認證,可以在此基礎上增加 proxy_auth,但 Basic 憑據也不應通過不可信網路裸露傳輸。