# MoaV, full documentation
> Complete MoaV documentation in one file, concatenated from the MkDocs sources in nav order.
> Short index: https://moav.sh/llms.txt
> Source: https://github.com/MotherofallVPNs/moav-site
> Generated by scripts/build-llms-full.sh, do not edit by hand.
---
# MoaV Documentation
**MoaV (Mother of all VPNs)** is a free, open-source multi-protocol censorship circumvention stack. Deploy a full arsenal of [anti-censorship protocols](https://moav.sh/docs/protocols/) on any VPS or home server with a single command.
MoaV generates ready-to-use **client bundles** for each user, containing config files, QR codes, and step-by-step instructions (in English and Farsi) for each enabled and successfully configured user-facing protocol. Non-technical users simply open the bundle's `README.html` in their browser, scan a QR code, and connect. No manual configuration needed.
Read the concise [Mission](https://moav.sh/docs/mission/), the project's [Impact](https://moav.sh/docs/impact/) model, and the public [Threat Model](https://moav.sh/docs/threat-model/).
---
**New here?** Start with the [Quick Start Guide](https://moav.sh/docs/quick-start/) to get up and running in minutes.
---
## Guides
- **[Quick Start](https://moav.sh/docs/quick-start/)**: Install, create a user, and share a bundle
- **[Setup Guide](https://moav.sh/docs/SETUP/)**: Complete installation with all options
- **[DNS Configuration](https://moav.sh/docs/DNS/)**: DNS records for your domain and provider
- **[VPS Deployment](https://moav.sh/docs/DEPLOY/)**: One-click deploy on Hetzner, DigitalOcean, Vultr, Linode
- **[Video Tutorials](https://moav.sh/docs/video-tutorials/)**: Video Walkthroughs
## Using MoaV
- **[Client Apps](https://moav.sh/docs/CLIENTS/)**: Connect from iOS, Android, macOS, Windows, Linux
- **[MoaV Client](https://moav.sh/docs/client/)**: MoaV client with a dashboard, load-balancing, and automatic failover
- **[CLI Reference](https://moav.sh/docs/CLI/)**: All `moav` commands and options
- **[Monitoring](https://moav.sh/docs/MONITORING/)**: Grafana + Prometheus dashboards
- **[Troubleshooting](https://moav.sh/docs/TROUBLESHOOTING/)**: Common issues and fixes
## Security & Philosophy
- **[Mission](https://moav.sh/docs/mission/)**: What MoaV is, who it serves, and how to help
- **[Impact](https://moav.sh/docs/impact/)**: Theory of change, outcomes, and measurable progress
- **[Threat Model](https://moav.sh/docs/threat-model/)**: Honest limits, adversaries, metadata risks, and safety assumptions
- **[OPSEC Guide](https://moav.sh/docs/OPSEC/)**: Security best practices for operators
- **[Mission & Philosophy](https://moav.sh/docs/philosophy/)**: The longer manifesto behind the project
- **[Supported Protocols](https://moav.sh/docs/protocols/)**: All 16+ circumvention transports and fallback paths, plus optional Psiphon, Tor and MahsaNet donation integrations, including the [DNS tunnels](https://moav.sh/docs/protocols/#dns-tunnels) that can remain usable where ordinary traffic is blocked but recursive DNS still resolves
## Support the project
- **[Support MoaV](https://moav.sh/docs/support/)**: Run a server, donate bandwidth, contribute code, translate, or fund the infrastructure
## Developer
- **[Development & Testing](https://moav.sh/docs/development/)**: installing from a branch or tag, repo layout, how CI and the end-to-end suite work, and how to contribute
---
# Quick Start
Install MoaV, then hand someone a link that connects them. That's the whole path, and it takes about ten minutes.
MoaV deploys [16+ circumvention transports and fallback paths](https://moav.sh/docs/protocols/), plus optional Psiphon, Tor and MahsaNet donation integrations, and turns each user into a share-ready **bundle** — configs, QR codes, and plain-language instructions in English and Farsi. The person receiving it doesn't need to understand any of it. Curious why this exists? Read [the mission](https://moav.sh/docs/philosophy/).
## What you need
- **A server** — Debian 12 / Ubuntu 22.04 or 24.04, or a **Raspberry Pi 4+** (ARM64). 1 vCPU / 1 GB RAM is the floor; 2 GB if you want monitoring.
- **A domain** — optional, but worth it. It unlocks several additional transports, particularly the TLS-based proxies and all DNS tunnels, which can remain usable where ordinary traffic is blocked but recursive DNS still resolves. See [Do I need a domain?](https://moav.sh/docs/DNS/#do-i-need-a-domain).
!!! tip "Point your DNS *before* installing"
Certificate issuance needs the domain already resolving to the server, so adding the records first makes the install smooth. The exact records are in [DNS Configuration](https://moav.sh/docs/DNS/#with-a-domain-the-records) — and after setup, `moav doctor dns` writes them out for you as a file you can import straight into Cloudflare.
No VPS yet? [VPS Deployment](https://moav.sh/docs/DEPLOY/) has provider-by-provider steps from ~$5/month. On a home server or Pi, check for CGNAT first and forward the [protocol ports](https://moav.sh/docs/DNS/#ports-to-forward).
## 1. Install
SSH in and run:
```bash
curl -fsSL moav.sh/install.sh | bash
```
It installs Docker, clones MoaV, and asks for three things: your **domain** (blank for domainless), an **email** for Let's Encrypt, and an **admin password** — which is also your Grafana password, so pick a real one.
When it finishes it prints your dashboard URLs and the DNS records to add.
The install, start to finish — 14s. Nothing downloads until you press play (808 KB).
!!! tip "Prefer to watch someone do it?"
A community walkthrough covers the whole path end to end — see [Video Tutorials](https://moav.sh/docs/video-tutorials/). Farsi only for now.
## 2. Create your first user
Two ways. Use whichever you prefer — they do the same thing.
=== "Web dashboard"
Open **`https://your-server:9443`** and log in — **any username**, with the admin password you chose.
??? warning "Your browser will warn about the certificate"
In domainless mode the dashboard uses a self-signed certificate, so you'll see a privacy warning the first time. That's expected — proceed past it. With a domain configured it uses your Let's Encrypt certificate and there's no warning.
Click **+ New**, enter a name, and the user appears in the table with a badge for every protocol they got — Reality, Trojan, Hy2, CDN, WG, AWG, XHTTP and so on. Hit **.zip** to download their bundle.
The dashboard is the easiest place to run day to day: it lists every user with their creation date and protocols, downloads bundles on demand, and shows live server stats.
Creating and packaging a user from the dashboard — 22s, 284 KB.
=== "Command line"
```bash
moav user add alice # one user
moav user add alice --package # ...and build the .zip
moav user add --batch 10 # ten at once
moav user list # who exists
```
Bundles land in `outputs/bundles/alice/`.
Adding, listing and packaging users from the CLI — 31s, 636 KB.
Either way you get the same bundle:
- **`README.html`** — the file to actually send. Step-by-step instructions in English and Farsi, with QR codes. They open it, pick their platform, scan, and they're online.
- Config files and share links for each enabled and successfully configured user-facing protocol, plus a one-paste **subscription** for MahsaNG, v2rayNG and Hiddify.
Send it over something private — Signal, encrypted email, in person. See [Client Apps](https://moav.sh/docs/CLIENTS/) for what to tell them per platform.
## 3. Know these four commands
```bash
moav status # what's running, which profiles are up, health at a glance
moav doctor # diagnose problems: DNS, ports, certificates, resources
moav logs # tail a service when something misbehaves
moav test alice # prove alice's configs actually pass traffic, end to end
```
`moav doctor` is the one to reach for first when anything looks wrong — it checks the things that break most often and usually names the problem outright. `moav test` is the one to run before you tell someone their bundle works, because it connects through each protocol for real and reports the exit IP.
Running plain **`moav`** opens an interactive menu over all of it, so there's nothing to memorize. Every entry maps to a command in the [CLI Reference](https://moav.sh/docs/CLI/).
## 4. Watch it work (optional)
If you enabled monitoring, **Grafana** is at **`https://your-server:9444`** — user `admin`, same password.
Ten dashboards ship preconfigured, so there's nothing to build:
| Dashboard | What it tells you |
|---|---|
| **sing-box** | Per-user connections and throughput for Reality, Trojan, Hysteria2, Shadowsocks |
| **WireGuard** · **AmneziaWG** | Peer handshakes, transfer per peer |
| **DNS tunnels** | Traffic across dnstt, Slipstream, MasterDNS, XDNS |
| **Xray** · **telemt** | XHTTP/XDNS and Telegram MTProxy activity |
| **Conduit** · **Snowflake** | Bandwidth you're donating to Psiphon and Tor users |
| **System** · **Containers** | CPU, memory, disk, and per-container resource use |
Not running monitoring? `moav start monitoring` turns it on — it wants ~2 GB RAM. Details in [Monitoring](https://moav.sh/docs/MONITORING/).
## Where to go next
- **[Client Apps](https://moav.sh/docs/CLIENTS/)** — what your users install, per platform
- **[CLI Reference](https://moav.sh/docs/CLI/)** — every command
- **[DNS Configuration](https://moav.sh/docs/DNS/)** — records, DNS tunnels, CDN mode
- **[Setup Guide](https://moav.sh/docs/SETUP/)** — every configuration option in depth
- **[OPSEC Guide](https://moav.sh/docs/OPSEC/)** — running and sharing this safely
- **[Troubleshooting](https://moav.sh/docs/TROUBLESHOOTING/)** — when something breaks
---
# Mission
MoaV, Mother of all VPNs, is open-source resilient connectivity infrastructure for censorship and shutdown environments. It helps trusted operators deploy multi-protocol access nodes so users have fallback routes when VPNs, domains, apps, or protocols are blocked.
MoaV is not trying to be another commercial VPN brand. It is a public-interest deployment stack for people who need the open internet to keep working under pressure.
## The talk
**Rage-coding the Mother of all VPNs** — [Shayan Eskandari](https://github.com/shayanb) at DappCon 2026, Berlin. Why MoaV exists, what it takes to keep sixteen protocols working under pressure, and what was learned building it.
## Why MoaV exists
Internet shutdowns and protocol blocking are now routine tools of control. During protests, crackdowns, elections, and conflicts, governments can throttle bandwidth, block popular apps, fingerprint VPN protocols, and isolate people from the outside world.
Most circumvention tools help only if they are already reachable. A single blocked domain, protocol, app store, payment route, or infrastructure provider can cut off a large group of users at once.
MoaV is built around a different assumption: no single route survives every censor. The useful system is the one that degrades gracefully.
## What MoaV does
MoaV turns a low-cost server into a multi-protocol circumvention node. It automates setup, generates user bundles, and supports multiple transports so operators do not have to assemble a stack by hand.
The goal is simple:
- make deployment fast for trusted operators
- support many fallback protocols
- reduce dependence on one provider or domain
- make operator documentation clear
- keep the code open source and auditable
- help communities add capacity before the next shutdown
## Who MoaV serves
MoaV is designed for:
- people in censored environments who need access to the open internet
- journalists, activists, students, families, and civil-society groups affected by blocking
- diaspora communities that can donate servers, bandwidth, and operational support
- open-source internet-freedom projects that need reusable deployment tooling
The first community focus is Iran, but the design is not Iran-only. The same patterns apply anywhere networks are filtered, throttled, or partially shut down.
## What MoaV is not
MoaV is not a promise of perfect anonymity. It is not a token network. It is not a magic way around every form of surveillance. It is access infrastructure, and it should be used with a clear understanding of risk.
Read the [Threat Model](https://moav.sh/docs/threat-model/) for the limits, adversaries, and safety assumptions.
## How to help
If you want to help users reach the open internet:
1. [Deploy MoaV](https://moav.sh/docs/quick-start/) on a VPS.
2. Read the [OPSEC Guide](https://moav.sh/docs/OPSEC/) before sharing access.
3. Share user bundles only through trusted channels.
4. Enable donation paths such as [Psiphon Conduit](https://moav.sh/docs/support/#donate-bandwidth-instead-of-users), [Tor Snowflake](https://moav.sh/docs/support/#donate-bandwidth-instead-of-users), or [MahsaNet](https://moav.sh/docs/mahsanet/) when appropriate.
5. Contribute code, protocol support, documentation, testing, or translations.
## Related pages
- [Impact](https://moav.sh/docs/impact/)
- [Threat Model](https://moav.sh/docs/threat-model/)
- [Architecture](https://moav.sh/docs/architecture/)
- [Supported Protocols](https://moav.sh/docs/protocols/)
- [Mission & Philosophy](https://moav.sh/docs/philosophy/)
---
# Impact
MoaV is built on a practical theory of change: censorship becomes harder to enforce when access capacity is distributed across many small operators, many protocols, and many fallback paths.
The project does not depend on one perfect transport. It makes it easier to keep adding routes.
## The problem
When governments block the internet, people lose access to news, family, organizers, emergency information, and the outside world. Existing circumvention tools help, but many are centralized, protocol-specific, or difficult for ordinary supporters to operate.
Censors exploit that fragility. They block known VPN protocols, domains, app stores, payment routes, and large infrastructure providers. A tool that works today can fail during the next crisis.
## The intervention
MoaV gives trusted operators a repeatable way to deploy multi-protocol access nodes. The project combines:
- setup automation
- transport diversity
- per-user bundles
- operator documentation
- safety guidance
- monitoring and health checks
- bandwidth donation paths
This turns spare servers and community support into usable circumvention capacity.
## Expected outcomes
MoaV aims to produce:
- more independent access nodes before censorship events
- faster deployment when demand spikes
- more fallback routes when one protocol is blocked
- better operator safety and documentation
- reusable open-source infrastructure for the wider internet-freedom ecosystem
## What success looks like
Success is measurable. Useful metrics include:
- number of deployed nodes
- number of supported protocols
- time from fresh server to working node
- setup success rate
- number of user bundles generated
- number of operators onboarded
- protocol availability under blocking conditions
- security issues found and fixed
- documentation and localization coverage
- reuse by other open-source projects
Not every metric should be public. Live node inventory, active-user counts, and sensitive operational details can create risk. Public reporting should focus on aggregate progress and reusable outputs.
## Why open source matters
Open source is not just a value statement here. It is part of the safety model.
Public code lets operators inspect what they run, lets researchers audit the implementation, and lets other projects reuse the parts that work. Grant money and volunteer time should compound into public infrastructure, not a closed service.
## Where MoaV fits
MoaV sits between end-user VPN apps and low-level protocol research. It packages protocols, operational practice, and deployment automation into something a trusted operator can run.
That makes it useful to:
- internet-freedom funders
- open-source infrastructure maintainers
- diaspora support networks
- censorship measurement projects
- protocol developers who need real deployment paths
## Related pages
- [Mission](https://moav.sh/docs/mission/)
- [Threat Model](https://moav.sh/docs/threat-model/)
- [Architecture](https://moav.sh/docs/architecture/)
- [OPSEC Guide](https://moav.sh/docs/OPSEC/)
---
# Threat Model
MoaV is useful because it improves access resilience. It does not make every user anonymous against every adversary.
This page explains what MoaV is designed to protect, what it does not protect, and what operators should assume before deploying it.
**What the server stores about users:** volume and liveness per user, never a link between a user and a destination. The full policy, including what an operator can optionally switch on and the limits of anonymising a small population, is in [What MoaV Records](https://moav.sh/docs/OPSEC/#what-moav-records).
## Who MoaV is meant to help
MoaV is designed for:
- people in censored environments who need access to the open internet
- journalists, civil-society groups, activists, students, and families affected by blocking
- diaspora communities that can provide trusted technical support
- operators who can safely run servers outside high-risk jurisdictions
## Adversaries
MoaV assumes adversaries may include:
- state censors blocking domains, IPs, protocols, app stores, and payment routes
- network operators performing DPI, throttling, or traffic shaping under state pressure
- active probers that connect to suspected proxy servers
- hosting providers that may suspend nodes after complaints
- attackers targeting users, operators, or project infrastructure
- malicious operators pretending to run trusted nodes
## What MoaV tries to protect
MoaV tries to improve:
- access to blocked websites and services
- availability of fallback routes during blocking events
- operator ability to deploy and rotate nodes quickly
- integrity of open-source deployment scripts and documentation
- user safety through clear limits and safer defaults
## What MoaV does not fully protect
MoaV does not fully protect against:
- device compromise
- targeted surveillance by a capable state actor
- unsafe user behavior after connecting
- metadata exposure from the local network, hosting provider, payment system, or destination service
- trust problems caused by unknown or malicious node operators
- legal risk for operators in hostile jurisdictions
If a user's device is compromised, a network tool cannot make that device safe. If an operator is in a jurisdiction where running circumvention infrastructure is dangerous, MoaV does not remove that legal or physical risk.
## Metadata risks
Even when traffic content is encrypted, metadata can remain visible. Examples include:
- server IP addresses
- connection timing
- protocol choice
- traffic volume
- cloud-provider billing records
- operator logs
- destination-side account activity
MoaV should minimize unnecessary logs and make safer defaults easy, but operators remain responsible for how they host, monitor, and share access.
## Operator safety principles
Operators should:
- run nodes only where they can safely do so
- avoid publishing sensitive node inventory
- use unique credentials per user
- revoke compromised users quickly
- keep admin panels locked down
- avoid unnecessary logging
- keep systems updated
- separate personal identity from operational infrastructure where possible
- read the [OPSEC Guide](https://moav.sh/docs/OPSEC/)
## User safety principles
Users should:
- get configs only from trusted sources
- keep devices updated
- avoid logging into high-risk personal accounts when unnecessary
- assume local network observers may see that they are using unusual traffic
- understand that MoaV provides access, not total anonymity
## Misuse and abuse
Any access tool can be used outside its intended beneficiary group. MoaV's answer is transparency and careful operation, not centralized surveillance.
The project should avoid collecting user identities, avoid building unnecessary tracking features, and keep deployment auditable. Public operators should still have abuse-response plans and should understand the policies of their hosting providers.
## Public reporting
Do not publish live operational details that could help censors block active users. Public reports should focus on aggregate progress, security fixes, documentation, and reusable open-source outputs.
## Related pages
- [OPSEC Guide](https://moav.sh/docs/OPSEC/)
- [Architecture](https://moav.sh/docs/architecture/)
- [Supported Protocols](https://moav.sh/docs/protocols/)
- [Mission](https://moav.sh/docs/mission/)
---
# Architecture
How MoaV is wired together. For protocol-level details see [protocols.md](https://moav.sh/docs/protocols/); for CLI behavior see [CLI.md](https://moav.sh/docs/CLI/); for DNS-tunnel mechanics see [DNS.md](https://moav.sh/docs/DNS/).
## How traffic flows
What a MoaV server looks like from the outside in: clients reach it by whichever protocol still works, everything egresses through the server, and two profiles additionally relay bandwidth for other people's networks.
```
┌───────────────┐ ┌───────────────┐
┌───────────────┐ │ Psiphon Users │ │ Tor Users │
│ Your Clients │ │ (worldwide) │ │ (worldwide) │
│ (private) │ └───────┬───────┘ └───────┬───────┘
└───────┬───────┘ │ │
│ │ │
├─────────────────┐ │ │
│ │ (when IP blocked) │ │
│ ┌──────┴───────┐ │ │
│ │ CDN (VLESS) │ │ │
│ └──────┬───────┘ │ │
┌──────────────╪─────────────────╪────────────────────────────────────╪──────────────────╪─────────┐
│ │ │ Restricted Internet │ │ │
└──────────────╪─────────────────╪────────────────────────────────────╪──────────────────╪─────────┘
╔══════════════╪═════════════════╪════════════════════════════════════╪══════════════════╪═════════╗
║ ┌────────┼─────────────────┼───────┼──────┐ │ │ ║
║ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ║
║ ┌─────────┐┌─────────┐┌───────┐┌─────────┐┌────────┐ ┌───────────┐ ┌───────────┐ ║
║ │ Reality ││WireGuard││ Trust ││ DNS ││Telegram│ │ Conduit │ │ Snowflake │ ║
║ │ Trojan ││AmneziaWG││Tunnel ││ tunnels ││MTProxy │ │ (donate │ │ (donate │ ║
║ │Hysteria2││wstunnel ││ ││ (4, on ││ │ │ bandwidth)│ │ bandwidth)│ ║
║ │ AnyTLS ││ ││ ││ port 53)││ │ │ │ │ │ ║
║ │ SS2022 ││ ││ ││ ││ │ │ │ │ │ ║
║ │ CDN WS ││ ││ ││ ││ │ │ │ │ │ ║
║ ├─────────┤└────┬────┘└───┬───┘└────┬────┘└───┬────┘ └─────┬─────┘ └─────┬─────┘ ║
║ │ sing-box│ │ │ │ │ ┌────────────────┐ │ │ MoaV ║
║ └────┬────┘ │ │ │ │ │ Grafana :9444 │ │ │ server ║
║ │ │ │ │ │ │ Admin :9443 │ │ │ ║
╚══════╪══════════╪═════════╪═════════╪═════════╪══╪════════════════╪═╪══════════════════╪═════════╝
│ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Open Internet │
└─────────────────────────────────────────────────────────────────────────────────────────────────┘
```
## Container topology
Every protocol is one or more containers grouped into a docker-compose **profile**. `moav start` reads the `ENABLE_*` flags from `.env` and brings up only the profiles whose flag is on (see [CLI → moav start](https://moav.sh/docs/CLI/#moav-start)).
| Profile | Containers | Protocols it serves |
|---|---|---|
| `proxy` | `sing-box` | Reality (VLESS), Trojan, AnyTLS *(opt-in)*, Hysteria2, Shadowsocks-2022, CDN VLESS+WS |
| `xhttp` | `xray` | VLESS + XHTTP + Reality |
| `wireguard` | `wireguard`, `wstunnel` | WireGuard direct UDP, plus a `wss://` WebSocket fallback for UDP-blocked networks |
| `amneziawg` | `amneziawg` | AmneziaWG (obfuscated WireGuard) |
| `dnstunnel` | `dns-router`, `dnstt`, `slipstream`, `masterdns`, `xray` | All four [DNS tunnels](https://moav.sh/docs/protocols/#dns-tunnels), sharing port 53 |
| `trusttunnel` | `trusttunnel` | TrustTunnel (HTTP/2 + QUIC over TLS) |
| `telegram` | `telemt` | Telegram MTProxy (fake-TLS) |
| `admin` | `admin`, `docker-proxy` | The dashboard on `:9443` |
| `monitoring` | `grafana`, `prometheus`, exporters, `cadvisor` | Metrics and dashboards on `:9444` |
| `conduit` | `psiphon-conduit` | Bandwidth donated to Psiphon |
| `snowflake` | `snowflake` + exporter | Bandwidth donated to Tor |
| `client` | `client` | Local testing (`moav test`) |
AnyTLS is opt-in because it resists TLS-in-TLS fingerprinting but has narrower client support. `all` starts every profile whose flag is on.
## DNS-router fan-out
All four DNS tunnels share **port 53** through a small Go service called `dns-router`, which inspects each query's subdomain prefix and forwards to the matching backend. Each tunnel container listens on its own internal port; only `dns-router` binds the public port.
```
Public 53/udp
│
┌──────▼──────┐
│ dns-router │
└──────┬──────┘
│
subdomain routing:
t.* ─────► dnstt
s.* ─────► slipstream
m.* ─────► masterdns
x.* ─────► xray (XDNS via FinalMask)
```
Delegating a tunnel only requires adding its NS record (`t.` / `s.` / `m.` / `x.`); see [DNS → NS Delegations](https://moav.sh/docs/DNS/#with-a-domain-the-records). Disabling a tunnel via `ENABLE_*=false` removes its container; `dns-router` simply has no backend to forward to.
## Bundle generation flow
User credentials and per-protocol configs originate inside the `bootstrap` container, then get rendered into per-user bundles on the host. The split exists because container-side bundle generation can't see the host's `outputs/` mount layout.
```
moav user add alice
│
▼
┌─────────────────────────────────────────────────────────┐
│ bootstrap container (sing-box-user-add.sh) │
│ - generates UUID + per-protocol keys │
│ - writes state/users/alice/credentials.env (volume) │
└────────────────────┬────────────────────────────────────┘
│ HOST sees state/users/ via volume
▼
┌─────────────────────────────────────────────────────────┐
│ host: generate-single-user.sh │
│ - reads credentials.env + .env │
│ - writes outputs/bundles/alice/{*.txt, *.json, *.png, │
│ subscription.txt, README.html, ...} │
└─────────────────────────────────────────────────────────┘
```
Bundles split into three groups:
- **V2Ray-compatible** (Reality, Trojan, AnyTLS, Hysteria2, SS-2022, CDN, XHTTP) — share-link `.txt`s, QR `.png`s, a single base64 `subscription.txt` importable by MahsaNG / v2rayNG / Hiddify / Streisand.
- **L3 VPNs** (WireGuard, AmneziaWG, TrustTunnel) — `.conf` / `.toml` configs + QR.
- **DNS tunnels** (dnstt, Slipstream, MasterDNS, XDNS) and **donations** (GooseRelay) — text instruction files + protocol-specific config blobs (`xdns-config.json`, `gooserelay-AppsScript.gs` + `gooserelay-client_config.json`, etc.).
`README.html` is a bilingual (EN/FA) collapsible bundle viewer with embedded QR images and one-click subscription import.
## Monitoring stack
The `monitoring` profile is opt-in. When enabled, it adds Prometheus + Grafana plus a set of exporters — one per protocol. Each exporter lives in the same Compose profile as its target service (not in `monitoring`), so disabling a protocol takes its metrics down too.
```
Exporters (each in its target's profile)
├── clash-exporter (sing-box Clash API)
├── singbox-exporter (log parser)
├── xray-exporter
├── telemt-exporter (REST /v1/health)
├── wireguard-exporter
├── amneziawg-exporter
├── snowflake-exporter (snowflake profile)
├── node-exporter (host metrics)
└── cAdvisor (container metrics)
│
│ scraped by
▼
┌──────────────┐
│ Prometheus │ + recording rules (e.g. Conduit lifetime)
└──────┬───────┘
│
▼
┌──────────────┐
│ Grafana │ (+ optional grafana-proxy → Cloudflare CDN)
│ dashboards │
└──────────────┘
```
Pre-built dashboards land in `configs/monitoring/grafana/dashboards/`. The Conduit lifetime panels depend on a recording rule plus an offset watcher — see [Monitoring → Conduit lifetime bandwidth](https://moav.sh/docs/MONITORING/#conduit-lifetime-bandwidth).
## Security & isolation model
Every service runs in its own container with least-privilege defaults applied in `docker-compose.yml`:
- **Capability drop + selective add** — services start from `cap_drop: ALL` and add back only what they need (e.g. `NET_ADMIN` for WireGuard, `NET_BIND_SERVICE` for privileged ports). Most also set `read_only: true` with a small `tmpfs` for `/tmp`, `no-new-privileges: true`, and `mem_limit`/`cpus` caps.
- **Non-root** — services that must read the root-owned Let's Encrypt cert (sing-box, wstunnel) start their entrypoint as root only long enough to copy the cert into a tmpfs, then drop to an unprivileged user via `setpriv` before exec'ing the daemon.
- **No direct Docker socket** — the admin dashboard reads container status through a read-only [docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) scoped to `CONTAINERS`/`NETWORKS` only, never mounting `/var/run/docker.sock` into the app.
- **Admin auth fails closed** — the dashboard refuses to serve (HTTP 503) if `ADMIN_PASSWORD` is empty or one of the known-insecure defaults, and uses constant-time comparison; an optional IP allow-list narrows access further. See [OPSEC](https://moav.sh/docs/OPSEC/).
- **Secrets** live under the `moav_state` Docker volume (`state/keys/`, `state/users//`), generated with `openssl rand` / `wg genkey` / `x25519`, mounted read-only into the admin service.
## Service lifecycle & health
`ENABLE_*` flags in `.env` select which profiles `moav start` brings up. The `certbot` service is a one-shot that obtains the TLS cert before the cert-consuming services start; `moav cert install` schedules ongoing renewal (see [CLI → Certificates](https://moav.sh/docs/CLI/#certificates)). `restart: unless-stopped` recovers services across crashes and reboots. Core engines (sing-box, xray, telemt) declare Compose healthchecks so `moav doctor` and dependency ordering can distinguish "running" from "actually serving"; extending healthchecks to the remaining long-running services is in progress.
## See also
- [Setup Guide](https://moav.sh/docs/SETUP/) — step-by-step deployment walkthrough
- [DNS Configuration](https://moav.sh/docs/DNS/) — NS records, resolver-mode vs direct-mode XDNS, port 53
- [CLI Reference](https://moav.sh/docs/CLI/) — every `moav` command, including the disabled-profile prompt
- [Supported Protocols](https://moav.sh/docs/protocols/) — protocol-level cipher, port, and client-compat detail
- [Monitoring](https://moav.sh/docs/MONITORING/) — dashboards, Conduit lifetime, GeoIP setup
---
# Supported Protocols
MoaV deploys 16+ circumvention transports and fallback paths, plus optional Psiphon, Tor and MahsaNet donation integrations. Each has different stealth characteristics, speed profiles, and network requirements. This diversity ensures that when one protocol is blocked, others remain available.
## Protocol Overview
| Protocol | Port | Stealth | Speed | Domain Required |
|----------|------|---------|-------|-----------------|
| [Reality (VLESS)](#reality-vless) | 443/tcp | Very High | High | No |
| [Trojan](#trojan) | 8443/tcp | High | High | Yes |
| [AnyTLS](#anytls) | 8445/tcp | Very High | High | Yes |
| [Hysteria2](#hysteria2) | 443/udp | High | Very High | Yes |
| [Shadowsocks-2022](#shadowsocks-2022) | 8388/tcp+udp | High | Very High | No |
| [CDN (VLESS+WS)](#cdn-vlessws) | 443 via CDN | Very High | Medium | Cloudflare: yes · CloudFront: no |
| [TrustTunnel](#trusttunnel) | 4443/tcp+udp | Very High | High | Yes |
| [WireGuard](#wireguard) | 51820/udp | Medium | Very High | No |
| [AmneziaWG](#amneziawg) | 51821/udp | Very High | High | No |
| [WireGuard (wstunnel)](#wireguard-wstunnel) | 8080/tcp | High | High | No |
| [Telegram MTProxy](#telegram-mtproxy) | 993/tcp | High | Medium | No |
| [dnstt](#dnstt) | 53/udp | Medium | Low | Yes |
| [Slipstream](#slipstream) | 53/udp | Medium | Low-Medium | Yes |
| [MasterDNS](#masterdns) | 53/udp | Medium | Medium | Yes |
| [GooseRelay](#gooserelay) | 8444/tcp | Very High | Low-Medium | No |
| [Psiphon Conduit](#psiphon-conduit) | dynamic | High | Medium | No |
| [XHTTP (VLESS+XHTTP+Reality)](#xhttp-vlessxhttpreality) | 2096/tcp | Very High | High | No |
| [XDNS (VLESS+mKCP+DNS)](#xdns-vlessmkcpdns) | 53/udp | Medium | Low | Yes |
| [Tor Snowflake](#tor-snowflake) | dynamic | High | Low | No |
| [MahsaNet](#mahsanet) | — | — | — | No |
## Protocols in Detail
### Reality (VLESS)
**Primary protocol.** VLESS with Reality makes your proxy traffic resemble a real TLS connection to a legitimate website (e.g., `dl.google.com`). The server presents a genuine TLS certificate from the target site, passing even active probing.
- **Port:** 443/tcp
- **Engine:** [sing-box](https://github.com/SagerNet/sing-box)
- **Clients:** Streisand, Hiddify, v2rayNG, v2rayN, NekoBox
### Trojan
Password-authenticated TLS proxy. Traffic looks like normal HTTPS. Uses your domain's real TLS certificate from Let's Encrypt.
- **Port:** 8443/tcp
- **Engine:** [sing-box](https://github.com/SagerNet/sing-box)
- **Clients:** Streisand, Hiddify, v2rayNG, v2rayN, Shadowrocket
### AnyTLS
Password-authenticated TLS proxy designed to resist **TLS-in-TLS fingerprinting**. By varying record sizes and padding, AnyTLS removes the tell-tale TLS-inside-TLS pattern that DPI uses to detect TLS-tunneling proxies, giving it high stealth against the filtering techniques it targets. Reuses the same sing-box engine, the Trojan TLS certificate, and your server domain.
- **Port:** 8445/tcp
- **Engine:** [sing-box](https://github.com/SagerNet/sing-box) (1.13.x)
- **Clients:** Hiddify, sing-box (SFA/SFI), NekoBox/NekoRay, Mihomo Party, Shadowrocket 2.2.65+
- **Note:** Opt-in — enable with `ENABLE_ANYTLS=true`. Requires a domain (TLS). Client support is narrower than VLESS/Trojan; older or Clash-only clients (v2rayNG, Streisand, V2Box, Clash Verge) do **not** support AnyTLS.
### Hysteria2
QUIC-based protocol optimized for high throughput on lossy networks. Includes built-in obfuscation to bypass QUIC blocking.
- **Port:** 443/udp
- **Engine:** [sing-box](https://github.com/SagerNet/sing-box)
- **Clients:** Streisand, Hiddify, v2rayNG, v2rayN
- **Note:** Requires UDP. Blocked in some censored networks that drop all non-DNS UDP.
- **Congestion control:** `up_mbps`/`down_mbps` are left unset and `ignore_client_bandwidth: true` is set, keeping both ends on BBR and stopping a client-advertised bandwidth from switching the link to Brutal (which can saturate a low-RAM VPS). This BBR is Hysteria2's own QUIC-layer controller inside sing-box — unrelated to the kernel `tcp_bbr` module, so it has no host dependency.
### Shadowsocks-2022
AEAD-2022 Shadowsocks (`2022-blake3-aes-128-gcm`), the modern Shadowsocks generation with per-user keys and built-in resistance to active probing and replay attacks. Needs **no domain and no TLS certificate**, so it works in domainless mode and is a good fallback when certificate-based protocols aren't an option. Wire-compatible with the Outline app.
- **Port:** 8388/tcp + 8388/udp
- **Engine:** [sing-box](https://github.com/SagerNet/sing-box)
- **Clients:** Outline (iOS/Android/desktop), NekoBox/NekoRay, Hiddify, Streisand, sing-box — via the standard `ss://` URI
- **Note:** On by default (`ENABLE_SS=true`). If port 8388 is fingerprinted by your ISP, change `PORT_SS` in `.env` to a less-conspicuous port and `moav restart sing-box`.
### CDN (VLESS+WS)
Routes VLESS traffic through Cloudflare's CDN via WebSocket. When your server's IP is blocked, traffic goes through Cloudflare instead, which makes IP-based blocking substantially harder, because clients connect through CDN infrastructure.
**Opt-in:** `ENABLE_CDN=false` by default, because the link only works once the subdomain is proxied and rewritten to the CDN port. Turn it on after [CDN mode](https://moav.sh/docs/DNS/#cdn-mode) is set up.
- **Port:** 443 (Cloudflare) → 2082 (origin)
- **Engine:** [sing-box](https://github.com/SagerNet/sing-box)
- **Clients:** Streisand, Hiddify, v2rayNG, v2rayN
- **Requires:** a Cloudflare-proxied domain you control; AWS CloudFront can use the distribution hostname and needs no custom domain
### TrustTunnel
Modern VPN protocol that looks like regular HTTPS traffic. Supports both HTTP/2 (TCP) and HTTP/3 (QUIC/UDP).
- **Port:** 4443/tcp + 4443/udp
- **Engine:** [TrustTunnel](https://github.com/TrustTunnel/TrustTunnel) (server) / [TrustTunnelClient](https://github.com/TrustTunnel/TrustTunnelClient) (client)
- **Clients:** TrustTunnel app (iOS, Android, macOS, Windows, Linux)
### WireGuard
Fast kernel-level VPN. Simple, audited, and widely supported. Direct UDP connection.
- **Port:** 51820/udp
- **Engine:** [sing-box](https://github.com/SagerNet/sing-box) + [wstunnel](https://github.com/erebe/wstunnel)
- **Clients:** WireGuard app (all platforms)
- **Note:** Easily fingerprinted by DPI, so in a censored network it typically **fails to connect at all**. Use [AmneziaWG](#amneziawg) (obfuscation) or the wstunnel variant (UDP blocked) instead.
### AmneziaWG
Obfuscated WireGuard variant designed to resist DPI. It keeps WireGuard's speed and cryptography but disguises the traffic so it no longer looks like WireGuard on the wire. This is the protocol to reach for when plain WireGuard is fingerprinted and blocked.
- **Port:** 51821/udp
- **Engine:** [amneziawg-go](https://github.com/amnezia-vpn/amneziawg-go) (userspace) + [amneziawg-tools](https://github.com/amnezia-vpn/amneziawg-tools)
- **Clients:** the dedicated **[AmneziaWG app](https://docs.amnezia.org/documentation/amnezia-wg/)** (recommended — supports every obfuscation parameter) or the **AmneziaVPN** app. Import the `.conf` from your user bundle or scan its QR.
#### How the obfuscation works
Plain WireGuard is trivial to fingerprint: fixed handshake sizes (148/92 bytes), a static message-type header, and clockwork timing. AmneziaWG erases those tells in two layers.
**Layer 1 — always on.** This is what makes the traffic *not look like WireGuard*, and it defeats the large majority of signature-based blocking:
- `Jc` / `Jmin` / `Jmax` — junk packets sent *before* the handshake, so the first packet is no longer a recognizable WireGuard handshake.
- `S1` / `S2` — random junk prepended to the handshake init/response, so they are no longer the tell-tale 148/92 bytes.
- `H1`–`H4` — the four fixed WireGuard message-type headers replaced with random values.
**Layer 2 — optional (`AMNEZIAWG_HEADER_PROTECTION`, default off).** A newer set that protects *every* packet, aimed at aggressive statistical/ML DPI rather than simple signatures:
- `HeaderProtectionKey` — encrypts the header of every packet (data included), removing the per-packet fingerprint that survives Layer 1.
- `ContentPaddingAddition` / `RandomTrailers` — pad payloads and append random trailing bytes so packet sizes don't form a recognizable distribution.
> **Compatibility trade-off.** Layer 2 only works if the client supports it. The dedicated AmneziaWG app does; the **AmneziaVPN app's `.conf` importer currently drops these keys**, so a bundle imported there **connects but relays no traffic**. MoaV keeps Layer 2 **off by default** — both apps work, and Layer 1 already defeats most DPI. Turn it on only when every client uses the AmneziaWG app:
>
> ```bash
> # .env
> AMNEZIAWG_HEADER_PROTECTION=true
> ```
>
> One interface has a single obfuscation profile, so after changing this you must re-issue bundles (`moav regenerate-users`) — otherwise client and server disagree on the wire format and every tunnel goes silent.
**Which layer do I need?**
- *No / light censorship:* Layer 1 is already more than enough.
- *Signature-based VPN blocking (most censored networks):* Layer 1 — the sweet spot.
- *Aggressive DPI (active probing + traffic-shape analysis):* Layer 2, with the AmneziaWG app on every client.
If the app says **Connected** but nothing loads, that is almost always a Layer 2 mismatch — see [AmneziaWG connects but no traffic](https://moav.sh/docs/TROUBLESHOOTING/#amneziawg-connects-but-no-traffic).
### WireGuard (wstunnel)
WireGuard tunneled through WebSocket (TCP). Works when UDP is completely blocked. When a `DOMAIN` is configured the tunnel is served over **`wss://` (TLS)** using the server's Let's Encrypt certificate, so the WebSocket upgrade resembles ordinary HTTPS; it falls back to plain `ws://` only in domainless mode. A per-install **HTTP-upgrade path secret** is also required, so a scanner probing port 8080 can't complete the WebSocket upgrade blind. The exact client command (correct `wss://`/`ws://` scheme and path prefix) is emitted in each user bundle's `wireguard-instructions.txt`.
- **Port:** 8080/tcp
- **Engine:** [wstunnel](https://github.com/erebe/wstunnel) wrapping the WireGuard container
- **Clients:** WireGuard app + wstunnel binary
- **Note:** After upgrading an existing install, rebuild the image (`moav build wstunnel`) and re-bootstrap to generate the path secret and enable `wss://`; older bundles keep working over `ws://` until re-issued.
### Telegram MTProxy
Telegram-specific proxy with Fake-TLS V2. Emulates real TLS connections, including certificate mimicry and timing simulation. Provides direct access to Telegram when it's blocked.
- **Port:** 993/tcp (IMAPS port for stealth)
- **Engine:** [telemt](https://github.com/telemt/telemt)
- **Clients:** Telegram app (built-in proxy settings)
??? note "Anti-DPI Tuning Settings"
telemt has 17+ configurable settings for hostile network environments. All configurable in `.env`:
**Traffic Disguise (anti-DPI):**
| Setting | Default | Purpose |
|---------|---------|---------|
| `TELEMT_KEEPALIVE_RANDOM` | `true` | Randomize keepalive payload to break DPI pattern-matching |
| `TELEMT_KEEPALIVE_JITTER` | `4` | ±N seconds randomness on keepalive timing |
| `TELEMT_KEEPALIVE_INTERVAL` | `20` | Base keepalive interval in seconds |
| `TELEMT_WARMUP_JITTER` | `200` | Randomize connection establishment timing (ms) |
**Connection Pool Resilience:**
| Setting | Default | Purpose |
|---------|---------|---------|
| `TELEMT_POOL_SIZE` | `12` | Number of persistent connections to Telegram DCs |
| `TELEMT_REINIT_SECS` | `600` | Rebuild all connections every N seconds (prevents long-connection fingerprinting) |
| `TELEMT_HARDSWAP` | `true` | Build new pool before tearing down old (zero-downtime rotation) |
| `TELEMT_HARDSWAP_DELAY_MIN` | `500` | Min delay between new connections during swap (ms) |
| `TELEMT_HARDSWAP_DELAY_MAX` | `1200` | Max delay between new connections during swap (ms) |
**Fast Reconnect:**
| Setting | Default | Purpose |
|---------|---------|---------|
| `TELEMT_FAST_RETRIES` | `10` | Quick retries before exponential backoff |
| `TELEMT_BACKOFF_BASE` | `300` | Backoff start interval (ms) |
| `TELEMT_BACKOFF_CAP` | `10000` | Maximum backoff interval (ms) |
**Config Stability:**
| Setting | Default | Purpose |
|---------|---------|---------|
| `TELEMT_STABLE_SNAPSHOTS` | `3` | Require N consistent config snapshots before applying changes |
| `TELEMT_APPLY_COOLDOWN` | `120` | Minimum seconds between config changes |
**For aggressive censorship** (e.g., Iran during shutdowns): increase `TELEMT_POOL_SIZE` to 16-20, decrease `TELEMT_REINIT_SECS` to 300, and increase `TELEMT_FAST_RETRIES` to 20.
Full tuning docs: [telemt TUNING.en.md](https://github.com/telemt/telemt/blob/main/docs/TUNING.en.md) | [API docs](https://github.com/telemt/telemt/blob/main/docs/API.md)
### GooseRelay
SOCKS5 tunnelled through a **Google Apps Script** web app that the user deploys in their own Google account, which forwards to this VPS exit server. On the wire the client only ever appears to make a domain-fronted HTTPS request to `google.com` — the payload is AES-256-GCM encrypted end-to-end between the GooseRelay endpoints, so Apps Script relays ciphertext, but Google can still observe request metadata. This is the **GooseRelay** component bundled in MahsaNG v16. Extremely stealthy (looks like Google traffic), but throughput is capped by the Apps Script ~20k-calls/day-per-account quota.
- **Port:** `${PORT_GOOSE}`/tcp (default 8444 on the host → 8443 in the container; 8443 on the host is Trojan's)
- **Engine:** [GooseRelayVPN](https://github.com/kianmhz/GooseRelayVPN) (Go), server built from source
- **Clients:** MahsaNG v16+, or the standalone GooseRelay client + a user-deployed Apps Script forwarder
- **Encryption:** AES-256-GCM, shared 64-hex `tunnel_key` (in each user's `gooserelay-instructions.txt`)
- **Requires:** No domain. `PORT_GOOSE` must be reachable from Google's network. The user sets `RELAY_URLS = ['http://SERVER_IP:PORT_GOOSE/tunnel']` in their Apps Script.
- **Note:** Opt-in — set `ENABLE_GOOSERELAY=true` in `.env`. Egress is routed through sing-box. Real-time apps (Telegram/X) drain the Apps Script quota fast; add more deployments under different Google accounts for capacity.
### XHTTP (VLESS+XHTTP+Reality)
**Experimental.** VLESS over XHTTP transport with Reality TLS camouflage, powered by Xray-core. Uses the XHTTP (formerly splithttp) transport for multiplexed HTTP requests, making traffic look like regular web browsing. Reality handles TLS without needing a domain.
- **Port:** 2096/tcp
- **Engine:** [Xray-core](https://github.com/XTLS/Xray-core)
- **Clients:** V2rayNG, Hiddify, Streisand, V2Box, V2rayN, V2rayU, NekoBox
- **Note:** Uses Xray-core (separate from sing-box). Disable with `ENABLE_XHTTP=false` in `.env`.
### Psiphon Conduit
Bandwidth donation to the Psiphon network. Psiphon users worldwide route through your server. Not a protocol you connect to — it's a way to help others bypass censorship.
- **Engine:** [Psiphon Conduit](https://github.com/Psiphon-Inc/conduit)
- **Clients:** [Psiphon](https://psiphon.ca/) app (iOS, Android, Windows)
#### How your Conduit helps people in Iran
There are two ways your running Conduit reaches users:
1. **Public pool — automatic, nothing to share.** The moment Conduit is
running it donates bandwidth to the Psiphon network. Psiphon app users —
including in Iran — are brokered through your server automatically. They
don't need a link, an invite, or any setup. This is the main way Conduit
helps and requires zero action on the user's side.
2. **Personal Pairing — share a private path with specific people.** Psiphon's
Conduit lets you give friends/family a private, prioritized path through
your station. The Psiphon app has a "pairing URL" field for this. To set it
up: install Psiphon's **Ryve** app (the Conduit manager), import your
station with the claim link MoaV generates, then in Ryve enable Personal
Pairing and generate a pairing link to send to people in Iran.
#### `moav conduit link`
```bash
moav conduit link # Claim link + QR + step-by-step sharing guide
moav conduit status # Is it running + connected clients / bandwidth
```
This prints the **Ryve claim deep link** (`network.ryve.app://…claim=…`) and
its QR code, plus the sharing walkthrough above.
> **⚠ Security:** the claim link/QR embeds this Conduit's **private key** — it
> is for importing the station into *your own* phone's Ryve app. Treat it like
> a password; do **not** post it publicly (anyone with it can take over your
> station). The public-safe link you give to users is the **Personal Pairing**
> link generated *inside Ryve*, not the claim link. As of
> [Psiphon-Inc/conduit#205](https://github.com/Psiphon-Inc/conduit/issues/205)
> the pairing-URL export lives only in the Conduit/Ryve app UI, so MoaV
> surfaces the claim link and the steps rather than minting a pairing URL
> itself. (`moav donate info` is an alias for `moav conduit link`.)
### Tor Snowflake
Bandwidth donation to the Tor network. Acts as a Snowflake proxy, helping Tor users in censored regions connect. Like Conduit, this is about helping others.
- **Engine:** [Snowflake](https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake)
- **Clients:** [Tor Browser](https://www.torproject.org/) with Snowflake bridge
### MahsaNet
Config donation to [MahsaServer.com](https://www.mahsaserver.com/), a decentralized VPN config sharing platform for the [Mahsa VPN](https://www.mahsaserver.com/) app. With over 12 million users in Iran, Mahsa VPN connects to donated VPN configurations from servers worldwide. Unlike Conduit and Snowflake (which donate bandwidth), MahsaNet donates your server's VPN config links — Mahsa VPN users then connect directly to your server.
- **Supported protocols:** Reality (VLESS), Hysteria2, Trojan, CDN (VLESS+WS)
- **Clients:** [Mahsa VPN](https://www.mahsaserver.com/) app (Android, iOS)
- **Setup:** Register on MahsaServer.com, get API key, then `moav donate`
- **Dashboard:** Donate, list, and manage configs from the Admin Dashboard
## DNS Tunnels
The last transports standing. When a network blocks or throttles almost everything else, DNS usually still resolves — breaking it breaks the whole internet for everyone. DNS tunnels encode traffic inside DNS queries, so they can remain usable where ordinary traffic is blocked but recursive DNS still resolves.
They are **slow**. Treat them as the fallback that keeps chat and messaging alive, not as an everyday transport.
### How it works
MoaV runs **four** DNS tunnels **simultaneously** on the same public port 53. A small Go service, `dns-router`, is the only thing bound to that port; it reads each query's subdomain prefix and forwards to the matching tunnel container on an internal port.
```
Public 53/udp
│
┌──────▼──────┐
│ dns-router │ ← the only listener on 53
└──────┬──────┘
│ routes by subdomain prefix
t.* ─────► dnstt (KCP + Noise)
s.* ─────► slipstream (QUIC-over-DNS)
m.* ─────► masterdns (ARQ, MahsaNG-native)
x.* ─────► xray (XDNS via FinalMask)
│
▼
sing-box ──► internet
```
Because they are separated by subdomain rather than by port, there is no "pick one" decision: a user connects with whichever tunnel their client supports, and all four can serve traffic at once.
### What MoaV sets up for you
Each tunnel needs an **NS delegation** handing its subdomain to your server, plus one A record for the nameserver itself:
```
dns.yourdomain.com A YOUR_SERVER_IP # the nameserver
t.yourdomain.com NS dns.yourdomain.com # dnstt
s.yourdomain.com NS dns.yourdomain.com # Slipstream
m.yourdomain.com NS dns.yourdomain.com # MasterDNS
x.yourdomain.com NS dns.yourdomain.com # XDNS
```
`moav doctor dns` writes exactly the records your configuration needs to `outputs/dns-records.txt`, ready to import into Cloudflare. Full walkthrough: [DNS Configuration](https://moav.sh/docs/DNS/#with-a-domain-the-records).
All four are on by default. Toggle them individually with `ENABLE_DNSTT` / `ENABLE_SLIPSTREAM` / `ENABLE_MASTERDNS` / `ENABLE_XDNS`, or set the combination in one command:
```bash
moav switch-dns # show what is on
moav switch-dns dnstt+slipstream+masterdns+xdns # all four
moav switch-dns dnstt+slipstream # the classic pair
moav switch-dns off # no DNS tunnels
```
A disabled tunnel's container stays down and `dns-router` simply has no backend to forward to. Port **53/udp** must reach the server; some ISPs block it outright on residential lines.
### Which one should I use?
| Tunnel | Subdomain | Speed vs dnstt | Loss resilience | Best for |
|---|---|---|---|---|
| **dnstt** | `t` | 1× *(baseline)* | low | **Widest client support** — standalone client on 25+ platforms |
| **Slipstream** | `s` | 1.5–5× | medium | Faster general use where a Slipstream client exists |
| **MasterDNS** | `m` | up to 9× | **high** *(ARQ + packet duplication + multi-resolver)* | **Harsh shutdowns**; native in [MahsaNG v16](https://moav.sh/docs/mahsanet/) |
| **XDNS** | `x` | ~1× | low | FinalMask clients (Happ, Xray CLI); per-user auth |
**Short answer:** in Iran during heavy throttling or a blackout, **MasterDNS** is the strongest and works straight from the MahsaNG app. Offer **dnstt** too, because its client runs almost everywhere.
!!! warning "The client's resolver matters more than the tunnel"
Every DNS tunnel depends on a public resolver **the client can still reach**, and `1.1.1.1` / `8.8.8.8` are commonly throttled or null-routed exactly when a tunnel is needed. XDNS round-robins across `XDNS_RESOLVERS`; dnstt and Slipstream take a resolver flag client-side. [findns](https://github.com/SamNet-dev/findns) and [dns-mns](https://gitlab.com/E-Gurl/dns-mns) scan for resolvers that still work on a given network — see [reachable resolvers](#reachable-dns-resolvers).
### Reachable DNS resolvers
Every DNS tunnel is only as good as the resolver the **client** can reach. During shutdowns the well-known ones (`1.1.1.1`, `8.8.8.8`, `9.9.9.9`) are routinely throttled, hijacked or null-routed, and a tunnel that worked yesterday will look broken.
Two scanners find resolvers that still answer on a given network:
- **[findns](https://github.com/SamNet-dev/findns)** — sweeps a range and reports which resolvers respond correctly
- **[dns-mns](https://gitlab.com/E-Gurl/dns-mns)** — same idea, maintained separately
Feed the survivors to the client: `XDNS_RESOLVERS` accepts a comma-separated list that XDNS round-robins across, and the dnstt / Slipstream clients each take a resolver flag. It's worth shipping users two or three known-good resolvers rather than one.
### dnstt
Encodes a TCP stream inside DNS queries using KCP + Noise. Extremely hard to block without breaking DNS itself; the slowest of the four and the most portable.
- **Port:** 53/udp *(subdomain `t`)* · **Engine:** [dnstt](https://www.bamsoftware.com/software/dnstt/)
- **Clients:** standalone dnstt client on 25+ platforms
- **Requires:** domain + NS delegation
### Slipstream
The same idea over **QUIC**, which buys real throughput — typically 1.5–5× dnstt.
- **Port:** 53/udp *(subdomain `s`)* · **Engine:** [slipstream-rust](https://github.com/Mygod/slipstream-rust) · [pre-built binaries](https://github.com/net2share/slipstream-rust-build/releases)
- **Requires:** domain + NS delegation
### MasterDNS
The most loss-resilient of the four: low-overhead ARQ, packet duplication and resolver load-balancing, which is what keeps it usable on throttled links. This is the MasterDNS component bundled in **MahsaNG v16**, so that app connects with no extra client.
- **Port:** 53/udp *(subdomain `MASTERDNS_SUBDOMAIN`, default `m`)* · **Engine:** [MasterDnsVPN](https://github.com/masterking32/MasterDnsVPN) (Go)
- **Clients:** MahsaNG v16+, or the standalone client (Linux/Windows/macOS/Termux)
- **Encryption:** AES-256-GCM (`DATA_ENCRYPTION_METHOD=5`); the shared key ships in each user's bundle
- **Extra:** `MASTERDNS_PUBLIC_SUBDOMAIN` publishes a *different* delegation name than the one used internally — generated bundles then use the public one
### XDNS (VLESS+mKCP+DNS)
**Experimental.** Xray-core's mKCP transport with FinalMask, and the only DNS tunnel here with **per-user authentication** — at the cost of needing a FinalMask-aware client.
- **Port:** 53/udp *(subdomain `x`)* · **Engine:** [Xray-core](https://github.com/XTLS/Xray-core) *(built from main for FinalMask)*
- **Clients:** Happ (beta), Xray CLI. **Not** standard v2rayNG yet.
- **Best for:** Telegram and light chat apps — not fast enough for browsing
??? note "XDNS Tuning"
| Setting | Default | Purpose |
|---------|---------|---------|
| `XDNS_MTU` | `35` | mKCP packet size. Smaller = works with more DNS resolvers. 35=safest, 67=most, 130=unrestricted |
| `XDNS_SUBDOMAIN` | `x` | Subdomain for XDNS queries (x.yourdomain.com) |
| `XDNS_RESOLVERS` | `1.1.1.1,8.8.8.8` | CSV of public DNS resolvers the client round-robins across in a single mKCP session (Xray v26.4.13+, [PR #5872](https://github.com/XTLS/Xray-core/pull/5872)). See [Reachable DNS resolvers](#reachable-dns-resolvers) — replace the defaults with resolvers that actually answer on your network. Set empty to fall back to single-resolver mode. |
| `XDNS_METHOD` | `txt` | Finalmask record mode in generated client bundles. `txt` is the widest-compatibility default; `aaaa` ([Xray #6123](https://github.com/XTLS/Xray-core/pull/6123)) gives higher throughput per query but **requires an Xray client core ≥ v26.6.1** (Happ / Xray CLI). Server side needs no change. |
MTU depends on domain name length — shorter domain allows higher MTU. The values above are for ~19-character domains.
For aggressive censorship: use `MTU=35` and connect via a DNS resolver you can actually reach from inside the censored network (see below).
## Choosing Protocols
**For censored networks (Iran, China, Russia):**
1. Start with **Reality** — high stealth against the filtering techniques it targets, a strong first choice on networks where it currently works
2. Add **CDN mode** — works when your server IP is blocked
3. Enable **AmneziaWG** — for full VPN when WireGuard is fingerprinted
4. Enable **DNS tunnels** — last resort when almost everything is blocked
**For general privacy:**
1. **WireGuard** — fastest, simplest
2. **Reality** — when WireGuard is blocked
**For helping others:**
1. **Conduit** — donate bandwidth to Psiphon users
2. **Snowflake** — donate bandwidth to Tor users
3. **MahsaNet** — donate VPN configs to Mahsa VPN users in Iran
---
# Mission & Philosophy
This is the longer manifesto behind MoaV. For the concise project description, start with [Mission](https://moav.sh/docs/mission/). For limits and safety assumptions, read the [Threat Model](https://moav.sh/docs/threat-model/). For outcomes and measurement, read [Impact](https://moav.sh/docs/impact/).
Internet freedom doesn't happen by accident. It doesn't come from governments deciding to be generous, or from corporations choosing not to surveil. It comes from people: engineers, activists, diaspora communities, and strangers with a spare VPS, building the infrastructure that makes it real.
We built MoaV because the tools already existed but the friction was too high. Running a reliable multi-protocol circumvention server shouldn't require a week of configuration and a systems-engineering background. With MoaV it takes ten minutes. One command. A $5 server. And you're part of the network that keeps people connected when their governments decide they shouldn't be.
This is not someone else's problem to solve. The window to act is between blackouts, not during them.
## Internet Access Is a Human Right
The United Nations Human Rights Council has repeatedly affirmed that the same rights people have offline must also be protected online. The Universal Declaration of Human Rights, Article 19:
> *Everyone has the right to freedom of opinion and expression; this right includes freedom to hold opinions without interference and to seek, receive and impart information and ideas through any means and regardless of frontiers.*
Internet shutdowns are not abstract policy debates. They cut people off from family, healthcare information, financial services, education, and the ability to document what is happening around them. They are used deliberately during protests and crises, precisely when communication matters most.
## Why MoaV Exists
MoaV was created to **democratize access to anti-censorship tools**. Running a VPN server shouldn't require deep technical expertise. Running *multiple* protocols, so users can find one that works when others are blocked, shouldn't require managing a dozen separate tools.
MoaV packages 16+ circumvention transports and fallback paths, plus optional Psiphon, Tor and MahsaNet donation integrations, into a single deployment. One command deploys all of them. A $5 VPS is enough. The goal is simple: make it as easy as possible for anyone with a spare server to provide reliable internet access to people who need it.
## What Infrastructure Actually Means
Here is the difference between using a tool and being infrastructure.
**Using a tool**: you install a VPN app. It works, or it doesn't. When it gets blocked, you try the next one. You are a consumer of access.
**Being infrastructure**: you run a server. Other people connect through it. When the protocols they're using get blocked, your server already has the fallback ready. You are a node in the network of free communication.
MoaV was built to make the second thing as easy as the first.
## Why Multi-Protocol Matters
No single protocol survives all censorship regimes. Governments invest heavily in Deep Packet Inspection (DPI) and adapt their blocking continuously:
- **Protocol whitelisting**: only DNS, HTTP, and HTTPS allowed; everything else dropped.
- **SNI inspection**: TLS handshakes inspected to block connections to non-approved domains.
- **QUIC/UDP blocking**: all UDP except DNS dropped, killing WireGuard and Hysteria2.
- **Active probing**: censors connect to suspected proxy servers to verify they're running proxy software.
- **Throttling**: connections not outright blocked but throttled to unusable speeds.
MoaV's approach: run multiple fallback routes. Each protocol uses a different gap in the censor's capabilities.
| Censorship method | MoaV counter |
|---|---|
| Protocol blocking | Reality mimics legitimate TLS to approved sites |
| UDP blocking | WireGuard tunneled through WebSocket (TCP) |
| IP blocking | CDN mode routes through Cloudflare's network |
| DPI on SNI | TrustTunnel looks like regular HTTPS traffic |
| Total shutdown | DNS tunnels work when only DNS is allowed |
| Active probing | Shadowsocks-2022 AEAD ciphers resist probes; decoy site serves innocent content |
| Throttling | Hysteria2's QUIC maximizes throughput on constrained links |
You don't know which protocol will survive the next shutdown. Neither does the censor. Running many of them is not inefficient. It is the point. See [Supported Protocols](https://moav.sh/docs/protocols/) for the full list.
## The Internet Is Closing
Iran has repeatedly shown why resilient access infrastructure matters. In 2019, the state imposed a near-total shutdown during fuel-price protests. In 2022 and 2023, during the Woman, Life, Freedom movement, authorities blocked major platforms, throttled bandwidth, and targeted circumvention tools. More recently, connectivity disruptions and protocol-level blocking have continued during periods of political pressure and regional tension.
The pattern is familiar: access is restricted, people rush to find working tools, and demand for circumvention spikes exactly when normal distribution channels are most fragile.
This is the moment MoaV is built for. Not because one stack solves censorship everywhere, but because every extra working route matters when the easy routes disappear.
## A Global Pattern
Iran is not alone. Every time a government restricts connectivity, the response is the same: millions of people immediately try to route around it, and most of them don't know how.
- **Uganda**, January 2026 elections: VPN demand spiked **2,557%** after social platforms were blocked.
- **Nepal**, September 2025: peaked at **2,892%** when social media was banned.
- **United Kingdom**, July 2025: age-verification rollout drove a single-day spike of **1,987%**.
- **Myanmar**, February 2021: the military cut the internet hours after the coup. Mobile first. Then broadband. Then only a few whitelisted ports.
- **Russia**, post-February 2022: did not cut the internet. It blocked the tools used to circumvent filtering, including Psiphon, Tor, and Signal. The lesson: you do not have to turn off the internet to control it; you can make resistance harder to use.
- **China**: two decades of the Great Firewall. Protocol after protocol identified, fingerprinted, blocked. VPN vendors in a permanent arms race.
And the laws that seem unthinkable right now keep becoming law in democracies. The EU's Chat Control proposal would mandate client-side scanning of encrypted messages. France has proposed banning end-to-end encryption for apps used to coordinate "criminal" activity. The UK Online Safety Act gives regulators the power to demand backdoors. The infrastructure that keeps communication free in Iran is the same infrastructure that will matter in Europe when those laws come into force.
## The Arms Race Gets Creative
One of the things that gives us hope, and that governments consistently underestimate, is the ingenuity of people building tools to stay connected under pressure.
Every censorship technique creates its own workaround. Block VPN protocols, developers build obfuscated ones. Block obfuscated VPNs, they route through CDNs too large to block. Block CDNs, they build DNS tunnels. Block DNS, and you break your own country's domestic internet.
But the creativity doesn't stop at DNS:
- **[BaleVPN](https://github.com/kookoo1sabzy/BaleVPN)** routes traffic through Bale, Iran's officially approved video-call platform. The tunnel encodes IP traffic as what looks like a Bale voice call. To the network, an approved domestic app doing approved domestic things. To the user, internet access. The government built the infrastructure for its own circumvention.
- **[GooseRelay](https://moav.sh/docs/protocols/#gooserelay)** (shipped natively in MoaV) routes traffic through Google Apps Script. To the censor, an HTTPS request to a Google Workspace serverless function used by millions of businesses. Blocking GooseRelay means blocking Apps Script globally, which means breaking every company and university using it in the country. The cost of the block exceeds the benefit.
- **[SNI Spoofing](https://github.com/aleskxyz/SNI-Spoofing-Go)** uses a different opening: the unencrypted hostname in the TLS handshake. A local proxy sends a fake ClientHello with a decoy hostname, for example `microsoft.com`, while the real connection continues underneath. The DPI box sees something benign; the traffic gets through.
The censor's playbook has a finite number of pages. The circumvention community keeps adding new chapters.
## You Are Donating Bandwidth (Or You Could Be)
Three of the donation paths MoaV bundles are not for you. They are for everyone else.
**[Psiphon Conduit](https://psiphon.ca)** turns your server into a relay node for Psiphon users, people who can't reach the app directly and need a trusted intermediary. Psiphon has tens of millions of users in Iran, Russia, Belarus, Venezuela, and dozens of other censored countries. Your VPS becomes part of the network they depend on.
**[Tor Snowflake](https://snowflake.torproject.org/)** does the same for Tor. Your server becomes a Tor bridge, a relay that Tor users can connect to when the public ones are blocked. You're not an exit node; you're handling the first step for someone who otherwise can't reach the network at all.
**[MahsaNet](https://moav.sh/docs/mahsanet/)** is the MahsaNG peer network, and it's worth understanding what makes it different. It's not just a relay pool, it's a distribution channel. When you donate your server config to MahsaNet, you're publishing your server's address and credentials to a network that MahsaNG users can query directly from the app. No diaspora contact required. No Telegram group to find. The app discovers your server automatically, the moment it's needed. MahsaNG has its own distribution infrastructure that already reaches the 12 million+ people using the app.
The marginal cost is bandwidth, a few dollars a month at most on a standard VPS plan. The marginal impact is someone being able to say they're alive.
## Iran's Shutdown History
Iran's censorship infrastructure operates at multiple layers: the National Information Network (NIN, the domestic intranet), Deep Packet Inspection at major peering points, protocol whitelisting during heavy periods (only ports 53/80/443 permitted), active probing of suspected proxy servers, and throttling that maintains the appearance of connectivity while making it unusable.
The chronology that shaped MoaV's design:
- **November 2019**: near-total internet shutdown during fuel-price protests. Amnesty International documented at least 304 deaths; other estimates are higher. The shutdown prevented documentation of events and coordination of emergency response.
- **September 2022 to 2023, Woman, Life, Freedom**: following Mahsa (Jina) Amini's death in morality-police custody, nationwide protests met months of internet disruption. WhatsApp, Instagram, and Signal were blocked, bandwidth was throttled, and VPN protocols were targeted.
- **Ongoing disruptions**: Iran continues to combine platform blocking, throttling, protocol filtering, and domestic-network dependency during periods of pressure. That uncertainty is enough to justify building capacity before the next crisis.
## The Window Is Open. It Won't Stay That Way.
This is the trap. The state allows a partial reopening after protests wind down, enough for people to feel like things are normalizing, enough to make the isolation seem temporary. Meanwhile, everything the government learned about circumvention tool usage during a blackout goes into improving the next one. Which DNS resolvers kept working. Which protocols leaked through. Which apps people used when everything else was blocked.
That data is now in the hands of the people planning the next shutdown.
The time to build capacity is not during the shutdown. During a shutdown, new server deployments can't reach the people who need them. Domain names can't be shared through a blocked internet. Configuration files can't be distributed when the distribution channels are offline.
**The servers that matter in the next crisis are the ones being deployed right now, while the window is open.**
## The Argument in One Line
Every time a government has tried to cut the internet completely, it has proven why distributed infrastructure matters. And every time, the people who kept the connections alive were engineers and activists who had set up their servers before the crisis, not during it.
We can be those people. Not as a political statement, not as an act of heroism, but as a practical decision, made now, that runs in the background and serves people we'll never know.
That's how infrastructure works.
## Contributing
If you have a VPS and want to help:
1. **[Deploy MoaV](https://moav.sh/docs/quick-start/)** and share access with people who need it.
2. **[Enable Conduit](https://moav.sh/docs/support/#donate-bandwidth-instead-of-users)** to relay bandwidth for Psiphon users worldwide.
3. **[Enable Snowflake](https://moav.sh/docs/support/#donate-bandwidth-instead-of-users)** to relay bandwidth for Tor users.
4. **[Donate configs to MahsaNet](https://moav.sh/docs/mahsanet/)** so 12M+ MahsaNG users discover your server automatically.
5. **[Contribute code](https://github.com/MotherofallVPNs/moav)**: fix bugs, add protocols, improve documentation.
## Sources & Further Reading
References and starting points:
- Iran shutdown timeline, NIN architecture: [NetBlocks](https://netblocks.org/), [Access Now Shutdown Tracker](https://www.accessnow.org/keepiton/)
- VPN demand statistics: [Top10VPN demand statistics](https://www.top10vpn.com/research/vpn-demand-statistics/)
- Internet traffic analysis: Doug Madory / [Kentik](https://www.kentik.com/)
- Mahsa Amini protests: Amnesty International reports, 2022 to 2023
- BaleVPN, TCP over Bale voice calls: [github.com/kookoo1sabzy/BaleVPN](https://github.com/kookoo1sabzy/BaleVPN)
- SNI Spoofing Go, local proxy sending decoy ClientHello: [github.com/aleskxyz/SNI-Spoofing-Go](https://github.com/aleskxyz/SNI-Spoofing-Go)
---
# MoaV Setup Guide
Complete guide to deploy MoaV on a VPS or home server.
## Prerequisites
**Server Requirements:**
- Debian 12, Ubuntu 22.04, or Ubuntu 24.04 (Raspberry Pi OS works too)
- Architecture: x64 (AMD64) or ARM64 (Raspberry Pi 4, Apple Silicon)
- Minimum: 1 vCPU, 1GB RAM, 10GB disk
- Public IPv4 address
- Public IPv6 address (optional, see [IPv6 Support](#ipv6-support))
**Domain (Optional but Recommended):**
- Required for: Trojan, AnyTLS, Hysteria2, TrustTunnel, CDN mode, DNS tunnels (dnstt, Slipstream, MasterDNS, XDNS)
- Not required for: Reality, XHTTP, Shadowsocks-2022, Snell, WireGuard, AmneziaWG, Telegram MTProxy, Admin dashboard, Conduit, Snowflake
- Per-protocol checklist: [Do I need a domain?](https://moav.sh/docs/DNS/#do-i-need-a-domain)
- See [Domainless Mode](#domainless-mode) if you don't have a domain
**Ports to Open:**
| Port | Protocol | Service | Requires Domain |
|------|----------|---------|-----------------|
| 443/tcp | TCP | Reality (VLESS) | No — borrows a public SNI via `REALITY_TARGET` |
| 443/udp | UDP | Hysteria2 | Yes |
| 8443/tcp | TCP | Trojan | Yes |
| 8445/tcp | TCP | AnyTLS | Yes |
| 8388/tcp+udp | TCP+UDP | Shadowsocks-2022 | No |
| 8389/tcp | TCP | Snell (off by default) | No |
| 4443/tcp+udp | TCP+UDP | TrustTunnel | Yes |
| 2082/tcp | TCP | CDN WebSocket | Yes (Cloudflare) or No (CloudFront) |
| 51820/udp | UDP | WireGuard | No |
| 51821/udp | UDP | AmneziaWG | No |
| 8080/tcp | TCP | wstunnel | No |
| 9443/tcp | TCP | Admin dashboard | No |
| 9444/tcp | TCP | Grafana (monitoring) | No |
| 993/tcp | TCP | Telegram MTProxy (telemt) | No |
| 2096/tcp | TCP | XHTTP (VLESS+XHTTP+Reality) | No |
| 53/udp | UDP | DNS tunnels — dnstt, Slipstream, MasterDNS, XDNS (all 4 share port 53 via dns-router) | Yes |
| 8444/tcp | TCP | GooseRelay (when `ENABLE_GOOSERELAY=true`) | No |
| 80/tcp | TCP | Let's Encrypt | Yes (during setup) |
---
## Quick Start
!!! tip "The whole install is one command"
```bash
curl -fsSL moav.sh/install.sh | bash
```
It installs Docker, clones MoaV, and asks for three things: your **domain** (leave blank for domainless), an **email** for Let's Encrypt, and an **admin password**. When it finishes it prints your dashboard URLs and the DNS records to add.
If that's all you need, follow it through to your first user in [**Quick Start**](https://moav.sh/docs/quick-start/) — about ten minutes end to end.
The rest of this page is the reference: every option, and what to do when the defaults don't fit.
## Step-by-Step Setup
### Step 1: Get a Server
Choose a VPS provider and create a server:
| Provider | Minimum Plan | Price | Deploy Guide |
|----------|--------------|-------|--------------|
| Hetzner | CX22 (2 vCPU, 4GB) | €5.39/mo | [DEPLOY.md#hetzner](https://moav.sh/docs/DEPLOY/#hetzner) |
| DigitalOcean | Basic (1 vCPU, 1GB) | $6/mo | [DEPLOY.md#digitalocean](https://moav.sh/docs/DEPLOY/#digitalocean) |
| Vultr | 25GB SSD (1 vCPU, 1GB) | $5/mo | [DEPLOY.md#vultr](https://moav.sh/docs/DEPLOY/#vultr) |
| Linode | Nanode 1GB | $5/mo | [DEPLOY.md#linode](https://moav.sh/docs/DEPLOY/#linode) |
- VPS Price Trackers: [VPS-PRICES](https://vps-prices.com/)، [VPS Price Tracker](https://vpspricetracker.com/), [Cheap VPS Price Cheat Sheet](https://docs.google.com/spreadsheets/d/e/2PACX-1vTOC_THbM2RZzfRUhFCNp3SDXKdYDkfmccis4vxr7WtVIcPmXM-2lGKuZTBr8o_MIJ4XgIUYz1BmcqM/pubhtml)
- [Time4VPS](https://www.time4vps.com/?affid=8471): 1 vCPU، 1GB RAM، IPv4، 3.99€/ماه
**Home Server:** Raspberry Pi 4 (2GB+ RAM) or any ARM64/x64 Linux works. See [DNS.md](https://moav.sh/docs/DNS/#home-server-raspberry-pi) for dynamic DNS setup.
### Step 2: Configure DNS
Point your domain to your server **before** running setup.
**Minimum DNS Records:**
| Type | Name | Value | Notes |
|------|------|-------|-------|
| A | @ | YOUR_SERVER_IP | Main domain |
**Additional Records (for all features):**
| Type | Name | Value | Notes |
|------|------|-------|-------|
| A | dns | YOUR_SERVER_IP | For DNS tunnel NS delegation |
| NS | t | dns.yourdomain.com | dnstt tunnel subdomain |
| NS | s | dns.yourdomain.com | Slipstream tunnel subdomain |
| NS | m | dns.yourdomain.com | MasterDNS tunnel subdomain |
| NS | x | dns.yourdomain.com | XDNS tunnel subdomain |
| A | cdn | YOUR_SERVER_IP | CDN mode (Cloudflare: **Proxied** orange cloud) |
**Important:** For Cloudflare users, the main `@` record must be **DNS only** (gray cloud). Only the `cdn` record should be **Proxied** (orange cloud).
**CDN mode** (fronting VLESS+WebSocket behind Cloudflare or AWS CloudFront) has its own full walkthrough — including the CloudFront distribution setup — in [DNS → CDN mode](https://moav.sh/docs/DNS/#cdn-mode). It is off by default (`ENABLE_CDN=false`).
See [DNS.md](https://moav.sh/docs/DNS/) for provider-specific instructions.
**Verify DNS is working:**
```bash
dig +short yourdomain.com
# Should return your server IP
# Or use MoaV's built-in DNS check (after install):
moav doctor dns
```
### Step 3: Install MoaV
SSH into your server and run:
```bash
curl -fsSL moav.sh/install.sh | bash
```
This installs:
- Docker and Docker Compose
- Git and qrencode
- MoaV to `/opt/moav`
- `moav` command (available globally)
**Manual Installation** (if you prefer):
```bash
# Install Docker
curl -fsSL https://get.docker.com | sh
# Install dependencies
apt install -y git qrencode
# Clone MoaV
git clone https://github.com/MotherofallVPNs/moav.git /opt/moav
cd /opt/moav
```
### Step 4: Configure Environment
```bash
cd /opt/moav
cp .env.example .env
nano .env
```
**Required Settings:**
```bash
# Your domain (must match DNS from Step 2)
DOMAIN=yourdomain.com
# Email for Let's Encrypt certificates
ACME_EMAIL=you@example.com
# Admin dashboard password (change this!)
ADMIN_PASSWORD=your-secure-password
```
**Optional Settings:**
```bash
# Server IP (auto-detected if empty)
SERVER_IP=
# Initial users to create during bootstrap
INITIAL_USERS=1
# Reality target (site to impersonate)
# Good choices: dl.google.com, www.apple.com, www.doi.org
REALITY_TARGET=dl.google.com:443
# CDN mode. OFF by default: a CDN link only works once the record is proxied and
# port-rewritten, so set ENABLE_CDN=true once that is in place. CDN_SUBDOMAIN is
# the record you proxy (Cloudflare); CDN_ADDRESS and CDN_SNI override the host
# clients dial, which is how CloudFront is configured.
ENABLE_CDN=true
CDN_SUBDOMAIN=cdn
CDN_ADDRESS=
CDN_SNI=
CDN_TRANSPORT=ws
# Enable/disable services
ENABLE_REALITY=true
ENABLE_TROJAN=true
ENABLE_HYSTERIA2=true
ENABLE_ANYTLS=false
ENABLE_SS=true
ENABLE_XHTTP=true
ENABLE_WIREGUARD=true
ENABLE_AMNEZIAWG=true
ENABLE_TELEMT=true
ENABLE_DNSTT=true
ENABLE_SLIPSTREAM=true
ENABLE_MASTERDNS=true
ENABLE_XDNS=true
ENABLE_TRUSTTUNNEL=true
ENABLE_GOOSERELAY=false
ENABLE_CONDUIT=true
ENABLE_ADMIN_UI=true
```
### Step 5: Run Bootstrap
Initialize MoaV (generates keys, obtains certificates, creates users):
```bash
moav bootstrap
# Or manually:
docker compose --profile setup run --rm bootstrap
```
This will:
1. Generate Reality and dnstt keypairs
2. Obtain TLS certificate from Let's Encrypt
3. Generate WireGuard server keys
4. Create initial users (default: 5)
5. Generate user bundles with configs and QR codes
> The domain prompt accepts your domain in any form (`example.com`, `https://example.com/`, `example.com:443` — all work). If you stop mid-way, re-running `moav bootstrap` picks up where you left off.
Bootstrap: domain prompt, key generation, certificate issuance, first users — 24s, 1.7 MB.
**DNS Tunnel Preparation** (optional):
If you want to use the DNS tunnel, free port 53 first:
```bash
# Stop systemd-resolved (uses port 53)
systemctl stop systemd-resolved
systemctl disable systemd-resolved
# Set up direct DNS
echo -e "nameserver 1.1.1.1\nnameserver 8.8.8.8" > /etc/resolv.conf
```
### Step 6: Start Services
Starting services and reading the status table — 26s, 1.3 MB.
```bash
# Start all services
moav start
# Or start specific profiles
moav start proxy admin # Main proxy + dashboard
moav start proxy admin wireguard # Add WireGuard
moav start all # Everything
```
See [CLI Reference → Profiles](https://moav.sh/docs/CLI/#profiles) for the full profile/service/`ENABLE_*` matrix. Common profiles: `proxy`, `xhttp`, `wireguard`, `amneziawg`, `dnstunnel`, `trusttunnel`, `telegram`, `admin`, `conduit`, `snowflake`, `gooserelay`, `monitoring`. From 1.8.2, `moav start` filters profiles whose `ENABLE_*` is `false` in `.env` — disabled services never start by accident.
**Open Firewall Ports:**
```bash
# Proxy services
ufw allow 443/tcp # Reality
ufw allow 443/udp # Hysteria2
ufw allow 8443/tcp # Trojan
ufw allow 8445/tcp # AnyTLS
ufw allow 8388 # Shadowsocks-2022
ufw allow 8389/tcp # Snell (only if ENABLE_SNELL=true)
# TrustTunnel
ufw allow 4443/tcp # HTTP/2
ufw allow 4443/udp # HTTP/3 (QUIC)
# CDN (if using)
ufw allow 2082/tcp # CDN WebSocket
# WireGuard
ufw allow 51820/udp # Direct
ufw allow 8080/tcp # wstunnel
# AmneziaWG
ufw allow 51821/udp # Obfuscated WireGuard
# XHTTP
ufw allow 2096/tcp # VLESS+XHTTP+Reality
# DNS tunnel
ufw allow 53/udp
# Admin
ufw allow 9443/tcp
# Monitoring (Grafana)
ufw allow 9444/tcp
```
**Verify Services:**
```bash
moav status
moav doctor # Run all diagnostic checks
```
### Step 7: Download User Bundles
What a bundle contains: the connection guide, per-protocol configs and QR codes — 14s, 948 KB.
User bundles are ready in `outputs/bundles/`:
```bash
ls outputs/bundles/
# user01/ user02/ user03/ user04/ user05/
```
**Each bundle contains:**
- `README.html` - User instructions (English + Farsi)
- `reality.txt` - Reality share link + QR code
- `trojan.txt` - Trojan share link
- `anytls.txt` - AnyTLS share link (if `ENABLE_ANYTLS=false`)
- `shadowsocks.txt` / `shadowsocks-qr.png` - Shadowsocks-2022 `ss://` URI + QR
- `snell.txt` / `snell-qr.png` - Snell config (Surge + Clash.Meta; only if `ENABLE_SNELL=true`)
- `hysteria2.txt` - Hysteria2 share link
- `cdn-vless.txt` - CDN share link (if CDN_DOMAIN set)
- `wireguard.conf` - WireGuard config + QR code
- `wireguard-wstunnel.conf` - WireGuard over WebSocket
- `amneziawg.conf` - AmneziaWG config (if enabled)
- `trusttunnel.txt` - TrustTunnel credentials (if enabled)
- `xhttp.txt` - XHTTP share link (if enabled)
- `dnstt-instructions.txt` - DNS tunnel instructions
**Download Options:**
**1. Admin Dashboard (Easiest):**
1. Open `https://your-server:9443` in browser
2. Log in with **any username** and your `ADMIN_PASSWORD` — only the password is checked
3. Click **Download** next to any user in the "User Bundles" section
**Creating users from the dashboard:**
1. Click **+ Create User** in the User Bundles section
2. Enter a username (e.g. `alice`)
3. For multiple users, check **Batch** and enter a count — creates `alice_01`, `alice_02`, etc.
4. Click **Create** and wait for completion
**2. Create a Zip Package:**
```bash
moav user package user01
# Creates: outputs/bundles/user01.zip
```
**3. SCP Download:**
```bash
# From your local machine
scp root@YOUR_SERVER:/opt/moav/outputs/bundles/user01.zip ./
# Or the whole folder
scp -r root@YOUR_SERVER:/opt/moav/outputs/bundles/user01 ./user01-bundle/
```
### Step 8: Distribute to Users
Send the bundle (or just the README.html + relevant protocol files) to users.
**Secure Distribution:**
- **In-person** - Safest. Show QR code or AirDrop
- **Signal** - Send files with disappearing messages
- **Encrypted email** - PGP or ProtonMail-to-ProtonMail
**Avoid:**
- Unencrypted email
- Public file sharing links
- SMS/Telegram regular chats
Users open `README.html` in their browser for instructions and QR codes.
---
## Domainless Mode
Leave `DOMAIN=` empty in `.env` and MoaV starts only the transports that need no certificate.
Which protocols those are, the ports to forward, and the home-server/dynamic-IP caveats are all in
**[DNS → Without a domain](https://moav.sh/docs/DNS/#without-a-domain)**.
Adding a domain later is non-destructive: set `DOMAIN=` and run `moav bootstrap`. Existing users keep
working and pick up the new protocols on their next bundle.
## CDN-Fronted Mode (Cloudflare)
CDN mode fronts VLESS+WebSocket behind a CDN so the client appears to talk to Cloudflare or AWS.
The DNS records, the two mandatory Cloudflare settings (Origin Rule → port 2082 and SSL/TLS
Flexible), the AWS CloudFront alternative that needs no domain, and the `521`/`525` diagnosis table
are all in **[DNS → CDN mode](https://moav.sh/docs/DNS/#cdn-mode)** and the provider tabs beside it.
What lives here is the MoaV side — the `.env` variables:
| Variable | Purpose |
|---|---|
| `ENABLE_CDN` | Master switch for CDN links, **`false` by default**. Turn on after the record is proxied and rewritten to `PORT_CDN`; check with `moav doctor dns` |
| `CDN_SUBDOMAIN` | Cloudflare subdomain to front (default `cdn`); leave empty when using CloudFront |
| `CDN_DOMAIN` | Optional override for the hostname the CDN serves. Derived from `CDN_SUBDOMAIN` + `DOMAIN` when unset, so it is absent from `.env.example`; set it explicitly for CloudFront (`d123.cloudfront.net`) |
| `CDN_ADDRESS` | What clients actually connect to — set to `www.yourdomain.com` for stealth |
| `CDN_SNI` | SNI presented by the client |
| `CDN_TRANSPORT` | `ws` (the shipped default, and **required** for CloudFront) or `httpupgrade` |
| `CDN_WS_PATH` | Generated automatically with 48-bit entropy; treat it as a secret |
After changing any of these, run `moav bootstrap` to re-render, then `moav regenerate-users` so
existing bundles carry the new CDN link.
## Choosing a Reality Target (SNI)
Reality protocols (VLESS+Reality and XHTTP+Reality) impersonate a legitimate website during the TLS handshake. The **Reality target** (also called SNI) is the domain your proxy pretends to be. DPI sees a normal TLS connection to that domain, not a proxy.
### Requirements
The target domain **must** support:
- **TLS 1.3** — required for Reality's handshake
- **HTTP/2 (h2)** — required for ALPN negotiation
### How to Verify a Target
Test any domain **from your server** (not locally — some domains are geo-restricted):
```bash
curl -vsI --tlsv1.3 --http2 https://TARGET_DOMAIN 2>&1 | grep -iE "SSL|ALPN|TLSv1.3"
```
**Good output** (both TLS 1.3 and h2 — wording varies by curl version):
```
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
```
If you get no output or the connection closes immediately, the domain either doesn't support TLS 1.3/H2 or is unreachable from your server — don't use it.
### Choosing a Good Target
**For censored regions (Iran, China, Russia, etc.):**
Avoid well-known targets like `google.com` or `microsoft.com` — censors monitor these heavily and can detect Reality by comparing your handshake to the real site.
Instead, choose a domain that:
1. **Is popular domestically** — blocking it would cause collateral damage (banks, fintech, e-commerce)
2. **Has heavy TLS traffic** — your connection blends in with millions of real users
3. **Isn't commonly used as a proxy target** — novel targets are harder to fingerprint
**Examples for Iran:**
| Domain | Why |
|--------|-----|
| `blubank.com` | Major fintech app, high traffic, can't be easily blocked |
| `divar.ir` | Popular classifieds site |
| `snapp.ir` | Ride-hailing app (like Uber) |
**Generic (less optimal but widely compatible):**
| Domain | Notes |
|--------|-------|
| `dl.google.com` | Default, works everywhere but well-known |
| `www.doi.org` | Academic, low profile |
| `gateway.icloud.com` | Apple services |
> **Tip:** The best target is one that your ISP cannot afford to block. A domestic banking site is harder to block than a foreign tech company.
### Configuration
```bash
# In .env — for sing-box (Reality VLESS)
REALITY_TARGET=blubank.com:443
# For Xray-core (XHTTP) — can be different from sing-box
XHTTP_REALITY_TARGET=blubank.com:443
```
After changing targets, re-bootstrap and regenerate user bundles:
```bash
moav bootstrap
moav user regenerate
```
> **Note:** `REALITY_TARGET` and `XHTTP_REALITY_TARGET` are independent — you can use different targets for each protocol to diversify your fingerprint.
---
## Managing Users
```bash
moav user add alice # create a user (keys, configs, QR codes)
moav user add alice --package # ...and build the distributable zip
moav user add --batch 10 # bulk-create
moav user list # who exists
moav user base64 alice # that user's subscription string
moav user revoke alice # remove access (destructive)
moav regenerate-users # rebuild every bundle from state; keys unchanged
```
Bundles land in `outputs/bundles//`. Every flag and subcommand: **[CLI Reference](https://moav.sh/docs/CLI/)**.
## Service Management
```bash
moav status # per-container health and which profiles are up
moav start [service|profile] # 'moav start all' brings up everything
moav stop [service]
moav restart [service]
moav logs [service] # first stop when something misbehaves
moav doctor # diagnostics: DNS, ports, certs, resources
```
Profiles group the services (`proxy`, `wireguard`, `amneziawg`, `dnstunnel`, `trusttunnel`, `xhttp`,
`telegram`, `admin`, `conduit`, `snowflake`, `monitoring`). Full reference: **[CLI](https://moav.sh/docs/CLI/)**.
## Server Migration
Export your MoaV configuration and migrate to a new server.
**Export:**
```bash
moav export
# Creates: moav-backup-YYYYMMDD_HHMMSS.tar.gz
```
Includes: `.env`, keys, user credentials, bundles.
**Import on New Server:**
```bash
# 1. Install MoaV on new server (Steps 1-3)
# 2. Copy backup to new server
scp moav-backup-*.tar.gz root@NEW_SERVER:/opt/moav/
# 3. Import
cd /opt/moav
moav import moav-backup-*.tar.gz
# 4. Update to new IP
moav migrate-ip $(curl -s https://api.ipify.org)
# 5. Update DNS to point to new server
# 6. Start services
moav start
```
---
## IPv6 Support
MoaV supports dual-stack (IPv4 + IPv6). When enabled, user bundles include both IPv4 and IPv6 connection options.
**Enable:**
1. Enable IPv6 on your VPS (usually in provider control panel)
2. Verify: `curl -6 -s https://api6.ipify.org`
3. If already set up, regenerate bundles: `moav regenerate-users`
**Disable:**
```bash
# In .env
SERVER_IPV6=disabled
```
**Note:** IPv6 is optional. Most censored regions have low IPv6 adoption, so it's a "nice to have" but not critical for circumvention.
---
## Bandwidth Donation (Conduit & Snowflake)
Donate bandwidth to help others bypass censorship. Both services can run simultaneously.
**Psiphon Conduit** — Donate bandwidth to Psiphon's relay network (millions of users worldwide):
```bash
# Start
moav start conduit
# Configure bandwidth and max clients (interactive)
moav donate setup # Select option 2: Conduit
# View Ryve deep link and QR code (for claiming in Ryve app)
moav donate info
# Check stats (connected clients, bandwidth donated)
moav donate status
```
**Tor Snowflake** — Donate bandwidth as a Tor Snowflake proxy:
```bash
# Start
moav start snowflake
# Configure bandwidth and capacity (interactive)
moav donate setup # Select option 3: Snowflake
# Check stats (people served, bandwidth relayed)
moav donate status
```
**Configuration in `.env`:**
```bash
CONDUIT_BANDWIDTH=100 # Mbps limit (default: 100)
CONDUIT_MAX_COMMON_CLIENTS=200 # Max concurrent clients (default: 200)
SNOWFLAKE_BANDWIDTH=5 # Mbps limit (default: 5)
SNOWFLAKE_CAPACITY=50 # Max concurrent clients (default: 50)
```
Changes via `moav donate setup` are written to `.env` and the service is restarted automatically.
---
## MahsaNet Config Donation
> Donating configs is a way to support the network rather than a setup step; this will move to a dedicated Support page. It stays here for now because that page does not exist yet.
Donate your server's VPN configs to [MahsaServer.com](https://www.mahsaserver.com/), a decentralized config sharing platform for the Mahsa VPN app (2M+ users in Iran). Mahsa VPN users connect directly to your donated configs.
### Prerequisites
1. **Register** at [mahsaserver.com](https://www.mahsaserver.com/) and verify your email
2. **Become a verified donor** — fill out the verified donor form on the website
3. **Generate an API key** at [mahsaserver.com/user/api](https://www.mahsaserver.com/user/api)
### Setup
```bash
# Set up your API key (interactive — validates the key)
moav donate setup # Select option 1: MahsaNet
```
Or manually add to `.env`:
```bash
MAHSANET_API_KEY=your_api_key_here
```
### Configuration
Configure in `.env`:
```bash
# Protocols to donate (space-separated)
# Supported: reality, hysteria2, trojan, cdn, xhttp, telegram
MAHSANET_PROTOCOLS="reality hysteria2"
# Pool determines where configs appear in the Mahsa VPN app
# Options: mahsa (default), warp, popup, telegram
# Note: telegram protocol configs are always sent to the "telegram" pool regardless of this setting
MAHSANET_POOL=mahsa
```
**Protocol notes:**
- `reality` — VLESS+Reality, works without a domain, recommended
- `hysteria2` — QUIC-based, fast, requires domain + UDP
- `trojan` — TLS-based, requires domain
- `cdn` — VLESS+WS via Cloudflare, requires CDN setup
- `xhttp` — VLESS+XHTTP+Reality via Xray-core, requires xhttp profile
- `telegram` — Telegram MTProxy link, automatically goes to the "telegram" pool
### Donating Configs
```bash
# Generate new users and donate their configs
moav donate
# You'll be prompted for:
# - Number of users to create (default: 1)
# - Username prefix (default: mahsa)
```
This creates dedicated users (e.g., `mahsa01`, `mahsa02`) and submits their config share links to MahsaNet.
### Managing Donations
```bash
# Show all donation services status (MahsaNet + Conduit + Snowflake stats)
moav donate status
# List your donated MahsaNet configs
moav donate list
# Select and delete specific configs
moav donate delete
# Remove all donated configs from MahsaNet
moav donate remove
```
### Admin Dashboard
When `MAHSANET_API_KEY` is set, the Admin Dashboard shows a **MahsaNet** section where you can:
- View donation stats (total, active, inactive configs)
- Donate new configs (with count, prefix, and protocol selection)
- See all donated configs with health status and usage count
- Collapse the section to a one-liner summary
### How It Works
1. `moav donate` creates new MoaV users with the standard user provisioning pipeline
2. For each user, it reads the share link files (e.g., `reality.txt`, `hysteria2.txt`)
3. Each link is validated (correct prefix, structure, length)
4. Links are submitted to the MahsaNet API as config donations
5. Mahsa VPN users worldwide can then connect through your server
---
## Monitoring (Grafana + Prometheus)
Optional Grafana + Prometheus stack. Enable with `ENABLE_MONITORING=true` (the installer defaults
it on above ~1 GB RAM) and start it with `moav start monitoring`.
Dashboards, the exporters, reaching Grafana, and the CDN-accelerated option are covered in
**[Monitoring](https://moav.sh/docs/MONITORING/)**.
## Updating MoaV
```bash
moav update
```
Or manually:
```bash
cd /opt/moav
git pull
docker compose --profile all build
moav restart
```
### Breaking Changes
Some updates include breaking changes that require regenerating configs. Check the [CHANGELOG](https://github.com/MotherofallVPNs/moav/blob/main/CHANGELOG.md) for breaking change notices.
**If an update has breaking changes:**
```bash
# Option 1: Rebuild configs (keeps users, regenerates server config)
moav config rebuild
moav restart
# Option 2: Fresh start (new keys, new users)
moav uninstall --wipe
cp .env.example .env
nano .env # Configure domain, email, password
./moav.sh bootstrap
```
After breaking changes, you must redistribute new config bundles to all users.
### Testing a Development Branch
```bash
moav update -b dev # Switch to dev branch
# Return to stable:
moav update -b main
```
---
## Uninstalling MoaV
### Keep Data (Reinstall Later)
Remove containers but preserve configuration for later:
```bash
moav uninstall
```
This removes:
- All Docker containers
- Global `moav` command
Preserves: `.env`, keys, certificates, user bundles, Docker volumes
To reinstall:
```bash
./moav.sh install
moav start
```
### Complete Removal (Fresh Start)
Remove everything for a completely fresh installation:
```bash
moav uninstall --wipe
```
This removes:
- All Docker containers and volumes
- `.env` and all generated configs
- All keys and certificates
- All user bundles
To start fresh:
```bash
cp .env.example .env
nano .env # Configure domain, email, password
./moav.sh
```
---
## Re-bootstrapping
If you need to regenerate keys without a full wipe:
```bash
# Remove bootstrap flag only
docker run --rm -v moav_moav_state:/state alpine rm /state/.bootstrapped
# Re-run bootstrap
moav bootstrap
```
---
## CLI Reference
See [CLI.md](https://moav.sh/docs/CLI/) for complete command reference.
## Troubleshooting
See [TROUBLESHOOTING.md](https://moav.sh/docs/TROUBLESHOOTING/) for common issues and solutions.
## Security
See [OPSEC.md](https://moav.sh/docs/OPSEC/) for security best practices.
---
# DNS Configuration
What DNS records MoaV needs, and how to add them. Most setups need **one to six records**; the rest of this page is provider quirks and edge cases, folded away until you need them.
## Do I need a domain?
**Not strictly — but get one.** MoaV runs fine on a bare IP, and if you can't register a domain, skip to [without a domain](#without-a-domain). But a domain **unlocks several additional transports**, and it is the only way to run the **DNS tunnels** — which can remain usable where ordinary traffic is blocked but recursive DNS still resolves. A domain costs a few dollars a year; see [getting a domain](#getting-a-domain).
| Protocol | Bare IP | With a domain |
|---|:-:|:-:|
| Reality (VLESS) | ✅ | ✅ |
| XHTTP (VLESS+XHTTP+Reality) | ✅ | ✅ |
| WireGuard *(direct + wstunnel)* | ✅ | ✅ |
| AmneziaWG | ✅ | ✅ |
| Telegram MTProxy | ✅ | ✅ |
| Shadowsocks-2022 | ✅ | ✅ |
| CDN-fronted VLESS *(via AWS CloudFront)* | ✅ | ✅ |
| Admin dashboard · Conduit · Snowflake | ✅ | ✅ |
| **Trojan** | — | ✅ |
| **AnyTLS** | — | ✅ |
| **Hysteria2** | — | ✅ |
| **TrustTunnel** | — | ✅ |
| **CDN-fronted VLESS** *(via Cloudflare)* | — | ✅ |
| **dnstt · Slipstream · MasterDNS · XDNS** *(DNS tunnels)* | — | ✅ |
The domain-only ones need either a Let's Encrypt certificate or an NS delegation, and both require a real domain. Nothing is lost by adding a domain later: set `DOMAIN=` and re-run `moav bootstrap`.
## With a domain: the records
Add only the rows for the features you enable. This table is the whole story — everything below it is provider-specific detail.
| Record | Name | Value | Cloudflare proxy | Needed for |
|---|---|---|:-:|---|
| A | `@` | server IP | DNS only | **Always** — Trojan, Hysteria2, Reality, TLS |
| A | `dns` | server IP | DNS only | Any DNS tunnel (the nameserver for the delegations below) |
| NS | `t`, `s`, `m`, `x` | `dns.yourdomain.com` | — | One per [DNS tunnel](https://moav.sh/docs/protocols/#dns-tunnels) you expose |
| A | `cdn` | server IP | **Proxied** | [CDN mode](#cdn-mode) |
| A | `www` | server IP | **Proxied** | [CDN mode](#cdn-mode) stealth connect address (`CDN_ADDRESS=www.…`) |
| A | `grafana` | server IP | **Proxied** | Faster Grafana over the CDN *(optional)* |
**Minimum** (no DNS tunnels): just the `@` A record. That already enables Reality, Trojan, Hysteria2 and TrustTunnel.
Each `NS` row is a separate delegation handing that subdomain to your own server:
```
t.yourdomain.com NS dns.yourdomain.com # dnstt
s.yourdomain.com NS dns.yourdomain.com # Slipstream
m.yourdomain.com NS dns.yourdomain.com # MasterDNS
x.yourdomain.com NS dns.yourdomain.com # XDNS
```
Add only the tunnels you want — see [DNS Tunnels](https://moav.sh/docs/protocols/#dns-tunnels) for what each one is and which to pick. Some registrars require a **trailing dot** on NS values (`dns.yourdomain.com.`); Cloudflare and most modern panels do not.
!!! tip "MoaV writes the zone file for you"
`moav doctor dns` generates **`outputs/dns-records.txt`** — a BIND-style zone file containing exactly the records your configuration needs, with the enabled/disabled state of each tunnel noted in comments. In Cloudflare you can feed it straight to **DNS → Records → Import and Upload** instead of adding records by hand.
## CDN mode
CDN mode fronts VLESS+WebSocket behind a CDN, so the client appears to talk to Cloudflare/AWS rather than to your server. Two things are true of **any** CDN you put in front of MoaV:
- **The origin port is `2082`.** MoaV's CDN listener does not bind 80 or 443, so the CDN must be told to reach your server on 2082.
- **The CDN terminates TLS.** That inbound is plain HTTP by design — the encryption users get is VLESS's own, inside the WebSocket.
How you express those two facts differs per provider, which is the next section. Verifying it works is the same everywhere: see [CDN returns 521 / 525](#troubleshooting).
!!! note "CDN links are off until you turn them on"
`ENABLE_CDN=false` is the default, because a CDN link generated before the CDN is actually fronting traffic looks valid to the user and cannot connect. Set `ENABLE_CDN=true` in `.env` once the steps below are done. On Cloudflare, `moav doctor dns` confirms the record is *proxied*, not merely resolving; on CloudFront use the `curl` verify in that tab instead (`moav doctor dns` does not recognise CloudFront yet).
## Provider setup
The records are the same everywhere; only the UI differs. Cloudflare additionally needs two settings for CDN mode.
=== "Cloudflare"
DNS → Records. Set every record to **DNS only** (gray cloud) **except** `cdn` / `www` / `grafana`, which must be **Proxied** (orange cloud).
**CDN mode needs two extra settings** (both required):
1. **Origin Rule** (Rules → Origin Rules): when hostname = `cdn.yourdomain.com`, rewrite **Destination Port → 2082**. MoaV's CDN listener doesn't bind 80/443.
2. **SSL/TLS → Overview → Flexible**: MoaV's CDN inbound is plain HTTP; Cloudflare terminates TLS for the client. If other subdomains need Full (Strict), scope a **Configuration Rule** to `cdn.` only.
Verify both settings: `curl -so /dev/null -w "%{http_code}" https://cdn.yourdomain.com/x` — `400`/`404` means sing-box is answering and CDN mode works. Anything else is diagnosable: see [CDN returns 521 / 525](#troubleshooting).
=== "AWS CloudFront"
An alternative CDN that **needs no domain** — you get a `*.cloudfront.net` name automatically. CloudFront rejects bare-IP origins, so use free wildcard DNS: `YOUR_IP.sslip.io` (pure DNS, no traffic passes through it).
**First, confirm the origin is reachable.** CloudFront connects to your server over the public internet on 2082, so that has to work before AWS is in the picture:
```bash
curl -so /dev/null -w "%{http_code}\n" http://YOUR_IP:2082/x
```
`400` or `404` means sing-box is answering — proceed. A timeout or refused means a firewall or cloud security-group is blocking 2082; fix that first, or CloudFront will just report the origin down.
??? example "Create the distribution (console or CLI)"
**Origin:** `YOUR_IP.sslip.io`, HTTP only, port **2082**.
**Behavior:** viewer protocol **HTTPS only**; methods **GET,HEAD,OPTIONS,PUT,POST,PATCH,DELETE**; **CachePolicy = CachingDisabled**, **OriginRequestPolicy = AllViewer** (these two forward the WebSocket upgrade headers — omitting them causes `bad "Sec-WebSocket-Key" header`). `PriceClass_200`+ includes Middle East / Asia edges.
!!! warning "The console's Review screen hides the origin port"
This is the single most common mistake. The **Review and create** page shows the origin domain but **not** its protocol or port, and the console defaults a custom origin to **HTTPS / 443**. Your origin is plain **HTTP on 2082**. Before creating (or via the origin's **Edit** afterward), confirm **Protocol: HTTP only** and **HTTP port: 2082**. Left at 443, CloudFront gets connection-refused and every request returns `502`.
CLI create (replace the IP); the same two policy IDs also fix an existing distribution that's missing them:
```bash
aws cloudfront create-distribution --distribution-config '{
"CallerReference":"moav-'$(date +%s)'","Comment":"MoaV CDN","Enabled":true,
"Origins":{"Quantity":1,"Items":[{"Id":"moav","DomainName":"YOUR_IP.sslip.io",
"CustomOriginConfig":{"HTTPPort":2082,"HTTPSPort":443,"OriginProtocolPolicy":"http-only"}}]},
"DefaultCacheBehavior":{"TargetOriginId":"moav","ViewerProtocolPolicy":"https-only",
"AllowedMethods":{"Quantity":7,"Items":["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],
"CachedMethods":{"Quantity":2,"Items":["GET","HEAD"]}},
"CachePolicyId":"4135ea2d-6df8-44a3-9df3-4b5a84be39ad",
"OriginRequestPolicyId":"216adef6-5c7f-47e4-b989-5492eafa07d3","Compress":false},
"PriceClass":"PriceClass_200"}'
```
Then in `.env` (`CDN_TRANSPORT=ws` is the default and is what CloudFront needs; `httpupgrade` will not work):
```bash
ENABLE_CDN=true
CDN_SUBDOMAIN=
CDN_DOMAIN=d123.cloudfront.net
CDN_ADDRESS=d123.cloudfront.net
CDN_SNI=d123.cloudfront.net
CDN_TRANSPORT=ws
```
`moav bootstrap`, then wait for the distribution to finish deploying (~10-15 min — the console shows a timestamp instead of *Deploying*; testing earlier gives misleading errors) and verify:
```bash
curl -so /dev/null -w "%{http_code}\n" https://d123.cloudfront.net/x
```
`400` **or** `404` means it works end to end (CloudFront → origin:2082 → sing-box; `/x` is just not the secret path). `502`/`504` means CloudFront can't reach the origin — recheck the origin port (see the warning above) and the firewall. `403` means the SNI does not match the distribution: AWS blocked domain fronting in 2018, so `CDN_SNI` must be your `*.cloudfront.net` name (or a CNAME you attached), never the root domain.
!!! note "`moav doctor dns` does not recognise CloudFront yet"
Its CDN check looks for a Cloudflare `cf-ray` header and reports **NOT proxied** for anything else — so it false-fails a working CloudFront setup. Ignore that one line for CloudFront and trust the `curl` above; the rest of `moav doctor dns` is still accurate. ([tracking issue](https://github.com/MotherofallVPNs/MoaV/issues))
You can run Cloudflare **and** CloudFront together for redundancy.
!!! info "Origin exposure"
With CloudFront the origin's `2082` is reachable directly on the public internet, and the CloudFront-to-origin leg is plain HTTP. User traffic stays safe (VLESS encrypts inside the WebSocket), but the *existence* of a WS endpoint on `2082` is visible to a scanner. To hide it, restrict inbound `2082` to [CloudFront's origin-facing IP ranges](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/LocationsOfEdgeServers.html) in your cloud security group.
## Verify
```bash
moav doctor dns # MoaV's own check
dig +short yourdomain.com # → your server IP
dig NS t.yourdomain.com # → dns.yourdomain.com in AUTHORITY
```
Propagation is usually 5–30 min (rarely up to 48 h). Cross-check worldwide at [dnschecker.org](https://dnschecker.org).
## Without a domain
Leave `DOMAIN=` empty in `.env`. MoaV detects this and starts only the transports that work on a bare IP (Reality uses `REALITY_TARGET`, e.g. `dl.google.com`, for TLS camouflage instead of your domain). No DNS records, no certificates, no port 80.
You can add a domain at any time — set `DOMAIN=` and run `moav bootstrap`. Existing users keep working and pick up the new protocols on their next bundle.
### Ports to forward
Only needed if the server sits behind a router (home, office, NAT).
| Port | Service | Needed when |
|---|---|:-:|
| `443/tcp` | Reality (VLESS) | always |
| `2096/tcp` | XHTTP | always |
| `51820/udp` | WireGuard | always |
| `8080/tcp` | wstunnel *(WireGuard over WebSocket, for UDP-blocked networks)* | always |
| `51821/udp` | AmneziaWG | always |
| `993/tcp` | Telegram MTProxy | always |
| `9443/tcp` | Admin dashboard | always |
| `80/tcp` | Let's Encrypt (ACME) | **domain only**, during issuance/renewal |
| `443/udp` | Hysteria2 | **domain only** |
| `8443/tcp` | Trojan | **domain only** |
| `4443/tcp` + `4443/udp` | TrustTunnel (HTTP/2 + QUIC) | **domain only** |
| `53/udp` | [DNS tunnels](https://moav.sh/docs/protocols/#dns-tunnels) *(all four via `dns-router`)* | **domain only** |
| `2082/tcp` | CDN origin | only if the CDN reaches your origin directly |
### Home server / Raspberry Pi
MoaV runs on a Pi 4+ (2 GB+ RAM) or any ARM64/x64 Linux box. Three things differ from a VPS:
**Check for CGNAT first.** `curl ifconfig.me` must match your router's WAN IP. If it doesn't, your ISP is sharing that address and **no amount of port forwarding will work** — you need a VPS, an IPv6-only setup, or a tunnel from a host that does have a public IP.
**Forward the ports above** to the server's LAN address, and give it a static DHCP lease so that address stops moving.
**Dynamic IP?** If you're using a domain, a residential IP that changes will silently break every record pointing at it. Run a DDNS updater on a 5-minute cron:
- **[DuckDNS](https://www.duckdns.org)** — free subdomain, works with no domain of your own
- **Your own domain** — a small script against your DNS provider's API (Cloudflare tokens are the usual choice)
After the IP moves, re-run `moav cert renew` if a certificate was issued against the old address, and remember that DNS-tunnel NS delegations point at `dns.yourdomain.com`, so that record needs the DDNS update too.
## Troubleshooting
**Not propagated** — wait, and test other resolvers: `dig @8.8.8.8 yourdomain.com`, `dig @1.1.1.1 …`.
**NS record not working** — confirm the `dns` A record exists, add a trailing dot if your registrar needs one, and give delegations longer to propagate.
**Certificate acquisition failed** — check the `@` A record, ensure port 80 is open and free during ACME, and remember domainless mode issues no certs.
**Can't connect from outside a home network** — verify port forwarding, rule out CGNAT (`curl ifconfig.me` vs router WAN IP), and test from mobile data rather than the same Wi-Fi.
**CDN returns 521 / 525** — probe it with
`curl -so /dev/null -w "%{http_code}" https://cdn.yourdomain.com/x`:
| Code | Meaning | Fix |
|---|---|---|
| `400` / `404` | sing-box is answering — CDN mode works | — |
| `521` | the CDN can't reach your origin on port 2082 | Cloudflare: the **Origin Rule** is missing or wrong. CloudFront: the origin's **HTTP port** isn't 2082 |
| `525` | TLS handshake to the origin failed | Cloudflare **SSL/TLS must be Flexible** — the CDN inbound is plain HTTP by design |
| `1016` / `NXDOMAIN` | the `cdn` A record is missing, or not **Proxied** | add it, orange cloud on |
**CDN connects but the client won't** — on CloudFront check `CDN_TRANSPORT=ws`; the default `httpupgrade` is sing-box-specific and fails there with `bad "Sec-WebSocket-Key" header`.
## Getting a domain
Any registrar with WHOIS privacy works; [Namecheap, Porkbun, Njalla](https://njal.la) accept crypto. Keep the name generic — it's the first thing DPI sees in the TLS SNI, so avoid `vpn`/`proxy`/`tunnel` and random strings, and favour boring infrastructure-style names. The full naming-and-SNI strategy lives in the [OPSEC Guide](https://moav.sh/docs/OPSEC/) so it stays in one place.
---
# VPS Deployment
Deploy MoaV on any VPS in minutes. The flow is the same everywhere: create an Ubuntu server, SSH in, and run the one-line installer.
## How It Works
1. **Create a VPS** with the recommended specs (1 vCPU, 2 GB RAM recommended) and an Ubuntu 22.04 image
2. **SSH into your server** once it boots (usually 1-2 minutes): `ssh root@YOUR_IP`
3. **Run the installer:**
```bash
curl -fsSL moav.sh/install.sh | bash
```
It installs Docker + prerequisites, clones MoaV to `/opt/moav`, installs the global `moav` command, and launches the interactive setup wizard.
The installer is safe to re-run and prompts for everything it needs. On low-RAM hosts it offers to add a swapfile so image builds don't get OOM-killed.
---
## Hetzner
Hetzner offers excellent value with servers starting at €3.79/month in European data centers.
### Steps
1. Go to [Hetzner Cloud Console](https://console.hetzner.cloud/)
2. Click **"Add Server"**
3. Choose:
- **Location**: Choose closest to your users
- **Image**: Ubuntu 22.04
- **Type**: CX22 (2 vCPU, 4 GB RAM) recommended, or CX11 (1 vCPU, 2 GB) minimum
- **Networking**: Enable IPv4 and IPv6
4. Add your SSH key
5. Click **"Create & Buy now"**
6. Wait 1-2 minutes, then SSH in: `ssh root@YOUR_IP`
7. Run `curl -fsSL moav.sh/install.sh | bash` and follow the setup wizard
### Recommended Specs
- **Minimum**: CX11 (1 vCPU, 2 GB RAM) - €3.79/month
- **Recommended**: CX22 (2 vCPU, 4 GB RAM) - €5.39/month
---
## Linode
Linode (now Akamai) offers reliable servers with good global coverage.
### Steps
1. Go to [Linode Cloud Manager](https://cloud.linode.com/)
2. Click **"Create Linode"**
3. Choose:
- **Image**: Ubuntu 22.04 LTS
- **Region**: Choose closest to your users
- **Linode Plan**: Shared CPU - Nanode 1 GB ($5/mo) or Linode 2 GB ($12/mo)
4. Set your root password and add your SSH key
5. Click **"Create Linode"**
6. Wait 1-2 minutes, then SSH in: `ssh root@YOUR_IP`
7. Run `curl -fsSL moav.sh/install.sh | bash` and follow the setup wizard
### Recommended Specs
- **Minimum**: Nanode 1 GB (1 vCPU, 1 GB RAM) - $5/month
- **Recommended**: Linode 2 GB (1 vCPU, 2 GB RAM) - $12/month
---
## Vultr
Vultr offers competitive pricing with many global locations.
### Steps
1. Go to [Vultr Dashboard](https://my.vultr.com/)
2. Click **"Deploy +"** → **"Deploy New Server"**
3. Choose:
- **Choose Server**: Cloud Compute - Shared CPU
- **Server Location**: Choose closest to your users
- **Server Image**: Ubuntu 22.04 LTS x64
- **Server Size**: 25 GB SSD ($5/mo) minimum
4. Add your SSH key
5. Click **"Deploy Now"**
6. Wait 1-2 minutes, then SSH in: `ssh root@YOUR_IP`
7. Run `curl -fsSL moav.sh/install.sh | bash` and follow the setup wizard
### Recommended Specs
- **Minimum**: 25 GB SSD (1 vCPU, 1 GB RAM) - $5/month
- **Recommended**: 55 GB SSD (1 vCPU, 2 GB RAM) - $10/month
---
## DigitalOcean
DigitalOcean is popular and beginner-friendly with excellent documentation.
### Steps
1. Go to [DigitalOcean Dashboard](https://cloud.digitalocean.com/)
2. Click **"Create"** → **"Droplets"**
3. Choose:
- **Region**: Choose closest to your users
- **Image**: Ubuntu 22.04 (LTS) x64
- **Size**: Basic → Regular → $6/mo (1 GB RAM) or $12/mo (2 GB RAM)
- **Authentication**: SSH Key (recommended)
4. Click **"Create Droplet"**
5. Wait 1-2 minutes, then SSH in: `ssh root@YOUR_IP`
6. Run `curl -fsSL moav.sh/install.sh | bash` and follow the setup wizard
### Recommended Specs
- **Minimum**: Basic (1 vCPU, 1 GB RAM) - $6/month
- **Recommended**: Basic (1 vCPU, 2 GB RAM) - $12/month
---
## After Installation
The setup wizard will guide you through:
1. Entering your domain name
2. Providing email for TLS certificates
3. Setting the admin dashboard password
4. Selecting which protocols to enable
5. Creating initial users
Once it finishes, `moav status` shows the running services and `moav help` lists everything else.
### Prerequisites Before Setup
Before running the setup, make sure:
1. **Domain configured**: Your domain's DNS A record points to your server's IP
2. **Ports open**: Most VPS providers have all ports open by default, but verify:
- 443/tcp (Reality)
- 443/udp (Hysteria2)
- 8443/tcp (Trojan)
- 4443/tcp+udp (TrustTunnel)
- 2082/tcp (CDN WebSocket, if using Cloudflare)
- 51820/udp (WireGuard)
- 80/tcp (Let's Encrypt verification)
---
## Troubleshooting
### Installer failed partway
The installer is idempotent — just re-run it:
```bash
curl -fsSL moav.sh/install.sh | bash
```
### Docker not running
```bash
sudo systemctl start docker
sudo systemctl enable docker
```
### DNS not propagated yet
Wait a few minutes and verify:
```bash
dig +short yourdomain.com
```
Should return your server's IP address.
---
See [SETUP.md](https://moav.sh/docs/SETUP/) for detailed manual installation and configuration instructions.
---
# Run MoaV with an AI agent
MoaV publishes its documentation in a form coding agents read directly, so you can hand the whole thing to Claude, ChatGPT, Cursor or Copilot and have it walk the setup with you. Most operators find this the fastest route from a bare VPS to a working server.
| File | What it is | When to use it |
|---|---|---|
| [moav.sh/llms.txt](https://moav.sh/llms.txt) | Compact index — install command, `.env` location, dashboard and Grafana URLs, and links to every page | Start here. Small enough for any context window. |
| [moav.sh/llms-full.txt](https://moav.sh/llms-full.txt) | The entire documentation in one file | When the agent can take the whole corpus, or you want it to work offline from one paste. |
## Getting started
Point your agent at the index and tell it what you want:
```text
Read https://moav.sh/llms.txt and follow it to set up a MoaV server for me.
Server: , Debian 12, I have root SSH access.
Domain: — DNS is at Cloudflare.
Walk me through it, and ask before anything destructive or anything that
needs a secret from me.
```
That is enough to get going. The agent will find the one-command install, the bootstrap flow, and `moav user add` from the index. If it can run commands on the server itself, it can do most of the work; if not, it will give you commands to paste.
Good things to ask for once the server is up:
- *"Add five users and package their bundles"* — `moav user add`, `--batch`, `--package`
- *"Why can't my friend connect on Reality?"* — `moav doctor`, `moav logs`, `moav test`
- *"Which transports are enabled, and which need a domain?"* — reads your `.env` against the protocol table
- *"Set up monitoring and show me the dashboards"* — the `monitoring` profile and Grafana
## Two things worth setting up first
Neither is required, but both remove a lot of back-and-forth.
**SSH key access.** If your agent can SSH into the server itself, it can run the install, read `moav doctor` output and fix what it finds, instead of handing you commands one at a time. Add your key with `ssh-copy-id`, confirm `ssh ` works without a password, and give the agent the hostname. Key-based auth is the right way to do this — see [OPSEC](https://moav.sh/docs/OPSEC/) before enabling anything broader.
**A Cloudflare API token**, if your DNS is there. The records MoaV needs — including the NS delegations for the DNS tunnels — are fiddly to enter by hand, and an agent with a scoped token can create them for you. Make it **DNS-edit only, for the one zone**, not a global key. `moav doctor dns` also writes the records out as an importable zone file if you would rather do it yourself: see [DNS Configuration](https://moav.sh/docs/DNS/#with-a-domain-the-records).
## Keep it safe
An agent operating a live server deserves the same care as a new admin.
- **Never paste secrets into a prompt or a public issue.** Not `.env`, not private keys, not a user's share link — those contain working credentials. Give the agent a path to read on the server instead.
- **Confirm before destructive commands.** `moav uninstall`, `moav user revoke`, re-bootstrapping and `docker system prune -a` all remove things that are awkward or impossible to get back.
- **Keep the admin dashboard closed.** Don't let an agent expose it, disable its auth, or widen `ADMIN_IP_WHITELIST` for convenience.
- **Don't publish server details.** Keep IPs, domains and share URIs out of anything public, including issues and pastebins used to share logs with an agent.
- **Review what it changed.** `git diff` in `/opt/moav`, and `moav doctor` afterwards.
## Contributing with an agent
The files above document *operating* a server. If you are changing MoaV itself, the repository has its own guide for agents — [AGENTS.md](https://github.com/MotherofallVPNs/MoaV/blob/main/AGENTS.md) covers the layout, the conventions that bite, and how to run the tests. [Development & Testing](https://moav.sh/docs/development/) is the human version.
---
# Video tutorials
Community-made walkthroughs of installing and running MoaV.
!!! info "No English tutorial yet — one in Farsi"
Switch the language in the top bar (**فارسی**) for a full server walkthrough by [@iaghapour](https://x.com/iaghapour).
**Made one, or thinking about it?** The fastest way in is the **✏️ edit button** in the corner of this page — it opens this file straight in GitHub, so you can add your video and send a PR without cloning anything. Or just [open an issue](https://github.com/MotherofallVPNs/moav-site/issues/new) with the link and we will add it.
A recording of a real install is worth more than any amount of prose, and it finds bugs the maintainers never hit — several fixes in [2.1.0](https://github.com/MotherofallVPNs/MoaV/releases/tag/v2.1.0) came from watching the Farsi one. Credit stays with the author; we link rather than re-host. (The docs live in [moav-site](https://github.com/MotherofallVPNs/moav-site), separate from the main MoaV repo.)
Prefer reading? [Quick Start](https://moav.sh/docs/quick-start/) is the same path in about ten minutes.
## What a good tutorial covers
Roughly the order a new operator needs. Nobody has to cover all of it — one clear piece is useful on its own.
**Getting a server running**
1. A VPS and a domain pointed at it — [VPS Deployment](https://moav.sh/docs/DEPLOY/), [DNS Configuration](https://moav.sh/docs/DNS/)
2. The one-command install, and what `moav bootstrap` asks for
3. **Running it at home** instead: a Raspberry Pi or spare box, checking for CGNAT first, forwarding the ports — [Home server / Raspberry Pi](https://moav.sh/docs/DNS/#home-server-raspberry-pi)
**Getting people connected**
4. Creating a user and sending them their bundle — `moav user add NAME --package`
5. Connecting from a phone: importing a config, and which app suits which protocol — [Client Apps](https://moav.sh/docs/CLIENTS/)
6. Choosing between protocols, and what to do when one is blocked — [Supported Protocols](https://moav.sh/docs/protocols/#which-one-should-i-use), then `moav doctor`
**Going further**
7. **The MoaV client** — running [moav-client](https://moav.sh/docs/client/) on a desktop so several protocols are probed and the fastest live one is used automatically, rather than switching by hand
8. **Routing rules and plugins**, which is where it stops being only a VPN. Send local and national sites *direct* so banking and government portals still work and your exit bandwidth is not wasted; block ad and tracker domains for every device on the tunnel; block torrent traffic on a donated server. The client's rule engine is hot-swappable, so this is a satisfying thing to demo live.
9. **The admin dashboard and Grafana** — adding users from a browser, and watching per-protocol throughput and per-user traffic: [admin commands](https://moav.sh/docs/CLI/#admin), [Monitoring](https://moav.sh/docs/MONITORING/)
---
# Client Setup Guide
This guide explains how to connect to MoaV from various devices.
Everything below arrives in the bundle you were sent. Opening its **`README.html`** is usually enough — it detects nothing, assumes nothing, and walks through one platform at a time in English and Farsi:
A bundle from the inside: connection guide, per-protocol configs, QR codes — 14s, 948 KB.
## Quick reference
### Protocol Support by Port
| Protocol | Port | Description |
|----------|------|-------------|
| [Reality (VLESS)](https://github.com/XTLS/REALITY) | 443/tcp | TLS camouflage, hard to detect with common techniques |
| [Trojan](https://trojan-gfw.github.io/trojan/) | 8443/tcp | HTTPS mimicry, battle-tested |
| [AnyTLS](https://github.com/anytls/anytls-go) | 8445/tcp | Resists TLS-in-TLS fingerprinting, high stealth against the filtering techniques it targets |
| [Shadowsocks-2022](https://github.com/shadowsocks/shadowsocks-org/blob/main/docs/doc/sip022.md) | 8388/tcp+udp | AEAD-2022 anti-active-probing; same protocol Outline VPN uses |
| [Snell](https://manual.nssurge.com/others/snell.html) | 8389/tcp | Lightweight TCP proxy with HTTP obfs. Needs a Snell **v5** client (Surge 5+, Stash, recent Mihomo/Clash.Meta) |
| [Hysteria2](https://v2.hysteria.network/) | 443/udp | QUIC-based, fast on lossy networks |
| CDN (VLESS+WS) | 443 via Cloudflare | When server IP is blocked |
| [TrustTunnel](https://trusttunnel.org/) | 4443/tcp+udp | HTTP/2 & QUIC, looks like HTTPS |
| [WireGuard](https://www.wireguard.com/) (Direct) | 51820/udp | Full VPN mode, simple setup |
| [AmneziaWG](https://github.com/amnezia-vpn/amneziawg-linux-kernel-module) | 51821/udp | Obfuscated WireGuard, designed to resist common DPI signatures |
| [WireGuard](https://www.wireguard.com/) + [wstunnel](https://github.com/erebe/wstunnel) | 8080/tcp | VPN wrapped in WebSocket |
| [DNS Tunnel (dnstt)](https://www.bamsoftware.com/software/dnstt/) | 53/udp | Last resort, slow but hard to block |
| [Slipstream](https://github.com/Mygod/slipstream-rust) | 53/udp | QUIC-over-DNS, 1.5-5x faster than dnstt |
| [Telegram MTProxy](https://github.com/telemt/telemt) | 993/tcp | Fake-TLS V2, direct Telegram access |
| [XHTTP (VLESS+XHTTP+Reality)](https://github.com/XTLS/Xray-core) | 2096/tcp | XHTTP transport with Reality TLS, experimental |
| [Psiphon](https://psiphon.ca/) | Various | Standalone app, uses Psiphon network |
| [Tor](https://www.torproject.org/) (Snowflake) | Various | Uses Tor network |
### Client Apps
#### iOS
| App | Protocols | Link |
|-----|-----------|------|
| [Shadowrocket](https://apps.apple.com/us/app/shadowrocket/id932747118) | VLESS, VMess, Trojan, Hysteria2, AnyTLS (2.2.65+), WireGuard | [App Store ($2.99)](https://apps.apple.com/us/app/shadowrocket/id932747118) |
| [Streisand](https://apps.apple.com/us/app/streisand/id6450534064) | VLESS/Reality, VMess, Trojan, Hysteria2, WireGuard | [App Store (Free)](https://apps.apple.com/us/app/streisand/id6450534064) |
| [Hiddify](https://apps.apple.com/us/app/hiddify-proxy-vpn/id6596777532) | VLESS, VMess, Hysteria2, Trojan, AnyTLS, Reality, SSH | [App Store (Free)](https://apps.apple.com/us/app/hiddify-proxy-vpn/id6596777532) |
| [V2Box](https://apps.apple.com/ca/app/v2box-v2ray-client/id6446814690) | VLESS, VMess, Trojan, Hysteria2, Reality | [App Store](https://apps.apple.com/ca/app/v2box-v2ray-client/id6446814690) |
| [sing-box](https://apps.apple.com/us/app/sing-box-vt/id6673731168) | VLESS, VMess, Trojan, Hysteria2, AnyTLS, WireGuard | [App Store (Free)](https://apps.apple.com/us/app/sing-box-vt/id6673731168) |
| [Loon](https://apps.apple.com/us/app/loon/id1373567447) | VLESS/Reality, Hysteria2, Trojan, WireGuard | [App Store](https://apps.apple.com/us/app/loon/id1373567447) |
| [Pharos Pro](https://apps.apple.com/us/app/pharos-pro/id1456610173) | VLESS, Hysteria2, Trojan, TUIC | [App Store ($2.99)](https://apps.apple.com/us/app/pharos-pro/id1456610173) |
| [Onion Browser](https://apps.apple.com/us/app/onion-browser/id519296448) | Tor | [App Store (Free)](https://apps.apple.com/us/app/onion-browser/id519296448) |
| [Psiphon](https://apps.apple.com/us/app/psiphon-vpn-freedom-online/id1276263909) | Psiphon | [App Store (Free)](https://apps.apple.com/us/app/psiphon-vpn-freedom-online/id1276263909) |
| [WireGuard](https://apps.apple.com/us/app/wireguard/id1441195209) | WireGuard | [App Store (Free)](https://apps.apple.com/us/app/wireguard/id1441195209) |
| [AmneziaWG](https://apps.apple.com/app/amneziawg/id6478942365) | AmneziaWG | [App Store (Free)](https://apps.apple.com/app/amneziawg/id6478942365) |
| [TrustTunnel](https://apps.apple.com/app/trusttunnel/id6478890498) | TrustTunnel | [App Store (Free)](https://apps.apple.com/app/trusttunnel/id6478890498) |
#### Android
| App | Protocols | Link |
|-----|-----------|------|
| [v2rayNG](https://github.com/2dust/v2rayNG) | VLESS, VMess, Trojan, Shadowsocks | [GitHub](https://github.com/2dust/v2rayNG/releases) |
| [Hiddify](https://hiddify.com/) | VLESS, VMess, Hysteria2, Trojan, AnyTLS, Reality, SSH | [GitHub](https://github.com/hiddify/hiddify-app/releases) |
| [NekoBox](https://github.com/MatsuriDayo/NekoBoxForAndroid) | VLESS, VMess, Trojan, Hysteria2, AnyTLS (sing-box) | [GitHub](https://github.com/MatsuriDayo/NekoBoxForAndroid/releases) |
| [V2Box](https://play.google.com/store/apps/details?id=dev.hexasoftware.v2box) | VLESS, VMess, Trojan, Hysteria2, Reality | [Play Store](https://play.google.com/store/apps/details?id=dev.hexasoftware.v2box) |
| [sing-box](https://github.com/SagerNet/sing-box) | VLESS, VMess, Trojan, Hysteria2, AnyTLS, WireGuard | [F-Droid](https://f-droid.org/packages/io.nekohasekai.sfa/) / [GitHub](https://github.com/SagerNet/sing-box/releases) |
| [HTTP Injector](https://play.google.com/store/apps/details?id=com.evozi.injector) | VLESS, Hysteria, DNS Tunnel, WireGuard, SSH | [Play Store](https://play.google.com/store/apps/details?id=com.evozi.injector) |
| [Clash Meta](https://github.com/MetaCubeX/ClashMetaForAndroid) | VLESS, VMess, Hysteria2, Trojan | [GitHub](https://github.com/MetaCubeX/ClashMetaForAndroid/releases) |
| [Tor Browser](https://www.torproject.org/download/) | Tor | [Play Store](https://play.google.com/store/apps/details?id=org.torproject.torbrowser) / [Official](https://www.torproject.org/download/) |
| [Psiphon](https://psiphon.ca/) | Psiphon | [Play Store](https://play.google.com/store/apps/details?id=com.psiphon3) / [APK](https://psiphon.ca/en/download.html) |
| [WireGuard](https://www.wireguard.com/) | WireGuard | [Play Store](https://play.google.com/store/apps/details?id=com.wireguard.android) |
| [AmneziaWG](https://play.google.com/store/apps/details?id=org.amnezia.awg) | AmneziaWG | [Play Store](https://play.google.com/store/apps/details?id=org.amnezia.awg) |
| [TrustTunnel](https://trusttunnel.org/) | TrustTunnel | [Play Store](https://play.google.com/store/apps/details?id=org.trusttunnel.app) / [GitHub](https://github.com/TrustTunnel/TrustTunnelClient) |
#### Windows
| App | Protocols | Link |
|-----|-----------|------|
| [v2rayN](https://github.com/2dust/v2rayN) | VLESS, VMess, Trojan, Hysteria2, TUIC | [GitHub](https://github.com/2dust/v2rayN/releases) |
| [Hiddify](https://hiddify.com/) | VLESS, VMess, Hysteria2, Trojan, AnyTLS, Reality | [GitHub](https://github.com/hiddify/hiddify-app/releases) |
| [NekoRay](https://github.com/MatsuriDayo/nekoray) | VLESS, VMess, Trojan, Hysteria2, AnyTLS (sing-box) | [GitHub](https://github.com/MatsuriDayo/nekoray/releases) ¹ |
| [Mihomo Party](https://github.com/mihomo-party-org/mihomo-party) | VLESS, VMess, Hysteria2, Trojan, AnyTLS | [GitHub](https://github.com/mihomo-party-org/mihomo-party/releases) |
| [Clash Verge](https://github.com/clash-verge-rev/clash-verge-rev) | VLESS, VMess, Hysteria2, Trojan | [GitHub](https://github.com/clash-verge-rev/clash-verge-rev/releases) |
| [Tor Browser](https://www.torproject.org/download/) | Tor | [Official](https://www.torproject.org/download/) |
| [Psiphon](https://psiphon.ca/) | Psiphon | [Official](https://psiphon.ca/en/download.html) |
| [WireGuard](https://www.wireguard.com/) | WireGuard | [Official](https://www.wireguard.com/install/) |
| [AmneziaWG](https://github.com/amnezia-vpn/amneziawg-windows-client/releases) | AmneziaWG | [GitHub](https://github.com/amnezia-vpn/amneziawg-windows-client/releases) |
| [TrustTunnel](https://trusttunnel.org/) | TrustTunnel | [GitHub](https://github.com/TrustTunnel/TrustTunnelClient/releases) |
#### macOS
| App | Protocols | Link |
|-----|-----------|------|
| [Streisand](https://apps.apple.com/us/app/streisand/id6450534064) | VLESS/Reality, VMess, Trojan, Hysteria2, WireGuard | [App Store (Free)](https://apps.apple.com/us/app/streisand/id6450534064) |
| [v2rayN](https://github.com/2dust/v2rayN) | VLESS, VMess, Trojan, Hysteria2 | [GitHub](https://github.com/2dust/v2rayN/releases) |
| [Hiddify](https://hiddify.com/) | VLESS, VMess, Hysteria2, Trojan, AnyTLS, Reality | [GitHub](https://github.com/hiddify/hiddify-app/releases) |
| [NekoRay](https://github.com/MatsuriDayo/nekoray) | VLESS, VMess, Trojan, Hysteria2, AnyTLS (sing-box) | [GitHub](https://github.com/MatsuriDayo/nekoray/releases) ¹ |
| [Clash Verge](https://github.com/clash-verge-rev/clash-verge-rev) | VLESS, VMess, Hysteria2, Trojan | [GitHub](https://github.com/clash-verge-rev/clash-verge-rev/releases) |
| [sing-box](https://sing-box.sagernet.org/) | VLESS, VMess, Trojan, Hysteria2, AnyTLS, WireGuard | [Homebrew](https://formulae.brew.sh/formula/sing-box) / [GitHub](https://github.com/SagerNet/sing-box) |
| [Tor Browser](https://www.torproject.org/download/) | Tor | [Official](https://www.torproject.org/download/) |
| [Psiphon](https://psiphon.ca/) | Psiphon | [App Store (Apple Silicon)](https://apps.apple.com/us/app/psiphon/id1276263909) |
| [WireGuard](https://www.wireguard.com/) | WireGuard | [App Store](https://apps.apple.com/us/app/wireguard/id1451685025) |
| [AmneziaWG](https://apps.apple.com/app/amneziawg/id6478942365) | AmneziaWG | [App Store](https://apps.apple.com/app/amneziawg/id6478942365) |
| [TrustTunnel](https://trusttunnel.org/) | TrustTunnel | [GitHub](https://github.com/TrustTunnel/TrustTunnelClient/releases) |
#### Linux
| App | Protocols | Link |
|-----|-----------|------|
| [Hiddify](https://hiddify.com/) | VLESS, VMess, Hysteria2, Trojan, AnyTLS, Reality | [GitHub](https://github.com/hiddify/hiddify-app/releases) |
| [v2rayN](https://github.com/2dust/v2rayN) | VLESS, VMess, Trojan, Hysteria2 | [GitHub](https://github.com/2dust/v2rayN/releases) |
| [sing-box](https://sing-box.sagernet.org/) | VLESS, VMess, Trojan, Hysteria2, AnyTLS, WireGuard, DNS | [GitHub](https://github.com/SagerNet/sing-box) |
| [Clash Verge](https://github.com/clash-verge-rev/clash-verge-rev) | VLESS, VMess, Hysteria2, Trojan | [GitHub](https://github.com/clash-verge-rev/clash-verge-rev/releases) |
| [Mihomo Party](https://github.com/mihomo-party-org/mihomo-party) | VLESS, VMess, Hysteria2, Trojan, AnyTLS | [GitHub](https://github.com/mihomo-party-org/mihomo-party/releases) |
| [Tor Browser](https://www.torproject.org/download/) | Tor | [Official](https://www.torproject.org/download/) |
| [WireGuard](https://www.wireguard.com/) | WireGuard | [Official](https://www.wireguard.com/install/) |
| [AmneziaWG](https://github.com/amnezia-vpn/amneziawg-linux-kernel-module) | AmneziaWG | `awg-quick` CLI (awg-tools) |
| [TrustTunnel](https://trusttunnel.org/) | TrustTunnel | [GitHub](https://github.com/TrustTunnel/TrustTunnelClient/releases) |
| **MoaV Client** | All MoaV protocols | Built-in (Docker) |
¹ NekoRay: Repository notes it is no longer actively maintained. Consider alternatives like Hiddify or Clash Verge.
**Notes:**
- Psiphon is not available via MoaV client - use [official Psiphon apps](https://psiphon.ca/download.html)
- iOS has no official Tor Browser; use [Onion Browser](https://apps.apple.com/us/app/onion-browser/id519296448) instead (Tor Project recommended)
- Psiphon for Linux is not officially available
## Protocol priority
Try these in order. If one doesn't work, try the next:
1. **Reality (VLESS)** - Primary, a strong first choice on networks where it currently works (port 443/tcp)
2. **Hysteria2** - Fast alternative, uses QUIC/UDP (port 443/udp)
3. **Trojan** - Backup, uses your domain's TLS cert (port 8443/tcp)
4. **CDN (VLESS+WS)** - When server IP is blocked, routes via Cloudflare (port 443 via CDN)
5. **TrustTunnel** - HTTP/2 & QUIC, looks like normal HTTPS (port 4443)
6. **WireGuard (Direct)** - Full VPN mode, simple setup (port 51820/udp)
7. **WireGuard (wstunnel)** - VPN wrapped in WebSocket, for restrictive networks (port 8080/tcp)
8. **Tor (Snowflake)** - Uses Tor network (no server needed)
9. **DNS Tunnel (dnstt)** - Last resort, very slow but hard to block (port 53/udp)
10. **Slipstream** - QUIC-over-DNS, 1.5-5x faster than dnstt (port 53/udp)
11. **Psiphon** - Standalone app only, uses Psiphon network (not via MoaV client)
**Telegram-specific:** Use the **Telegram MTProxy** link (in `telegram-proxy-link.txt`) directly in the Telegram app. This only works for Telegram traffic — it's not a general proxy.
---
## Set up your device
Pick your platform. Every path is the same three steps: install an app, import the bundle, connect.
=== "iOS"
### Shadowrocket (Recommended, $2.99)
The best all-in-one client for iOS.
**Download:** App Store (requires non-IR Apple ID)
**Import via QR Code:**
1. Open Shadowrocket
2. Tap the scanner icon (top-left)
3. Scan the QR code from your bundle (`reality-qr.png`)
4. Tap "Add" to save
**Import via Link:**
1. Copy the link from `reality.txt`
2. Open Shadowrocket
3. It auto-detects and asks to add - tap "Add"
**Import via Config File:**
1. AirDrop or share `reality-singbox.json` to your phone
2. Open with Shadowrocket
3. Import and save
**Connect:**
1. Toggle the switch ON
2. Allow VPN configuration when prompted
3. You're connected!
### Streisand (Free)
Good free alternative.
**Download:** App Store
**Setup:**
1. Open Streisand
2. Tap "+" to add server
3. Choose "Import from clipboard"
4. Paste the link from `reality.txt`
### Hiddify (Free, Iran-focused)
Specifically designed for Iran.
**Download:** App Store or https://hiddify.com
**Setup:**
1. Open Hiddify
2. Tap "Add Profile"
3. Paste or scan your Reality link
---
=== "Android"
### v2rayNG (Recommended, Free)
**Download:**
- Google Play: "v2rayNG"
- GitHub: https://github.com/2dust/v2rayNG/releases
**Import via QR Code:**
1. Open v2rayNG
2. Tap "+" button
3. Select "Import config from QRcode"
4. Scan `reality-qr.png`
**Import via Link:**
1. Copy link from `reality.txt`
2. Open v2rayNG
3. Tap "+" → "Import config from clipboard"
**Connect:**
1. Tap the server to select it
2. Tap the "V" button at bottom to connect
3. Allow VPN permission
### NekoBox (Free, sing-box based)
More advanced, uses sing-box core.
**Download:** GitHub: https://github.com/MatsuriDayo/NekoBoxForAndroid/releases
**Setup:**
1. Open NekoBox
2. Tap "+" → "Import from clipboard"
3. Paste your Reality link
4. Or import `reality-singbox.json` directly
### Hiddify (Free)
**Download:** https://hiddify.com or GitHub
**Setup:**
1. Open Hiddify
2. Add profile via link or QR code
---
=== "macOS"
### V2rayU (Free)
**Download:** https://github.com/yanue/V2rayU/releases
**Setup:**
1. Install and open V2rayU
2. Click menu bar icon → "Import"
3. Paste your Reality link
4. Click "Turn v2ray-core On"
### NekoRay (Free)
Cross-platform GUI client.
**Download:** https://github.com/MatsuriDayo/nekoray/releases
**Setup:**
1. Install and open NekoRay
2. Server → Add profile from clipboard
3. Paste your Reality link
### Command Line (sing-box)
For advanced users:
```bash
# Install sing-box
brew install sing-box
# Run with config
sing-box run -c reality-singbox.json
```
---
=== "Windows"
### v2rayN (Free)
**Download:** https://github.com/2dust/v2rayN/releases
**Setup:**
1. Extract and run v2rayN.exe
2. Click "Server" → "Add [VLESS]"
3. Or paste link: "Server" → "Import from clipboard"
4. Click "System Proxy" → "Set Global Proxy"
### NekoRay (Free)
Same as macOS version.
**Download:** https://github.com/MatsuriDayo/nekoray/releases
---
## Protocol-specific notes
Most protocols just work once the subscription is imported. These have quirks worth knowing.
??? note "Snell"
Snell has **no share-link or subscription** — it isn't part of the V2Ray subscription. Your bundle ships `snell.txt` with a **Surge** proxy line and a **Clash.Meta / Mihomo** YAML block; paste whichever your client uses.
It requires a client that supports **Snell v5**: **Surge 5+**, **Stash**, or a **recent Mihomo / Clash.Meta**. Apps that only speak Snell v1–v4 cannot connect. Snell is off by default — the operator turns it on with `ENABLE_SNELL=true`.
- **Surge (iOS/macOS):** open the config, add the `MoaV-Snell-*` line under `[Proxy]`, then select that proxy.
- **Stash / Mihomo / Clash.Meta:** add the YAML block under `proxies:` and select `MoaV-Snell-*`.
??? note "WireGuard"
MoaV provides two WireGuard connection methods:
- **Direct Mode** (`wireguard.conf`) - Simple, fast, uses UDP port 51820
- **wstunnel Mode** (`wireguard-wstunnel.conf`) - Wrapped in WebSocket, uses TCP port 8080, for networks that block UDP
### Direct Mode (Recommended)
Use this when UDP traffic is allowed. Simple and fast.
**Your config file:** `wireguard.conf`
#### iOS / Android
1. Install "WireGuard" from App Store / Play Store
2. Tap "+" → "Create from QR code"
3. Scan `wireguard-qr.png`
4. Name it (e.g., "MoaV WG")
5. Toggle ON to connect
#### macOS / Windows / Linux
1. Install WireGuard from https://wireguard.com/install/
2. Click "Import tunnel(s) from file"
3. Select `wireguard.conf`
4. Click "Activate"
### wstunnel Mode (For Restrictive Networks)
Use this when UDP is blocked or heavily throttled. Wraps WireGuard in a WebSocket tunnel.
**Your config file:** `wireguard-wstunnel.conf`
#### Requirements
You need both WireGuard and wstunnel client:
- WireGuard: https://wireguard.com/install/
- wstunnel: https://github.com/erebe/wstunnel/releases
#### macOS / Linux Setup
> **Use the exact command from your bundle.** `wireguard-instructions.txt` in
> your user bundle has the ready-to-paste command — it uses `wss://YOUR_DOMAIN:8080`
> (TLS) when the server has a domain, plus a per-install `--http-upgrade-path-prefix`
> secret. The examples below are the generic (domainless) form.
```bash
# 1. Download wstunnel from GitHub releases
# https://github.com/erebe/wstunnel/releases
# 2. Start wstunnel client (connect to server's port 8080)
# Domain server: wss://YOUR_DOMAIN:8080 --http-upgrade-path-prefix
wstunnel client -L udp://127.0.0.1:51820:moav-wireguard:51820 ws://YOUR_SERVER_IP:8080
# 3. In another terminal, import WireGuard config
# The config points to 127.0.0.1:51820 (local wstunnel)
sudo wg-quick up ./wireguard-wstunnel.conf
```
#### Windows Setup
1. Download wstunnel.exe from GitHub releases
2. Open PowerShell/CMD and run:
```
wstunnel.exe client -L udp://127.0.0.1:51820:moav-wireguard:51820 ws://YOUR_SERVER_IP:8080
```
3. Keep this running
4. Import `wireguard-wstunnel.conf` in WireGuard app
5. Activate the tunnel
#### iOS / Android (Advanced)
wstunnel on mobile requires additional apps or rooted devices. For most users, try other protocols (Reality, Hysteria2) instead if direct WireGuard is blocked.
**Note:** Replace `YOUR_SERVER_IP` with your actual server IP address.
---
??? note "AmneziaWG"
AmneziaWG is a DPI-resistant fork of WireGuard that obfuscates packet headers and sizes to bypass deep packet inspection.
**Your config files:**
- `amneziawg.conf` - AmneziaWG client configuration (includes obfuscation parameters)
### Mobile Apps (iOS/Android)
1. Install **AmneziaWG** ([iOS](https://apps.apple.com/app/amneziawg/id6478942365) / [Android](https://play.google.com/store/apps/details?id=org.amnezia.awg))
2. Tap "+" and scan the QR code or import `amneziawg.conf`
3. Enable the connection
### Desktop
- **Windows:** Download [AmneziaWG Client](https://github.com/amnezia-vpn/amneziawg-windows-client/releases), import `amneziawg.conf`
- **macOS:** Install [AmneziaWG](https://apps.apple.com/app/amneziawg/id6478942365) or use `awg-quick up amneziawg.conf`
- **Linux:** Use `awg-quick up amneziawg.conf` (included in awg-tools)
---
??? note "Hysteria2"
### Using Shadowrocket / v2rayNG
Both support Hysteria2 links. Import `hysteria2.txt` the same way as Reality.
### Using Hysteria2 CLI
For desktop:
```bash
# Download from https://github.com/apernet/hysteria/releases
# Run with config
./hysteria -c hysteria2.yaml
```
This creates a local proxy on:
- SOCKS5: `127.0.0.1:1080`
- HTTP: `127.0.0.1:8080`
Configure your browser/apps to use this proxy.
---
??? note "AnyTLS"
AnyTLS is a password-authenticated TLS proxy designed to resist **TLS-in-TLS fingerprinting**, giving it high stealth against the filtering techniques it targets. It runs on the same sing-box engine as Trojan and reuses your domain's TLS certificate. It is **opt-in** (enabled with `ENABLE_ANYTLS=true` on the server) and uses the same per-user password as your Trojan/Hysteria2 entries.
**Your config file:** `anytls.txt`
**Important:** AnyTLS is a newer protocol with **narrower client support** than VLESS/Trojan. Use a recent build of one of these apps:
- **Hiddify** (iOS, Android, macOS, Windows)
- **sing-box** (SFA on Android, SFI on iOS, CLI on desktop)
- **NekoBox** (Android) / **NekoRay** (desktop)
- **Mihomo Party** (macOS, Windows)
- **Shadowrocket** 2.2.65 or newer (iOS)
Clients without AnyTLS support (e.g., v2rayNG, Streisand, V2Box, Clash Verge) will fail to import the link — switch to one of the apps above.
### Import the link
The `anytls.txt` link works in any of the supported apps:
1. Copy the link from `anytls.txt`
2. Import into your client app (paste from clipboard, or scan `anytls-qr.png` if present)
3. Connect
**Link format:**
```
anytls://password@yourdomain.com:8445?sni=yourdomain.com&insecure=0#MoaV-AnyTLS-username
```
### iOS (Shadowrocket 2.2.65+ / Hiddify)
1. Open Shadowrocket or Hiddify
2. Tap the scanner icon → scan `anytls-qr.png`, or paste the link from `anytls.txt`
3. Toggle ON to connect
### Android (NekoBox / Hiddify / sing-box)
1. Open NekoBox, Hiddify, or sing-box (SFA)
2. Tap "+" → "Import from clipboard"
3. Paste the link from `anytls.txt`
4. Connect
### Desktop (NekoRay / Mihomo Party / sing-box)
1. Open NekoRay, Mihomo Party, or the sing-box CLI
2. Import the link from `anytls.txt`
3. Connect
**Note:** AnyTLS requires a domain (TLS) and shares the Trojan certificate. If import fails, confirm your client actually supports AnyTLS (see the list above) and is up to date.
---
??? note "CDN VLESS+WS (When IP Blocked)"
Use this when direct connections to your server are blocked but Cloudflare IPs are accessible.
**Your config file:** `cdn-vless.txt`
CDN mode routes your traffic through Cloudflare's CDN, making it appear as regular HTTPS traffic to a CDN-hosted website.
### Using Any VLESS Client
The CDN link works in any app that supports VLESS with WebSocket transport:
1. Copy the link from `cdn-vless.txt`
2. Import into your client app (Shadowrocket, v2rayNG, Hiddify, etc.)
3. Connect
**Link format:**
```
vless://UUID@cdn.yourdomain.com:443?security=tls&type=httpupgrade&path=/auto-generated-path&sni=yourdomain.com&host=cdn.yourdomain.com&fp=random&alpn=http/1.1#MoaV-CDN-username
```
### iOS (Shadowrocket)
1. Open Shadowrocket
2. Tap scanner icon → scan `cdn-vless-qr.png`
3. Or paste the link from `cdn-vless.txt`
4. Toggle ON to connect
### Android (v2rayNG / Hiddify)
1. Open v2rayNG or Hiddify
2. Tap "+" → "Import from clipboard"
3. Paste the link from `cdn-vless.txt`
4. Connect
**Note:** CDN mode is slower than direct connections but works when your server's IP is blocked.
---
??? note "TrustTunnel"
TrustTunnel uses HTTP/2 and HTTP/3 (QUIC), making traffic look like regular HTTPS.
**Your config files:**
- `trusttunnel.txt` - Credentials and instructions
- `trusttunnel.toml` - CLI client configuration
- `trusttunnel.json` - JSON format for apps
### Mobile Apps (iOS/Android)
1. Download TrustTunnel from App Store or Play Store
2. Tap "+" to add a new VPN
3. Enter the settings from `trusttunnel.txt`:
- Server: `yourdomain.com:4443`
- Username: (from bundle)
- Password: (from bundle)
4. Connect
### Desktop (CLI Client)
```bash
# Download from https://github.com/TrustTunnel/TrustTunnelClient/releases
# Run with config file
trusttunnel_client --config trusttunnel.toml
```
The CLI client creates a TUN interface for full VPN functionality.
---
??? note "DNS Tunnel (Last Resort)"
Use this only when all other methods are blocked. DNS tunneling is slow but often works when everything else is blocked.
### dnstt
See `dnstt-instructions.txt` in your bundle for detailed steps.
**Summary:**
1. Download dnstt-client from https://www.bamsoftware.com/software/dnstt/
2. Run: `dnstt-client -doh https://1.1.1.1/dns-query -pubkey YOUR_KEY t.yourdomain.com 127.0.0.1:1080`
3. Configure apps to use SOCKS5 proxy `127.0.0.1:1080`
### Slipstream (Faster DNS Tunnel)
Slipstream is a QUIC-over-DNS tunnel that is 1.5-5x faster than dnstt. See `slipstream-instructions.txt` in your bundle.
**Summary:**
1. Download slipstream-client from https://github.com/net2share/slipstream-rust-build/releases
2. Copy the certificate file `slipstream-cert.pem` from your bundle
3. Run: `slipstream-client --domain s.yourdomain.com --cert slipstream-cert.pem --dns-server 1.1.1.1:53 --socks-listen 127.0.0.1:1080`
4. Configure apps to use SOCKS5 proxy `127.0.0.1:1080`
**Modes:**
- **Resolver mode** (default, stealthier): Uses public DNS resolvers (~60 KB/s)
- **Authoritative mode** (faster, less stealthy): Connects directly to server (~3-4 MB/s)
### XDNS (Xray mKCP DNS Tunnel)
XDNS encodes VPN traffic inside DNS-like packets using Xray-core's mKCP transport with FinalMask. Works when most protocols are blocked. Slow but reliable during heavy internet shutdowns — best for Telegram and chat apps, not web browsing.
**Important:** XDNS requires a client app with FinalMask support. Standard v2rayNG does not support this yet. Use Happ (Android beta) or Xray CLI.
**Setup:**
1. Find `xdns-config.json` in your user bundle
2. Import into an Xray-compatible client with FinalMask support
3. The config connects directly to the server IP on port 53
4. Use as SOCKS5 proxy: `127.0.0.1:7891`
5. **For Telegram:** Settings > Proxy > SOCKS5 > `127.0.0.1:7891`
**Tips:**
- Best for **Telegram only** — too slow for web browsing
- MTU 35 (default) is safest. Try 67 or 130 for faster speeds if your network allows
- MTU must match on both server and client
- All four DNS tunnels (dnstt, Slipstream, MasterDNS, XDNS) run simultaneously on port 53 — `dns-router` fans queries out by subdomain, so no conflict
- **Resolver choice matters.** The default `xdns-config.json` round-robins across multiple public DNS resolvers (set by `XDNS_RESOLVERS` in the server's `.env`); if it keeps dropping, swap in resolvers that actually answer from your network. See [protocols.md → Reachable DNS resolvers](https://moav.sh/docs/protocols/#reachable-dns-resolvers) for scanner tools ([findns](https://github.com/SamNet-dev/findns), [dns-mns](https://gitlab.com/E-Gurl/dns-mns)).
---
??? note "Psiphon"
Psiphon is a standalone circumvention tool that doesn't require your own server. It connects to the Psiphon network - a large, distributed system designed for censorship circumvention.
**When to use Psiphon:**
- You don't have access to a MoaV server
- Your MoaV server is blocked
- You need a quick, no-setup solution
### iOS
1. Download "Psiphon" from App Store (requires non-IR Apple ID)
2. Open the app
3. Tap "Start" to connect
4. The app automatically finds working servers
### Android
1. Download from:
- Google Play: "Psiphon"
- Direct APK: https://psiphon.ca/en/download.html
2. Open the app
3. Tap "Start" to connect
### Windows
1. Download from https://psiphon.ca/en/download.html
2. Run the executable (no installation needed)
3. Click "Connect"
4. Configure browser to use the local proxy shown in the app
### macOS
1. Download from https://psiphon.ca/en/download.html
2. Open the app
3. Click "Connect"
4. Configure system or browser proxy settings
**Note:** Psiphon uses various protocols internally (SSH, OSSH, etc.) and automatically switches between them to find working connections.
---
??? note "XHTTP"
XHTTP uses VLESS with XHTTP transport and Reality TLS camouflage, powered by Xray-core. No domain is required.
**Your config file:** `xhttp.txt`
### Compatible Client Apps
XHTTP requires Xray-based clients that support the XHTTP transport:
| Platform | App | Link |
|----------|-----|------|
| Android | [V2rayNG](https://github.com/2dust/v2rayNG) | [GitHub](https://github.com/2dust/v2rayNG/releases) |
| Android | [Hiddify](https://hiddify.com/) | [GitHub](https://github.com/hiddify/hiddify-app/releases) |
| Android | [NekoBox](https://github.com/MatsuriDayo/NekoBoxForAndroid) | [GitHub](https://github.com/MatsuriDayo/NekoBoxForAndroid/releases) |
| iOS | [Streisand](https://apps.apple.com/us/app/streisand/id6450534064) | [App Store (Free)](https://apps.apple.com/us/app/streisand/id6450534064) |
| iOS | [Hiddify](https://apps.apple.com/us/app/hiddify-proxy-vpn/id6596777532) | [App Store (Free)](https://apps.apple.com/us/app/hiddify-proxy-vpn/id6596777532) |
| iOS | [V2Box](https://apps.apple.com/ca/app/v2box-v2ray-client/id6446814690) | [App Store](https://apps.apple.com/ca/app/v2box-v2ray-client/id6446814690) |
| Windows | [V2rayN](https://github.com/2dust/v2rayN) | [GitHub](https://github.com/2dust/v2rayN/releases) |
| macOS | [V2rayU](https://github.com/yanue/V2rayU) | [GitHub](https://github.com/yanue/V2rayU/releases) |
### Import
1. Copy the link from `xhttp.txt`
2. Import into your client app (V2rayNG, Hiddify, Streisand, etc.)
3. Connect
**Note:** XHTTP is enabled by default. Disable with `ENABLE_XHTTP=false` in `.env` if not needed.
---
## Testing from a server or CI
MoaV ships a built-in multi-protocol **client container**, used mainly to **verify a server's protocols actually work** — run straight from the server itself or in CI, without touching a phone or desktop. Typical uses:
- **Connectivity testing** — run `moav test ` on the server to check every protocol in a user's bundle
- **CI / automated testing** — the same container backs MoaV's end-to-end test suite (`tests/client-test.sh`)
- **Ad-hoc connections** — `moav client connect ` brings up a local SOCKS5/HTTP proxy for a quick check
!!! tip "Want a full client for everyday use?"
This container is optimized for testing. For a standalone client with a **web dashboard**, **load-balancing across all healthy endpoints**, **automatic failover**, and **live routing rules** — the kind you'd leave running on a home server or Linux desktop — see the dedicated **[MoaV Client](https://moav.sh/docs/client/)** page.
### Testing Connectivity
Test all protocols for a user to verify server is working:
```bash
# Test all protocols for user1
moav test user1
# Output results as JSON (for scripts/automation)
moav test user1 --json
```
The test checks: Reality, Trojan, Hysteria2, WireGuard (config validation), dnstt, and Slipstream.
**Sample output:**
```
═══════════════════════════════════════════════════════════════
MoaV Connection Test Results
═══════════════════════════════════════════════════════════════
Config: /bundles/user1
Time: Wed Jan 28 10:30:00 UTC 2026
───────────────────────────────────────────────────────────────
✓ reality Connected via VLESS/Reality
✓ trojan Connected via Trojan
✓ hysteria2 Connected via Hysteria2
✓ wireguard Config valid, endpoint reachable
○ dnstt No dnstt config found in bundle
═══════════════════════════════════════════════════════════════
```
### Client Mode (Connect Through Server)
!!! tip "For everyday use, prefer the MoaV Client"
`moav client connect` exists mainly to verify a server from the server side. If you
want a client to actually **use** — endpoint probing, load-balancing across healthy
endpoints, automatic failover, routing rules and a dashboard — that is
**[MoaV Client](https://moav.sh/docs/client/)**, a separate and more capable project. The built-in client
mode here is deliberately minimal and may be reduced to testing only.
Run MoaV as a local proxy client:
```bash
# Auto-detect best working protocol
moav client connect user1
# Force a specific protocol
moav client connect user1 --protocol reality
moav client connect user1 --protocol hysteria2
moav client connect user1 --protocol trojan
moav client connect user1 --protocol wireguard
moav client connect user1 --protocol dnstt
moav client connect user1 --protocol tor
```
**Local proxy endpoints:**
- SOCKS5: `127.0.0.1:1080`
- HTTP: `127.0.0.1:8080`
Configure these ports in `.env`:
```bash
CLIENT_SOCKS_PORT=1080
CLIENT_HTTP_PORT=8080
```
**Protocol fallback order (auto mode):**
1. Reality (VLESS) - A strong first choice on networks where it currently works
2. Hysteria2 - Fast, UDP-based
3. Trojan - TLS-based backup
4. WireGuard - Full VPN
5. Tor (Snowflake) - Uses Tor network (no server needed)
6. dnstt - Last resort, slow but hard to block
> **Note:** Psiphon is not available via MoaV client. Use the [official Psiphon apps](https://psiphon.ca/en/download.html) instead.
### Building the Client Image
The client image is built automatically when running `moav test` or `moav client`. To build manually:
```bash
moav client build
```
### Technical Details
The client container includes:
- **sing-box** - Handles Reality, Trojan, Hysteria2
- **wireguard-go** - Userspace WireGuard implementation
- **wstunnel** - WebSocket tunnel for WireGuard
- **dnstt-client** - DNS tunnel client
- **snowflake-client** - Tor Snowflake pluggable transport
- **tor** - Tor daemon
**Container capabilities:**
- Runs without privileged mode for most protocols
- WireGuard requires `--cap-add NET_ADMIN` for full functionality
- Uses Alpine Linux for minimal image size
---
## Highly censored networks
1. **Keep multiple configs** - Have Reality, Hysteria2, WireGuard, XDNS, and DNS tunnel ready
2. **Download client apps in advance** - Store APKs, wstunnel binaries, and Psiphon offline
3. **Use mobile data** as backup - Sometimes less filtered than home internet
4. **Avoid peak hours** - Filtering can be heavier during protests/events
5. **Update configs quickly** - If server is blocked, switch to backup
6. **Try wstunnel if UDP is blocked** - Some ISPs block UDP; wstunnel wraps WireGuard in TCP/WebSocket
7. **Reality is often best** - Mimics legitimate HTTPS traffic to common sites
8. **Keep Psiphon as backup** - No server needed, works independently of your MoaV setup
9. **Enable TLS Fragment and MUX** - See below for client-side optimizations
---
## Connection optimization (fragment & MUX)
MoaV's generated sing-box configs already include optimal Fragment and MUX settings. If you're using third-party apps (Hiddify, v2rayNG, NekoBox, etc.) or importing via share links, you can enable these manually for better performance in censored networks.
### TLS Fragment
TLS Fragment splits the TLS ClientHello message into smaller pieces, making it harder for DPI (Deep Packet Inspection) systems to detect the SNI (Server Name Indication) and block the connection. This is a **client-side only** feature — no server changes needed.
**When to use:** When connections are being blocked or reset during the TLS handshake, which is common in Iran and similar environments.
**Which protocols benefit:**
| Protocol | Fragment | Why |
|----------|----------|-----|
| Reality (VLESS) | Yes | Hides SNI from DPI during TLS handshake |
| Trojan | Yes | Same — TLS-based, benefits from fragment |
| CDN (VLESS+WS) | No | TLS terminates at Cloudflare, not your server |
| Hysteria2 | No | Uses QUIC/UDP, not TCP-based TLS |
| WireGuard / AmneziaWG | No | Not TLS-based |
#### sing-box JSON Config
MoaV's generated configs already include this. If you're building your own config:
```json
{
"outbounds": [
{
"type": "vless",
"tls": {
"enabled": true,
"server_name": "example.com",
"record_fragment": true
}
}
]
}
```
The `record_fragment` option (sing-box 1.12+) automatically splits TLS records. This is simpler than Xray-core's granular settings and works well for most scenarios.
#### Hiddify
1. Go to **Settings** → **Config Options**
2. Find **TLS Fragment** section
3. Enable it and set:
- **Size**: `10-100` (bytes per fragment)
- **Sleep**: `10-50` (ms delay between fragments)
#### v2rayNG
1. Go to **Settings** → **TLS/Reality**
2. Enable **TLS Fragment**
3. Recommended values:
- **Length**: `50-200`
- **Interval**: `10-50`
- **Packets**: `1-3`
#### Shadowrocket
Shadowrocket does not currently support TLS Fragment. Use the sing-box app or Hiddify if you need this feature on iOS.
### MUX (Multiplexing)
MUX multiplexes multiple connections over a single TCP connection, reducing the number of TLS handshakes and making traffic patterns harder to fingerprint.
**When to use:** When you experience frequent connection drops or slow initial connections. Also useful to reduce the number of observable connections to the server.
**Which protocols benefit:**
| Protocol | MUX | Why |
|----------|-----|-----|
| Reality (VLESS) | No | Incompatible with VLESS Vision flow (`xtls-rprx-vision`) |
| Trojan | Yes | Reduces handshakes, improves stability |
| CDN (VLESS+WS) | Yes | Fewer WebSocket connections through CDN |
| Hysteria2 | No | QUIC already multiplexes natively |
| WireGuard / AmneziaWG | No | Not applicable |
> **Important:** MUX is **not compatible** with Reality (VLESS Vision). Enabling MUX on a Reality connection will break it. MoaV's generated configs handle this correctly.
#### sing-box JSON Config
MoaV's generated Trojan and CDN configs already include this:
```json
{
"outbounds": [
{
"type": "trojan",
"multiplex": {
"enabled": true,
"protocol": "h2mux",
"max_connections": 2,
"padding": true
}
}
]
}
```
- `protocol`: `h2mux` is recommended (HTTP/2 multiplexing)
- `max_connections`: `2` balances speed and stealth
- `padding`: `true` adds random padding to obscure traffic patterns
#### Hiddify
1. Go to **Settings** → **Config Options**
2. Find **MUX** section
3. Enable and set:
- **Protocol**: `h2mux`
- **Max Connections**: `2`
- **Padding**: On
#### v2rayNG
1. Go to **Settings** → **MUX**
2. Enable **MUX**
3. Set **Concurrency**: `2-4`
### Summary: What to Enable Per Protocol
| Protocol | Fragment | MUX | Notes |
|----------|----------|-----|-------|
| Reality (VLESS) | Yes | **No** | Vision flow is incompatible with MUX |
| Trojan | Yes | Yes | Best with both enabled |
| CDN (VLESS+WS) | No | Yes | Fragment won't help (CDN terminates TLS) |
| Hysteria2 | No | No | QUIC handles both natively |
| WireGuard | No | No | Different protocol layer |
| AmneziaWG | No | No | Has its own obfuscation |
> **Note:** MoaV v1.3.7+ automatically includes these optimizations in generated sing-box JSON configs. If you import via share links (vless://, trojan://, hy2://), you may need to enable Fragment and MUX manually in your app settings.
## Donating bandwidth (server operators)
Psiphon Conduit and Tor Snowflake are **server** features, not something a user
installs — they donate your spare bandwidth to Psiphon and Tor users worldwide.
See [Protocols → Psiphon Conduit / Tor Snowflake](https://moav.sh/docs/protocols/#psiphon-conduit)
and enable them with `moav start conduit` / `moav start snowflake`.
## When it won't connect
Client-side symptoms — can't connect at all, TLS handshake timeouts, slow or dropping connections, "invalid config" — are covered in [Troubleshooting](https://moav.sh/docs/TROUBLESHOOTING/#nothing-connects).
### "Connection failed" or "Timeout"
1. Check your internet connection
2. Try a different protocol (Reality → Hysteria2 → Trojan)
3. Try a different DNS (1.1.1.1 or 8.8.8.8)
4. Restart the app
### "TLS handshake failed"
- Your ISP might be blocking the connection
- Try Hysteria2 (uses UDP instead of TCP)
- Try DNS tunnel as last resort
### "Certificate error"
- Check that your device's date/time is correct
- Try Reality protocol (doesn't use your domain's cert)
### Very slow connection
- Try Hysteria2 (optimized for lossy networks)
- Check if your ISP is throttling
- DNS tunnel is inherently slow - only for emergencies
### Nothing works
- The server IP might be blocked
- Contact admin for a new server/config
- Try using a different network (mobile data vs WiFi)
---
---
# MoaV Client
**[moav-client](https://github.com/MotherofallVPNs/moav-client)** is a standalone, self-hosted client for MoaV servers. You run it on your own Linux box, home server, or desktop; it ingests a MoaV subscription bundle, probes every endpoint end-to-end through its tunnel, load-balances across the healthy ones, and exposes a single local **SOCKS5 / HTTP CONNECT** proxy for the rest of your machine to use. A dark React dashboard — styled to match the MoaV admin panel — gives live visibility into endpoint health, per-protocol throughput, routing rules, and logs.

!!! note "How this differs from a connect-and-go app"
Phone/desktop apps like [Hiddify, NekoBox, sing-box, or Shadowrocket](https://moav.sh/docs/CLIENTS/#client-apps) are the simplest way to connect a single device. **moav-client** is for when you want an always-on local proxy that automatically **picks the best live endpoint**, **fails over** when one dies, and gives you a **dashboard + routing rules** — e.g. on a home server or Linux desktop that other devices route through. To simply **test** whether a server's protocols work — on the server itself or in CI — use the lightweight [MoaV Client Container](https://moav.sh/docs/CLIENTS/#testing-from-a-server-or-ci) instead.
## Install
One command installs Docker (if missing), clones the repo, lets you pick which sidecars to build, seeds config, and brings the stack up:
```bash
curl -fsSL moav.sh/client-install.sh | bash
```
It works interactively — even piped through `bash` — or fully headless, and installs a global `moavc` command.
Once it finishes, these are exposed on the local machine:
| What | Address |
|------|---------|
| Dashboard | `http://localhost:3001` |
| SOCKS5 proxy | `socks5h://localhost:1080` |
| HTTP CONNECT | `http://localhost:8081` |
| REST + WS API | `http://localhost:8088` |
Point your browser or system proxy at `socks5h://localhost:1080` — every connection then routes through the healthiest MoaV endpoint.
## Manage it with `moavc`
```bash
moavc status # service status + health + URLs
moavc info # just the dashboard / proxy / API URLs
moavc logs -f proxy-core # tail logs
moavc probe # trigger a latency probe
moavc sidecar add tor # enable + build + start a sidecar
moavc expose lan # network reach: loopback | lan | public
moavc update [-b ] # pull (optionally switch branch) + rebuild
moavc uninstall [--wipe] # remove the stack (--wipe deletes config/data)
```
## The dashboard
The web UI at `:3001` is organized into tabs:
- **Endpoints** — live status and latency per endpoint; toggle each on/off (sidecar toggles also stop/start its Docker container) and edit priority inline.
- **Configs** — import another MoaV server's bundle by dropping its `.zip`; list, remove, and reload sources.
- **Analytics** — per-protocol upload/download with a rolling 2-minute throughput chart, plus a per-endpoint table of dials, errors, and failovers.
- **Plugins** — first-match-wins routing rules (proxy / direct / block by domain, IP CIDR, GeoIP, port…), editable live from a curated template catalog.
- **Settings** — load-balancing strategy (latency / priority / weighted), network exposure, access URLs, SNI-spoofing, and config backup / restore.
- **Debug / Diagnostics** — streaming log tail and per-endpoint connectivity checks (TCP / DNS / traceroute, optionally *through* a chosen tunnel).
## Network exposure
By default the proxy binds to loopback only. Widen it from the Settings tab or the CLI:
```bash
moavc expose loopback # 127.0.0.1 — only this machine (default, safest)
moavc expose lan # 0.0.0.0 — every device on your LAN can use it
moavc expose public # LAN bind + you port-forward on your router
```
`lan` and `public` add optional SOCKS5 and dashboard authentication.
## Supported protocols
Protocol cryptography is delegated to **sing-box** (and **xray** for XHTTP), with optional sidecars for the rest:
VLESS / Reality · VLESS+WS+TLS (CDN) · Trojan · AnyTLS · Shadowsocks-2022 · Hysteria2 · VLESS+XHTTP+Reality · WireGuard · AmneziaWG · TrustTunnel · MasterDNS · Psiphon · Tor.
See the [Supported Protocols](https://moav.sh/docs/protocols/) reference for what each one is and when to use it.
## Learn more
Full documentation — configuration reference, architecture, plugin rules, and per-protocol dial details — lives in the repo:
- **[The moav:// bundle](https://moav.sh/docs/moav-bundle/)** — the compact subscription the client imports.
- **Repository:** [github.com/MotherofallVPNs/moav-client](https://github.com/MotherofallVPNs/moav-client)
- **README:** install, config, and CLI reference (available in [English](https://github.com/MotherofallVPNs/moav-client/blob/main/README.md) and [فارسی](https://github.com/MotherofallVPNs/moav-client/blob/main/README-fa.md))
---
# The `moav://` bundle
Every MoaV user bundle's `subscription.txt` carries a single **`moav://`** line: a
compact URL that encodes the user's entire enabled proxy surface at once,
alongside the usual per-protocol share links (`vless://`, `trojan://`, …).
The `moav://` line is **additive** — it sits next to the legacy URIs, not in
place of them:
- **[MoaV Client](https://moav.sh/docs/client/)** recognizes the line, expands it back into one
endpoint per protocol, and de-duplicates it against the legacy URIs (by
protocol + address), so importing a subscription yields each server once.
- Every other client ignores the unknown `moav://` scheme and uses the legacy
URIs. Nothing regresses.
## Why
A MoaV subscription is N separate URIs that repeat the same host, UUID, Reality
keypair, and passwords for every protocol. The `moav://` form factors the shared
parts out once, so the bundle is far smaller and rotating a shared credential is
a one-line change instead of editing every URI.
## Using it
There's nothing to configure. When you provision or regenerate a user, the
server writes the `moav://` line into that user's `subscription.txt` (and it
flows into the base64 subscription automatically). To use it, just import your
subscription into the MoaV Client the way you already do — paste the
subscription, its URL, or drop the server `.zip`. See
[MoaV Client → Install](https://moav.sh/docs/client/#install).
## Format
```text
moav://@?&p=&p=…#