重大更新:serv00部署服务加保活脚本

推荐使用Cloudflare更加稳定

由于在serv00部署的服务使用pm2保活存在进程被清理的情况,所以我之后在serv00中加入了restart.sh自动重启脚本配合cron来保活,但是这种方法依然被清理进程。既然在serv00内部保活存在定期服务被清理的情况,我们可以选择通过外部连接serv00并执行restart.sh,从而保活serv00

该脚本需要结合restart.sh使用,你有其他脚本保活依然可以放入使用(路径使用绝对路径)

制作不易,请各位道友先赞后看

先贴个图:

serv00的SSH登录记录

huggingface后台

访问huggingface网址

在huggingface中部署serv00应用进程自动保活脚本

Dockerfile文件

FROM python:3.8-slim-buster

WORKDIR /app

RUN apt-get update && apt-get install -y openssh-client
RUN pip install paramiko schedule flask

COPY vps_monitor.py .

EXPOSE 8080

CMD ["python", "-u", "vps_monitor.py"]

README.md添加app_port: 8080

给出了两个保活版本(根据需要选择一个就行)

一个Serv00账号监控一个进程

vps_monitor.py文件:

import paramiko
import schedule
import time
import os
import sys
from flask import Flask, jsonify, render_template_string
from threading import Thread
import logging

app = Flask(__name__)

vps_status = {}

# 设置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler(sys.stdout),
        logging.StreamHandler(sys.stderr)
    ]
)
logger = logging.getLogger()

def get_vps_configs():
    configs = []
    index = 1
    while True:
        hostname = os.environ.get(f'HOSTNAME_{index}')
        if not hostname:
            break
        
        config = {
            'index': index,
            'hostname': hostname,
            'username': os.environ.get(f'USERNAME_{index}'),
            'password': os.environ.get(f'PASSWORD_{index}'),
            'script_path': os.environ.get(f'SCRIPT_PATH_{index}')
        }
        configs.append(config)
        
        logger.info(f"Config {index}: {config['hostname']}, {config['username']}, {config['script_path']}")
        
        index += 1
    return configs

def check_and_run_script(config):
    logger.info(f"Checking VPS {config['index']}: {config['hostname']}")
    client = None
    try:
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        
        client.connect(
            hostname=config['hostname'],
            username=config['username'],
            password=config['password'],
            port=22
        )
        
        script_path = config['script_path']
        script_name = os.path.basename(script_path)
        
        check_command = f"ps -eo args | grep {script_name} | grep -v grep"
        
        stdin, stdout, stderr = client.exec_command(check_command)
        output = stdout.read().decode('utf-8').strip()
        
        if output and script_path in output:
            status = "Running"
            logger.info(f"Script is running on {config['hostname']}")
        else:
            logger.info(f"Script not running on {config['hostname']}. Executing restart script.")
            restart_command = f"nohup /bin/sh {script_path} > /dev/null 2>&1 &"
            stdin, stdout, stderr = client.exec_command(restart_command)
            
            status = "Restarted"
            logger.info(f"Script restarted on {config['hostname']}")
        
        vps_status[config['index']] = {
            'index': config['index'],
            'hostname': config['hostname'],
            'status': status,
            'last_check': time.strftime('%Y-%m-%d %H:%M:%S'),
            'username': config['username']
        }
        
    except Exception as e:
        logger.error(f"Error occurred while checking VPS {config['index']} - {config['hostname']}: {str(e)}")
        vps_status[config['index']] = {
            'index': config['index'],
            'hostname': config['hostname'],
            'status': f"Error: {str(e)}",
            'last_check': time.strftime('%Y-%m-%d %H:%M:%S'),
            'username': config['username']
        }
    finally:
        if client:
            client.close()

def check_all_vps():
    logger.info("Starting VPS check")
    vps_configs = get_vps_configs()
    for config in vps_configs:
        check_and_run_script(config)
    
    # 创建表格头
    table = "+---------+-----------------------+----------+-------------------------+----------+\n"
    table += "| Index   | Hostname              | Status   | Last Check              | Username |\n"
    table += "+---------+-----------------------+----------+-------------------------+----------+\n"
    
    # 添加每个VPS的状态
    for index in sorted(vps_status.keys()):
        status = vps_status[index]
        table += "| {:<7} | {:<21} | {:<8} | {:<23} | {:<8} |\n".format(
            status['index'],
            status['hostname'][:21],
            status['status'][:8],
            status['last_check'],
            status['username'][:8]
        )
        table += "+---------+-----------------------+----------+-------------------------+----------+\n"
    
    logger.info("\n" + table)

@app.route('/')
def index():
    html = '''
    <h1>VPS Status Overview</h1>
    <table border="1">
        <tr>
            <th>Index</th>
            <th>Hostname</th>
            <th>Status</th>
            <th>Last Check</th>
            <th>Username</th>
        </tr>
        {% for index in vps_status.keys()|sort %}
        {% set data = vps_status[index] %}
        <tr>
            <td>{{ data['index'] }}</td>
            <td><a href="/status/{{ data['index'] }}">{{ data['hostname'] }}</a></td>
            <td>{{ data['status'] }}</td>
            <td>{{ data['last_check'] }}</td>
            <td>{{ data['username'] }}</td>
        </tr>
        {% endfor %}
    </table>
    '''
    return render_template_string(html, vps_status=vps_status)

@app.route('/status/<int:index>')
def vps_status_detail(index):
    if index in vps_status:
        return jsonify(vps_status[index])
    else:
        return jsonify({"error": "VPS not found"}), 404

@app.route('/health')
def health_check():
    return jsonify({"status": "healthy", "uptime": time.time() - start_time}), 200

def run_flask():
    app.run(host='0.0.0.0', port=8080)

def main():
    global start_time
    start_time = time.time()
    
    logger.info("===== VPS monitoring script is starting =====")
    
    flask_thread = Thread(target=run_flask)
    flask_thread.start()
    logger.info("Flask server started in background")

    vps_configs = get_vps_configs()
    logger.info(f"Found {len(vps_configs)} VPS configurations")

    logger.info("Running initial VPS check")
    check_all_vps()

    schedule.every(15).minutes.do(check_all_vps)
    logger.info("Scheduled VPS check every 15 minutes")
    
    logger.info("===== VPS monitoring script is running =====")
    
    heartbeat_count = 0
    while True:
        schedule.run_pending()
        time.sleep(60)
        heartbeat_count += 1
        if heartbeat_count % 5 == 0:  # 每5分钟输出一次心跳信息
            logger.info(f"Heartbeat: Script is still running. Uptime: {heartbeat_count} minutes")

if __name__ == "__main__":
    main()

脚本15分钟运行一次,可以自行修改时间

huggingface后台变量

USERNAME_X   
HOSTNAME_X
PASSWORD_X
SCRIPT_PATH_X

X为数字编号如(1,2,3),每个主机4项要相同才能对应,可以有多个号
如:

USERNAME_1     
HOSTNAME_1
PASSWORD_1
SCRIPT_PATH_1
USERNAME_2     
HOSTNAME_2
PASSWORD_2
SCRIPT_PATH_2

USERNAME为serv00用户名,HOSTNAME为主机名(如:s3.serv00.com),PASSWORD为serv00密码,SCRIPT_PATH为执行脚本的绝对路径(如:/usr/home/serv00用户名/domains/域名/public_html/restart.sh

效果图

一个Serv00账号监控多个进程

vps_monitor.py文件

import paramiko
import schedule
import time
import os
import sys
from flask import Flask, jsonify, render_template_string
from threading import Thread
import logging

app = Flask(__name__)

vps_status = {}

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler(sys.stdout),
        logging.StreamHandler(sys.stderr)
    ]
)
logger = logging.getLogger()

def get_vps_configs():
    configs = []
    index = 1
    while True:
        hostname = os.environ.get(f'HOSTNAME_{index}')
        if not hostname:
            break
        
        username = os.environ.get(f'USERNAME_{index}')
        password = os.environ.get(f'PASSWORD_{index}')
        
        script_paths = []
        script_index = 1
        while True:
            script_path = os.environ.get(f'SCRIPT_PATHS_{index}_{script_index}')
            if not script_path:
                break
            script_paths.append(script_path.strip())
            script_index += 1
        
        for script_path in script_paths:
            configs.append({
                'index': index,
                'hostname': hostname,
                'username': username,
                'password': password,
                'script_path': script_path
            })
        
        index += 1
    return configs

def check_and_run_script(config):
    logger.info(f"Checking VPS {config['index']}: {config['hostname']} - {config['script_path']}")
    client = None
    try:
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(hostname=config['hostname'], username=config['username'], password=config['password'], port=22)
        
        script_path = config['script_path']
        script_name = os.path.basename(script_path)
        key = f"{config['index']}:{config['hostname']}:{script_name}"
        
        check_command = f"ps aux | grep '{script_path}' | grep -v grep"
        
        stdin, stdout, stderr = client.exec_command(check_command)
        output = stdout.read().decode('utf-8').strip()
        
        if output and script_path in output:
            status = "Running"
        else:
            logger.info(f"Script {script_name} not running. Attempting to restart.")
            stdin, stdout, stderr = client.exec_command(f"nohup /bin/sh {script_path} > /dev/null 2>&1 & echo $!")
            new_pid = stdout.read().decode('utf-8').strip()
            
            if new_pid.isdigit():
                status = "Restarted"
            else:
                status = "Restart Failed"
        
        vps_status[key] = {
            'index': config['index'],
            'status': status,
            'last_check': time.strftime('%Y-%m-%d %H:%M:%S'),
            'username': config['username'],
            'script_name': script_name
        }
        
    except Exception as e:
        logger.error(f"Error occurred while checking VPS {config['index']} - {config['hostname']} - {script_name}: {str(e)}")
        vps_status[f"{config['index']}:{config['hostname']}:{script_name}"] = {
            'index': config['index'],
            'status': f"Error: {str(e)}",
            'last_check': time.strftime('%Y-%m-%d %H:%M:%S'),
            'username': config['username'],
            'script_name': script_name
        }
    finally:
        if client:
            client.close()

def check_all_vps():
    logger.info("Starting VPS check")
    for config in get_vps_configs():
        check_and_run_script(config)
    
    table = "+---------+-----------------------+------------------+----------+-------------------------+----------+\n"
    table += "| Index   | Hostname              | Script Name      | Status   | Last Check              | Username |\n"
    table += "+---------+-----------------------+------------------+----------+-------------------------+----------+\n"
    
    for key, status in vps_status.items():
        index, hostname, script_name = key.split(':')
        table += "| {:<7} | {:<21} | {:<16} | {:<8} | {:<23} | {:<8} |\n".format(
            status['index'], hostname[:21], script_name[:16], status['status'][:8],
            status['last_check'], status['username'][:8]
        )
        table += "+---------+-----------------------+------------------+----------+-------------------------+----------+\n"
    
    logger.info("\n" + table)

@app.route('/')
def index():
    html = '''
    <h1>VPS Status Overview</h1>
    <table border="1">
        <tr>
            <th>Index</th>
            <th>Hostname</th>
            <th>Script Name</th>
            <th>Status</th>
            <th>Last Check</th>
            <th>Username</th>
        </tr>
        {% for key, data in vps_status.items() %}
        <tr>
            <td>{{ data.index }}</td>
            <td><a href="/status/{{ key }}">{{ key.split(':')[1] }}</a></td>
            <td>{{ data.script_name }}</td>
            <td>{{ data.status }}</td>
            <td>{{ data.last_check }}</td>
            <td>{{ data.username }}</td>
        </tr>
        {% endfor %}
    </table>
    '''
    return render_template_string(html, vps_status=vps_status)

@app.route('/status/<path:key>')
def vps_status_detail(key):
    return jsonify(vps_status[key]) if key in vps_status else (jsonify({"error": "VPS or script not found"}), 404)

@app.route('/health')
def health_check():
    return jsonify({"status": "healthy", "uptime": time.time() - start_time}), 200

def run_flask():
    app.run(host='0.0.0.0', port=8080)

def main():
    global start_time
    start_time = time.time()
    
    logger.info("===== VPS monitoring script is starting =====")
    
    Thread(target=run_flask).start()
    logger.info("Flask server started in background")

    check_all_vps()
    schedule.every(15).minutes.do(check_all_vps)
    logger.info("Scheduled VPS check every 15 minutes")
    
    logger.info("===== VPS monitoring script is running =====")
    
    heartbeat_count = 0
    while True:
        schedule.run_pending()
        time.sleep(60)
        heartbeat_count += 1
        if heartbeat_count % 5 == 0:
            logger.info(f"Heartbeat: Script is still running. Uptime: {heartbeat_count} minutes")

if __name__ == "__main__":
    main()

对于有一个账号想保活多个任务/多个程序的,只需要在serv00中有多个restart.sh文件如(restart1.shrestart2.sh
huggingface后台参数

HOSTNAME_X
USERNAME_X
PASSWORD_X
SCRIPT_PATHS_X_1
SCRIPT_PATHS_X_2
SCRIPT_PATHS_X_3

同一账号的X必须项目,SCRIPT_PATHS_X_数字可以随便填写,只需要绝对路径对上就行

效果图

具体操作详见:

由于huggingface不定期访问会休眠,所以需要加个定时任务,下面的随便选一个把你的huggingface网址放入进行保活即可。

https://console.rapjob.com/

相关项目:

51 Likes

先赞后看

1 Like

强啊

1 Like

你好快啊

1 Like

1 Like

1 Like

MARK

1 Like

mark

1 Like

怎么注册serv00呀,我这里一直说超时

1 Like

好东西 :tieba_013:

1 Like

非常nice

1 Like

你也太强了吧!

1 Like

大佬强:+1:t2:

1 Like

先赞后看,感谢佬友

1 Like

感谢 mark

1 Like

谢佬

1 Like

有没有frp保活的?

1 Like

在serv00部署的,把路径填入你的启动脚本就行了

那个大佬给个详细操作教程,谢谢了。

1 Like

huggingface这里文件已经给了,放进去就行。其余的教程都在链接里 :wink: