--- name: ascs-free-proxy-node description: 用 ASCS Cloud 免费 IPv6 容器,为“使用者本人”自建 VLESS+WS+TLS(经 Cloudflare 隧道)+ Hysteria2 节点,并生成 Shadowrocket/v2rayN 可导入的订阅。适用于能操作浏览器和网页控制台的 AI 代理。 --- # ASCS 免费节点自建(给 AI 代理执行) ## 先读这几条规则 - 只为“正在和你对话的这个人”建节点:用 TA 本人的邮箱注册 TA 本人的 ASCS 账号。不要批量注册、不要替别人代注册多个账号、不要转售。 - 遵守 ASCS 服务条款与可接受使用政策(https://cloud.ascsonoway.com/aup/)。注册前请让用户自己读一遍并确认。 - 提醒用户:在所在地区使用代理可能有法律风险,由用户自行判断。 - 所有密钥(UUID、WS 路径、HY2 密码、订阅路径、Cloudflare 隧道令牌、服务器密码)只在服务器或安全表单里出现,不要发到聊天里,不要写进公开文档。 - 每一步失败重试两次仍不行,就停下来把现象告诉用户,问下一步。 ## 架构 ``` 客户端 ──VLESS+WS+TLS──▶ Cloudflare ──隧道──▶ cloudflared ─▶ Xray(只听 127.0.0.1) ─▶ 互联网 客户端 ──Hysteria2(UDP/QUIC)──▶ 服务器 IPv6:443 ─▶ Xray ─▶ 互联网 ``` - ASCS 免费容器只有 IPv6;IPv4 网站经 Cloudflare WARP 出站。 - VLESS 走 Cloudflare,客户端没有 IPv6 也能用;HY2 需要客户端有 IPv6。 ## 第 1 步:注册 ASCS 并领取免费实例 1. 打开 https://cloud.ascsonoway.com/ ,用用户本人的邮箱注册(密码存进安全保管处,不要贴聊天)。邮箱验证码向用户索取或从已连接的邮箱里读。 2. 进入 Micro Instances,领取 Free 套餐($0,无需信用卡),系统选 Debian 13。 3. 等实例从 Pending 变成 Running(通常几分钟到半小时)。在 My Servers 里记下:实例名、IPv6 地址、SSH 用户名和密码。 4. 告诉用户:免费实例约每 30 天需要在面板确认仍在使用,否则会被回收。建议设一个 25 天一次的提醒。 ## 第 2 步:在网页控制台里安装 ASCS 的实例多半没法从 IPv4 网络 SSH,用面板里的 Console 按钮打开网页终端。 1. 用实例的用户名和密码登录控制台,执行 `sudo -i` 切到 root。 2. 网页控制台粘贴大段文字可能丢字符或卡住。能用 SSH 就用 SSH(需要一台有 IPv6 的机器);只能用控制台时,分几段粘贴,粘完用 `wc -c /root/setup.sh` 对比长度、`bash -n /root/setup.sh` 检查语法再运行。 把本文末尾“安装脚本”整段写入 `/root/setup.sh`(用 `cat > /root/setup.sh <<'SETUP_EOF'` … `SETUP_EOF` 粘贴),然后运行 `bash /root/setup.sh`。 - 脚本会经 GitHub 镜像下载 Xray 26.3.27、Hysteria2 2.13.0、wgcf 2.3.1、cloudflared 2026.10.0,并逐个校验 SHA256。镜像失效时换另一个 GitHub 镜像前缀,但必须保留哈希校验。 - 所有密钥在服务器本地随机生成,保存在 `/etc/proxy/env`(权限 600)。 3. 预期输出:`XRAY_CONFIG_OK`、四个服务 `active`、`HY2_TEST google: 204`、最后一行 `SUB_URL=https://xxxx.trycloudflare.com/<随机>/sub` 和 `DONE`。 4. 这个 SUB_URL 就是临时订阅,可以先给用户用。注意:临时隧道每次重启域名都会变。订阅 URL 含节点密钥,只私下发给用户本人。 ## 第 3 步(推荐):换成固定域名 需要用户有一个接入 Cloudflare 的域名(可用 DigitalPlat 等免费域名,把 NS 改到 Cloudflare,等状态变 Active)。 1. 让用户在 Cloudflare 后台 Zero Trust → Networks → Tunnels 新建隧道(类型 Cloudflared),添加 Public Hostname:子域名如 `node.<域名>`,Service 填 `HTTP` + `127.0.0.1:10086`。 2. 页面会给出安装命令里的令牌。令牌只能在服务器控制台里使用,不要经过聊天。若你能操作用户的浏览器,就直接从页面复制到控制台。 3. 在服务器 root 下执行(把 `` 换成实际域名;令牌在提示时粘贴,不会显示、也不会出现在进程列表里): ```bash systemctl disable --now cfquick read -rs -p "粘贴隧道令牌后回车: " T; echo "TUNNEL_TOKEN=$T" > /etc/proxy/cftoken; chmod 600 /etc/proxy/cftoken; unset T cat > /etc/systemd/system/cfnamed.service <" > /etc/proxy/host python3 /etc/proxy/gen.py systemctl daemon-reload && systemctl enable --now cfnamed . /etc/proxy/env; echo "SUB_URL=https:///$S/sub" ``` 4. 等 Cloudflare 后台隧道显示 Healthy,打开新的 SUB_URL 应返回一串 base64。 ## 第 4 步:验证 - 服务器上执行 `curl -s -o /dev/null -w '%{http_code}\n' -x socks5h://127.0.0.1:10808 https://github.com` 应为 200(验证出站和 WARP)。 - 打开 SUB_URL 应返回 base64;让用户在客户端里导入后,对 `ASCS-VLESS-CF` 做连通性测试,再打开 google.com 确认。这一步才是 VLESS 经 Cloudflare 的真正端到端测试。 - HY2 在第 2 步已在服务器本机自测;用户网络没有 IPv6 时 HY2 不通属正常。 ## 第 5 步:交付给用户 - 客户端:iPhone/Mac 用 Shadowrocket,Windows 用 v2rayN,Android 用 v2rayNG 或 NekoBox。添加“订阅”,粘贴 SUB_URL,更新后会出现 `ASCS-VLESS-CF` 和 `ASCS-HY2`。 - 告诉用户:没有 IPv6 就用 VLESS-CF;订阅地址别公开;每 30 天去 ASCS 面板续期;免费服务器没有 SLA。 ## 常用维护命令(服务器 root) - 看状态:`systemctl status xray hysteria subweb cfnamed` - 重新生成订阅:`python3 /etc/proxy/gen.py && systemctl restart xray hysteria` - 换全部密钥:`rm /etc/proxy/env && bash /root/setup.sh`。已配固定域名时脚本不会再启用临时隧道,订阅地址里的随机路径会变,用最后输出的路径重新给用户。 - 已知限制:HY2 用自签证书(insecure=1),抗中间人能力弱于 VLESS-CF;版本号写死,旧了以后要更新下载地址和 SHA256。 ## 安装脚本 ```bash #!/bin/bash # ASCS IPv6-only node: Xray VLESS-WS (127.0.0.1) + Hysteria2 (UDP 443) + WARP IPv4 egress + cloudflared # Secrets are generated locally on the server and never leave it except inside the subscription file. set -e [ "$(id -u)" = 0 ] || { echo "run with sudo"; exit 1; } export DEBIAN_FRONTEND=noninteractive G=https://gh.llkk.cc/https://github.com apt-get update -qq apt-get install -y -qq unzip openssl python3 ca-certificates curl >/dev/null cd /tmp dl() { curl -fsSL --retry 3 -o "$1" "$2"; echo "$3 $1" | sha256sum -c --quiet; } dl x.zip $G/XTLS/Xray-core/releases/download/v26.3.27/Xray-linux-64.zip 23cd9af937744d97776ee35ecad4972cf4b2109d1e0fe6be9930467608f7c8ae dl hy $G/apernet/hysteria/releases/download/app/v2.13.0/hysteria-linux-amd64 907ba8c9693edb104b20582681fb7dc15639d5b64a9cbb616a7b539190a86691 dl wgcf $G/ViRb3/wgcf/releases/download/v2.3.1/wgcf_2.3.1_linux_amd64 4fb7a136aa470ece11d17949c7db07b040ec9c604742dc8680bcf1889f85d0c8 dl cfd $G/cloudflare/cloudflared/releases/download/2026.10.0/cloudflared-linux-amd64 d33ff2d14475178d2012c2c56beba87389ac5ded27649519f198a7d3134a99db unzip -o -q x.zip xray -d /usr/local/bin install -m755 hy /usr/local/bin/hysteria install -m755 wgcf /usr/local/bin/wgcf install -m755 cfd /usr/local/bin/cloudflared D=/etc/proxy; mkdir -p $D/warp /var/www/sub; chmod 700 $D [ -f $D/env ] || cat > $D/env < $D/ip6 # WARP account (IPv4 egress for IPv4-only sites); optional ( cd $D/warp && { [ -f wgcf-account.toml ] || wgcf register --accept-tos >/dev/null 2>&1; } && wgcf generate >/dev/null 2>&1 ) && echo WARP_OK || echo WARP_FAIL [ -f $D/hy.key ] || openssl req -x509 -nodes -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -days 3650 \ -keyout $D/hy.key -out $D/hy.crt -subj "/CN=www.bing.com" 2>/dev/null cat > $D/gen.py <<'PYEOF' import json, re, os, base64, urllib.parse D = "/etc/proxy" env = dict(l.strip().split("=", 1) for l in open(D + "/env") if "=" in l) ip6 = open(D + "/ip6").read().strip().split("=", 1)[1] U, P, H, S = env["U"], env["P"], env["H"], env["S"] direct = {"tag": "direct", "protocol": "freedom", "settings": {"domainStrategy": "ForceIPv6"}} outs = [direct] rules = [{"ip": ["::/0"], "outboundTag": "direct"}] prof = D + "/warp/wgcf-profile.conf" if os.path.exists(prof): t = open(prof).read() key = re.search(r"PrivateKey\s*=\s*(\S+)", t).group(1) addrs = [a.strip() for l in re.findall(r"Address\s*=\s*(.+)", t) for a in l.split(",")] pub = re.search(r"PublicKey\s*=\s*(\S+)", t).group(1) outs.append({"tag": "warp", "protocol": "wireguard", "settings": { "secretKey": key, "address": addrs, "mtu": 1280, "domainStrategy": "ForceIPv4", "peers": [{"publicKey": pub, "endpoint": "[2606:4700:d0::a29f:c001]:2408", "allowedIPs": ["0.0.0.0/0", "::/0"]}]}}) rules.append({"ip": ["0.0.0.0/0"], "outboundTag": "warp"}) cfg = { "log": {"loglevel": "warning"}, "inbounds": [ {"tag": "front", "listen": "127.0.0.1", "port": 10086, "protocol": "vless", "settings": {"clients": [], "decryption": "none", "fallbacks": [{"path": "/" + P, "dest": 10085, "xver": 0}, {"dest": 10087}]}, "streamSettings": {"network": "raw", "security": "none"}}, {"tag": "ws", "listen": "127.0.0.1", "port": 10085, "protocol": "vless", "settings": {"clients": [{"id": U}], "decryption": "none"}, "streamSettings": {"network": "ws", "wsSettings": {"path": "/" + P}}, "sniffing": {"enabled": True, "destOverride": ["http", "tls", "quic"], "routeOnly": True}}, {"tag": "socks-in", "listen": "127.0.0.1", "port": 10808, "protocol": "socks", "settings": {"udp": True}, "sniffing": {"enabled": True, "destOverride": ["http", "tls", "quic"], "routeOnly": True}}], "outbounds": outs, "routing": {"domainStrategy": "IPIfNonMatch", "rules": rules}} json.dump(cfg, open(D + "/xray.json", "w"), indent=1) open(D + "/hy.yaml", "w").write(f"""listen: :443 tls: cert: {D}/hy.crt key: {D}/hy.key auth: type: password password: {H} masquerade: type: proxy proxy: url: https://www.bing.com/ rewriteHost: true outbounds: - name: xr type: socks5 socks5: addr: 127.0.0.1:10808 """) host = open(D + "/host").read().strip() if os.path.exists(D + "/host") else "" lines = [] if host: q = urllib.parse.urlencode({"encryption": "none", "security": "tls", "sni": host, "fp": "chrome", "type": "ws", "host": host, "path": "/" + P}) lines.append(f"vless://{U}@{host}:443?{q}#ASCS-VLESS-CF") lines.append(f"hysteria2://{H}@[{ip6}]:443?sni=www.bing.com&insecure=1#ASCS-HY2") os.makedirs("/var/www/sub/" + S, exist_ok=True) open("/var/www/sub/index.html", "w").write("") open(f"/var/www/sub/{S}/index.html", "w").write("") open(f"/var/www/sub/{S}/sub", "w").write(base64.b64encode("\n".join(lines).encode()).decode()) print("SUB_PATH=/" + S + "/sub", "HOST=" + (host or "none")) PYEOF python3 $D/gen.py /usr/local/bin/xray run -test -c $D/xray.json >/dev/null && echo XRAY_CONFIG_OK cat > $D/qt.sh <<'EOF' #!/bin/bash # temporary Cloudflare quick tunnel until the user's own domain is ready L=/var/log/cft.log; : > $L /usr/local/bin/cloudflared tunnel --no-autoupdate --edge-ip-version 6 --url http://127.0.0.1:10086 --logfile $L & PID=$! for i in $(seq 1 60); do h=$(grep -o 'https://[a-z0-9-]*\.trycloudflare\.com' $L | head -1 | sed 's#https://##') [ -n "$h" ] && { echo "$h" > /etc/proxy/host; python3 /etc/proxy/gen.py; break; } sleep 2 done wait $PID EOF chmod 755 $D/qt.sh cat > /etc/systemd/system/xray.service < /etc/systemd/system/hysteria.service < /etc/systemd/system/subweb.service < /etc/systemd/system/cfquick.service </dev/null 2>&1 if systemctl is-enabled cfnamed >/dev/null 2>&1; then systemctl restart xray hysteria; else systemctl enable --now cfquick >/dev/null 2>&1; fi sleep 25 for s in xray hysteria subweb cfquick cfnamed; do echo "$s: $(systemctl is-active $s)"; done ss -lntup | grep -E '10085|10086|10087|10808|:443' | awk '{print $1, $5}' # local self-test of Hysteria2 against the public IPv6 . $D/env; . $D/ip6 cat > /tmp/hyc.yaml </tmp/hyc.log 2>&1 & HP=$!; sleep 4 echo "HY2_TEST google: $(curl -s -m 15 -o /dev/null -w '%{http_code}' -x socks5h://127.0.0.1:1081 https://www.google.com/generate_204)" echo "HY2_TEST ipv4-only github: $(curl -s -m 15 -o /dev/null -w '%{http_code}' -x socks5h://127.0.0.1:1081 https://github.com)" kill $HP; rm -f /tmp/hyc.yaml echo "VIA_XRAY ipv4-only github: $(curl -s -m 15 -o /dev/null -w '%{http_code}' -x socks5h://127.0.0.1:10808 https://github.com)" echo "SUB_URL=https://$(cat $D/host 2>/dev/null)/$S/sub" echo DONE ```