Skip to main content

SSH 隧道管理器

基于 Python 3.10 实现,支持 本地 (local)远程 (remote)动态 (dynamic) 三种端口转发模式。通过 YAML 配置文件管理多个隧道,并通过命令行参数灵活选择运行一个或多个隧道。

一、SSH 的转发模式介绍

SSH有三种将目标主机的服务“映射”到本地访问的方式,分别是本地端口转发、远程端口转发和动态端口转发。三种方式对比如下:

类型 常用参数 核心功能 典型应用场景
本地端口转发 -L 访问远程网络中的服务 想访问公司内网数据库、远程服务器上的Web服务
远程端口转发 -R 将本地服务暴露给外部网络 把本地的个人网站、开发服务展示给外网同事看
动态端口转发 -D 建立一个加密的SOCKS代理服务器 不固定转发端口,让浏览器或应用程序通过代理安全上网

1.1 Local本地转发- 将远程的服务映射本地

通过一个跳板机 (your-jump-server.com),将内网中 internal-server.local 的 80 端口(Web 服务)映射到你本地电脑的 8080 端口。

配置示例

tunnels:
  - id: web_server                     # 唯一标识符,用于命令行选择(-c web_server)
    name: "本地访问内网Web服务"          # 人类可读的描述,仅用于展示
    type: local                        # 指定为本地端口转发模式(对应 ssh -L)
    
    # --- SSH 连接参数(跳板机)---
    ssh_host: "your-jump-server.com"   # 跳板机的域名或 IP(你能够直接 SSH 到的公网服务器)
    ssh_port: 22                       # 跳板机的 SSH 端口,默认 22
    ssh_user: "your_username"          # 登录跳板机的用户名
    ssh_pkey: "~/.ssh/id_rsa"          # 私钥路径(推荐),也可以改用 ssh_password 字段
    
    # --- 转发规则(本地 → 内网目标)---
    local_port: 8080                   # 你本地电脑上将要监听的端口(例如访问 http://localhost:8080)
    remote_host: "internal-server.local"  # 内网目标的地址(从跳板机的视角能访问到的内网主机名或 IP)
    remote_port: 80                    # 内网目标上真正提供服务的端口(这里是 HTTP 服务)

工作机制图解

你的电脑 (本地)               跳板机 (SSH Server)              内网服务器
+-------------+              +------------------+           +-----------------+
|             | SSH 隧道加密  |                  |  明文转发  |                 |
| localhost:8080| ==========> | your-jump-server | ---------> | internal-server:80 |
|             | (动态端口)     |                  |   (端口80)  |                 |
+-------------+              +------------------+           +-----------------+
  1. 建立 SSH 连接:脚本(或 ssh 命令)用你的私钥登录跳板机。
  2. 本地监听:在你的电脑上启动一个 TCP 监听,端口为 local_port (8080)。
  3. 流量转发:当有程序访问 localhost:8080 时,SSH 客户端会通过加密隧道将数据发送给跳板机。
  4. 跳板机请求:跳板机解密后,作为客户端去连接 remote_host:remote_port (internal-server.local:80)。
  5. 数据回传:目标服务的响应原路返回。

关键注意事项

字段 注意点
ssh_host 必须是你能够 直接 SSH 登录 的机器,它通常拥有访问内网其他机器的网络权限。
remote_host 这个地址是 从跳板机角度 能解析/访问的。可以是内网 IP(如 192.168.1.100),也可以是内网域名。
local_port 确保本地 8080 端口没有被其他程序占用(可用 netstat -tulnp | grep 8080 检查)。
ssh_pkey vs ssh_password 强烈建议使用密钥认证(更安全);如果必须用密码,在配置中写 ssh_password: "your_password"(注意密码会明文存在配置文件中)。

实际效果对比

  • 没有隧道时:你无法直接访问 http://internal-server.local,因为它位于内网,不可路由。
  • 有了这个隧道后:你在浏览器打开 http://localhost:8080,就能看到内网 Web 服务的内容。对内网服务器来说,请求的来源是跳板机。

1.2 Remote 转发 — 将本地服务暴露到外网

作用:通过公网跳板机,将你本地电脑上的服务暴露给外部网络访问。类似 ssh -R

配置示例

tunnels:
  - id: expose_api
    name: "暴露本地Flask服务给公网"
    type: remote
    ssh_host: "public-server.com"    # 公网跳板机(有固定IP)
    ssh_port: 22
    ssh_user: "deploy"
    ssh_pkey: "~/.ssh/id_rsa"
    remote_port: 2222                # 跳板机上对外监听的端口
    local_host: "localhost"          # 本地服务的地址(通常为 localhost 或 127.0.0.1)
    local_port: 5000                 # 本地服务的端口
    # remote_bind_address: "0.0.0.0" # 可选:让跳板机监听所有网络接口(需服务器 GatewayPorts yes)

字段详解

字段 含义
type: remote 指定为远程端口转发模式
ssh_host/port/user/pkey 连接公网跳板机的参数(同 local)
remote_port 跳板机上将要监听的端口。外部用户访问 跳板机IP:remote_port 即连接到你的本地服务
local_host 你本地服务的地址。通常是 localhost127.0.0.1,也可以是同一局域网的其他机器
local_port 你本地服务的端口(例如 Flask 的 5000)
remote_bind_address 可选。默认跳板机只监听 127.0.0.1(仅本机可访问)。设为 "0.0.0.0" 后,外网任何人都可访问。需要跳板机 SSH 服务配置 GatewayPorts yes

工作机制

你的电脑 (本地)               跳板机 (公网)                    外部用户
+-------------+              +------------------+            +-------------+
|             | SSH 隧道加密  |                  |  普通TCP    |             |
| localhost:5000| <========= | public-server:2222| <--------- | 任意客户端   |
| (Flask服务)  | (动态端口)   | (监听公网)         |            |             |
+-------------+              +------------------+            +-------------+
  1. 你建立 SSH 连接到公网跳板机,并请求在跳板机上监听 remote_port
  2. 当外部用户访问 跳板机IP:remote_port 时,跳板机将连接通过 SSH 隧道反向转发到你本地的 local_host:local_port
  3. 你的本地服务处理请求,响应原路返回。

典型使用场景

  • 演示/调试:把本地开发的网站临时给同事看,无需部署到服务器。
  • 穿透 NAT:你的电脑在公司内网或家庭宽带(无公网IP),通过一台有公网IP的云主机让外部访问本地服务。
  • 远程访问内网设备:本地有一个监控摄像头(RTSP 流),通过远程转发让外网观看。

注意事项

  1. 跳板机需允许 TCP 转发/etc/ssh/sshd_config 中确保 AllowTcpForwarding yes
  2. 监听地址问题:默认 remote_bind_address 为空(或 127.0.0.1),意味着只有登录到跳板机本机才能访问 remote_port。如果要公网访问,必须:
    • 设置 remote_bind_address: "0.0.0.0"
    • 并在 sshd_config 中开启 GatewayPorts yes(重启 sshd)。
  3. 防火墙:跳板机的防火墙需放开 remote_port 的入站连接。
  4. 安全性:暴露的服务应具备认证机制,防止未授权访问。

1.3 Dynamic 转发— SOCKS5 代理

作用:在本地创建一个 SOCKS5 代理端口,所有支持 SOCKS 的应用可动态请求代理访问任意目标。类似 ssh -D

配置示例

tunnels:
  - id: socks_proxy
    name: "SOCKS5代理"
    type: dynamic
    ssh_host: "my-server.com"
    ssh_port: 22
    ssh_user: "proxy_user"
    ssh_pkey: "~/.ssh/proxy_key"
    local_port: 1080                # 本地 SOCKS 代理端口
    # remote_bind_address: ""       # 动态转发无需此项

字段详解

字段 含义
type: dynamic 指定为动态端口转发模式
local_port 你在本地电脑上开启的 SOCKS5 代理端口(例如 1080)
其他 SSH 连接参数 同 local,用于登录跳板机

工作机制

你的电脑 (本地)                跳板机 (SSH Server)                 互联网/内网
+------------------------+    +------------------+            +-----------------+
| SOCKS5代理 localhost:1080| => | my-server.com     | ========> | 任意目标:任意端口 |
| (浏览器/curl配置代理)    |    | (解密请求,按需连接)|            | (根据应用请求)  |
+------------------------+    +------------------+            +-----------------+
  1. SSH 客户端在本地 localhost:1080 启动一个 SOCKS5 代理服务器。
  2. 应用程序(浏览器、curl、即时通讯工具等)配置使用该代理(socks5://127.0.0.1:1080)。
  3. 应用程序发起连接时,会先通过 SOCKS 协议告诉代理“我要连接的主机和端口”。
  4. SSH 客户端将这一请求加密后发给跳板机,由跳板机真正去连接目标服务器。
  5. 跳板机返回的数据原路返回。

典型使用场景

  • 浏览器翻墙/访问内网:配置浏览器 SOCKS 代理,即可访问跳板机所在网络内的任意网站(如公司内部 Wiki、GitLab)。
  • 命令行工具:使用 proxychainscurl --socks5 让命令行程序走代理。
  • 临时调试:一个代理端口可访问多种服务,无需逐个配置 local 转发。

与 local 转发的本质区别

维度 local dynamic
目标指定 预先固定 主机:端口 动态由应用告知
应用要求 无需特殊支持 必须支持 SOCKS5 或配合 proxychains 使用
一个端口能连多少个目标 1个 无数个
典型用途 固定服务映射(数据库、内网站点) 浏览网页、多种服务通吃

注意事项

  1. 应用支持:并非所有程序都能原生使用 SOCKS5。老旧的数据库客户端、部分命令行工具需要搭配 proxychains 或类似工具。
  2. DNS 解析:默认 DNS 解析是在本地完成的,可能导致内网域名无法解析。可以配置远程 DNS(如 ssh -D 1080 -o "ProxyCommand=none" 或使用 --socks5-hostname 在 curl 中)。
  3. 服务端无额外配置:动态转发只需要服务端 AllowTcpForwarding yes(通常默认开启),无需 GatewayPorts

二、配置说明

  • 本地转发 (type: local):将远程服务映射到本地端口,类似 ssh -L
  • 远程转发 (type: remote):将本地服务暴露到远程服务器,类似 ssh -R
  • 动态转发 (type: dynamic):创建 SOCKS5 代理,类似 ssh -D

远程转发如需监听所有网络接口,需在远程 SSH 服务器上设置 GatewayPorts yes, 并在配置中添加 remote_bind_address: "0.0.0.0"

config.yaml示例:

tunnels:
  - id: web_server
    name: "本地访问内网Web服务"
    type: local
    ssh_host: "your-jump-server.com"
    ssh_port: 22
    ssh_user: "your_username"
    ssh_pkey: "~/.ssh/id_rsa"      # 或使用密码
    local_port: 8080
    remote_host: "internal-server.local"
    remote_port: 80

  - id: expose_api
    name: "暴露本地Flask服务到公网"
    type: remote
    ssh_host: "public-server.com"
    ssh_port: 22
    ssh_user: "deploy"
    ssh_password: "your_password"
    remote_port: 2222
    local_host: "localhost"
    local_port: 5000
    # remote_bind_address: "0.0.0.0"   # 如需监听所有接口(需服务器GatewayPorts yes)

  - id: socks_proxy
    name: "SOCKS5代理"
    type: dynamic
    ssh_host: "my-server.com"
    ssh_port: 22
    ssh_user: "proxy_user"
    ssh_pkey: "~/.ssh/proxy_key"
    local_port: 1080

三、使用方法

​ 根据实际环境修改 config.yaml 中的隧道配置。

3.1 从项目中运行

  1. 列出所有可用的隧道:

    uv run pyssh_tunnel -l
    
  2. 启动一个或多个隧道(通过 -c 指定 ID,可重复):

    uv run pyssh_tunnel -c web_server -c socks_proxy
    
  3. Ctrl+C 停止所有隧道。

3.2 安装pyssh_tunnel

  1. 使用pip install pyssh_tunnel

  2. 使用命令行执行

    pyssh_tunnel -c web_server -c socks_proxy
    

四、命令行参数

  • -c, --config-id:要启动的隧道 ID(可多次使用)
  • -l, --list:列出所有隧道配置
  • --config-file:指定配置文件路径(默认 config.yaml
  • --log-file:日志文件路径(默认输出到控制台)
  • --log-level:日志级别(DEBUG/INFO/WARNING/ERROR)
$ pyssh_tunnel -h
usage: pyssh_tunnel [-h] [-c IDS] [-l] [--config-file CONFIG_FILE] [--log-file LOG_FILE]
                    [--log-level {DEBUG,INFO,WARNING,ERROR}]

SSH隧道管理器

options:
  -h, --help            show this help message and exit
  -c IDS, --config-id IDS
                        选择要启动的隧道ID (可多次使用)
  -l, --list            列出所有可用隧道配置
  --config-file CONFIG_FILE
                        配置文件路径 (默认: config.yaml)
  --log-file LOG_FILE   日志文件路径
  --log-level {DEBUG,INFO,WARNING,ERROR}
                        日志级别

该实现支持同时运行多个不同类型的隧道,每个隧道独立运行在后台线程中,收到中断信号时会优雅关闭所有连接。

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyssh_tunnel-0.1.0.tar.gz (40.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyssh_tunnel-0.1.0-py3-none-any.whl (12.1 kB view details)

Uploaded Python 3

File details

Details for the file pyssh_tunnel-0.1.0.tar.gz.

File metadata

  • Download URL: pyssh_tunnel-0.1.0.tar.gz
  • Upload date:
  • Size: 40.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.9

File hashes

Hashes for pyssh_tunnel-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d2ffe7b901674ef76f0c411fb1fb0462b000fd4dcda0e8ad67dd2934b0121e34
MD5 c8258aff005412347f32fb537835d5ce
BLAKE2b-256 c7318831e4e454003e569994df8a067dcce060a13b93a64510f40d3648b0e6fa

See more details on using hashes here.

File details

Details for the file pyssh_tunnel-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pyssh_tunnel-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6a0eba8fa71f6de70419a3ff11c24b49e22ccdf6ddb6abfd5856ef82fe3f6f27
MD5 16e8b55b69b9e48ff4e0b4e6a397871c
BLAKE2b-256 14a36119b8ba12c84e4b287b8211e4ade0285602c8380ff5d6210116de60d596

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page