[2.3.0] - 2026-10-21
sing-box 1.14, the new Snell protocol (on by default), opt-in Hysteria2 gecko obfuscation, component version bumps (incl. a Grafana security patch), a CDN flag fix so an upgrade no longer silently turns off a configured CDN, and a fix so moav update cleanly discards staged local changes. No breaking changes; keys, users, and certificates are untouched.
Added
- Snell protocol (new sing-box inbound), on by default. A lightweight TCP proxy with HTTP obfuscation, no TLS/domain required (
ENABLE_SNELL=true,PORT_SNELL=8389,SNELL_OBFS). Shared-key (one PSK for all users, like the DNS tunnels) — sing-box's multi-user snell has no client-compatible auth, so revoking a user needs a key rotation + re-issue. Needs a Snell v5 client (Surge 5 / Stash / Clash Mi / Mihomo / Clash Meta for Android / FlClash — not v2rayNG or Hiddify). Validated end-to-end against a real Mihomo client and the real sing-box 1.14 binary. - sing-box updated to 1.14.0. Our config is already on 1.14's modern surface, so no config change is required; validated by running the real 1.14
sing-box checkagainst the live config (clean, no deprecation warnings). New CI gates render the config and run both a static compatibility check and the realsing-box check/format. - Opt-in Hysteria2 gecko obfuscation.
HYSTERIA2_OBFS_TYPE(defaultsalamander) can select the new gecko obfuscator, which fragments the QUIC handshake and resists Iran/CN/RU DPI better. Opt-in because gecko needs a client core of sing-box >= 1.14 or hysteria >= 2.9.2 — re-issue bundles and confirm your users' apps before enabling it. --jsonoutput for automation (moav status,moav doctor [check],moav user list,moav user add,moav user remove|revoke;moav test --jsonunchanged in shape). One document on stdout, progress/logs on stderr, and secret-free by construction: no keys, passwords, share-links or server addresses —statusonly emits the dashboard URLs when they are domain-based,doctordetails are colour-stripped and redacted (IPv4/IPv6, links, key-shaped tokens),user listcarries names + service membership only.user remove --jsonreports a per-user result and exits non-zero on an unknown user (the text path still exits 0). Requested by the MoaV deploy app (moav-deploy-app#8).- Non-interactive
install.sh:MOAV_NONINTERACTIVE=1(or--non-interactive) withMOAV_DOMAIN,MOAV_EMAIL,MOAV_ADMIN_PASSWORD,MOAV_DOMAINLESS=1andENABLE_*toggles from the environment, or--answers FILEread from a regular file that must be mode0600and owned by the caller. Fails closed on any missing/invalid answer (weak or non-round-trippable passwords included), never accepts the password on the command line, never prints it, writes.envat0600withoutsed, only fills empty/placeholder values on an existing.env, derivesDEFAULT_PROFILESfrom the toggles, and skips the swap / kernel-tuning host changes.MOAV_BOOTSTRAP=1opts into runningmoav bootstrap --yesat the end.
Changed
- Component version bumps (audit 2026-09-11):
- Grafana 13.2.0 → 13.2.1 — upstream security fixes (CVE-2026-12704, CVE-2026-14199).
- telemt 3.5.5 → 3.5.7 — install-probe fix, websocket-lane recovery, macOS status-schema fixes.
- Xray-core v26.7.28 → v26.9.9.
- slipstream 2026.02.22.1 → v2026.04.22.1 (server + client builds).
- MasterDNS 2026.05.10 → v2026.06.13 (release SHA256SUMS still verified at build).
- TrustTunnelClient held at 1.0.49. v1.1.5 swaps the QUIC stack (quiche → ngtcp2) while the server side stays 1.1.0, so it needs a live client/server compatibility test before bumping.
- Client test tool: migrated the WireGuard path from the removed sing-box
wireguardoutbound to the 1.14 endpoint form. - Protocol count is now 18+ across the README, agent guide, and docs (Snell brought the transports to 18; the roster is 21 counting the 3 donation integrations).
- Claude issue-triage
--max-turnsraised 6 → 15: the triage finished its work in ~8 turns, but the action failed a run that exceeded the cap. It no longer fails after completing. moav bootstrap --yeshonours the savedDEFAULT_PROFILESinstead of entering the interactive service selection (which, without a TTY, fell through to "select later" and left a fresh install with nothing built or started).moav test --jsonkeeps stdout clean: the progress lines and the client image build now go to stderr, so the JSON no longer has to be scraped out ofdocker buildoutput.confirm()(CLI and installer) returns its default without opening/dev/ttywhenMOAV_NONINTERACTIVE=1.
Fixed
- A configured CDN no longer needs a second toggle, and an upgrade no longer turns it off.
ENABLE_CDNnow ships unset (commented) in.env.exampleinstead of=false, socdn_enabled()'s rule governs everywhere: CDN is on exactly whenCDN_SUBDOMAINis set and proxied through Cloudflare, and off otherwise. Because the flag is unset,moav updateno longer appendsENABLE_CDN=falseonto an upgrading server — the append that could silently drop a working CDN at the next bootstrap. The compactmoav://bundle builder now gates oncdn_enabledas well, matching every other CDN path (it was the lone reader of the raw flag). An explicitENABLE_CDN=true/falsestill wins. moav update"Discard changes" now fully resets. The Discard option usedgit checkout -- ., which only clears unstaged edits; staged changes (git statusMM/A, e.g. a hand-editeddocker-compose.ymlor added exporter files) survived and the pull still aborted with "local changes would be overwritten by merge" even after Discard reported success. It now usesgit reset --hard, which clears the index too.moav update -b <ref>now accepts a tag, not only a branch. Switching an install to a release candidate (moav update -b v2.3.0-rc.1) failed with "Branch '…' does not exist" because the target was validated against branch refs only. It now resolves tags too (fetching them first) and checks out a tag in detached HEAD without attempting a pull..envno longer carries inline comments on variable lines.moav updatecopied new options from.env.exampleverbatim, so a line likePORT_SNELL=8389 # Snellreached the live.env; a consumer reading the value with a rawgrep|cutthen folded the comment into it (the AmneziaWG port once became<ip>:51821 # AmneziaWG …, so clients connected but relayed nothing). Every note now sits on its own line in.env.example, the update path strips a trailing inline comment defensively, and a CI gate keeps it that way.- XDNS now carries VLESS Encryption (Xray >= 26.9 compatible). This release's Xray bump (v26.9.9) began rejecting a VLESS outbound with no TLS/encryption that dials a public IP, so xray refused to start and XDNS failed (caught by the rc.3 e2e). XDNS dials a public resolver/server over mKCP, so the VLESS layer now carries its own encryption: a server-wide X25519 keypair is minted at bootstrap (openssl, no extra binary; stored in
state/keys/xdns.env), withdecryptionon the server XDNS inbound andencryptionin every client bundle. This also hardens XDNS (its DNS-tunnelled VLESS was previously unencrypted) and unblocks it for anyone on an already-updated Xray client. - Telegram release notification pins its link preview to the release page. The preview showed whatever link appeared first in the notes body (e.g. a client's App Store page) instead of the release. It now sets
link_preview_options.urlto the release/issue URL. Same fix in moav-client. moav statuslost published ports whendocker compose ps --format jsonreturned an array: the array-to-lines split cut inside a container'sPublisherslist, so a service with two ports showed none and the next row was skipped. The split is now brace-depth aware.
Testing
tests/cli-json-test.sh— every--jsonshape (valid JSON, stdout-only, no planted secret substring), via the real dispatcher with a fakedockerand fake provisioning scripts.tests/install-noninteractive-test.sh— answers validation,0600/ ownership checks, argv password refusal,.envrendering and re-run safety.
Quick Install
curl -fsSL https://moav.sh/install.sh | bashThis will install MoaV to /opt/moav and guide you through setup.
Documentation
moav.sh/docs — full documentation
Get started
- Quick Start — install to first user in ~10 minutes
- Client Setup — connect from phones and desktops
- DNS Configuration — records, delegations, freeing port 53
Reference
- CLI Reference — every command and flag
- Setup Guide — every option, in depth
- Monitoring — Grafana dashboards and metrics
- Troubleshooting — symptom-first fixes
Understand it
- Supported Protocols — per-protocol ports, ciphers, stealth
- Architecture — container topology and bundle flow
- Threat Model — what is and is not protected
- Guide — operator-side hardening
Help out
- Support MoaV — run a server, contribute, translate, donate
- Translating the Docs — one page is a complete contribution
🤖 Running it with an AI agent? 🤖 moav.sh/llms.txt is a compact orientation for coding agents; llms-full.txt is the whole corpus. Both ship as release assets.