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 启动它。
相关推荐
干啥都是小小白12 小时前
Linux C编程
linux·运维·服务器
赖small强13 小时前
【Linux 网络基础】WebSockets 技术指南
linux·网络·https·websockets·ping/pong
司铭鸿13 小时前
化学式解析的算法之美:从原子计数到栈的巧妙运用
linux·运维·服务器·算法·动态规划·代理模式·哈希算法
专家大圣13 小时前
告别局域网束缚!飞牛云 NAS+cpolar 让远程管理更简单
开发语言·网络·内网穿透·cpolar
代码AC不AC13 小时前
【Linux】调试器 gdb / cgdb
linux·gdb·调试器·cgdb
last demo13 小时前
MariaDB 数据库管理
linux·运维·服务器·数据库·php·mariadb
生信大表哥13 小时前
Python单细胞分析-基于leiden算法的降维聚类
linux·python·算法·生信·数信院生信服务器·生信云服务器
swanwei13 小时前
2025年11月22-23日互联网技术热点TOP3及影响分析(AI增量训练框架开源)
网络·人工智能·程序人生·安全·百度
x***010614 小时前
SQL 注入漏洞原理以及修复方法
网络·数据库·sql
xixixi7777714 小时前
3GPP核心网的演进:是一条清晰的去电信化和IT化道路
网络·协议·通信·3gpp