Skip to content

This repository does not operate a public instance.

Self-hosted Conversion Service and Web Console

A work-in-progress Rust conversion backend plus a static Web Console that operates a Conversion Service you run. Native and the Cloudflare Worker share the same host-neutral HTTP and conversion modules. You clone, run, or deploy your own copy.

The button publishes Conversion plus Console on one Worker origin. It does not collect an access token. After deploy, GET /sub stays anonymous until you add SUB_HUB_ACCESS_TOKEN as a Secret.

Inputs

url accepts one or more ordered sources separated by |. Unsupported or invalid nodes are skipped; source and config errors fail the request.

  • VLESS

    vless:// share URI. TCP, WebSocket, and gRPC with TLS or Reality, including Vision where the target can keep it.

  • Shadowsocks

    SIP002 ss://. Closed ciphers: aes-128-gcm, aes-256-gcm, chacha20-ietf-poly1305, and the two 2022-blake3-aes-*-gcm methods. simple-obfs http/tls is kept on most targets; Surge skips it.

  • Trojan

    trojan://. TCP+TLS and WebSocket+TLS.

  • VMess

    vmess:// plus v2rayN JSON v2. Other VMess dialects are rejected.

  • Hysteria2

    hysteria2:// and hy2://. Hop, salamander, and pin follow per-target Keep-pass.

  • TUIC v5

    tuic://uuid:password@host:port with a closed query set.

  • HTTPS subscriptions

    Remote contents that contain those share URIs. Omit expand or set expand=false to leave remotes as client refs on targets that can name them. expand=true inlines. sing-box still inlines when expand is omitted.

  • ACL4SSR config

    Optional HTTPS config= selects a strict ACL4SSR INI. Absent or empty config= is the default PROXY/AUTO policy, not an ACL4SSR profile and not a second Rule frontend.

Policy and query

  • Absent or empty config= uses PROXY/AUTO (select AUTO + nodes + Direct, url-test AUTO, MATCH → PROXY).
  • expand is accepted. The Web Console switch defaults on and writes expand=true.
  • filename is a download-name stem (1–64 bytes). The service appends the per-target extension. Omitted uses sub-hub-<target>.<ext>.
  • A GET/HEAD request-target over 8 KiB returns 414.

Client targets

target must be one of these exact tokens. Popular apps that import the document are listed; those names are not extra HTTP tokens. Do not use stash, surfboard, or shadowrocket as target.

  • clash / mihomo

    Mihomo YAML. clash is the Clash-compatible name; Clash Meta clients typically import clash.

    Clash Verge Rev, FlClash, Clash Meta for Android, Stash, OpenClash, Karing, Hiddify

  • quanx

    Quantumult X conf.

    Quantumult X

  • singbox

    sing-box JSON.

    SFA, SFI/SFM, GUI.for.sing-box, Throne, Karing, Hiddify, NekoBox

  • loon

    Loon conf.

    Loon

  • egern

    Egern YAML.

    Egern

  • surge

    Surge conf. Surfboard follows Surge and does not support VLESS.

    Surge, Surfboard

Web Console

The Workshop PWA lives in apps/console. It points at a Conversion Service origin you type, collects the access token in its own field, assembles GET /sub or GET /sub/:token, previews that same Subscription URL, and copies or downloads the result.

  • clash://install-config is offered on every platform. On iPhone and iPad it also offers first-party one-click import for Surge, Loon, Egern, and sing-box.
  • It does not add POST conversion or extra query switches.
  • Same-origin layout all on a Worker does not need SUB_HUB_CORS_ORIGINS. A Vite Workshop against loopback does.

How to run it

There is no hosted Sub Hub here. Pick Native for a machine you control, GitHub Release binaries if you do not want a Rust toolchain, or the Cloudflare Worker to publish Conversion plus Console.

  • Native (development)

    mise install, then cargo run --locked -p sub-hub-native. The safe default listener is 127.0.0.1:25500. Verify with GET /version.

  • Native (GitHub Releases)

    Unsigned linux-amd64, windows-amd64, and macos-arm64 archives. They do not include the Web Console and are not signed or notarized.

  • Cloudflare Worker

    Deploy-to-Cloudflare publishes layout all: one Worker, Console assets on that same origin. GET /version stays public. Set SUB_HUB_ACCESS_TOKEN as a Secret on a public Worker so clients use GET /sub/<token>.

Closed HTTP surface

The current compatibility surface contains only:

  • GET /version
  • GET /sub and HEAD /sub
  • GET /sub/:token and HEAD /sub/:token when SUB_HUB_ACCESS_TOKEN is set
  • There is no POST conversion, capabilities endpoint, or administration API.
  • GET /version stays public when tokens are set. Wrong token: 401 Unauthorized!. Unset token: GET /sub stays anonymous and GET /sub/:token returns 404 Not Found.
  • When any node is skipped, GET/HEAD /sub adds x-subconverter-skipped (and x-subconverter-result: partial unless the response is already lossy).

Out of scope

  • No public conversion instance on this site or in this repository.
  • No Dockerfile, docker-compose, or GHCR publish job.
  • No AnyTLS, WireGuard, or SSR. No second Rule frontend.
  • No extra subconverter switches (include / exclude / emoji / udp / scv / sort).

License

Sub Hub is licensed under the GNU Affero General Public License v3.0 or later. It is commonly deployed as a network service; AGPL section 13 requires operators of modified network-facing versions to offer corresponding source to their users.

Corresponding source