分享几个serv00保活的脚本 (8-29更新)

前几天通过ProxySite 免费网络代理注册了个serv00

安装了Sing-box, 发现进程总是被kill掉

下面两个保活脚本是在linuxdo上找到的, 忘了哪个帖子了
脚本是青龙面板运行的, 我的青龙面板装在机顶盒刷的armbian里面, 无法访问浏览器, 所以就不放serv00的ip解禁脚本了

1. web面板登录脚本 (青龙面板)

首先是web面板的登录py脚本, 记得安装依赖模块, 我设置的cron是0 0 9 ? * 1
serv00_web_login.log日志文件需要先touch
脚本文件名: serv00_web_login.py

# -*- coding: utf-8 -*-
import os
import sys
import requests
import mechanize
from html.parser import HTMLParser
import logging
from datetime import datetime

class MyHTMLParser(HTMLParser):
    def __init__(self, username):
        super().__init__()
        self.username = username
        self.success = False

    def handle_data(self, data):
        if f'Zalogowany jako: {self.username}' in data:
            self.success = True

# Use os.path.expanduser to expand the path
log_file_path = os.path.expanduser('../files/serv00_web_login.log')

# Configure logging
logging.basicConfig(
    filename=log_file_path,
    level=logging.INFO,
    format='%(asctime)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)

# List of accounts with their respective details
accounts = [
    {'name': 'serv00', 'username': '你的账户', 'password': '你的密码', 'url': '你的web面板登录地址比如https://panel8.serv00.com/login/'}
]

# 创建一个浏览器对象
br = mechanize.Browser()
br.set_handle_robots(False)   # 忽略 robots.txt

# 设置 User-Agent 头部
br.addheaders = [('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36')]

# Flag to track overall success
all_successful = True

logging.info("开始尝试登录...")

# Iterate over each account
for account in accounts:
    logging.info(f"{account['name']}尝试登录")

    try:
        # Open the login page
        response = br.open(account['url'])

        # Select the login form
        br.select_form(nr=1)

        # Fill in the form
        br['username'] = account['username']
        br['password'] = account['password']

        # Submit the form
        response = br.submit()

        # Use the custom HTML parser to verify login success
        parser = MyHTMLParser(account['username'])
        parser.feed(response.read().decode())

        if parser.success:
            logging.info(f"{account['name']}登录成功")
        else:
            logging.error(f"{account['name']}登录失败")
            all_successful = False  # Set the flag to False if any login fails

    except Exception as e:
        logging.error(f"{account['name']}登录失败报错: {e}")
        all_successful = False  # Set the flag to False if an exception occurs

# Exit with 0 if all logins were successful, otherwise exit with 1
if all_successful:
    logging.info("Serv00网页登录成功")
    requests.get("这里可以放bark通知url")
    sys.exit(0)
else:
    logging.error("Serv00网页登录失败")
    requests.get("这里可以放bark通知url")
    sys.exit(1)

2. ssh登录脚本 (青龙面板)

ssh登录脚本中会执行一个Sing-box的安装脚本(第3个脚本), 记得修改当前脚本中的路径
这里我设置的cron是0 0 */1 * * ?
脚本文件名: serv00_ssh_login.py

#!/bin/bash
# 运行此脚本青龙面板要安装Linux下的sshpass和jq依赖

echo "开始执行任务..."

# 设置 SSH 超时(单位:秒)
SSH_TIMEOUT=15

Serv00_username_1="你的账户"
Serv00_password_1="你的密码"
Serv00_host_1="你的主机地址"

# Bark 通知相关配置
BARK_URL="你的bark通知url"
BARK_GROUP="Alive"
BARK_TITLE="Serv00"
BARK_ICON="https://kechang.uk/pic/kechang_icon_round.png"

# 定义账号、密码和主机信息数组,每个元素包含 "账号:密码:主机",主机就是s*.serv00.com,一行一组(不需要,号)
CREDENTIALS=(
"$Serv00_username_1:$Serv00_password_1:$Serv00_host_1"
)

# 函数: 发送 Bark 推送通知
send_bark_notification() {
    local title="$1"
    local message="$2"
    local encoded_title=$(echo -n "$title" | jq -sRr @uri)
    local encoded_message=$(echo -e "$message" | jq -sRr @uri)
    local notification_url="$BARK_URL/$encoded_title/$encoded_message?group=$BARK_GROUP&icon=$(echo -n "$BARK_ICON" | jq -sRr @uri)"

    curl -s -X GET "$notification_url" > /dev/null
}
# 定义一个数组来存储输出和错误信息
declare -A OUTPUTS
# 用于标记是否有命令失败
has_error=false
# 用于存储成功的命令
successful_commands=()
# 用于存储失败的命令
failed_commands=()

# 循环遍历每行并执行命令
for cred in "${CREDENTIALS[@]}"; do
    IFS=':' read -r user pass host <<< "$cred"
    
    if [ -z "$user" ]; then
        continue
    fi
    
    # 在远程服务器上执行指定的命令
    OUTPUTS["$user"]=$(sshpass -p "$pass" ssh -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=$SSH_TIMEOUT -t $user@$host "bash /home/你的用户名/start.sh" 2>&1)
    if [ $? -ne 0 ];then
        echo "执行命令失败: $user: ${OUTPUTS["$user"]}"
        has_error=true
        failed_commands+=("$user")
    else
        successful_commands+=("$user")
    fi
done

# 构建消息内容
MESSAGE=""

# 添加成功的命令到消息
if [ ${#successful_commands[@]} -gt 0 ]; then
    MESSAGE+="保号成功:\\n"
    for user in "${successful_commands[@]}"; do
        MESSAGE+="$user\\n"
    done
fi

# 添加失败的命令到消息
if [ ${#failed_commands[@]} -gt 0 ]; then
    MESSAGE+="以下出错了😭:\\n"
    for user in "${failed_commands[@]}"; do
        MESSAGE+="$user\\n"
    done
fi

# 输出最终结果
if [ "$has_error" = true ]; then
    echo "请检查输入是否正确,或是否在 https://www.serv00.com/ip_unban/ 解锁了IP"
else
    echo "任务执行完成"
fi
MESSAGE+="All done."
echo $MESSAGE
# send_bark_notification "$BARK_TITLE" "$MESSAGE"
# 这里我设置的cron是 0 0/30 * * * ? 执行太频繁了, 所以把bark通知注释掉了

3. sing-box安装脚本 (Serv00)

下面这个sh脚本是修改了Sing-box的一键四协议安装脚本, 去掉了哪吒探针和ARGO, 执行即安装, 放在/home/你的用户名/目录下
需要在web面板开放一个55501的tcp端口, 55502的udp端口, 55503的udp端口(可以自定义, 下面脚本中对应修改就行)
脚本文件名: start.sh

#!/bin/bash

re="\033[0m"
red="\033[1;91m"
green="\e[1;32m"
yellow="\e[1;33m"
purple="\e[1;35m"
red() { echo -e "\e[1;91m$1\033[0m"; }
green() { echo -e "\e[1;32m$1\033[0m"; }
yellow() { echo -e "\e[1;33m$1\033[0m"; }
purple() { echo -e "\e[1;35m$1\033[0m"; }
reading() { read -p "$(red "$1")" "$2"; }
export LC_ALL=C
USERNAME="你的用户名"
HOSTNAME=$(hostname)
export UUID=${UUID:-'bc97f674-c578-4940-9234-0a1da46041b9'}

[[ "$HOSTNAME" == "s1.ct8.pl" ]] && WORKDIR="domains/${USERNAME}.ct8.pl/logs" || WORKDIR="domains/${USERNAME}.serv00.net/logs"
[ -d "$WORKDIR" ] || (mkdir -p "$WORKDIR" && chmod 777 "$WORKDIR")

install_singbox() {
  cd $WORKDIR
  generate_config
  download_singbox
  get_links
}

# Generating Configuration Files
generate_config() {

  openssl ecparam -genkey -name prime256v1 -out "private.key"
  openssl req -new -x509 -days 3650 -key "private.key" -out "cert.pem" -subj "/CN=$USERNAME.serv00.net"

  cat >config.json <<EOF
{
  "log": {
    "disabled": true,
    "level": "info",
    "timestamp": true
  },
  "dns": {
    "servers": [
      {
        "tag": "google",
        "address": "tls://8.8.8.8",
        "strategy": "ipv4_only",
        "detour": "direct"
      }
    ],
    "rules": [
      {
        "rule_set": [
          "geosite-openai"
        ],
        "server": "wireguard"
      },
      {
        "rule_set": [
          "geosite-netflix"
        ],
        "server": "wireguard"
      },
      {
        "rule_set": [
          "geosite-category-ads-all"
        ],
        "server": "block"
      }
    ],
    "final": "google",
    "strategy": "",
    "disable_cache": false,
    "disable_expire": false
  },
    "inbounds": [
    {
      "tag": "vmess-ws-in",
      "type": "vmess",
      "listen": "::",
      "listen_port": 55501,
      "users": [
      {
        "uuid": "$UUID"
      }
    ],
    "transport": {
      "type": "ws",
      "path": "/vmess",
      "early_data_header_name": "Sec-WebSocket-Protocol"
      }
    }
 ],
    "outbounds": [
    {
      "type": "direct",
      "tag": "direct"
    },
    {
      "type": "block",
      "tag": "block"
    },
    {
      "type": "dns",
      "tag": "dns-out"
    },
    {
      "type": "wireguard",
      "tag": "wireguard-out",
      "server": "162.159.195.100",
      "server_port": 4500,
      "local_address": [
        "172.16.0.2/32",
        "2606:4700:110:83c7:b31f:5858:b3a8:c6b1/128"
      ],
      "private_key": "mPZo+V9qlrMGCZ7+E6z2NI6NOV34PD++TpAR09PtCWI=",
      "peer_public_key": "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=",
      "reserved": [
        26,
        21,
        228
      ]
    }
  ],
  "route": {
    "rules": [
      {
        "protocol": "dns",
        "outbound": "dns-out"
      },
      {
        "ip_is_private": true,
        "outbound": "direct"
      },
      {
        "rule_set": [
          "geosite-openai"
        ],
        "outbound": "wireguard-out"
      },
      {
        "rule_set": [
          "geosite-netflix"
        ],
        "outbound": "wireguard-out"
      },
      {
        "rule_set": [
          "geosite-category-ads-all"
        ],
        "outbound": "block"
      }
    ],
    "rule_set": [
      {
        "tag": "geosite-netflix",
        "type": "remote",
        "format": "binary",
        "url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-netflix.srs",
        "download_detour": "direct"
      },
      {
        "tag": "geosite-openai",
        "type": "remote",
        "format": "binary",
        "url": "https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/sing/geo/geosite/openai.srs",
        "download_detour": "direct"
      },      
      {
        "tag": "geosite-category-ads-all",
        "type": "remote",
        "format": "binary",
        "url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-category-ads-all.srs",
        "download_detour": "direct"
      }
    ],
    "final": "direct"
   },
   "experimental": {
      "cache_file": {
      "path": "cache.db",
      "cache_id": "mycacheid",
      "store_fakeip": true
    }
  }
}
EOF
}

# Download Dependency Files
download_singbox() {
  ARCH=$(uname -m) && DOWNLOAD_DIR="." && mkdir -p "$DOWNLOAD_DIR" && FILE_INFO=()
  if [ "$ARCH" == "arm" ] || [ "$ARCH" == "arm64" ] || [ "$ARCH" == "aarch64" ]; then
      FILE_INFO=("https://github.com/eooce/test/releases/download/arm64/sb web" "https://github.com/eooce/test/releases/download/ARM/swith npm")
  elif [ "$ARCH" == "amd64" ] || [ "$ARCH" == "x86_64" ] || [ "$ARCH" == "x86" ]; then
      FILE_INFO=("https://eooce.2go.us.kg/web web" "https://eooce.2go.us.kg/npm npm")
  else
      echo "Unsupported architecture: $ARCH"
      exit 1
  fi
declare -A FILE_MAP
generate_random_name() {
    local chars=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890
    local name=""
    for i in {1..6}; do
        name="$name${chars:RANDOM%${#chars}:1}"
    done
    echo "$name"
}

for entry in "${FILE_INFO[@]}"; do
    URL=$(echo "$entry" | cut -d ' ' -f 1)
    RANDOM_NAME=$(generate_random_name)
    NEW_FILENAME="$DOWNLOAD_DIR/$RANDOM_NAME"
    
    if [ -e "$NEW_FILENAME" ]; then
        green "$NEW_FILENAME already exists, Skipping download"
    else
        curl -L -sS -o "$NEW_FILENAME" "$URL"
        green "Downloading $NEW_FILENAME"
    fi
    chmod +x "$NEW_FILENAME"
    FILE_MAP[$(echo "$entry" | cut -d ' ' -f 2)]="$NEW_FILENAME"
done
wait

if [ -e "${FILE_MAP[web]}" ]; then
    nohup ./"${FILE_MAP[web]}" run -c config.json >/dev/null 2>&1 &
    sleep 2
    pgrep -x "$(basename ${FILE_MAP[web]})" > /dev/null && green "$(basename ${FILE_MAP[web]}) is running" || { red "$(basename ${FILE_MAP[web]}) is not running, restarting..."; pkill -x "$(basename ${FILE_MAP[web]})" && nohup ./"${FILE_MAP[web]}" run -c config.json >/dev/null 2>&1 & sleep 2; purple "$(basename ${FILE_MAP[web]}) restarted"; }
fi

sleep 5
rm -f "$(basename ${FILE_MAP[npm]})" "$(basename ${FILE_MAP[web]})"
}

get_ip() {
ip=$(curl -s --max-time 2 ipv4.ip.sb)
if [ -z "$ip" ]; then
    if [[ "$HOSTNAME" =~ s[0-9]\.serv00\.com ]]; then
        ip=${HOSTNAME/s/web}
    else
        ip="$HOSTNAME"
    fi
fi
echo $ip
}

get_links() {
sleep 1
# get ip
IP=$(get_ip)
# get ipinfo
ISP=$(curl -s https://speed.cloudflare.com/meta | awk -F\" '{print $26"-"$18}' | sed -e 's/ /_/g') 
sleep 1
# yellow "注意:v2ray或其他软件的跳过证书验证需设置为true,否则hy2或tuic节点可能不通\n"
cat >list.txt <<EOF
vmess://$(echo "{ \"v\": \"2\", \"ps\": \"$ISP\", \"add\": \"$IP\", \"port\": \"55501\", \"id\": \"$UUID\", \"aid\": \"0\", \"scy\": \"none\", \"net\": \"ws\", \"type\": \"none\", \"host\": \"\", \"path\": \"/vmess?ed=2048\", \"tls\": \"\", \"sni\": \"\", \"alpn\": \"\", \"fp\": \"\"}" | base64 -w0)

EOF
cat list.txt
purple "\n$WORKDIR/list.txt saved successfully"
purple "Running done!"
sleep 2
rm -rf boot.log config.json sb.log core tunnel.yml tunnel.json fake_useragent_0.2.0.json
}

# Restart web, and bot processes
kill_serv() {
  # 获取进程的PID
  PID=$(ps aux | grep "run -c config.json" | grep -v "grep" | awk '{print \$2}')

  # 检查是否获取到PID
  if [ -z "$PID" ]; then
    echo "No web process found."
  else
    # 杀掉进程
    echo "$PID" | xargs kill -9
    echo "Killed processes: $PID."
  fi
}


#主菜单
menu() {
  kill_serv
  sleep 5
  green "install sing-box..."
  install_singbox
}
menu

祝大家玩的愉快!

15 Likes

你真快

2 Likes

好像没看到保活singbox的脚本,,,nohup ./web run -c config.json >/dev/null 2>&1 &

1 Like

1 Like

感谢佬的分享

1 Like

首先是web面板的登录py脚本, 记得安装依赖模块, 大哥,这个是啥意思啊,没找到入口

:bili_095::bili_095::bili_095:

感谢

py脚本在哪里跑都可以, 只要能定时跑就行, py脚本依赖一些模块, 就是import那些

1 Like

感谢分享

明白了,谢谢大哥

serv00 web面板也需要定期登录吗?我目前只搞了个定时任务ssh登录

看了一些帖子说web也是要定期登录的, 我设置的0 0 9 ? * 1

大哥,就一个定时登录脚本够吗?

两个啊 一个py一个sh

感谢大佬分享啊

二选一就行

感谢分享

感谢分享

点赞支持,感谢分享!