如何拥有一个免费节点?

^-^

零成本方法

参考零度解说https://www.freedidi.com/23618.html

https://www.dnshe.com

https://dash.cloudflare.com

vpn软件 https://flclash.cc https://clashverge.net/

自己租服务器

基本如果自己使用的话,租一个2核2g的香港或者美国的服务器就可以了,像国内的腾讯云阿里云,或者说国外的都可以。如果国内的话,大概100元以内可以下来。

安装时系统使用Ubuntu,打开远程界面

先进入管理员sudo -i

然后执行安装指令
bash <(wget -qO- https://raw.githubusercontent.com/fscarmen/sing-box/main/sing-box.sh)

语言可以直接选择中文,执行中那个安装选1,全部自动安装,然后接下来就一路默认即可。

安装完之后,他就会给你对应的节点地址。如果之后还要再查看节点地址的话,也是先进入管理员sudo -i,再使用指令sb即可查看。

sudo rsb

原生ip https://dash.cliproxy.com

要换购买的代理信息,选 2;要暂时撤销住宅出口,选 3;以后想重新启用,选 4。选 3 会保留节点资料,方便随时切回。每次修改的备份都在 /etc/sing-box/rsb-backups/

sudo tee /usr/local/sbin/rsb >/dev/null <<'PY'
#!/usr/bin/env python3
import getpass
import ipaddress
import json
import os
import shutil
import stat
import subprocess
import tempfile
from datetime import datetime
from pathlib import Path

BASE = Path("/etc/sing-box")
OUT = BASE / "conf/01_outbounds.json"
ROUTE = BASE / "conf/03_route.json"
BIN = BASE / "sing-box"
BACKUPS = BASE / "rsb-backups"

def read():
    out = json.loads(OUT.read_text())
    route = json.loads(ROUTE.read_text())
    nodes = [x for x in out["outbounds"] if x.get("tag") == "residential"]
    if len(nodes) != 1:
        raise RuntimeError("找不到唯一的 residential 节点,请先不要修改。")
    return out, route, nodes[0]

def openai_rule(rule):
    return (
        "api.openai.com" in rule.get("domain", [])
        or "geosite-openai" in rule.get("rule_set", [])
    ) and "outbound" in rule

def write_atomic(path, data):
    fd, name = tempfile.mkstemp(dir=path.parent, prefix=".rsb-")
    try:
        os.fchmod(fd, stat.S_IMODE(path.stat().st_mode))
        with os.fdopen(fd, "w") as file:
            json.dump(data, file, ensure_ascii=False, indent=2)
            file.write("\n")
        os.replace(name, path)
    finally:
        if os.path.exists(name):
            os.unlink(name)

def save(out, route):
    BACKUPS.mkdir(mode=0o700, exist_ok=True)
    os.chmod(BACKUPS, 0o700)
    folder = BACKUPS / datetime.now().strftime("%Y%m%d-%H%M%S-%f")
    folder.mkdir(mode=0o700)
    shutil.copy2(OUT, folder / OUT.name)
    shutil.copy2(ROUTE, folder / ROUTE.name)
    try:
        write_atomic(OUT, out)
        write_atomic(ROUTE, route)
        subprocess.run([str(BIN), "check", "-C", str(BASE / "conf")], check=True)
        subprocess.run(["systemctl", "restart", "sing-box"], check=True)
        subprocess.run(
            ["systemctl", "is-active", "--quiet", "sing-box"], check=True
        )
    except Exception:
        shutil.copy2(folder / OUT.name, OUT)
        shutil.copy2(folder / ROUTE.name, ROUTE)
        subprocess.run(["systemctl", "restart", "sing-box"], check=False)
        print("操作失败,已从备份恢复配置:", folder)
        raise
    print("保存成功。备份位置:", folder)

def test_proxy(node):
    host = str(node["server"])
    port = int(node["server_port"])
    user = str(node["username"])
    password = str(node["password"])
    config = 'proxy-user = ' + json.dumps(user + ":" + password) + "\n"
    result = subprocess.run(
        ["curl", "-4", "-fsS", "--connect-timeout", "8",
         "--max-time", "20", "--socks5-hostname", f"{host}:{port}",
         "--config", "-", "https://api.ipify.org"],
        input=config, text=True, capture_output=True
    )
    try:
        address = ipaddress.ip_address(result.stdout.strip())
    except ValueError:
        address = None
    if result.returncode != 0 or address is None:
        print("代理检测失败;未保存新参数。")
        if result.stderr:
            print(result.stderr.strip())
        return False
    print("代理检测成功,出口 IP:", address)
    return True

def main():
    if os.geteuid() != 0:
        raise RuntimeError("请使用 sudo rsb 运行。")
    if not BIN.is_file():
        raise RuntimeError("找不到 /etc/sing-box/sing-box,未修改配置。")

    while True:
        print("\n住宅代理管理")
        print("1. 查看当前配置(不显示密码)")
        print("2. 修改 IP、端口、用户名或密码")
        print("3. 改回服务器直连(保留住宅节点信息)")
        print("4. 启用住宅出口")
        print("5. 检测住宅代理出口 IP")
        print("0. 退出")
        choice = input("请选择:").strip()

        if choice == "0":
            return
        if choice not in ("1", "2", "3", "4", "5"):
            print("请输入菜单中的数字。")
            continue

        out, route, node = read()
        current = route.get("route", {}).get("final", "direct")

        if choice == "1":
            print("当前出口:", current)
            print("住宅代理地址:", node["server"])
            print("端口:", node["server_port"])
            print("用户名:", node.get("username", ""))
            print("密码:已隐藏")
            print("提示:原有 UDP 直连规则仍按服务器配置执行。")

        elif choice == "2":
            print("直接回车表示保留原值;密码输入时不会显示。")
            host = input(f'IP或域名 [{node["server"]}]:').strip()
            port = input(f'端口 [{node["server_port"]}]:').strip()
            user = input(f'用户名 [{node["username"]}]:').strip()
            password = getpass.getpass("新密码(回车保留原密码):")
            new = dict(node)
            if host:
                new["server"] = host
            if port:
                if not port.isdigit() or not 1 <= int(port) <= 65535:
                    print("端口必须是 1~65535;未修改。")
                    continue
                new["server_port"] = int(port)
            if user:
                new["username"] = user
            if password:
                new["password"] = password
            if test_proxy(new):
                node.update(new)
                save(out, route)
                print("当前出口模式仍为:", current)

        elif choice == "3":
            route["route"]["final"] = "direct"
            for rule in route["route"].get("rules", []):
                if openai_rule(rule) and rule.get("outbound") == "residential":
                    rule["outbound"] = "direct"
            save(out, route)
            print("已切换为服务器直连。")

        elif choice == "4":
            route["route"]["final"] = "residential"
            for rule in route["route"].get("rules", []):
                if openai_rule(rule) and rule.get("outbound") == "direct":
                    rule["outbound"] = "residential"
            save(out, route)
            print("已切换为住宅出口。")

        elif choice == "5":
            test_proxy(node)

try:
    main()
except (OSError, ValueError, KeyError, RuntimeError,
        subprocess.CalledProcessError) as exc:
    print("错误:", exc)
    raise SystemExit(1)
PY
sudo chmod 700 /usr/local/sbin/rsb

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注