MEHS client CLI
mehs is the MEHS reference client. It authorizes a client, finalizes a data transport (tcp_tls or quic), authenticates the data connection, and then either binds the requested local proxy listeners (proxy mode) or brings up a TUN interface (--mode tun). Startup succeeds only after the data path is authenticated and the listeners or interface are usable. Authorization, finalization, transport authentication, or listener-bind failures reject startup. A failed flow-open rejects that local proxy request without making the session ready for that flow.
Ctrl-C stops the listeners (or removes the TUN routes), sends a session-level Close, closes the data path, and exits with status 0. After a session has been up, an unexpected EOF, transport failure, or server restart triggers reconnection with delays of 1, 2, 4, 8, 16, then 30 seconds. Only the 30-second retries count toward the default limit of five: ten retries and 181 seconds of scheduled waiting in total, plus time spent on connection attempts. Exhausting this budget exits with status 1. Set "inf_reconnect": true in the JSON file passed to --session-config to disable the attempt limit; it defaults to false and does not change error classification. A session lasting at least 60 seconds resets both the backoff and retry budget; shorter sessions do not. Any failure of the very first connection, including connection refusal or timeout, exits with status 1 without retrying. Authorization, certificate, configuration, and policy failures during session setup are fatal even when reconnecting. A server-sent Close is a clean completion.
MEHS_CLIENT_SECRET='<secret>' mehs \
--control localhost:8443 --client-id <id> --ca-file server-chain.pem \
--socks-bind 127.0.0.1:1080 --http-bind 127.0.0.1:8080
curl --socks5 127.0.0.1:1080 http://example.com/
| Flag | Meaning |
|---|---|
--control HOST:PORT | HTTPS control endpoint (required). HOST is the TLS server name. |
--client-id ID | Client ID (required). |
--secret SECRET | Client secret; prefer the MEHS_CLIENT_SECRET environment variable, since arguments are visible to other local users. |
--session-config PATH | Strict schema 1 JSON session settings; see mehs-client.example.json and the authoritative configuration reference. Every setting is applied: mode (including auto), pool counts, timeouts, keepalive, health checks, migration/selection, and buffer limits. |
--transport MODE | Data transport: tcp (default), quic, or auto (measures both carriers); the server must enable the selected listener(s). |
--e2e-crypto SUITE | off (default) or mlkem768-aes256; overrides session JSON and must be permitted by server policy. |
--tls-fingerprint NAME|PATH | Optional TLS ClientHello preset (chrome-stable, mobile-yandex-stable, firefox-stable, mobile-firefox-stable) or custom JSON profile. Defaults to rustls; mehs-data/1 ALPN/framing is preserved. QUIC data TLS remains rustls. |
--transport-profile NAME | Transport profile: mehs-data/1 (default), xhttp, trusttunnel (trusttunnel-http alias), or notmehs. Unknown names fail without fallback. |
--http-path PATH | URL path for HTTP-shaped profiles (default /mehs/stream; must match the server). |
--app-bypass NAME | Repeatable. This application (executable name or full path) connects directly. Linux/Windows. |
--app-only NAME | Repeatable. Only this application is tunnelled; others connect directly. Not combinable with --app-bypass. |
--data HOST:PORT | Data endpoint; default is the control host with port + 1. HOST must match the server certificate. For quic, this is the server's UDP quic_data_listen address. |
--ca-file PATH | PEM certificate(s) to trust; default is the built-in WebPKI roots. |
--socks-bind ADDR | SOCKS5 bind address; default 127.0.0.1:1080. |
--http-bind ADDR | HTTP CONNECT bind address; default disabled. |
--udp-associate | Enable SOCKS5 UDP ASSOCIATE; default disabled. Use for SOCKS5 voice calls/games that need UDP; HTTP CONNECT remains TCP-only. |
--remote-dns | Resolve SOCKS5/HTTP CONNECT destination names on the server; default disabled. Requires a server that supports domain destinations. Proxied names are not resolved locally; the client still resolves its own control/data endpoints locally. |
--verbose | Emit detailed setup, network, TLS, selection, session, proxy, and recovery diagnostics. |
--mode proxy|tun | proxy (default) serves local SOCKS5/HTTP; tun creates a system-wide virtual interface. TUN needs root/administrator, and wintun.dll beside mehs.exe on Windows. |
--tun-name NAME | TUN interface name; default mehs0. |
--tun-mtu N | TUN MTU, 576-9000; default 1400. |
--tun-route CIDR | Route only this prefix through the tunnel; repeatable. Default: all IPv4 and IPv6 traffic. The server addresses are always excluded. |
--tun-no-routes | Do not change host routes; the host configures them. |
--tun-exclude CIDR | Keep this prefix on the normal network path (split routing, e.g. a LAN); repeatable. |
--tun-allow-quic | Forward UDP port 443 instead of dropping it (it is dropped by default so browsers fall back to TCP). |
--tun-fd N | Use an already-open TUN descriptor (Android VpnService); implies --tun-no-routes. |
Each data connection is an independent MEHS link (tcp_connection_count / udp_connection_count of the chosen carrier); new flows are balanced round-robin and dead links are replaced automatically. --transport overrides the session config's mode; --transport auto (or mode: "auto") measures both carriers, picks the best, keeps a standby link on the other carrier, and migrates live (without interrupting open connections) when it stays clearly better. The client emits secret-free setup statuses (resolving_control, control_tls, authorizing, finalizing, resolving_data, data_connecting, data_authenticating, probing) followed by authenticated, ready, established, migrating, and terminal-failure status events as they become available. --verbose adds detailed MEHS events for DNS/network/TLS/control requests, link authentication, probe/selection, session health/retransmits, flows, migration, proxy/TUN setup, and reconnects; lifecycle output uses plain status tokens without code= or phase= fields. Without --verbose, status output remains unchanged. If every link ends, the supervisor reconnects with backoff. In TUN mode, killing the client does not leave routes behind: a detached reaper process (mehs --tun-reaper PID) and the next start remove them. SOCKS5 UDP ASSOCIATE is opt-in with --udp-associate (use it for proxy voice calls or games that need UDP); destination names are resolved locally unless --remote-dns is enabled, which sends proxied names to a server that supports domain destinations. In TUN mode UDP and DNS work transparently. Both TCP/TLS and QUIC data paths are implemented.
TUN mode examples
# Linux / macOS (root); adjust LAN exclusions to match your network
sudo -E mehs --control vpn.example.com:8443 --client-id laptop --ca-file ca.pem \
--mode tun --tun-exclude 192.168.0.0/16 --tun-exclude 10.0.0.0/8 \
--tun-exclude 172.16.0.0/12
# Windows (Administrator PowerShell, wintun.dll next to mehs.exe)
.\mehs.exe --control vpn.example.com:8443 --client-id laptop --ca-file ca.pem --mode tun --tun-exclude 192.168.0.0/16 --tun-exclude 10.0.0.0/8 --tun-exclude 172.16.0.0/12
# Split tunnel: only these ranges
sudo -E mehs ... --mode tun --tun-route 91.108.4.0/22 --tun-route 149.154.160.0/20
Verify with curl -4 https://api.ipify.org (it prints the server's IP). The server refuses private/LAN destinations and may lack IPv6 egress; IPv6 connections then fail and applications fall back to IPv4. Do not run TUN mode alongside another VPN that owns a TUN device and default route. Every CLI parameter is listed in the configuration reference, which is the authoritative schema 1 contract and documents how future schema changes are versioned.
Proxy examples
Local proxy mode is the CLI default and needs no administrator rights. This recommended setup resolves proxied destination names on the server (when supported) and leaves SOCKS5 UDP off unless an app needs it:
mehs --control vpn.example.com:8443 --client-id laptop --ca-file ca.pem \
--socks-bind 127.0.0.1:1080 --http-bind 127.0.0.1:8080 --remote-dns
Add --udp-associate for SOCKS5 voice calls or games that need UDP. --remote-dns and --udp-associate remain opt-in to preserve existing defaults; --remote-dns requires a server that supports domain destinations and does not change local resolution of the client's control/data endpoints. See ready-made profiles.