serv00 cron jobs复活 + ssh login & web login 双保活

我的 serv00 保活和进程管理进化史。。。

背景介绍:
众所周知,serv00 非常大方,提供了很强大的虚拟主机空间和相对宽松的 ssh 账号。不过系统要求三个月内至少登录面板或ssh一次,于是有了各位大佬的各种保活方法,其中有 ssh login 和 web login 两种。web login 又包括了利用 Github Actions、Vercel、青龙面板等等。

由于 serv00 的 ssh 账号没有 root 权限,所以就有了利用 pm2 建立后台监控进程,变相支持了后台 service 进程。但是 serv00 又会不定期清理长期运行的 process,所以就有了在 cron jobs 里加了定时检查。

保活工具 1.0: ssh login 保活

我的第一个保活工具:https://linux.do/t/topic/159415

原理就是利用 sshpass + cron jobs,在 serv00 服务器上自运行保活账号。

保活工具 2.0: 批量 cron jobs 复活
可是 serv00 又会不定期清理 cron jobs,擦,真是叔能忍婶不能忍,跟 cron jobs 死磕,于是工具继续进化:批量 cron jobs 复活

前提:

  1. 有一台自由管理的 vps 或者可长期运行的服务器
  2. 在这台服务器上配置无密码的 ssh 登录 serv00 账号

核心思想:在这台服务器上建立 cron job 定期检查 serv00 账号内的 cron jobs!!!如果不存在,则重新创建预先定义的 cron jobs。

步骤1:在你的服务器上配置无密码登录 serv00 账号配置
过程省略,请自行搜索和咨询AI。

步骤2:在你的服务器上,创建脚本:

/<your user home>/check_remote_jobs.sh

内容如下:

#!/bin/bash

# Configuration
MAX_RETRIES=2
TIMEOUT=10m
RETRY_DELAY=1m
LOG_FILE="/<your user home>/remote_jobs_check.log"

# Server configurations
declare -A SERVERS
SERVERS=(
    ["svr1"]="*/15 * * * * /home/<your serv00 username1>/<your command 1>
@reboot  /home/<your serv00 username1>/<your command 2>"
    ["svr2"]="7 * * * * /home/<your serv00 username2>/<your command 1>
@reboot  /home/<your serv00 username2>/<your command 2>"
)

# Define the order of servers
SERVER_ORDER=("svr1" "svr2")

# Logging function
log() {
    local server="$1"
    local message="$2"
    local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
    echo "[$timestamp] [$server] $message"
    echo "[$timestamp] [$server] $message" >> "$LOG_FILE"
}

# Function to execute SSH command with retry
ssh_execute() {
    local server_name="$1"
    local command="$2"
    local attempt=1

    while [ $attempt -le $MAX_RETRIES ]; do
        output=$(timeout $TIMEOUT ssh -T "$server_name" "$command" 2>&1)
        exit_code=$?

        if [ $exit_code -eq 0 ] || echo "$output" | grep -q "no crontab"; then
            echo "$output"
            return 0
        elif [ $exit_code -eq 124 ]; then
            log "$server_name" "Attempt $attempt ($command): SSH connection timed out"
        else
            log "$server_name" "Attempt $attempt ($command): SSH command failed with exit code $exit_code"
            log "$server_name" "Error output: $output"
        fi

        attempt=$((attempt + 1))
        [ $attempt -le $MAX_RETRIES ] && sleep $RETRY_DELAY
    done

    log "$server_name" "All SSH attempts failed"
    return 1
}

# Check cron jobs for a server
check_cron_jobs() {
    local server_name="$1"
    local cron_jobs="$2"

    log "$server_name" "Checking cron jobs"

    current_crontab=$(ssh_execute "$server_name" "/usr/bin/crontab -l")
    if [ $? -ne 0 ]; then
        log "$server_name" "Failed to check cron jobs"
        return 1
    fi

    if [ -z "$current_crontab" ] || echo "$current_crontab" | grep -q "no crontab"; then
        log "$server_name" "Cron jobs are empty. Adding defined jobs..."
        ssh_execute "$server_name" "echo '$cron_jobs' | /usr/bin/crontab -"
        if [ $? -eq 0 ]; then
            log "$server_name" "Cron jobs added successfully"
        else
            log "$server_name" "Failed to add cron jobs"
        fi
    else
        log "$server_name" "Current cron jobs:"
        echo "$current_crontab" | while IFS= read -r line; do
            log "$server_name" "  $line"
        done
        log "$server_name" "Checking for missing jobs..."

        IFS=$'\n'
        for job in $cron_jobs; do
            if ! echo "$current_crontab" | grep -Fq "$job"; then
                log "$server_name" "Adding missing job: $job"
                ssh_execute "$server_name" "(/usr/bin/crontab -l 2>/dev/null; echo '$job') | /usr/bin/crontab -"
            fi
        done
        unset IFS
    fi
    log "$server_name" "Cron job check completed"
}

# Main execution
log "SCRIPT" "Starting cron job check for all servers"
for server_name in "${SERVER_ORDER[@]}"; do
    if [[ -v "SERVERS[$server_name]" ]]; then
        check_cron_jobs "$server_name" "${SERVERS[$server_name]}"
    else
        log "SCRIPT" "Warning: Server $server_name not found in configurations"
    fi
done
log "SCRIPT" "Completed cron job check for all servers"

需要你配置就是 SERVERS 列表,包含 ssh 登录 Host 和 cron jobs,可添加多个。其中 srv1 和 srv2 就是你的服务器 ~/.ssh/config 中设置的登录 Host

~/.ssh/config 示例:

Host srv1
  HostName s5.serv00.com
  User <your serv00 username>
  IdentityFile ~/.ssh/<your ssh private key name>

另外,记得添加 SERVER_ORDER 列表,其决定检查顺序。

如果报错 timeout 找不到,请安装 timeout,例如在 Ubuntu 或 Debian上:

sudo apt install timeout -y

保活工具 3.0: web login
受到这个贴子的启发:https://linux.do/t/topic/168399

于是在其基础上,诞生了第三个工具:批量 headless web login

同样前提:

  1. 有一台自由管理的 vps 或者可长期运行的服务器

在你的 VPS 服务器上,创建:

/<your user home>/serv00_headless_login.py

内容如下:

import os
import sys
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('~/serv00_headless_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': 'svr1', 'username': '<your serv00 username1>', 'password': '<your serv00 password1>', 'url': 'https://panel5.serv00.com/login/'},
    {'name': 'svr2', 'username': '<your serv00 username2>', 'password': '<your serv00 password2>', 'url': 'https://panel6.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("Starting login attempts...")

# Iterate over each account
for account in accounts:
    logging.info(f"Attempting to log in to {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"Login successful for {account['name']}")
        else:
            logging.error(f"Login failed for {account['name']}")
            all_successful = False  # Set the flag to False if any login fails

    except Exception as e:
        logging.error(f"An error occurred while logging in to {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("All logins were successful.")
    sys.exit(0)
else:
    logging.error("Some logins failed.")
    sys.exit(1)

在你的 VPS 服务器上,创建 cron job,每个月 1 号 0 点执行一次,可以根据需要自行调整:

0 0 1 * * /usr/bin/python3 /<path-to-your-file>/serv00_headless_login.py

至此,完成了 cron jobs复活 + ssh login & web login 双保活。

收工。也许是未完待续。。。

5 个赞

我还是老老实实登录吧:triumph:

登录保活只是其一,其二是复活 cron jobs,因为官方提供了 cron jobs 但又不定期清理,很不爽啊~

1 个赞

学习了

这个非常全面了,谢谢

感谢,mark一下

大佬6666!

感谢大佬!