https://github.com/codingmiao/hppt
一款可通过任意协议转发tcp端口的工具 A tool to forward tcp ports over any protocol
https://github.com/codingmiao/hppt
java nat netty proxy
Last synced: 1 day ago
JSON representation
一款可通过任意协议转发tcp端口的工具 A tool to forward tcp ports over any protocol
- Host: GitHub
- URL: https://github.com/codingmiao/hppt
- Owner: codingmiao
- License: apache-2.0
- Created: 2023-12-22T14:14:27.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2026-06-10T03:15:20.000Z (2 days ago)
- Last Synced: 2026-06-10T05:08:48.844Z (2 days ago)
- Topics: java, nat, netty, proxy
- Language: Java
- Homepage:
- Size: 1.08 MB
- Stars: 122
- Watchers: 2
- Forks: 28
- Open Issues: 0
-
Metadata Files:
- Readme: readme.md
- License: LICENSE
Awesome Lists containing this project
- awesome-java - HPPT
README

hppt,一款可通过任意协议转发tcp端口的工具。
——只要两台机器间有任何通讯渠道(如http短连接、websocket、tcp,甚至kafka之类的消息队列),就能让两台机器间任意端口互通!
[中文](./readme.md) [English](./readme_en.md)
[github](https://github.com/codingmiao/hppt) [gitee](https://gitee.com/wowtools/hppt)
# 简介
日常工作中,我们常常因为无法访问某些远程端口而带来很多麻烦,例如下面的场景,服务器的防火墙只留了80/443端口用以web访问,
如果你希望访问到服务器上的数据库、SSH等端口,可以借助本工具把需要的端口映射出来:

# 快速开始
项目依赖jdk21,如未安装,请先前往[jdk官网](https://jdk.java.net/archive/)下载对应你操作系统的版本。
在[releases](https://github.com/codingmiao/hppt/releases)
页面下载最新版本编译好的hppt。
或自行下载源码编译:
```shell
mvn clean package -DskipTests
```
## 示例1 通过http端口,反向代理访问内部服务器SSH端口
假设你有一个服务器集群,仅有一个nginx提供了80/443端口对外访问(111.222.33.44:80),你想要访问集群中的应用服务器(192.168.0.2)
的22端口,则可以按如下结构部署

1、在集群中任一服务器上新建一个hppt目录,并上传hppt.jar、ss.yml、logback.xml文件到此目录下:
```
hppt
- hppt.jar
- ss.yml
- logback.xml
```
并调整ss.yml的配置信息:
```yaml
#使用http post协议传输数据,此协议最为简单,但性能略差,如有需要请查看websocket协议或hppt协议或自定义协议
type: post
#服务http端口
port: 20871
# 允许的客户端账号和密码
clients:
- user: user1
password: 12345
- user: user2
password: 112233
```
(注1:作为快速演示,这里的type选择了最简单的post类型,此场景下可按[这篇文档](_doc/demo/websocket.md)
配置websocket以获得更高性能,或是有独立端口的话可以按[这篇文档](_doc/demo/hppt.md)配置hppt协议)
(注2:实际应用中,为了确保安全,建议把密码设置得更复杂一些)
执行如下命令运行服务端的hppt
```shell
cd hppt
/bin/java -jar hppt.jar ss ss.yml
```
在nginx上增加一段配置指向hppt
```
server {
# 用https也ok的,对应修改nginx https配置即可
listen 80;
...
location /xxx/ {
proxy_pass http://localhost:20871/;
}
...
```
说明:
- `post` 协议的服务端不是普通网页服务,只接受形如 `POST /s?c=...` 和 `POST /r?c=...` 的协议请求
- 因此直接用浏览器访问 `http://111.222.33.44:80/xxx/`,通常会看到 `404`
- 如果你手工访问了协议路径但没有带 `c` 参数,例如 `/s` 或 `/r`,则会返回 `400`
- 这里的关键不是返回码本身,而是 nginx 是否已经把 `/xxx/` 正确转发到了 hppt 服务;浏览器访问并不是 `post` 协议的功能验证方式
注意:
- `sc.yml` 中的 `post.serverUrl` 可以写成 `http://111.222.33.44:80/xxx`,前提是 nginx 需要把 `/xxx/` 重写回后端根路径 `/`
- 本文示例中的 `proxy_pass http://localhost:20871/;` 末尾带 `/`,就是为了让客户端实际访问到后端的 `/s` 和 `/r`
- 如果你不经过 nginx,而是直连服务端端口,那么 `serverUrl` 不应额外带路径前缀,应直接写成 `http://host:20871`
2、自己笔记本上,新建一个hppt目录,拷贝hppt.jar 、sc.yml、logback.xml文件到此目录下:
```
hppt
- hppt.jar
- sc.yml
- logback.xml
```
并调整sc.yml的配置信息:
```yaml
# 和服务端的type保持一致
type: post
# 客户端用户名,每个sc进程用一个,不要重复
clientUser: user1
# 客户端密码
clientPassword: 12345
post:
# 服务端http地址,如无法直连,用nginx代理几次填nginx的地址也ok
serverUrl: "http://111.222.33.44:80/xxx"
# 这个示例中,不用nginx的话直接配原始的服务端端口
#serverUrl: "http://111.222.33.44:20871"
# 人为设置的延迟(毫秒),一般填0即可,如果传文件等数据量大、延迟要求低的场景,可以设一个几百毫秒的延迟来降低post请求发送频率
sendSleepTime: 0
forwards:
# 把192.168.0.2的22端口代理到本机的10022端口
- localPort: 10022
remoteHost: "192.168.0.2"
remotePort: 22
# 同理也可以代理数据库等任意TCP端口,只要服务端的hppt所在服务器能访问到的端口都行
- localPort: 10023
remoteHost: "192.168.0.3"
remotePort: 3306
```
执行如下命令启动客户端的hppt
jar包运行
```shell
cd hppt
/bin/java -jar hppt.jar sc sc.yml
```
随后,你就可以在公司用linux连接工具访问localhost的10022端口,来登录应用服务器了
## 示例2 内网穿透,通过公网转发,访问无公网IP的服务器
假设你家里有一台台式机(ssh端口为22),并且有一台公网VPS服务器(ip 111.222.33.44),你想在公司用笔记本登录家里的台式机,可按如下结构部署:

1、公网服务器上,新建一个hppt目录,拷贝hppt.jar、sc.yml、logback.xml文件到此目录下:
```
hppt
- hppt.jar
- sc.yml
- logback.xml
```
并调整sc.yml的配置信息:
```yaml
# 通讯协议 本示例使用了性能最好的hppt协议,加r前缀表示客户端和服务端角色互换。这里也可以配http post或websocket
type: rhppt
# 客户端用户名,每个sc进程用一个,不要重复
clientUser: user1
# 客户端密码
clientPassword: 12345
# 服务端口
rhppt:
port: 20871
# 心跳包发送周期
heartbeatPeriod: 30000
forwards:
# 把192.168.0.2的22端口代理到本机的10022端口
- localPort: 10022
remoteHost: "192.168.0.2"
remotePort: 22
# 同理也可以代理数据库等任意TCP端口,只要服务端的hppt所在服务器能访问到的端口都行
- localPort: 10023
remoteHost: "192.168.0.3"
remotePort: 3306
```
执行如下命令启动公网服务器上的hppt
jar包运行
```shell
cd hppt
/bin/java -jar hppt.jar sc sc.yml
```
2、家里的台式机上,新建一个hppt目录,拷贝hppt.jar、ss.yml、logback.xml文件到此目录下:
```
hppt
- hppt.jar
- ss.yml
- logback.xml
```
修改ss.yml
```yaml
# 通讯协议 客户端与服务端保持一致
type: rhppt
# 服务端监听端口
port: 20871
# 指向上一步启动的服务的ip和端口
rhppt:
host: "111.222.33.44"
port: 20871
# 心跳包检查周期,多少毫秒没有客户端发来心跳包则重启服务
heartbeatTimeout: 3600000
# 允许的客户端账号和密码
clients:
- user: user1
password: 12345
- user: user2
password: 112233
```
执行如下命令启动家里台式机上的hppt
jar包运行
```shell
cd hppt
/bin/java -jar hppt.jar ss ss.yml
```
随后,你就可以在公司用linux连接工具访问111.222.33.44的10022端口,来登录家里的台式机了
## 更多配置
[完整的配置文件说明](_doc/config.md)
## 管理接口
`ss` 服务端可选开启 RESTful 管理接口,用于健康检查、查看活跃客户端/session、重启当前业务 service、停止进程等运维操作。默认不开启;需要时可在 `ss.yml` 中配置 `management.port`:
```yaml
management:
host: 127.0.0.1
port: 19091
token: "change-me"
```
建议默认只监听 `127.0.0.1`,通过 SSH tunnel 或内网网关访问;如果监听非本机地址,必须配置 `token`。详细接口、鉴权和响应字段见 [_doc/management-api.md](_doc/management-api.md)。
## 示例3 编写自定义协议
下面通过一个用kafka做为“通信协议”的方式,演示如何编写自定义协议。
如下图所示,A、B两台机器间无法进行通信,但他们都可以访问到机器C上的kafka,我们在kafka中做两个topic供客户端发送/消费数据,使得A能够以C上的kafka作为桥梁访问到B上的SSH端口:

### 嵌入到java应用中
首先clone本项目到本地,然后`mvn clean install`把本项目安装到maven。
然后新建一个java工程,引入hppt-run以及kafka等maven依赖
```xml
org.wowtools.hppt
run
1.0-SNAPSHOT
```
然后就可以编写代码了:
编写一个服务端实现并在机器B上运行,你需要实现如下方法:
```java
public class ServerDemo extends ServerSessionService {
public ServerDemo(SsConfig ssConfig) {
super(ssConfig);
}
//初始化时需要做什么
public void init(SsConfig ssConfig) throws Exception {
}
//怎样发送字节到客户端
protected void sendBytesToClient(T ctx, byte[] bytes) {
}
//收到客户端的字节时,主动去调用receiveClientBytes(CTX ctx, byte[] bytes)
//当客户端断开时需要做什么
protected void closeCtx(T ctx) throws Exception {
}
//当本服务端关闭后,在此释放掉连接池等资源
protected void onExit() throws Exception {
}
}
```
完整的示例实现请参考[这里](kafkademo/src/main/java/org/wowtools/hppt/kafkademo/ServerDemo.java)
编写一个客户端实现并在机器B上运行,你需要实现如下方法:
```java
public class ClientDemo extends ClientSessionService {
public ClientDemo(ScConfig config) throws Exception {
super(config);
}
//怎样连接到服务端
protected void connectToServer(ScConfig config, Cb cb) throws Exception {
}
//怎样发送字节到服务端
protected void sendBytesToServer(byte[] bytes) {
}
//收到服务端的字节时,主动去调用receiveServerBytes(byte[] bytes)
}
```
完整的示例实现请参考[这里](kafkademo/src/main/java/org/wowtools/hppt/kafkademo/ClientDemo.java)
随后,你就可以通过访问A的10022端口,来连接B上的SSH 22端口了。
### 插件方式运行
也可以编写成一个插件,参考[这个模块](addons-kafka)
插件开发完后,按如下结构放置文件:
```
hppt
- addons
- addons.jar
- config files
- hppt.jar
- ss.yml or sc.yml
- logback.xml
```
然后在配置文件里`type`属性写上插件类:
ss.yml
```yaml
# 通讯协议 客户端与服务端保持一致
type: 'org.wowtools.hppt.addons.kafka.KafkaServerSessionService'
# 允许的客户端账号和密码
clients:
- user: user1
password: 12345
- user: user2
password: 112233
```
sc.yml
```yaml
type: 'org.wowtools.hppt.addons.kafka.KafkaClientSessionService'
localHost: 127.0.0.1
# 客户端用户名,每个sc进程用一个,不要重复
clientUser: user1
# 客户端密码
clientPassword: 12345
#是否启用内容加密,默认启用 需和服务端保持一致
enableEncrypt: true
forwards:
- localPort: 10022
remoteHost: "wsl"
remotePort: 22
```
参照前面的例子运行即可
# Q&A
## 性能如何?
本项目只做了转发和加解密操作,在网络成为瓶颈的实际场景中性能损耗很小。以下是通过代理下载一个331MB文件的测试对比(服务端带宽已限速,模拟真实网络环境):
| 协议 | 下载耗时 | 速度 | 损耗 |
|------|---------|------|------|
| 直连 | 83.2s | 4.00 MB/s | - |
| HPPT | 84.1s | 3.96 MB/s | 1% |
| WebSocket | 84.0s | 3.96 MB/s | 1% |
| POST | 83.8s | 3.96 MB/s | 1% |
在带宽受限的真实网络环境中,三种协议的损耗都在1%左右。如果在性能敏感的场景,建议使用长连接协议(hppt/websocket),POST等短连接协议仅在环境不允许长连接的情况下再使用。
## 安全性如何?
必须使用指定的用户才能连接,数据传输过程中对字节进行了加密以防监听,如果你还需要更多的个性化验证,比如用户登录,可以发邮件到[liuyu@wowtools.org](liuyu@wowtools.org)
进行定制化开发。
## hppt是什么意思
`hppt`是翻转的`http`,最初,本项目用于把http协议反转以实现两台机器的tcp通信,随着逐渐扩充和完善,本项目不仅支持http协议,而是成为了一个支持任意协议的通用的连接工具,但本项目依然保留了这个带有反转意味的名字o(* ̄︶ ̄*)o
...(还有什么好玩的想法给我提issue或者发邮件哈)