Skip to content

Operational Security Guide

Security recommendations for running and using MoaV safely.

Table of Contents


For Server Operators

Server Security

  1. Keep system updated:

    apt update && apt upgrade -y
    # Enable automatic security updates
    apt install unattended-upgrades
    dpkg-reconfigure unattended-upgrades
    

  2. Use SSH keys, disable password auth:

    # In /etc/ssh/sshd_config:
    PasswordAuthentication no
    PermitRootLogin prohibit-password
    

  3. Change SSH port (optional but recommended):

    # 1. Add firewall rule for new port FIRST
    ufw allow 2222/tcp
    
    # 2. Then change SSH config
    # In /etc/ssh/sshd_config:
    Port 2222
    
    # 3. Restart SSH
    systemctl restart sshd
    
    # 4. Test new port works (from another terminal), then remove old rule
    ufw delete allow 22/tcp
    

Firewall & Docker

Important: Docker bypasses UFW/iptables. Docker publishes ports by inserting iptables rules before UFW's chains. This means ufw deny 9443 does NOT block access to port 9443 if Docker is publishing it. Ports listed in docker-compose.yml under ports: are publicly accessible regardless of UFW rules.

Ports listed under expose: (without ports:) are Docker-internal only and NOT affected.

See: Docker packet filtering docs

Basic UFW setup (for non-Docker ports like SSH):

ufw allow 22/tcp      # SSH (IMPORTANT: always allow SSH first!)
ufw enable

Warning: UFW rules only effectively control non-Docker services (SSH, system services). For Docker-published ports, use the methods below.

Protocol ports (published by Docker — UFW rules are informational only):

Port Service Notes
443/tcp Reality (VLESS) Required
443/udp Hysteria2 Required if enabled
8443/tcp Trojan Required if enabled
4443/tcp+udp TrustTunnel Required if enabled
2082/tcp CDN WebSocket Required if enabled
51820/udp WireGuard Required if enabled
51821/udp AmneziaWG Required if enabled
8080/tcp wstunnel Required if enabled
993/tcp Telegram MTProxy Required if enabled
2096/tcp XHTTP Required if enabled
53/udp XDNS (default) or dnstt/Slipstream Required if DNS tunnels enabled
5353/udp dnstt/Slipstream (when XDNS uses 53) Only if dnstt/Slipstream enabled alongside XDNS
80/tcp Let's Encrypt Required during cert renewal
9443/tcp Admin dashboard See access control below
9444/tcp Grafana See access control below
2083/tcp Grafana CDN proxy See access control below

Protocol ports (Reality, Hysteria2, etc.) are designed to be public — they require authentication. The concern is admin/monitoring ports.

MoaV's admin dashboard has built-in IP whitelisting. Set in .env:

# Allow only your IP (comma-separated for multiple)
ADMIN_IP_WHITELIST=YOUR_HOME_IP,YOUR_OFFICE_IP

# Then restart admin
moav restart admin

This blocks all other IPs at the application level, regardless of Docker/UFW.

Option 2: Bind to localhost + SSH tunnel

For maximum security, bind admin/monitoring to 127.0.0.1 so they're only accessible via SSH tunnel:

# In .env — bind to localhost only
PORT_ADMIN=127.0.0.1:9443
PORT_GRAFANA=127.0.0.1:9444

Then access via SSH tunnel:

# From your local machine
ssh -L 9443:127.0.0.1:9443 -L 9444:127.0.0.1:9444 root@YOUR_SERVER
# Then open https://localhost:9443 in your browser

Option 3: ufw-docker (Advanced)

ufw-docker patches UFW to work with Docker by adding rules to the DOCKER-USER iptables chain. This makes ufw commands effective for Docker ports.

# Install
sudo wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
sudo chmod +x /usr/local/bin/ufw-docker
sudo ufw-docker install
sudo systemctl restart ufw

# Allow specific ports from any IP
sudo ufw-docker allow moav-sing-box 443/tcp
sudo ufw-docker allow moav-sing-box 443/udp

# Allow admin only from your IP
sudo ufw-docker allow moav-admin 8443/tcp from YOUR_IP

Trade-offs: Requires modifying UFW config files (/etc/ufw/after.rules). Rules use ufw route syntax. Needs reload after container restarts. Works well but adds complexity. For most users, ADMIN_IP_WHITELIST is simpler.

Admin & Monitoring Access Control

Admin dashboard (https://server:9443): - Username: admin - Password: set during install (in .env as ADMIN_PASSWORD) - Reset: moav admin password - IP whitelist: ADMIN_IP_WHITELIST in .env

Grafana (https://server:9444): - Username: admin - Password: same as ADMIN_PASSWORD - Accessible from any IP by default (password-protected)

Internal services (not publicly accessible): - Prometheus (9091) — expose: only, Docker-internal - All exporters — expose: only, Docker-internal - cAdvisor — expose: only, Docker-internal - Docker socket proxy — expose: only, Docker-internal

Domain Security

  1. Use WHOIS privacy — hide personal information in domain registration
  2. Use a neutral registrar — avoid country-specific registrars
  3. Keep registration info generic — don't use real name if possible
  4. Pay anonymously — use crypto if available
  5. Separate domain from identity — don't use a domain linked to your name

Credential Management

  1. Never share master credentials — each user gets unique credentials
  2. Revoke compromised users immediately:
    moav user revoke compromised_user
    
  3. Rotate server keys periodically — re-bootstrap if concerned
  4. Keep backups:
    moav export    # Creates moav-backup-TIMESTAMP.tar.gz
    
  5. Use strong admin password — at least 16 characters, generated randomly

Monitoring

  1. Use moav doctor to check for configuration issues:

    moav doctor         # All checks
    moav doctor dns     # DNS only
    moav doctor ports   # Port conflicts
    

  2. Check logs regularly:

    moav logs sing-box    # Proxy logs
    moav logs admin       # Admin dashboard logs
    

  3. Inspect connections to see who's connecting and what they're accessing:

    ./scripts/inspect-connections.sh          # All connections (last 6h)
    ./scripts/inspect-connections.sh IR 24h   # Filter by country
    ./scripts/inspect-connections.sh --csv    # CSV export
    

  4. Grafana dashboards (if monitoring enabled):

  5. Per-user traffic and connections
  6. GeoIP country distribution
  7. Protocol breakdown
  8. System health (CPU, RAM, disk)

  9. Watch for unusual patterns:

  10. Sudden traffic spikes from unexpected countries
  11. Single IPs with very high error counts (scanning/probing)
  12. Connections to suspicious destinations

Docker Security Hardening

MoaV applies these hardening measures to all containers (since v1.7.2):

  • cap_drop: ALL — drops all Linux capabilities, adds back only what's needed
  • read_only: true — read-only root filesystem with targeted tmpfs mounts
  • no-new-privileges: true — prevents privilege escalation
  • mem_limit and cpus — resource limits per container
  • Non-root users — containers run as unprivileged moav user where possible
  • Docker socket proxy — admin uses tecnativa/docker-socket-proxy instead of mounting the raw Docker socket

If Server is Blocked

  1. Try different protocols first — switch from Reality to Hysteria2, XHTTP, or CDN mode
  2. CDN mode — routes through Cloudflare/CloudFront, works when server IP is blocked
  3. DNS tunnels — XDNS/dnstt/Slipstream work when most traffic is blocked
  4. If IP is burned:
    # On old server: export
    moav export
    
    # On new server: import and update IP
    moav import moav-backup-*.tar.gz
    moav migrate-ip NEW_IP
    moav start
    
  5. Donate bandwidth — even if your server is blocked for your users, it can still serve millions through Psiphon Conduit, Tor Snowflake, and MahsaNet

For Users

Device Security

  1. Use a separate profile/user for circumvention apps on shared devices
  2. Don't screenshot QR codes — or delete immediately after import
  3. Delete bundle files after importing to your apps
  4. Use device encryption — enable full disk encryption
  5. Set strong device PIN/password

Connection Security

  1. Verify you're connected:
  2. Check your IP: https://whatismyip.com
  3. Should show server IP, not your real IP

  4. Use HTTPS everywhere even over tunnel:

  5. The tunnel encrypts transport, HTTPS encrypts content
  6. Protects against compromised tunnel endpoints

  7. Don't trust public WiFi even with VPN:

  8. Your device can still be attacked locally
  9. Tunnel doesn't protect against local network attacks

App Security

  1. Keep apps updated — updates often fix detection bypasses
  2. Download from official sources:
  3. iOS: App Store (Happ, Streisand, Hiddify)
  4. Android: GitHub releases (Happ, v2rayNG, Hiddify)
  5. Avoid random APK sites

  6. Backup your configs — export from apps, store securely

Behavior Security

  1. Don't share your credentials — each person should have their own
  2. Don't share screenshots showing server addresses or QR codes
  3. Don't mention specific servers in public forums
  4. Use secure messaging to receive configs (Signal, encrypted email)

If You Suspect Compromise

  1. Stop using that config immediately
  2. Contact admin for new credentials
  3. Check your device for malware
  4. Change passwords for any accounts accessed over that connection

Distribution Security

Sharing Bundles Safely

DO: - Use end-to-end encrypted messaging (Signal, Telegram secret chat) - Share in person when possible (scan QR code directly) - Use encrypted file sharing (OnionShare) - Delete messages after recipient confirms receipt

DON'T: - Email unencrypted configs - Post links in public channels - Share via unencrypted cloud storage - Send screenshots of QR codes to groups

  1. In Person — safest, scan QR code directly
  2. Signal — send configs as files, enable disappearing messages
  3. Telegram (Secret Chat only) — NOT regular chats, use self-destruct timer
  4. Admin Dashboard — share download links directly (HTTPS, password-protected)

Disclaimer: This is not legal advice.

  • Laws vary by country — running or using circumvention tools may carry legal risks
  • Assess your personal risk level
  • The decoy website provides plausible deniability (server looks like a normal HTTPS site)

Data Retention

MoaV is configured for minimal logging: - No URLs logged - No request content - Basic connection stats only (for admin dashboard) - IP addresses are in memory only (not persisted to disk)

To minimize logging further:

# In .env
LOG_LEVEL=error


Emergency Procedures

If You Think You're Monitored

  1. Stop using current credentials
  2. Contact admin through alternate channel
  3. Get fresh credentials
  4. Consider using a different device
  5. Assess whether to continue using service

If Server is Seized

User data exposure is limited: - No content is logged - IP addresses are in memory only - User identifiers are usernames (not real names)

But assume: - Server IP is known - User identifiers are known - Active connections at time of seizure are known

If User is Compromised

As admin: 1. Revoke user immediately: moav user revoke username 2. Monitor for unusual activity 3. Consider rotating server if credentials were extracted 4. Do NOT contact compromised user through normal channels


Checklist

Server Operator

  • [ ] SSH keys only, no password auth
  • [ ] SSH port changed from default 22
  • [ ] System auto-updates enabled
  • [ ] Admin IP whitelist configured (ADMIN_IP_WHITELIST)
  • [ ] Strong admin password (16+ characters)
  • [ ] Unique user credentials for everyone
  • [ ] moav doctor passes all checks
  • [ ] Backup plan if blocked (new IP or migration ready)
  • [ ] Secure distribution channel established
  • [ ] Monitoring enabled (Grafana) or logs checked regularly

User

  • [ ] Device encrypted
  • [ ] App from official source
  • [ ] Config imported securely
  • [ ] Bundle files deleted after import
  • [ ] Knows which protocol to try if one fails
  • [ ] Knows how to contact admin securely