^-^
零成本方法
参考零度解说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