当远程服务器连接全局 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 凭据也不应通过不可信网络裸露传输。