首页 / 资讯动态 / Ubuntu下Nginx与PHP服务状态监控脚本

Ubuntu下Nginx与PHP服务状态监控脚本

在Ubuntu服务器上维护Nginx和PHP服务时,最让人头疼的不是初始配置,而是服务无声无息地挂掉后,流量还在继续涌入,返回的全是502或504错误。等你发现时,业务可能已经中断了十几分钟。靠人工盯着日志或者等报警系统触发,往往存在延迟。最直接的解决办法就是写一个驻留在本地的监控脚本,让它以秒级或分钟级频率检查服务状态,一旦发现异常立即自动修复并记录日志。下面我会给出一个完整的、可直接部署的Bash脚本方案,并拆解每个模块的设计思路,让你不仅能用,还能根据自己的环境灵活改造。

脚本核心设计思路:状态检测、自动修复、日志记录三位一体

一个合格的监控脚本不能只做“看门狗”,它至少要完成三件事:准确判断Nginx和PHP-FPM是否真正在运行,而不是仅仅检查进程是否存在;在服务异常时尝试重启,并验证重启是否成功;将所有事件详细记录到日志文件,方便事后追溯。我们还要考虑脚本自身不能成为资源负担,所以要用轻量级的检测手段,避免频繁调用消耗大的命令。

检测Nginx状态,很多人习惯用pidof nginx或者ps aux | grep nginx,但这两种方式都有盲区。进程存在不代表Nginx能正常处理请求,比如配置错误导致启动失败但旧进程残留,或者工作进程僵死。更可靠的做法是直接请求本地HTTP端口,检查响应状态码和内容。检测PHP-FPM则要复杂一些,因为它是通过Unix Socket或TCP端口通信的,我们需要检查Socket文件是否存在且可写,或者检查PHP-FPM的主进程和子进程池状态。

完整的监控脚本代码

下面这个脚本整合了上述所有逻辑,你可以直接保存为nginx_php_monitor.sh,放在/usr/local/bin/目录下,并配合crontab定时执行。

#!/bin/bash

# ============================================
# Nginx与PHP-FPM服务状态监控脚本
# 适用于Ubuntu 20.04/22.04环境
# 功能:检测服务状态,异常时自动重启并记录日志
# ============================================

# 配置变量
LOG_FILE="/var/log/service_monitor.log"
NGINX_CHECK_URL="http://127.0.0.1/nginx_status"
PHP_FPM_SOCKET="/run/php/php8.1-fpm.sock"
PHP_FPM_SERVICE="php8.1-fpm"
NGINX_SERVICE="nginx"
MAX_RETRY=3
RETRY_INTERVAL=5
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')

# 确保日志目录存在
mkdir -p "$(dirname "$LOG_FILE")"

# 日志记录函数
log_message() {
    echo "[$TIMESTAMP] $1" >> "$LOG_FILE"
}

# 检查Nginx是否正常响应
check_nginx() {
    # 使用curl请求本地nginx状态页,设置超时避免卡死
    local http_code
    http_code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 --max-time 10 "$NGINX_CHECK_URL")
    
    if [ "$http_code" = "200" ]; then
        return 0
    else
        return 1
    fi
}

# 检查PHP-FPM Socket是否可用
check_php_fpm() {
    # 检查Socket文件是否存在
    if [ ! -S "$PHP_FPM_SOCKET" ]; then
        return 1
    fi
    
    # 使用cgi-fcgi或直接通过Socket发送状态请求
    # 这里使用SCRIPT_FILENAME和QUERY_STRING来触发PHP-FPM响应
    local response
    response=$(echo -e "GET /status HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n" | \
               timeout 5 nc -U "$PHP_FPM_SOCKET" 2>/dev/null | head -n 1)
    
    if echo "$response" | grep -q "200 OK"; then
        return 0
    else
        return 1
    fi
}

# 重启服务函数
restart_service() {
    local service_name="$1"
    local retry_count=0
    
    while [ $retry_count -lt $MAX_RETRY ]; do
        systemctl restart "$service_name" 2>/dev/null
        
        sleep "$RETRY_INTERVAL"
        
        # 重启后验证
        if [ "$service_name" = "$NGINX_SERVICE" ]; then
            if check_nginx; then
                log_message "SUCCESS: $service_name 重启成功,当前状态正常"
                return 0
            fi
        elif [ "$service_name" = "$PHP_FPM_SERVICE" ]; then
            if check_php_fpm; then
                log_message "SUCCESS: $service_name 重启成功,当前状态正常"
                return 0
            fi
        fi
        
        retry_count=$((retry_count + 1))
        log_message "WARNING: $service_name 第${retry_count}次重启后验证失败,准备重试"
    done
    
    log_message "ERROR: $service_name 重启${MAX_RETRY}次后仍然异常,请人工介入检查"
    return 1
}

# 主监控逻辑
main() {
    local nginx_status="正常"
    local php_status="正常"
    local need_restart_nginx=false
    local need_restart_php=false
    
    # 检测Nginx
    if ! check_nginx; then
        nginx_status="异常"
        need_restart_nginx=true
        log_message "ALERT: Nginx检测失败,HTTP请求未返回200状态码"
    fi
    
    # 检测PHP-FPM
    if ! check_php_fpm; then
        php_status="异常"
        need_restart_php=true
        log_message "ALERT: PHP-FPM Socket检测失败,Socket文件或服务不可用"
    fi
    
    # 记录当前状态
    log_message "INFO: 检测完成 - Nginx: $nginx_status, PHP-FPM: $php_status"
    
    # 执行重启操作
    if [ "$need_restart_nginx" = true ]; then
        log_message "ACTION: 开始尝试重启Nginx服务"
        restart_service "$NGINX_SERVICE"
    fi
    
    if [ "$need_restart_php" = true ]; then
        log_message "ACTION: 开始尝试重启PHP-FPM服务"
        restart_service "$PHP_FPM_SERVICE"
    fi
}

# 执行主函数
main

exit 0
脚本关键模块深度解析

这个脚本不是简单地把检测和重启拼凑在一起,有几个细节决定了它在生产环境中的可靠性。首先是Nginx的检测方式,我用了curl直接请求本地状态页,而不是检查进程。你需要在Nginx配置中提前开启stub_status模块,在server块里加上如下配置:

location /nginx_status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    deny all;
}

这样做的好处是,只有当Nginx真正能处理HTTP请求时才会返回200,避免了进程假死的情况。curl的超时参数--connect-timeout 5和--max-time 10也很关键,防止脚本因为网络或服务卡死而无限等待,导致后续的crontab任务堆积。

PHP-FPM的检测部分,我选择了直接通过Unix Socket发送一个简化的HTTP请求。这里没有依赖php-fpm的status页面,因为默认情况下pm.status_path是关闭的,需要额外配置。用nc命令向Socket写入一个GET请求,只要PHP-FPM主进程能接收并返回HTTP响应头,就说明服务是存活的。如果你的PHP-FPM监听的是TCP端口(比如9000端口),可以把nc -U换成nc -w 3 127.0.0.1 9000,逻辑完全一样。

部署与自动化配置

脚本写好后,需要赋予执行权限并配置定时任务。执行以下命令:

sudo chmod +x /usr/local/bin/nginx_php_monitor.sh

然后编辑crontab,让脚本每两分钟运行一次。这里不建议设置成一分钟一次,因为如果服务真的挂了,重启操作本身需要时间,太频繁的检测可能导致重复重启。

sudo crontab -e
# 添加以下行
*/2 * * * * /usr/local/bin/nginx_php_monitor.sh

日志文件会持续增长,建议配合logrotate进行日志轮转。在/etc/logrotate.d/目录下创建一个配置文件service_monitor:

/var/log/service_monitor.log {
    weekly
    rotate 4
    compress
    missingok
    notifempty
    create 640 root adm
}
扩展监控维度:从存活检测到性能预警

基础脚本只解决了“死没死”的问题,但很多线上故障是“半死不活”的状态,比如Nginx能响应但延迟飙升,PHP-FPM子进程全部被慢请求占满导致新请求排队。你可以在脚本里增加响应时间检测,用curl的-w参数提取time_total,当响应时间超过阈值(比如3秒)时记录警告日志,但不触发重启。这样运维人员就能从日志中发现性能劣化的趋势。

另一个实用的扩展是检查PHP-FPM的子进程使用率。可以通过解析PHP-FPM的status页面(需要开启pm.status_path)获取active processes和max children的比值,当使用率超过80%时发送告警。这比等服务彻底挂掉再重启要主动得多。

多版本PHP环境下的适配

Ubuntu系统上可能同时安装多个PHP版本,比如php7.4-fpm和php8.1-fpm并存。脚本中的PHP_FPM_SOCKET和PHP_FPM_SERVICE变量需要根据实际运行的版本调整。你可以用以下命令查看当前系统中所有PHP-FPM的Socket文件:

ls -la /run/php/

如果一台服务器上运行着多个PHP版本,建议为每个版本创建独立的监控配置,或者修改脚本让它遍历所有Socket文件逐一检测。systemctl列表里也会显示所有已安装的php-fpm服务单元,用systemctl list-units | grep php-fpm可以快速确认服务名称。

避免误报和重复告警的策略

任何监控系统最怕的就是误报,半夜被报警叫起来发现服务其实没问题,这对运维人员的折磨不亚于真的故障。脚本里设置了MAX_RETRY=3,每次重启间隔5秒,总共15秒的恢复窗口。在这期间如果服务恢复正常,日志只会记录到WARNING级别,不会上升到ERROR。你还可以在脚本开头加一个锁文件机制,防止上一个实例还没执行完,crontab又启动了新的实例,造成并发重启的混乱。

LOCK_FILE="/var/run/service_monitor.lock"
exec 200>"$LOCK_FILE"
flock -n 200 || { log_message "ERROR: 脚本已在运行中,退出"; exit 1; }

这段代码用文件描述符和flock命令实现了进程互斥,放在主逻辑之前即可。如果脚本执行时间超过crontab的间隔,后续任务会自动跳过,不会堆积。

整个方案的核心价值在于,它不需要引入任何第三方监控系统,完全靠服务器自身的能力实现了基础自治。对于中小型项目或者边缘节点服务器来说,这种轻量级的自愈机制比搭建一整套Prometheus加Alertmanager要务实得多。把脚本部署到位,再配合日志轮转和必要的性能阈值检测,Ubuntu下的Nginx与PHP服务稳定性会提升一个明显的台阶。