Open-source project
cfal/shoes avatar
cfal/shoes

shoes: one Rust proxy process serving VMess, VLESS, Shadowsocks, Trojan and Hysteria2

A multi-protocol proxy server written in Rust (HTTP, SOCKS5, Vmess, Vless, Shadowsocks, Trojan, Snell, Hysteria2, TUIC v5, AnyTLS, Naiveproxy, XTLS)

1,264 stars133 forksRustMIT

At a glance

What is it?
shoes is a Rust multi-protocol proxy server that listens on a single YAML configuration, routing by SNI to a dozen inbound protocols and supporting both TCP and QUIC transports. It currently ships as a vendored branch with publishing disabled, because a local HTTP/3 patch has not reached an upstream release.
Who is it for?
shoes suits an operator who wants one process to terminate several proxy protocols on different ports, with SNI routing so one TLS port can serve several domains, and who is willing to build from source rather than take a published crate.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A single config file drives every inbound listener

shoes takes a list of YAML config files on the command line and turns them into listeners. The invocation is shoes followed by one or more config paths, and the configuration is a list of server entries, each with an address and a protocol block. The examples in the README show the range in a few lines: a VMess server on port 16823, a Hysteria2 server on 443 with QUIC transport, a TUIC v5 server, a mixed HTTP and SOCKS5 server on 7890, and a TUN entry for transparent proxying. The YAML is structured as nested blocks rather than a flat list of settings, and the full reference lives in CONFIG.md with a directory of ready made files under examples/, including reality_basic.yaml, mixed.yaml, multi_hop_chain.yaml and named_certificates.yaml. Several config files can be passed at once, so a deployment can split server definitions from routing rules, as in the example that runs server1.yaml, server2.yaml and rules.yaml together.

SNI routing lets one port serve several domains

The feature that most shapes the configuration is TLS with SNI routing. Instead of one listener per domain, a single TLS listener holds a map of hostnames to targets, and the connection is dispatched on the Server Name Indication in the handshake. The VLESS example shows the shape: the listener is 0.0.0.0:443, and under tls_targets the key vless.example.com carries a certificate, a key, a vision flag, ALPN protocols and a nested protocol block naming the vless type and its user id. The AnyTLS and NaiveProxy examples use the same structure with different hostnames and nested protocol types. The practical effect is that a single certificate and a single port can front several distinct services, which is what a shared hosting or multi tenant setup needs. The cost is that the configuration nests, and a real deployment ends up with a handful of hostnames inside a TLS target block rather than a flat list of servers.

Transports are a separate axis from protocols

The README separates proxy protocols from transport protocols, and the two multiply out into a large matrix. On the proxy side there is HTTP and HTTPS, SOCKS5 with UDP ASSOCIATE, a mixed mode that auto-detects HTTP or SOCKS5, VMess AEAD, VLESS with fallback support, Shadowsocks, Trojan, Snell v3, Hysteria2, TUIC v5, AnyTLS and NaiveProxy, plus H2MUX for use with VMess, VLESS, Trojan, Shadowsocks and Snell. On the transport side there is SagerNet UDP over TCP for Shadowsocks, SOCKS5, AnyTLS and NaiveProxy, ShadowTLS v3, TLS, WebSocket under the Shadowsocks SIP003 convention, XHTTP and SplitHTTP across HTTP/1.1, HTTP/2 and HTTP/3, XTLS Reality, and XTLS Vision for VLESS. Every protocol can run over TCP or over QUIC, and the QUIC examples in the README set transport: quic with a quic_settings block carrying the certificate, key and ALPN protocols. A reader evaluating this project should treat the protocol list as the feature list and the transport list as the flexibility.

Reality support with post-quantum key exchange options

The Reality configuration is the most involved example in the README, and it shows two details that are newer than the rest of the tool. The server side has a reality_targets map keyed by hostname, with a private key, a list of short ids including an empty string, and a dest address, wrapping a nested vless protocol block. The client side has a reality protocol block with a public key, a short id and an sni_hostname, again wrapping a vless block. Separately from the keys themselves, the transport section notes that XTLS Reality here uses hybrid-first X25519MLKEM768 key exchange with optional ML-DSA-65 server authentication. The binary also has commands to generate the material, generate-reality-keypair and generate-reality-mldsa65-keypair, along with generate-shadowsocks-2022-password for a given cipher, so the secret values in a config are something the tool can produce for you rather than something you have to invent.

The install story has a wrinkle: this branch is not on crates.io

Precompiled binaries for x86_64 and Apple aarch64 are published on the GitHub releases page, and the README describes a cargo install shoes for the previously published release. The current branch is different, and the reason is stated plainly. This branch temporarily vendors an HTTP/3 correctness fix that Cargo excludes from crates.io packages, publishing is disabled until an upstream release includes the fix, and to retain the patch you build from the checkout with cargo install --path . --locked. The manifest confirms it: the package has publish = false, with a comment saying the local h3 patch must not be dropped by crates.io packaging, and the workspace has a patch entry pointing h3 at vendor/h3 with that directory excluded from the workspace. So the repository you are reading is, right now, ahead of the published crate. Anyone who installs from crates.io gets the older build without the HTTP/3 correction.

Validating a config before you start the server

There is a dry run flag, and it is worth using every time you change a config. The -d and --dry-run options validate the config and the certificates and then exit, and there is a check subcommand that is an alias for the same thing. Two other flags matter in operation: -t and --threads set the number of worker threads, defaulting to the CPU count, and --no-reload disables automatic config reloading on file changes. The hot reloading feature means that by default the process watches the config files and applies changes without a restart, which is convenient and also means a typo in a file you are editing can take the server down mid-session. Running the check command against the edited file first is the cheap way to avoid that. The other subcommands are version, an alias for --version, and the three key and password generators mentioned above.

bash
cargo install --path . --locked
bash
shoes --dry-run config.yaml
shoes check config.yaml
shoes --threads 8 config.yaml
shoes --no-reload config.yaml
shoes generate-reality-keypair
shoes generate-shadowsocks-2022-password 2022-blake3-aes-256-gcm

Routing, chaining and the limits of what the tool does not do

Rule based routing is expressed on the client side, as masks with an action, attached to an outbound chain. The Reality client example shows a rule with the mask 0.0.0.0/0 and the action allow, pointing at a client_chain that names the remote address and the protocol to use. Rules can match by IP and CIDR or by hostname masks, and a client chain supports multi-hop chains with load balancing, which is how a chain of servers is expressed rather than a separate configuration type. Access control is where the project draws a line. The README says that for advanced access control such as IP allowlists and blocklists, see tobaru, a separate project by the same author. So the gap is deliberate rather than an oversight, but it does mean the pieces must be deployed and reasoned about together. The other documented limits are protocol level: the cipher lists are per protocol, with VMess offering aes-128-gcm, chacha20-poly1305 and none, and the Shadowsocks list covering the AES-GCM and ChaCha20 variants plus the three 2022 blake3 ciphers.

A library with a TUN mode, FFI builds and a feature-gated test suite

The Cargo manifest reveals a project that is more than a server binary. The library is built as an rlib, a cdylib and a staticlib, with a comment noting that the staticlib is required for iOS, and there is an ffi feature flag to enable the FFI module for non-Android builds. The android/ directory at the top of the repository matches the TUN mode support listed in the README, which covers Linux, Android and iOS. The test suite is organised by feature flags rather than by a single suite, with separate integration, external network, optional peer, reality interop, privileged and stress test targets, each gated behind its own feature, plus a process_contract test that always runs. That structure tells you where the risk sits: the optional peer and reality interop tests need a counterpart to talk to, and the privileged tests need elevated rights for the TUN device.

Editorial conclusion

shoes suits an operator who wants one process to terminate several proxy protocols on different ports, with SNI routing so one TLS port can serve several domains, and who is willing to build from source rather than take a published crate. It is the wrong choice if you want a stable install from a package registry, because the current branch carries a vendored HTTP/3 patch and publishing is disabled, and a poor fit if you only need a single client protocol, where the configuration surface is larger than the job requires. Before adopting it, read CONFIG.md for the full YAML reference, run the check command against your configuration to validate it and the certificates without starting, and note that the README points to a separate project, tobaru, for IP allowlists and blocklists rather than building that in.

Frequently asked questions

Which proxy protocols does shoes support?

The README lists HTTP and HTTPS, SOCKS5 with UDP ASSOCIATE, a mixed mode that auto-detects HTTP or SOCKS5, VMess AEAD, VLESS, Shadowsocks, Trojan, Snell v3, Hysteria2, TUIC v5, AnyTLS, NaiveProxy, and H2MUX over VMess, VLESS, Trojan, Shadowsocks and Snell. Every protocol can run over TCP or QUIC.

How do I install shoes?

Precompiled binaries for x86_64 and Apple aarch64 are on the GitHub releases page. The current branch vendors an HTTP/3 fix that crates.io packaging would drop, so building from the checkout with cargo install --path . --locked is the documented way to keep the patch, and the package has publish = false in its manifest.

How do I validate a shoes config before starting it?

Use the -d or --dry-run flag, or the check subcommand, which validate the config and the certificates and then exit. The README also documents --threads for the worker thread count, defaulting to the CPU count, and --no-reload to disable automatic config reloading on file changes.

How does shoes route multiple domains on one port?

It uses TLS with SNI routing. A single listener on 0.0.0.0:443 holds a tls_targets map keyed by hostname, and each entry carries the certificate, key and a nested protocol block, so one port can front several domains with separate services behind it.

Does shoes include IP allowlists and blocklists?

No. The README points to a separate project called tobaru for advanced access control such as IP allowlists and blocklists, and shoes provides rule based routing by IP and CIDR or hostname masks with upstream proxy chaining and load balancing.

Official sources

  1. cfal/shoes on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/cfal-shoes.svg)](https://hysenlabs.com/projects/cfal-shoes)

Was this useful?