Serv00 进程保活最终解决方案

这个方案已经写出来差不多一个月了,Github 上也开了源,论坛里、群里也都介绍了使用方法,但是,目前除了我重构之后的 X-for-serv00 以及 Sb-for-serv00 以外,还没有哪个项目已经用上了的。遂在博客里对于这个方案进行进一步的介绍。

首先几个大前提,似乎还有很多人搞不清:

Serv00 不是 VPS,是一台独立服务器,新建了很多用户,按照用户进行隔离,并没有虚拟化一个完整的 FreeBSD Server 给用户,所以没有 Root 权限,但是内置了很多独立服务器自带的软件包、服务等等,可以说是有利有弊;
Serv00 不是 Linux 系统,是 FreeBSD 系统,虽说 Unix like 使用起来总是相似的,但是总归还是不一样的;
Serv00 自带了一个 Web 服务器——Apache。Apache 与 Nginx 功能相似但是使用方法是不一样的,而且在没有 Root 权限的情况下,很多东西你无法进行设置;
每个用户能够最多预留三个端口的使用权,而且端口范围在 1024-64000;
因为是独立服务器按照用户进行隔离,所以你不能对其进行重启、重装等操作,机器的重启与重装会影响这台 Server 上的一万名用户
And so on…
Serv00 的 Apache 服务器附带了一个插件——Phusion Passenger,利用其特性,我们能够在 Serv00 上实现访问网页即对进行实现保活。已知 WWW websites 在被访问时会按照其类型被唤醒,而且通过 Phusion Passenger 托管的 Django / NodeJS / Ruby on Rails 等类型的应用是可以端口复用,在 80 /443 端口提供 Web 服务的,所以只需要在这样一个脚本或者应用内写入进程的检测与唤醒即可通过网页对进程保活。

但是这样做还有一个问题,一个网站需要两个域名,一个用来保活,一个用来提供 Web 服务,很是不方便,但是,在 JavaScript 中,可以通过引入 chimurai/http-proxy-middleware 这个中间件将其合二为一,实现真正的访问即保活,访问即唤醒。

示例

app.js的内容如下:

const express = require("express");
const app = express();
const port = 3000;
var exec = require("child_process").exec;
const { createProxyMiddleware } = require("http-proxy-middleware");
const path = require('path');
const fs = require('fs');

const currentDir = __dirname;
process.chdir(currentDir);

app.use('/', createProxyMiddleware({
  target: 'http://127.0.0.1:PORT', //改成 Web 应用实际运行端口
  changeOrigin: true,
  ws: true, 
  onError: (err, req, res) => {
    res.writeHead(500, {
      'Content-Type': 'text/plain',
    });
    res.end('Please wait for a while and try to refresh the page.');
  },
}));

function keep_web_alive() {
    exec("pgrep -laf PROCESS", function (err, stdout, stderr) { //改成进程名,如:alist
      if (stdout.includes("PROCESS_COMMAND")) {  //改成进程实际运行命令,如:alist server
        console.log("web 正在运行");
      } else {
        exec(
          "START_COMMAND", // 改成启动脚本或者启动命令,如:chmod +x start.sh && ./start.sh 或者 ./alist server
          function (err, stdout, stderr) {
            if (err) {
              console.log("保活-调起web-命令行执行错误:" + err);
            } else {
              console.log("保活-调起web-命令行执行成功!");
            }
          }
        );
      }
    });
  }
  setInterval(keep_web_alive, 10 * 1000);

app.listen(port, () => console.log(`Example app listening on port ${port}!`));

package.json的内容如下:

{
    "name": "example",
    "version": "1.0.0",
    "description": "A simple Express.js server",
    "author": "k0baya",
    "main": "app.js",
    "license": "MIT",
    "private": false,
    "scripts": {
      "start": "node app.js"
    },
    "dependencies": {
      "express": "^4.19.2",
      "http-proxy-middleware": "^3.0.0"
    },
    "engines": {
      "node": "22"
    },
    "keywords": [
      "node"
    ]
  }

目录结构为:

/home/LOGIN/domains/DOMAIN/public_nodejs/
    ├──app.js
    ├──package.json
    └──其它应用所需文件(比如二进制文件、配置文件、启动脚本等)

先执行 npm22 install,再访问网页即可唤醒应用。监控网页即可对应用进行保活。

此外,自动续期直接去 Serv00 自带的 Cron job 内添加每个月一次的 sshpass 命令即可,滥用 GitHub Actions 是很差劲且没有必要的行为。