wstunnel 实现ssh跳板连接

wstunnel ssh跳板

  • 一、前言
  • 二、wstunnel
    • [2.1 服务端(Server)](#2.1 服务端(Server))
    • [2.2 客户端(Client)](#2.2 客户端(Client))
  • [三、ssh 跳板](#三、ssh 跳板)
  • 四、可能的问题
    • [4.1 客户端无法连接,或连接后立即断开](#4.1 客户端无法连接,或连接后立即断开)
    • [4.2 隧道已建立,但 SSH 连接失败](#4.2 隧道已建立,但 SSH 连接失败)

一、前言

本篇主要介绍如何通过wstunnel建立ssh隧道,实现对于封闭内网机器的远程访问。适用条件:

  1. 有一台具有公网IP的ECS服务器(如阿里云)
  2. 公司封闭内网机器
  3. 家庭机器

二、wstunnel

wstunnel 是为了解决封闭网络环境中,常用协议被阻断这一痛点而生。它利用 WebSocket 协议将任意 TCP 或 UDP 流量封装在 WebSocket 连接中,将网络数据"伪装"成正常的网页浏览流量,从而轻松穿透绝大多数防火墙和代理服务器的封锁。

换言之这玩意也可以用来做你想的那个事,但这不是本文重点

2.1 服务端(Server)

服务器端是我们整个隧道的中转站。它需要拥有一个公网 IP 地址,并且能够自由访问互联网。在我们的场景中,这台服务器就是那台 ECS 云主机。它的核心任务是运行 wstunnel 的服务端程序,同时监听来自"公司电脑"和"家庭电脑"的连接请求。

安装 wstunnel

你可以用自己的方式去官方的 release 下载,然后上传到ECS服务器。假设你的服务器能够连 github,也可以直接操作:

bash 复制代码
wget https://github.com/erebe/wstunnel/releases/download/v10.4.4/wstunnel_10.4.4_linux_amd64.tar.gz

tar -zxf wstunnel_10.4.4_linux_amd64.tar.gz

sudo mv wstunnel /usr/local/bin

sudo chmod +x /usr/local/bin/wstunnel

我们将 wstunnel 执行文件移动到 /usr/local/bin,这样就可以全局调用了。你可以用下面的语句确认是否安装成功:

bash 复制代码
wstunnel --help

输出说明文档则成功。

配置防火墙

wstunnel 需要监听两个端口,因此我们需要确保服务器的防火墙(如 ufw, firewalld)或云服务商的安全组策略允许外部流量访问这两个端口。

  • 端口 8080 (TCP): 用于 wstunnel 服务端监听来自公司电脑的 WebSocket 连接。这是隧道的入口。
  • 端口 2222 (TCP): 用于我们从家庭电脑发起 SSH 连接。这是我们将要访问的目标端口。注意这里的端口你可以自行配置,如果需要多台机器,则需要开放多个端口

这里因为不同人的ECS配置不同,这里不给出具体的操作步骤。请查阅自己ECS供应商给出的教程。

运行 wstunnel server

配置好防火墙后,我们就可以启动 wstunnel 服务端了。你可以使用普通的 websocket 连接(ws://),为了增加一层额外的安全性,这里推荐使用加密的 wss:// 协议。

注意:你的客户端和服务端需要使用相同的协议,不能服务端加密,客户端不加密。

bash 复制代码
wstunnel server wss://[::]:8080
  • server: 表示以服务端模式运行。
  • wss://[::]:8080: 这是服务端的核心配置。
    • wss://: 指定使用 WebSocket Secure 协议。wstunnel 会自动生成一个自签名 TLS 证书来加密隧道流量。
    • [::]/0.0.0.0: 表示监听服务器上所有可用的网络接口(包括公网 IP 和内网 IP)。
    • :8080: 指定监听的端口号。

持久化服务端服务

建议创建一个持久化的服务,避免ECS重启后的断联。这里我们用 systemd 创建一个后台服务:

  1. 创建一个 service 文件
bash 复制代码
sudo vim /etc/systemd/system/wstunnel-server.service

# 在 wstunnel-server.service 中,写入下面内容:
[Unit]
Description=wstunnel server for reverse tunnel (Secure)
After=network.target

[Service]
Type=simple
# 使用一个低权限用户运行服务,增强安全性
User=nobody
# 确保这里的路径和命令与你手动执行时的一致
ExecStart=/usr/local/bin/wstunnel server wss://0.0.0.0:8080
# 配置服务在失败时总是自动重启
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
  1. 保存退出后,执行以下命令来启用并启动这个新服务
bash 复制代码
# 重新加载 systemd 配置
sudo systemctl daemon-reload

# 设置服务开机自启
sudo systemctl enable wstunnel-server.service

# 立刻启动服务
sudo systemctl start wstunnel-server.service
  1. 检查一下是否运行
bash 复制代码
sudo systemctl status wstunnel-server.service

如果你看到绿色的 active (running) 字样,那么服务器端的配置已经全部完成了!它现在正静静地等待着来自你公司电脑的连接。

2.2 客户端(Client)

客户端是指那台位于公司内网,我们最终希望通过 SSH 访问的电脑。由于它没有公网 IP,我们无法从外部直接连接它。因此,我们需要在这台电脑上运行 wstunnel 的客户端程序,让它主动"走出去",与我们部署在公网 ECS 上的服务端建立一条持久的连接。这条连接就是我们的"反向隧道"。

安装 wstunnel

操作同服务端,略。

你可能需要确保一下 ssh 服务是否已开启:

bash 复制代码
sudo systemctl status ssh

如果服务未运行,使用 sudo systemctl start ssh 来启动它。

运行 wstunnel 客户端

在公司电脑的终端中,执行以下命令:

bash 复制代码
wstunnel client -R tcp://:2222:localhost:22 wss://198.51.100.10:8080

让我们详细解读这个关键命令:

  • client: 表示以客户端模式运行。
  • -R tcp://:2222:localhost:22: 这是定义反向隧道 (Remote-to-Local) 的参数,也是整个魔法的核心。它的意思是:
    • 请求远端服务器 (Remote),即我们的公网 ECS 使用 tcp 协议,在它自己的所有网络接口 (0.0.0.0) 的 2222 端口上进行监听。当有任何流量进入该端口时,请将这些流量通过隧道转发到本地 (Local),即当前这台公司电脑的 localhost:22 地址上。localhost:22 正是这台公司电脑上 SSH 服务监听的地址。
    • wss://198.51.100.10:8080: 指定要连接的 wstunnel 服务端地址。
      • wss://: 协议必须与服务端保持一致,这里我们使用加密的 WebSocket。
      • 198.51.100.10:8080: 公网服务器的 IP 地址和 wstunnel 服务端监听的端口。

执行该命令后,如果一切顺利,它会连接到服务器并保持在前台运行,等待隧道流量。

持久化客户端服务

与服务端一样,我们不希望因为关闭终端或电脑重启而导致隧道中断。因此,我们也为客户端配置一个 systemd 服务,让它在后台持久运行。

  1. 创建 service 服务
bash 复制代码
sudo vim /etc/systemd/system/wstunnel-client.service

# 在 wstunnel-client.service 中,添加以下内容:
[Unit]
Description=wstunnel client for reverse tunnel (Secure)
# 确保在网络连接建立之后再启动本服务
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
# 建议使用你自己的普通用户来运行此服务
User=your_company_user 
# 确保这里的命令和 IP 地址都是正确的
ExecStart=/usr/local/bin/wstunnel client -R tcp://:2222:localhost:22 wss://198.51.100.10:8080
# 同样配置自动重启,重启间隔可以稍长一些
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

注意:请将 your_company_user 替换成您在公司电脑上登录的实际用户名。同时,务必再次检查 ExecStart 行中的公网服务器 IP 地址是否正确。

  1. 保存并退出后,启用并启动该服务。
bash 复制代码
sudo systemctl daemon-reload
sudo systemctl enable wstunnel-client.service
sudo systemctl start wstunnel-client.service

三、ssh 跳板

配置到现在,你已经可以在 ECS 上直接 ssh 连接我们的公司电脑了:

bash 复制代码
ssh your_company_user@localhost -p 2222

但是,据我对于 wstunnel 的文档阅读,它并不支持你直接将数据转发到 0.0.0.0:2222,仅能提供一个 localhost 的服务。因此,我们从家里的电脑连接到公司,需要通过 ssh跳板(Proxy) 实现。

  1. 添加一个 ssh 目标配置

在 Windows 中打开(或创建) C:/Users/user_name/.ssh 文件夹,找到里面的 config 文件,并添加如下内容:

ini 复制代码
Host company  # 一个昵称,之后可以直接用 ssh company 连接
  HostName 127.0.0.1 # 作为跳板的机器上要连接的机器ip
  Port 2222 # 作为跳板的机器上要连接的机器 ssh 端口
  User your_company_user
  ProxyJump ecs_user@198.51.100.10

这里由于我们使用 wstunnel 作为隧道,所以 HostName 直接填 127.0.0.1 即可。注意把 198.51.100.10 换成你的 ECS 公网IP。

  1. 尝试连接
bash 复制代码
ssh company

这里需要输入两个密码,第一次是跳板机的密码,第二次是公司机器的密码。如果你不想总是输入密码,可以参考我之前的ssh免密博客,配置一下公钥。

四、可能的问题

首先,建议在配置为服务(Service)之前,现在终端中运行上面的语句,这样方便通过输出的日志检查错误原因。下面是一些可能出现的(我配置时遇到过)问题,简单整理一下。

4.1 客户端无法连接,或连接后立即断开

在公司电脑上启动 wstunnel client 后,它可能立即输出 "connection refused"、"connection timed out" 等错误。此时在服务器端查看日志,可能看到了有连接记录,但是报错。

可能的原因及解决方案

  1. 协议不匹配 (最常见)

    • 原因:这是最容易犯的错误。你在服务端启动时使用了 wss:// (加密),但在客户端连接时却用了 ws:// (未加密),或者反之。两者协议必须完全一致。
    • 解决方案:仔细检查并统一服务器和客户端的启动命令。推荐全部使用更安全的 wss://。
      • 服务器端应为: wstunnel server wss://0.0.0.0:8080
      • 客户端连接地址应为: wss://你的公网IP:8080
  2. 服务器防火墙/安全组未放行

    • 原因:公网服务器的防火墙(如 ufw)或云服务商的安全组策略没有放行 wstunnel 服务端监听的端口(本教程中为 8080)。
    • 解决方案:登录你的云服务控制台或服务器,检查防火墙入站规则,确保 8080 端口的 TCP 流量是被允许的。

4.2 隧道已建立,但 SSH 连接失败

通过 systemctl status 检查,wstunnel 的服务端和客户端都显示 active (running),日志也没有报错。但当你从家里电脑尝试 ssh company 时,连接被拒绝 (Connection Refused) 或超时 (Timed Out)。

可能的原因及解决方案

  1. 公网服务器未放行 SSH 入口端口

    • 原因:你只放行了 wstunnel 隧道的 8080 端口,但忘记了放行我们用于 SSH 连接的入口端口 2222。
    • 解决方案:再次检查公网服务器的防火墙/安全组,确保 2222 端口的 TCP 入站流量也被允许。
  2. 公司电脑上的 SSH 服务未运行

    • 原因:隧道本身是通的,但流量被转发到公司电脑的 22 端口后,发现没有任何服务在监听,导致连接被拒绝。
    • 解决方案:登录你的公司电脑,使用 sudo systemctl status ssh 命令检查 SSH 服务是否正在运行。如果未运行,使用 sudo systemctl start ssh 启动它。
相关推荐
SPC的存折3 小时前
1、Redis数据库基础
linux·运维·服务器·数据库·redis·缓存
爱学习的小囧4 小时前
VMware ESXi 6.7U3v 新版特性、驱动集成教程和资源包、部署教程及高频问答详情
运维·服务器·虚拟化·esxi6.7·esxi蟹卡驱动
小疙瘩4 小时前
只是记录自己发布若依分离系统到linux过程中遇到的问题
linux·运维·服务器
dldw7775 小时前
IE无法正常登录windows2000server的FTP服务器
运维·服务器·网络
运维有小邓@5 小时前
什么是重放攻击?如何避免成为受害者?
运维·网络·安全
光路科技5 小时前
工业数字化三大核心概念拆解:IIoT、工业互联网与工业4.0
网络
我是伪码农5 小时前
外卖餐具智能推荐
linux·服务器·前端
汤愈韬6 小时前
下一代防火墙通用原理
运维·服务器·网络·security
皮皮林5516 小时前
强烈建议大家使用 Linux 做开发?
linux
IMPYLH6 小时前
Linux 的 od 命令
linux·运维·服务器·bash