我的 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 复活
前提:
- 有一台自由管理的 vps 或者可长期运行的服务器
- 在这台服务器上配置无密码的 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
同样前提:
- 有一台自由管理的 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 双保活。
收工。也许是未完待续。。。