當遠端伺服器連線全域 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/squid | Squid 日誌 |
/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 憑據也不應通過不可信網路裸露傳輸。