Complete reference for the moav command-line interface.
- Installation
- Quick Reference
- Commands
- Profiles
- Service Names & Aliases
- Environment Variables
- Examples
# Install moav command globally (run from /opt/moav)
./moav.sh install
# Or using the script directly
./moav.sh [command]
# Uninstall global command
moav uninstallAfter installation, moav is available from any directory.
moav # Interactive menu
moav help # Show help
moav start # Start all services
moav stop # Stop all services
moav status # Show service status
moav logs # View logs (follow mode)
moav doctor # Run diagnostics
moav user add NAME # Add new user
moav user add --batch 5 # Batch create 5 users
moav user revoke NAME # Revoke user
moav test USERNAME # Test connectivity
moav admin password # Reset admin password
moav donate # Donate configs to MahsaNetLaunch the interactive menu for guided setup and management.
moavDisplay help message with all available commands.
moav help
moav --help
moav -hShow MoaV version.
moav version
moav --versionInstall moav command globally to /usr/local/bin.
./moav.sh installRemove MoaV containers and global command.
moav uninstall # Remove containers, keep data (.env, keys, bundles)
moav uninstall --wipe # Remove EVERYTHING (fresh install ready)Without --wipe (default):
- Stops and removes all Docker containers
- Removes the global
moavcommand - Preserves:
.env, keys, certificates, user bundles, Docker volumes
With --wipe:
- Removes all Docker containers AND volumes
- Removes
.envand all generated configs - Removes all keys and certificates
- Removes all user bundles
- Removes the global
moavcommand
After --wipe, run cp .env.example .env and ./moav.sh for a fresh setup.
Run prerequisites check (Docker, dependencies, ports).
moav checkRun diagnostic checks for common MoaV issues.
moav doctor # Run all checks
moav doctor docker # Docker and prerequisites
moav doctor memory # RAM availability
moav doctor disk # Disk space
moav doctor logs # Container log file sizes (offers to truncate oversized)
moav doctor dns # DNS records
moav doctor services # Enabled vs running services
moav doctor config # Config files and keys
moav doctor ports # Port availability
moav doctor conflicts # DNS-tunnel health (all 4 share port 53 via dns-router)
moav doctor env # Compare .env with .env.example
moav doctor updates # Check for MoaV updatesAvailable checks:
docker— Docker daemon running, Compose available, Docker disk usage summarymemory— Total RAM, available memory, warns if <1GB or <2GB with monitoring enableddisk— Disk space on root and Docker partition, warns if <2GB freelogs— Scans/var/lib/docker/containers/*/*-json.logfor files >100 MB; lists oversized files by container name and prompts to truncate in place.truncate -s 0keeps the FD live so Docker keeps writing — no service restart needed. Skips the prompt in non-interactive sessions (cron / piped runs) and prints the manual command instead. Pre-1.7.6 containers keep growing under Docker's unbounded default until they're recreated; this check is the fastest way to reclaim that space without a full restartdns— Verify DNS records for enabled protocols (A records, NS delegation, CDN)services— Compare enabled services in.envwith running containers; flag crash-looping servicesconfig— Check bootstrap has been run and config files exist for enabled protocolsports— Verify required ports are listening; detect systemd-resolved on port 53conflicts— Check DNS-tunnel health. All four tunnels (dnstt, Slipstream, MasterDNS, XDNS) share port 53 viadns-router, fanned out by subdomain (t./s./m./x.), so they coexist — this verifies enabled-vs-running state and thatdns-routerisn't crash-looping. Toggle individual tunnels withENABLE_*ormoav switch-dnsenv— Compare.envwith.env.examplefor missing variables; flag critical missing varsupdates— Check current version against latest GitHub release
Run first-time setup. Generates keys, obtains TLS certificates, creates initial users.
moav bootstrapThis command:
- Checks prerequisites
- Prompts for domain, email, admin password (if not in .env)
- Generates Reality and dnstt keypairs
- Obtains Let's Encrypt certificate
- Creates initial users
- Generates user bundles
Enable domainless mode for servers without a domain.
moav domainlessAvailable services in domainless mode:
- Reality (VLESS+Reality)
- XHTTP (VLESS+XHTTP+Reality)
- WireGuard (direct + wstunnel)
- AmneziaWG (obfuscated WireGuard)
- Telegram MTProxy (fake-TLS)
- Admin dashboard (self-signed certificate)
- Conduit (Psiphon bandwidth donation)
- Snowflake (Tor bandwidth donation)
Interactively change default services for moav start.
moav profilesSaves selection to DEFAULT_PROFILES in .env.
Update MoaV from git repository.
moav update # Update from current branch
moav update -b dev # Switch to dev branch and update
moav update -b main # Switch back to main branchOptions:
-b BRANCH- Switch to specified branch before updating
If local changes are detected, you'll be prompted to stash or discard them.
Free port 53 for dnstt by disabling systemd-resolved.
moav setup-dnsThis command:
- Stops systemd-resolved
- Disables it from starting on boot
- Configures /etc/resolv.conf with public DNS servers
Start services.
moav start # Start DEFAULT_PROFILES from .env
moav start all # Start all services whose ENABLE_* is true
moav start proxy # Start proxy profile only
moav start proxy admin # Start multiple profiles
moav start proxy wireguard admin # Start three profilesArguments:
- No arguments: uses
DEFAULT_PROFILESfrom.env - Profile names: start specific profiles (space-separated)
--force/-f: bypass the profile-filtering prompt (see below)
moav start respects the ENABLE_* flags in .env:
-
No args or
moav start all: starts only the profiles whoseENABLE_*istrue. Anything disabled is skipped (you'll seeSkipping disabled profiles: <list>). -
moav start <name>for a profile that's disabled in.env: you get a prompt:- Enable + start — flips
ENABLE_*=truein.env, then starts (persists for next time). - Skip — don't start;
.envstays as-is. - Start once — start now without modifying
.env(won't auto-start next time).
For profiles backed by multiple flags (
proxy,dnstunnel), option 1 shows which flags to set manually.--forcebypasses the prompt. Non-interactive shells default to skip. - Enable + start — flips
Stop services.
moav stop # Stop all running services
moav stop sing-box # Stop specific service
moav stop conduit snowflake # Stop multiple services
moav stop -r # Stop and remove containers
moav stop sing-box -r # Stop specific service and remove containerOptions:
-r- Remove containers after stopping (not just stop)
Restart services.
moav restart # Restart all running services
moav restart sing-box # Restart specific service
moav restart sing-box admin # Restart multiple servicesShow status of all services.
moav statusDisplays:
- Container status (running/stopped)
- Health status
- Port mappings
- Uptime
View service logs.
moav logs # All logs, follow mode (Ctrl+C to exit)
moav logs sing-box # Specific service logs
moav logs sing-box conduit # Multiple services
moav logs -n # Last 100 lines, no follow
moav logs sing-box -n # Specific service, no follow
moav logs -f conduit # Explicit follow modeOptions:
-n,--no-follow- Show last 100 lines without following-f,--follow- Follow mode (default)
Build Docker images.
moav build # Build all images
moav build sing-box # Build specific image
moav build conduit snowflake # Build multiple imagesList all users.
moav users
moav user list # Same as aboveAdd one or more users to all services. Users can also be created from the Admin Dashboard (User Bundles → + Create User).
# Single user
moav user add john # Add user 'john'
moav user add john --package # Add user and create zip bundle
moav user add john -p # Short form
# Multiple users
moav user add alice bob charlie # Add three users
moav user add alice bob charlie -p # Add three users with zip packages
# Batch mode (auto-numbered)
moav user add --batch 5 # Create user01, user02, ..., user05
moav user add --batch 10 --prefix team # Create team01, team02, ..., team10
moav user add --batch 5 --prefix dev -p # Create dev01..dev05 with packagesOptions:
--package,-p- Create distributable zip file with HTML guide--batch N,-b N- Create N users with auto-generated names--prefix NAME- Prefix for batch usernames (default: "user")
Batch mode features:
- Smart numbering: if user01-user03 exist,
--batch 2creates user04, user05 - Services reload once at the end (not after each user)
- Shows progress for each user and summary at the end
Creates bundle in outputs/bundles/USERNAME/ containing:
- Config files for all protocols
- QR codes for mobile import
- README.html with instructions
Revoke a user from all services.
moav user revoke john # Revoke user 'john'Removes user from:
- sing-box config (Reality, Trojan, Hysteria2, CDN)
- WireGuard config
- TrustTunnel credentials
- Deletes user bundle
Create distributable zip for an existing user.
moav user package john # Creates outputs/bundles/john.zipEvery user bundle includes a standard base64 V2Ray subscription — both as
outputs/bundles/<user>/subscription.txt and as a click-to-copy block at the
top of the bundle's README.html. Paste it once into
MahsaNG, v2rayNG, Hiddify, Streisand,
or any V2Ray app to import all proxy protocols at once — Reality, CDN, XHTTP,
Trojan, Shadowsocks-2022, Hysteria2 (standard vless:///trojan:///ss:///
hysteria2:// URIs, IPv4 + IPv6).
WireGuard/AmneziaWG/TrustTunnel/DNS-tunnel/GooseRelay/Telegram are intentionally excluded (not subscription-importable; the DNS tunnels and GooseRelay are set up in their own app tabs). Full walkthrough: docs/mahsanet.md.
Print GooseRelay setup instructions for a user (extracted from their bundle).
moav user gooserelay john # Print tunnel_key + Apps Script setup guideGooseRelay is opt-in (ENABLE_GOOSERELAY=true in .env). When enabled, each
user bundle includes gooserelay-instructions.txt with the shared tunnel_key
and a step-by-step guide for deploying the Google Apps Script forwarder. See
docs/protocols.md → GooseRelay for full details.
Test connectivity for a user across all protocols.
moav test john # Test all protocols
moav test john --json # Output results as JSON
moav test john -v # Verbose output for debugging
moav test john --verbose # Same as aboveOptions:
--json- Output results in JSON format-v,--verbose- Show detailed debug output
Tests: Reality, Trojan, Hysteria2, TrustTunnel, WireGuard, dnstt, Slipstream, MasterDNS
Sample output:
═══════════════════════════════════════════════════════════════
MoaV Connection Test Results
═══════════════════════════════════════════════════════════════
Config: /bundles/john
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
○ slipstream No slipstream config found in bundle
○ masterdns No masterdns config found in bundle
═══════════════════════════════════════════════════════════════
Client mode commands.
moav client # Show client help
moav client build # Build client Docker image
moav client test john # Same as 'moav test john'
moav client connect john # Connect as user (exposes proxy)Connect through your MoaV server and expose local proxy.
moav client connect john # Auto-detect best protocol
moav client connect john --protocol reality # Use specific protocol
moav client connect john -p hysteria2 # Short formOptions:
--protocol,-p- Specify protocol (default: auto)
Protocols: auto, reality, trojan, hysteria2, wireguard, tor, dnstt, slipstream, masterdns
Proxy endpoints (configurable in .env):
- SOCKS5:
localhost:10800(CLIENT_SOCKS_PORT) - HTTP:
localhost:18080(CLIENT_HTTP_PORT)
Build the client Docker image.
moav client buildReset the admin dashboard password.
moav admin password # Prompts for new password (or generates random)Donate VPN configs to sharing platforms.
moav donate # Show available donation servicesDonate VPN configs and bandwidth to help people bypass censorship. Supports three donation services:
- MahsaNet — Donate VPN config links to Mahsa VPN (2M+ users in Iran)
- Psiphon Conduit — Donate bandwidth to Psiphon's relay network (millions of users worldwide)
- Tor Snowflake — Donate bandwidth as a Tor Snowflake proxy
# Interactive donation wizard (shows all services, donates MahsaNet configs)
moav donate
# Configure donation services (MahsaNet API key, Conduit/Snowflake bandwidth)
moav donate setup
# Show all donation services status with live stats
moav donate status
# List donated MahsaNet configs
moav donate list
# Select and delete specific MahsaNet configs
moav donate delete
# Remove all donated MahsaNet configs
moav donate remove
# Show Conduit Ryve deep link and QR code
moav donate infoSubcommands:
setup— Configure any donation service (menu: MahsaNet / Conduit / Snowflake)status— Show all 3 services: MahsaNet config stats, Conduit connected clients and bandwidth, Snowflake people served and bandwidthlist— List all donated MahsaNet configs with status and healthdelete— Select and delete specific MahsaNet configs interactivelyremove— Remove all donated MahsaNet configs (with confirmation)info— Show Psiphon Conduit Ryve deep link and QR code for claiming in the Ryve app
Configuration in .env:
# MahsaNet
MAHSANET_API_KEY= # API key from mahsaserver.com/user/api
MAHSANET_PROTOCOLS="reality hysteria2" # Protocols to donate
MAHSANET_POOL=mahsa # Pool: mahsa, warp, popup, telegram
# Psiphon Conduit
CONDUIT_BANDWIDTH=100 # Bandwidth limit in Mbps
CONDUIT_MAX_COMMON_CLIENTS=200 # Max concurrent clients
# Tor Snowflake
SNOWFLAKE_BANDWIDTH=5 # Bandwidth limit in Mbps
SNOWFLAKE_CAPACITY=50 # Max concurrent clientsShow the Psiphon Conduit claim link, QR code, and sharing guide.
moav conduit # Same as 'moav conduit link'
moav conduit link # Ryve claim deep link + QR + sharing walkthrough
moav conduit status # Running state + connected clients / bandwidth
moav conduit help # UsageWhile Conduit runs it already serves Psiphon users (including in Iran) through the public pool — nothing needs to be shared for that. To give specific people a private path, use Personal Pairing: import the station into the Ryve app with the claim link this command prints, then generate a pairing link inside Ryve.
⚠ Security: the claim link/QR embeds this Conduit's private key (for your own phone's Ryve app). Treat it like a password — do not post it publicly. The link you share with users is the Personal Pairing link generated inside Ryve, not the claim link.
moav donate infois an alias.
Manage the watcher that keeps Conduit's lifetime bandwidth Grafana panels accurate across container restarts.
moav conduit-offsets install # Install the systemd watcher
moav conduit-offsets status # Show watcher state (enabled/disabled, last run)
moav conduit-offsets uninstall # Remove the watcherThe watcher installs itself automatically the first time Conduit and monitoring run together — you usually don't need to touch this. Set CONDUIT_OFFSETS_AUTOUPDATE=false in .env to opt out. Hosts without systemd skip the watcher; run scripts/update-conduit-offsets.sh from cron instead. See Monitoring → Conduit lifetime bandwidth.
Export full configuration backup.
moav export # Creates moav-backup-TIMESTAMP.tar.gz
moav export mybackup.tar.gz # Custom filenameBackup includes:
.envconfiguration- All cryptographic keys (Reality, WireGuard, dnstt)
- User credentials
- Generated user bundles
- TLS certificates
Security: Backup contains private keys. Transfer securely and delete after import.
Import configuration from backup.
moav import moav-backup-20240128.tar.gz
moav import /path/to/backup.tar.gzRestores:
.envfile- Keys and certificates
- User credentials
- User bundles
Update SERVER_IP and regenerate all user configs.
moav migrate-ip 203.0.113.50 # Set new IP
moav migrate-ip $(curl -s api.ipify.org) # Auto-detect current IPThis command:
- Updates
SERVER_IPin.env - Regenerates all user bundle configs
- Updates QR codes (if qrencode installed)
Regenerate all user bundles with current .env settings.
moav regenerate-usersUse this after:
- Changing domain
- Enabling/disabling protocols
- Adding CDN_DOMAIN
- Changing any configuration that affects client configs
Profiles group related services. Each maps to one or more ENABLE_* flags in .env; moav start filters disabled profiles automatically (see Profile filtering).
| Profile | Services | Controlled by |
|---|---|---|
proxy |
sing-box, decoy, certbot | ENABLE_REALITY / ENABLE_TROJAN / ENABLE_HYSTERIA2 / ENABLE_SS (any) |
xhttp |
xray | ENABLE_XHTTP |
wireguard |
wireguard, wstunnel, decoy, certbot | ENABLE_WIREGUARD |
amneziawg |
amneziawg | ENABLE_AMNEZIAWG |
dnstunnel |
dns-router, dnstt, slipstream, masterdns, xray (XDNS) | ENABLE_DNSTT / ENABLE_SLIPSTREAM / ENABLE_MASTERDNS / ENABLE_XDNS (any) |
trusttunnel |
trusttunnel | ENABLE_TRUSTTUNNEL |
telegram |
telemt | ENABLE_TELEMT |
admin |
admin, docker-proxy | ENABLE_ADMIN_UI |
conduit |
psiphon-conduit | ENABLE_CONDUIT |
snowflake |
snowflake, snowflake-exporter | ENABLE_SNOWFLAKE |
gooserelay |
gooserelay | ENABLE_GOOSERELAY (opt-in) |
monitoring |
prometheus, grafana, grafana-proxy, node-exporter, cadvisor + per-protocol exporters | ENABLE_MONITORING (opt-in) |
setup |
bootstrap, geoip-updater | (lifecycle, not user-toggled) |
client |
client | (for local testing) |
all |
All services above | (used by moav start all, moav build, moav logs, etc.) |
Usage:
moav start proxy admin # Start proxy and admin profiles
moav start all # Expands to every profile whose ENABLE_* is true| Service | Aliases |
|---|---|
| sing-box | proxy, singbox, reality |
| wireguard | wg |
| dnstt | dns |
| slipstream | slip |
| masterdns | mdns |
| psiphon-conduit | conduit |
Usage:
moav logs singbox # Same as 'moav logs sing-box'
moav restart wg # Same as 'moav restart wireguard'
moav stop conduit # Same as 'moav stop psiphon-conduit'Key variables in .env that affect CLI behavior:
| Variable | Description | Default |
|---|---|---|
DEFAULT_PROFILES |
Profiles started by moav start |
proxy admin |
CLIENT_SOCKS_PORT |
SOCKS5 port for client mode | 10800 |
CLIENT_HTTP_PORT |
HTTP port for client mode | 18080 |
INITIAL_USERS |
Users created during bootstrap | 5 |
MAHSANET_API_KEY |
MahsaNet API key for config donation | (empty) |
MAHSANET_PROTOCOLS |
Protocols to donate to MahsaNet | reality hysteria2 |
MAHSANET_POOL |
MahsaNet pool for donated configs | mahsa |
# 1. Install MoaV
curl -fsSL moav.sh/install.sh | bash
# 2. Configure environment
cd /opt/moav
cp .env.example .env
nano .env # Set DOMAIN, ACME_EMAIL, ADMIN_PASSWORD
# 3. Run bootstrap
moav bootstrap
# 4. Start services
moav start
# 5. Add a user
moav user add john --package
# 6. Download bundle
# Visit https://your-server:9443 or use SCP# Check status
moav status
# View logs
moav logs sing-box
# Add new user
moav user add alice
# Add multiple users at once
moav user add alice bob charlie
# Batch create users (auto-numbered)
moav user add --batch 10 --prefix team --package
# Test user connectivity
moav test alice
# Update MoaV
moav update# On old server
moav export
# Copy backup to new server
scp moav-backup-*.tar.gz root@new-server:/opt/moav/
# On new server
cd /opt/moav
moav import moav-backup-*.tar.gz
moav migrate-ip $(curl -s api.ipify.org)
moav start# Switch to dev branch
moav update -b dev
# Test changes
moav restart
# Return to stable
moav update -b main# Set up donation services (MahsaNet API key, Conduit/Snowflake bandwidth)
moav donate setup
# Donate 5 VPN configs to MahsaNet
moav donate
# Enter: 5 for count, "mahsa" for prefix
# See all donation stats (MahsaNet configs + Conduit clients + Snowflake served)
moav donate status
# Configure Conduit bandwidth limit
moav donate setup # Select option 2
# Get Conduit Ryve deep link (for claiming in Ryve app)
moav donate info
# List/delete MahsaNet configs
moav donate list
moav donate delete# For servers without a domain
moav domainless
moav start wireguard admin conduit
moav user add john