SSH隧道部署交易平台 — 来自中国的工程经验
每个交易平台都面临的基础设施问题
如果你曾构建过需要服务多国用户的交易平台,你一定知道这个问题:中国移动会屏蔽直接连接海外服务器的SSH。没有警告,没有错误信息——只有无声的连接超时,让你误以为服务器宕机,而实际上它运行正常。
我们的配置:主终端运行在美国的RackNerd服务器(107.174.186.162)上,但所有开发工作都在中国进行。直接SSH?被屏蔽。基于VPN的代理?对自动化部署脚本来说不可靠。经过数周失败尝试后,我们最终采用的解决方案是一个简单但有效的SSH链。
京东云跳板机架构
关键洞察:中国移动屏蔽海外SSH,但国内云服务器可以自由连接海外服务器。因此我们使用一台京东云Windows服务器(111.228.37.165)作为跳板机:
本地电脑(中国)
→ 京东云跳板机(国内IP,111.228.37.165)
→ RackNerd目标服务器(海外IP,107.174.186.162)
在Python中使用Paramiko实现如下:
import paramiko
# 第一步:连接京东云
ssh_jd = paramiko.SSHClient()
ssh_jd.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_jd.connect('111.228.37.165', port=22, username='root', password='***')
# 第二步:通过京东云打开到RackNerd的直接TCP通道
channel = ssh_jd.get_transport().open_channel(
'direct-tcpip',
('107.174.186.162', 22), # 目标
('127.0.0.1', 22) # 源
)
# 第三步:通过通道连接RackNerd
ssh_rn = paramiko.SSHClient()
ssh_rn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_rn.connect('107.174.186.162', port=22, username='root', password='***', sock=channel)
# 现在ssh_rn已连接——可使用sftp、exec_command等
sftp = ssh_rn.open_sftp()
sftp.put('local_file.html', '/var/www/blog/tools/file.html')
open_channel('direct-tcpip', ...)调用是核心——它指示京东云服务器将TCP连接转发到目标,有效创建SSH隧道,而无需在跳板机上配置端口转发。
部署速度问题
SSH链正常工作后,下一个问题是速度。要部署200多个HTML文件,通过SSH隧道逐个上传耗时极长。我们第一次尝试逐个上传文件——处理大约一半文件后,在300秒时超时。
解决方案:将所有文件打包成一个tar.gz,一次性上传,在服务器上解压:
import tarfile, os
# 本地打包
with tarfile.open('upload.tar.gz', 'w:gz') as tar:
for f in os.listdir('tools/'):
if f.endswith(('.html', '.json')):
tar.add(f'tools/{f}')
# 上传单个文件
sftp.put('upload.tar.gz', '/tmp/upload.tar.gz')
# 验证大小匹配(关键——我们遇到过上传截断的情况)
assert sftp.stat('/tmp/upload.tar.gz').st_size == os.path.getsize('upload.tar.gz')
# 在服务器上解压
ssh_rn.exec_command('cd /var/www/blog && tar xzf /tmp/upload.tar.gz')
这使5分钟的部署缩短到30秒以内。
Cloudflare CDN缓存陷阱
部署后,我们通过获取实时URL来验证——有时旧内容仍然显示。罪魁祸首:Cloudflare CDN缓存,即使Nginx配置了Cache-Control: no-cache。
棘手之处:我们的gfil-lab.com DNS设置为"仅DNS"(灰色云),而非"代理"(橙色云)。这意味着Cloudflare不应缓存任何内容——请求直接到达我们的Nginx服务器。但某些ISP和企业代理仍会缓存响应。解决方案:
# 在Nginx配置中添加缓存清除头
location ~* \.(html|xml|txt|md)$ {
add_header Cache-Control "no-cache, must-revalidate" always;
}
# 需要强制刷新时,添加查询参数
# https://gfil-lab.com/tools/entity.html?v=2
但真正的教训是:当本地文件正确但线上站点显示旧内容时,不要假设部署失败。先直接检查服务器(在服务器上执行curl http://localhost/tools/entity.html),然后再花数小时调试一个实际上成功的部署。
教训:始终先验证服务器端
我们浪费了整整一个审计周期,以为部署失败了。Claude审查者检查了实时URL,发现旧内容。我们重新部署。结果相同。结果发现服务器一直有正确的文件——陈旧内容来自中间缓存层。
我们现在的验证清单:
- 服务器端检查:在服务器上执行
curl http://localhost/path——绕过所有缓存 - 外部检查:从外部执行
curl https://domain/path——测试用户看到的内容 - 内容哈希:比较特定字符串(例如
grep -c "liudapao880807-arch" /var/www/blog/tools/entity.html),而非完整文件比较
此后,这个三步验证法多次帮助我们避免了虚假的"部署失败"警报。
试用我们的免费工具
这套基础设施为22个免费交易计算器提供支持,覆盖4种语言。试试头寸规模计算器——它支持外汇、黄金、加密货币和指数,为30多种交易品种提供正确的pip值。


Leave a Comment