An implementation of hysteria server written in C language for embedded system.
  • C 91%
  • CMake 5.5%
  • Makefile 3.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
zeroHYH b5fbe98cb9 feat: ESP32 runtime config, Hysteria2 UDP relay, realm robustness, status LED
- config: drop Kconfig; all runtime settings now live in SPIFFS config.yaml
  (renamed from server.yaml: wifi/realm/tls/auth/masquerade/led); ship a
  sanitized config.yaml.example and gitignore the real config.yaml/certs
- tls: remove compiled-in embedded_certs.h; TLS cert/key are provisioned via
  SPIFFS only (self-signed via upstream `hysteria cert`), documented in README
- udp: Hysteria2 UDP relay over QUIC unreliable datagrams (UDPMessage codec +
  fragmentation/reassembly, per-session upstream port, pre-auth silent discard,
  idle-session release); also start the QUIC server in direct (non-realm) mode
- realm: robust registration (drop futile DELETE on 409, wait out TTL), heartbeat
  sequence counter, graceful DELETE deregister on Linux SIGINT/SIGTERM
- sse: stream events via esp_tls directly; IPv6 STUN via esp_netif_get_all_ip6
- led: WS2812 status indicator (red/green/blue states + yellow/white pulses),
  low brightness, fully runtime-configurable (no recompile)
- build: externalize picoquic ESP32+ECDSA-TLS changes to
  patches/picoquic-esp32.patch with idempotent auto-apply (CMake+Makefile) and
  .gitmodules ignore=dirty; compile-time debug switch via
  idf.py -DCHYSTERIA_DEBUG_LOG=1 / make DEBUG=1
- cleanup: remove dead code (cert_pem_data/key_pem_data, realm_bytes_to_hex,
  hy2_quic_server_stop, in-function includes, deprecated esp_netif_next),
  redact secrets in config dump
- tests: UDPMessage codec/fragmentation + config led-parse cases
- docs: README versions/deps table, Hysteria-compatibility section, cert
  generation + provisioning, LED and UDP usage
2026-09-01 13:05:23 +08:00
deps feat: initial release of chysteria (lightweight C Hysteria 2 server) 2026-08-31 16:22:27 +08:00
examples/esp32_server feat: ESP32 runtime config, Hysteria2 UDP relay, realm robustness, status LED 2026-09-01 13:05:23 +08:00
include feat: ESP32 runtime config, Hysteria2 UDP relay, realm robustness, status LED 2026-09-01 13:05:23 +08:00
patches feat: ESP32 runtime config, Hysteria2 UDP relay, realm robustness, status LED 2026-09-01 13:05:23 +08:00
src feat: ESP32 runtime config, Hysteria2 UDP relay, realm robustness, status LED 2026-09-01 13:05:23 +08:00
test feat: ESP32 runtime config, Hysteria2 UDP relay, realm robustness, status LED 2026-09-01 13:05:23 +08:00
.gitignore feat: ESP32 runtime config, Hysteria2 UDP relay, realm robustness, status LED 2026-09-01 13:05:23 +08:00
.gitmodules feat: ESP32 runtime config, Hysteria2 UDP relay, realm robustness, status LED 2026-09-01 13:05:23 +08:00
CMakeLists.txt feat: ESP32 runtime config, Hysteria2 UDP relay, realm robustness, status LED 2026-09-01 13:05:23 +08:00
Makefile feat: ESP32 runtime config, Hysteria2 UDP relay, realm robustness, status LED 2026-09-01 13:05:23 +08:00
README.md feat: ESP32 runtime config, Hysteria2 UDP relay, realm robustness, status LED 2026-09-01 13:05:23 +08:00

chysteria

chysteria 是用 C 语言实现的轻量级 Hysteria 2 Server,专为资源受限的嵌入式设备(如 ESP32、OpenWrt 路由器)及 Linux 边缘服务器设计。

支持与官方 Hysteria 2 客户端正常通信,支持 Realm NAT 穿透 / Rendezvous 打洞 与 TCP / UDP 代理流量双向转发。


🌟 特性

  • 轻量紧凑:经过 -Os、LTO 及链接期死代码消除优化,Linux 二进制约 460KB;ESP32-C6(无 PSRAM)应用固件约 1.3MB,常驻堆余量 ~220KB。
  • Realm NAT 穿透:
    • 支持 realm://token@host/id 格式的监听地址。
    • RFC 5389 STUN 公网地址探测(IPv4 / IPv6)。
    • 双栈本地地址枚举:Linux 走 getifaddrs,ESP32 走 esp_netif_get_all_ip6,过滤 link-local / loopback。
    • HYRLMv1 打洞握手(SHA256 混淆掩码 + 对称 NAT 端口预测)。
    • SSE 长连接接收 punch 事件后异步打洞。
  • 标准 Hysteria 2 协议:
    • 基于 picoquic 实现 TLS 1.3 + QUIC 传输(ESP32 使用内置 mbedtls 后端)。
    • HTTP/3 认证握手(233 HyOK / QPACK)。
    • 0x401 TCP Request 解析与非阻塞双向转发。
    • UDP 中继:基于 QUIC 不可靠数据报(DATAGRAM),按规范封装 UDPMessage ([u32 SessionID][u16 PacketID][u8 FragID][u8 FragCount][varint addrLen][addr][payload]), 含分片/重组、按 SessionID 分配独立上游 UDP 端口、鉴权前静默丢弃、空闲超时释放。
  • Uber Zap 风格结构化日志:对齐官方 Go 版本格式(ISO8601\tLEVEL\tmsg\t{json})。
  • 运行期配置(无需重编译):全部经 SPIFFS 的 config.yaml + 证书文件加载;无 Kconfig、无内嵌证书,改配置或换证书只需 storage-flash + 重启。证书请用上游 hysteria cert 自行生成(见下)。
  • 双模跨平台构建:Makefile / CMake(Linux)与 ESP-IDF 组件(idf.py)。

🧩 环境与依赖版本

当前开发与验证所用的版本(构建产物与行为以这些版本为准):

组件 版本 / commit 固定方式 说明
ESP-IDF v5.5.2(target esp32c6) 工具链 eim/activate_idf_v5.5.2.sh components/ + sdkconfig 均基于此版本
Hysteria 协议 Hysteria 2(内部 "v4",QUIC+HTTP/3) 依 PROTOCOL.md 实现 兼容官方 hysteria 客户端
Hysteria 参考实现 HyNetworks/hysteria v2.12.2(619a6f8) 验证基准 协议线格式 / realm(extras/realm) 逐项比对对象
picoquic private-octopus/picoquic 534b2953(draft-16-final-5544,2026-08-29) git submodule(gitlink) 加本地补丁 patches/picoquic-esp32.patch(同基线)
picotls h2o/picotls f07f1c8(2026-07-15) git submodule(gitlink) 未改动
led_strip espressif/led_strip 2.5.5 main/idf_component.yml 约束 ~2.5 + dependencies.lock ESP32 状态指示灯驱动(RMT/WS2812)

复现要点:

  • 子模块 commit 由 gitlink 固定;deps/picoquic 的改动以补丁形式维护、构建时自动 apply(见「picoquic 补丁工作流」)。
  • 托管组件精确版本由 examples/esp32_server/dependencies.lock 锁定。
  • Linux 端用系统 gcc/cmake/libssl-dev(本仓库验证于 gcc 14.2 / OpenSSL 3.5 / cmake 3.30)。

📁 目录结构

chysteria/
├── CMakeLists.txt          # 双模构建:Linux 可执行 + ESP-IDF 组件(并自动 apply picoquic 补丁)
├── Makefile                # 原生 Linux 构建(自动初始化子模块、编译 QUIC/TLS 依赖、apply 补丁)
├── .gitmodules             # picoquic / picotls 子模块(picoquic 设 ignore=dirty)
├── patches/
│   └── picoquic-esp32.patch# picoquic 的 ESP32/mbedtls 移植 + ECDSA TLS 签名修复(构建时自动 apply)
├── include/                # 头文件 (STUN / 打洞 / 协议 / QUIC / 配置 / 日志)
├── src/                    # 核心源码
│   ├── main.c              # Linux CLI 入口、信号处理、优雅注销
│   ├── hysteria_quic.c     # QUIC/HTTP3 事件循环与 TCP 中继
│   ├── realm_manager.c     # STUN 探测、Rendezvous 注册/心跳/注销、SSE、双栈打洞
│   ├── realm_http.c        # Rendezvous REST / SSE 客户端(ESP 用 esp_tls,Linux 用 OpenSSL)
│   ├── realm_punch.c       # HYRLMv1 打洞包加解密
│   ├── hysteria_proto.c    # QUIC Varint 与 0x401 编解码
│   ├── hysteria_config.c   # config.yaml 解析
│   └── hysteria_log.c      # Zap 风格日志
├── examples/
│   └── esp32_server/       # 完整 ESP-IDF 示例工程(app_main、SPIFFS 配置、分区表、config.yaml.example)
├── deps/                   # 子模块依赖 (picoquic, picotls)
└── test/                   # 单元与集成测试

🛠️ Linux 构建

依赖

gcc、make、cmake、libssl-dev、pkg-config、git。

sudo apt-get install -y build-essential cmake libssl-dev pkg-config git

使用 Makefile(推荐)

自动初始化子模块、编译 picotls/picoquic、并给 picoquic 打 patches/picoquic-esp32.patch:

make -j$(nproc)                 # 产出 build/chysteria_server + 测试
make test                       # 运行单元 + 集成测试
make DEBUG=1                    # 调试构建:启用 HY_VERBOSE_DEBUG 详细日志
make clean                      # 清理产物
make clean-deps                 # 额外清理 picotls/picoquic 构建

使用 CMake

cmake -S . -B build && cmake --build build -j
ctest --test-dir build --output-on-failure   # UnitTests / IntegrationTests

picoquic 补丁工作流

本仓库对 deps/picoquic 的改动以补丁形式维护,源码树保持干净:

  • 补丁:patches/picoquic-esp32.patch(基线 commit 见文件头)。
  • 构建时自动、幂等地 apply(CMake configure 阶段与 make 均检测实际 git 状态)。
  • 手动:make patches(应用) / make unpatches(回退)。
  • 与上游同步:make unpatches && git -C deps/picoquic checkout -- . && git submodule update 后重新构建即自动再 apply。
  • 因此 git status 在 apply 后可能显示 deps/picoquic 修改;子模块已配置 ignore = dirty,主仓 git status 不会因此被污染。

🚀 使用指南(Linux)

配置示例 config.yaml

listen: realm://your_token@realm.example.com/your_realm_id   # 或 host:port 直连模式

tls:
  cert: /path/to/server.crt
  key:  /path/to/server.key

auth:
  type: password
  password: your_password

masquerade:
  type: proxy
  proxy:
    url: https://www.example.com
    rewriteHost: true

led:            # 可选,仅 ESP32 状态指示灯用到
  enable: true
  gpio: 8
  brightness: 2

证书建议为 ECDSA P-256(客户端按 TLS 要求校验证书签名,需 DER 编码的 ECDSA 签名,本仓库已正确处理)。

启动 / 停止

./build/chysteria_server -c config.yaml            # 标准启动
./build/chysteria_server -c config.yaml -l debug   # 详细日志

# Ctrl-C / SIGTERM:会向 Rendezvous 发送 DELETE 主动注销,立即释放 realm 槽位

🔌 ESP32 / ESP-IDF

完整示例工程位于 examples/esp32_server/(默认目标 esp32c6,USB-Serial/JTAG)。本工程可直接构建烧录;亦可将仓库根目录作为 components/chysteria 引入你自己的 ESP-IDF 工程。

构建与烧录

source $IDF_PATH/export                       # 或使用 eim activate <ver>
cd examples/esp32_server
idf.py set-target esp32c6
idf.py build
idf.py -p /dev/ttyACM0 flash monitor          # 首次或配置变更时可加:
idf.py -p /dev/ttyACM0 storage-flash          # 仅烧写 SPIFFS(config.yaml / 证书)

证书与配置准备(首次使用,仓库不含真实凭据/私钥)

config_data/ 里的 config.yaml、server.crt、server.key 均被 gitignore,需要你自备:

cd examples/esp32_server/config_data

# 1) 用上游 hysteria(v2.12.2)生成自签证书;--host 要与客户端 tls.sni 一致
#    (客户端用 tls.insecure 时 SAN 主要满足握手即可)
hysteria cert --host <client-sni> --cert server.crt --key server.key

# 2) 由模板生成本地配置并填写 WiFi/Realm/认证
cp config.yaml.example config.yaml
#   编辑 config.yaml:wifi.ssid/password、listen 的 token/realm id、auth.password

# 3) 一次性把固件 + config.yaml + 证书烧进 SPIFFS(storage 分区打包整个 config_data/)
idf.py -p /dev/ttyACM0 flash

运行期配置(免重编译,唯一配置入口)

启动时挂载 SPIFFS → 读 /spiffs/config.yaml(无 Kconfig,配置全部来自此文件);TLS 证书固定从 /spiffs/server.crt|key 读取(不再内嵌进固件)。改配置或换证书:编辑 config_data/ 下文件 → idf.py -p PORT storage-flash → 重启即生效,无需重新编译。若证书文件缺失,设备会在日志中报错并停止启动 QUIC。

examples/esp32_server/config_data/config.yaml 会被打包进 SPIFFS(分区见 partitions.csv 的 storage)。示例:

wifi:
  ssid: "YOUR_SSID"
  password: "YOUR_PASS"

listen: realm://<token>@<rendezvous.example.com>/<realm_id>   # 或 host:port 直连
# 自定义 STUN / 本地端口用查询参数:realm://<token>@<host>/<id>?stun=<stun.example.com:3478>&lport=4433

tls:
  cert: /spiffs/server.crt
  key:  /spiffs/server.key

auth:
  type: password
  password: "your_password"

led:                 # 板载 WS2812 状态指示灯(可选)
  enable: true
  gpio: 8
  brightness: 2      # 百分比 1-100,越小越暗

状态指示灯(WS2812 RGB)

config.yaml 的 led: 段配置(全运行期,改完 idf.py -p PORT storage-flash + 重启即生效,不重编译):

表现 含义
红(常亮暗) realm 未连接
绿(常亮暗) realm 已连接/注册
蓝(常亮暗) 有代理客户端已连接
黄(短脉冲) realm 心跳
白(短脉冲) 客户端请求(TCP/UDP)

enable: false 可整体关闭;gpio 默认 8(ESP32-C6-DevKitC-1 板载 RGB),brightness 默认 2%。无 led: 段时用内置默认(enable、GPIO8、2%)。

构建/sdkconfig 相关项

  • 调试构建(编译期详细日志:IPv6 ping 自检、原始 SSE dump、周期 free-heap 监视):已无 Kconfig 项,用 idf.py -DCHYSTERIA_DEBUG_LOG=1 build 开启(默认 release)。
  • 网络/系统(sdkconfig.defaults 固定):CONFIG_LWIP_IPV6=y + IPV6_AUTOCONFIG + IPV6_DHCP6(Realm 需 Global IPv6,app_main 会等待 SLAAC 分配);CONFIG_ESP_MAIN_TASK_STACK_SIZE=16384、CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=24576(打洞/TLS 握手栈需求)。
  • 运行期可变的 WiFi/Realm/认证/证书/LED 全部走 config.yaml,不再是编译期配置。

低内存说明

ESP32-C6(单核 + LP core、无 PSRAM)下按 low-profile 运行:QUIC 连接数与流数、中继缓冲均已收敛;TLS 走 mbedtls,证书链走系统 esp_crt_bundle。


🩺 Realm 运维行为(常见疑问)

  • 启动时反复 409 realm_taken:Rendezvous 端同一 realm_id 为单一槽位。若上一个实例是崩溃/重刷断电退出的(未能注销),其 session 会在服务端存活至 TTL(默认 60s) 自然过期;期间新实例每几秒重试注册 → 连续 409,直到旧 session 过期后成功。属正常自愈。
  • DELETE 返回 401:注销需携带当前 session token(而非配置里的 auth token)。因此启动早于旧 session 过期时无法主动抢占,只能等 TTL。
  • Linux 正常 Ctrl-C/SIGTERM 会主动注销,立即释放槽位,避免下一次启动吃 409。ESP32 的重启多来自 reflash/掉电(无优雅钩子),仍走 TTL 等待路径。
  • 多实例:并发运行的服务端应使用不同 realm_id(或不同 token),否则会互相抢占同一槽位而彼此 409。

🧭 与原版 Hysteria 的兼容性 / 差异

chysteria 是独立的 C 实现,协议线格式与官方一致(已逐项比对 HyNetworks/hysteria 的 PROTOCOL.md 与 extras/realm):

协议层(一致)

  • 认证:POST /auth + Hysteria-Auth,成功响应 HTTP 状态 233 HyOK。
  • TCP:0x401 TCPRequest / TCPResponse。
  • UDP:QUIC DATAGRAM 上的 UDPMessage,分片 FragID/FragCount 与官方 internal/frag 语义一致。
  • Realm 打洞:HYRLMv1\0 魔数 + SHA256(obfsKey+salt) XOR 掩码 + 对称 NAT 端口候选,与 extras/realm 一致。
  • Realm HTTP API:POST /v1/{id}(注册,用 auth token)、/v1/{id}/heartbeat、/v1/{id}/connects/{nonce}、GET /v1/{id}/events(SSE)、DELETE /v1/{id}(注销);除注册外均用 Authorization: Bearer <session_id>。
  • Realm URL scheme:realm://=TLS、realm+http://=明文,与官方一致。

配置层(子集,命名有差异)

  • listen 支持 realm://token@host/id 或 host:port(直连)。
  • chysteria 读:wifi:、tls:(cert/key/sniGuard)、auth.type=password、masquerade.proxy、顶层标量 stun:。
  • 不支持原版的:realm: 结构块(stunServers 列表 / stunTimeout / punchTimeout / heartbeatInterval / ipMode / insecure / portMapping)、obfs(salamander/gecko)、acme、bandwidth、resolver、sniff、acl、trafficStats、masquerade.file/string、auth fast-pattern。原版配置迁移时需按上述字段名调整。

UDP 大数据报说明

  • 单个数据报(≤~MTU)与 ≤2 分片的中继已在官方 hysteria client 端到端验证通过;更大的多分片(>2 datagram)消息在本机回环测试中连原版 server↔client 亦无法送达(quic-go 在回环/该 MTU 下的发送行为),属环境/客户端特性,非服务端逻辑差异。

✅ 测试

make test          # Linux:单元(STUN / 打洞编解码 / 协议)+ 集成(配置解析 / STUN / 回环打洞 / TCP 转发 / UDPMessage 编解码与分片)

ESP 侧以真机 + 官方 hysteria client 做端到端联通验证(含 TCP 与 UDP 中继)。


📄 开源许可

MIT License