# Copy to config.env and fill in. config.env is YOURS — keep it out of git. # Nothing here ships with real values; every field is a placeholder. # --- target VPS --- SERVER_IP="203.0.113.10" # public IPv4 SERVER_IPV6="2001:db8::10" # public IPv6 (optional; leave empty to skip AAAA) SSH_USER="root" # root, or a sudo user (scripts escalate via sudo) SSH_KEY="$HOME/.ssh/your-vps-key.pem" # private key for the VPS TZ="UTC" # server timezone (e.g. UTC, Asia/Shanghai, America/Los_Angeles) # --- domain --- PARENT_ZONE="example.com" # your DNS zone DOMAIN_ROOT="nodeA.example.com" # this node owns *.nodeA.example.com # --- DNS provider --- # Cloudflare is the default & has a turnkey record-creation script (02-cf-dns.py). # Any acme.sh-supported DNS provider works for the wildcard cert — set ACME_DNS_PLUGIN and # the matching credential vars below. For A/AAAA records on a non-CF provider, create them # yourself (see references/dns-records.md — it's two names, A + AAAA, DNS-only). DNS_PROVIDER="cloudflare" # informational: cloudflare | dnspod | aliyun | route53 | other ACME_DNS_PLUGIN="dns_cf" # acme.sh plugin: dns_cf | dns_dp | dns_ali | dns_aws | dns_gd | ... # Cloudflare (default). Token needs Zone:DNS:Edit. NEVER commit. CF_API_TOKEN="cf-token-with-Zone-DNS-Edit" CF_ZONE_ID="" # optional; 02-cf-dns.py looks it up if empty # Other providers — uncomment the pair your ACME_DNS_PLUGIN needs (acme.sh reads these env names): # DP_Id=""; DP_Key="" # dns_dp (DNSPod) # Ali_Key=""; Ali_Secret="" # dns_ali (Aliyun) # AWS_ACCESS_KEY_ID=""; AWS_SECRET_ACCESS_KEY="" # dns_aws (Route53) # GD_Key=""; GD_Secret="" # dns_gd (GoDaddy) # --- subdomain labels (CHOOSE YOUR OWN, NON-OBVIOUS ONES) --- # Your panels sit at .. If your zone is public, do NOT reuse an # obvious convention (a label that names the service it fronts) — anyone can then # enumerate your control planes from DNS. Pick random-ish labels and keep them to # yourself. These examples are neutral placeholders, deliberately NOT a real scheme. SUB_PANEL="console" # aaPanel -> console. SUB_XUI="gateway" # 3x-ui panel -> gateway. SUB_COVER="edge" # node cover -> edge. # landing page uses the bare . # --- aaPanel --- AAPANEL_USER="admin_you" AAPANEL_ENTRANCE="/change-this-entrance" # secret path, e.g. /8f3a1c AAPANEL_PORT="" # leave EMPTY — the installer assigns a random port; # scripts read it from the box (/www/server/panel/data/port.pl). # Only set this to force a specific value. AAPANEL_PASS="" # generate at runtime; store in password manager # --- 3x-ui --- XUI_USER="panel_you" XUI_PATH="/change-this-path/" # webBasePath, trailing slash XUI_PORT="14533" # panel listen 127.0.0.1:XUI_PORT XUI_PASS="" # generate at runtime; store in password manager WARP_SOCKS_PORT="40000" # cloudflare-warp proxy SOCKS5 port # --- three protocols x two egress paths = six inbounds, ONE client --- # All six inbounds (vmess/trojan/shadowsocks x direct/warp) are owned by a single # 3x-ui client "node-main", so the panel shows one client whose Info dialog lists # all six share links + one subscription. That one client carries BOTH credentials: # - XUI_UUID -> authenticates the two VMess inbounds # - NODE_PASSWORD -> authenticates the two Trojan AND two Shadowsocks inbounds # (trojan+ss share this one password by design — it's one client row; that's # what makes the single-client panel view work. See references/3x-ui-schema.md.) # Ports are internal (127.0.0.1, behind nginx) — only 443 is ever exposed publicly. # Paths are the WS cover paths: CHOOSE YOUR OWN, NON-OBVIOUS ONES (don't reuse a # convention, don't publish them — on a public zone they map your tunnels). These # examples are neutral placeholders, deliberately NOT a real scheme. # Shared client credentials (node-main) XUI_UUID="" # generate at runtime (uuidgen); VMess auth NODE_PASSWORD="" # generate at runtime; Trojan + Shadowsocks auth; store in password manager XUI_SUBID="" # generate at runtime; subscription id SS_METHOD="chacha20-poly1305" # non-2022 cipher: plain-string password, no exact-length base64 PSK to misconfigure # VMess PORT_VMESS_DIRECT="57707" PORT_VMESS_WARP="57708" WS_PATH_VMESS_DIRECT="/assets" WS_PATH_VMESS_WARP="/media" # Trojan PORT_TROJAN_DIRECT="57709" PORT_TROJAN_WARP="57710" WS_PATH_TROJAN_DIRECT="/static" WS_PATH_TROJAN_WARP="/uploads" # Shadowsocks PORT_SS_DIRECT="57711" PORT_SS_WARP="57712" WS_PATH_SS_DIRECT="/files" WS_PATH_SS_WARP="/download" # --- monitoring (optional; leave empty to skip) --- NEZHA_SERVER="" # e.g. report.example.com:8966 NEZHA_TLS="false" NEZHA_SECRET="" # shared agent key for your Nezha panel NEZHA_UUID="" # generate at runtime KOMARI_ENDPOINT="" # e.g. https://komari.example.com KOMARI_DISCOVERY_KEY="" # auto-discovery key for your Komari panel # --- node display name (monitoring / labels) --- NODE_NAME="Edge Node A" # --- optional QUIC plane (sing-box; blank ports skip that inbound) --- PORT_HY2_DIRECT="" PORT_HY2_WARP="" HY2_OBFS_PASSWORD="" # generate privately for salamander links HY2_UP_MBPS="500" # server-side bandwidth; match the actual link HY2_DOWN_MBPS="500" PORT_TUIC_DIRECT="" PORT_TUIC_WARP="" TUIC_CC="bbr" # --- optional internal SOCKS5 (16-add-socks5.py runs ON the VPS via env) --- SOCKS_PORT="" SOCKS_USER="" SOCKS_PASS="" LISTEN="127.0.0.1" # SSH-tunnel-only example