Nginx 配置检查与热更新

Nginx 配置文件检查、测试和热更新方法


📋 目录


配置检查

基本语法检查

# 检查配置文件语法
sudo nginx -t
 
# 输出示例:
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
 
# 检查并显示所有配置
sudo nginx -T
 
# 检查指定配置文件
sudo nginx -t -c /path/to/custom/nginx.conf

详细检查

# 查看配置文件路径
sudo nginx -t 2>&1 | grep "configuration file"
 
# 查看 include 的文件列表
sudo nginx -T | grep -E "^# configuration file"
 
# 统计配置指令数量
sudo nginx -T | grep -v "^#" | wc -l

常见问题检查

# 1. 检查括号匹配
cat /etc/nginx/nginx.conf | grep -o "[{}]" | sort | uniq -c
# 应该成对出现
 
# 2. 检查分号缺失
grep -n "[^;]$" /etc/nginx/nginx.conf | grep -v "#" | grep -v "{$"
 
# 3. 检查重复监听端口
grep -r "listen.*80" /etc/nginx/
 
# 4. 检查 server_name 重复
grep -r "server_name" /etc/nginx/sites-enabled/

热更新原理

Master-Worker 模型

热更新过程:

阶段 1: 检查配置
Master 进程读取新配置 → 验证语法 → 加载配置

阶段 2: 启动新 Worker
Master 进程启动新的 Worker 进程(使用新配置)

阶段 3: 切换流量
新 Worker 进程开始接受新连接
旧 Worker 进程停止接受新连接

阶段 4: 优雅停止旧 Worker
旧 Worker 进程处理完当前请求后退出

阶段 5: 完成更新
所有旧 Worker 进程退出,更新完成

信号处理

# Master 进程接收信号
 
HUP (Hang Up):
- 重载配置文件
- 启动新的 Worker 进程
- 优雅停止旧的 Worker 进程
- 不中断服务
 
USR2:
- 平滑升级 Nginx 二进制文件
- 启动新的 Master 进程
- 逐步切换流量
 
WINCH:
- 优雅停止 Worker 进程
- 用于配合 USR2 完成平滑升级
 
QUIT:
- 优雅停止整个 Nginx
- 处理完当前请求后退出

热更新方法

方法一: Reload 命令(推荐)

# 1. 检查配置
sudo nginx -t
 
# 2. 如果检查通过,重载配置
sudo systemctl reload nginx
# 或
sudo nginx -s reload
 
# 3. 验证是否成功
sudo systemctl status nginx
 
# 4. 查看 Worker 进程
ps aux | grep nginx

方法二: 直接向 Master 进程发送信号

# 1. 获取 Master 进程 PID
MASTER_PID=$(cat /var/run/nginx.pid)
 
# 2. 检查配置
sudo nginx -t
 
# 3. 发送 HUP 信号
sudo kill -HUP $MASTER_PID
 
# 4. 验证
ps aux | grep nginx

方法三: 使用脚本自动化

#!/bin/bash
# nginx-reload.sh
 
echo "检查 Nginx 配置..."
nginx -t
if [ $? -ne 0 ]; then
    echo "配置检查失败,请检查配置文件"
    exit 1
fi
 
echo "配置检查通过,正在重载..."
systemctl reload nginx
if [ $? -eq 0 ]; then
    echo "Nginx 重载成功"
else
    echo "Nginx 重载失败"
    exit 1
fi
 
echo "当前 Nginx 进程:"
ps aux | grep nginx

方法四: 配置自动生成和热更新

#!/bin/bash
# auto-deploy.sh
 
CONFIG_DIR="/etc/nginx"
BACKUP_DIR="/backup/nginx/$(date +%Y%m%d_%H%M%S)"
 
# 创建备份
echo "创建配置备份..."
mkdir -p $BACKUP_DIR
cp -r $CONFIG_DIR/* $BACKUP_DIR/
 
# 生成配置
echo "生成 Nginx 配置..."
generate_nginx_config() {
    # 这里调用你的配置生成脚本
    python3 /path/to/generate_config.py
}
 
generate_nginx_config
if [ $? -ne 0 ]; then
    echo "配置生成失败"
    exit 1
fi
 
# 检查配置
echo "检查 Nginx 配置..."
nginx -t
if [ $? -ne 0 ]; then
    echo "配置检查失败,回滚配置..."
    cp -r $BACKUP_DIR/* $CONFIG_DIR/
    exit 1
fi
 
# 热更新
echo "执行热更新..."
systemctl reload nginx
if [ $? -eq 0 ]; then
    echo "热更新成功"
else
    echo "热更新失败,回滚配置..."
    cp -r $BACKUP_DIR/* $CONFIG_DIR/
    systemctl reload nginx
    exit 1
fi
 
echo "部署完成"

配置回滚

手动回滚

# 1. 备份当前配置(如果更新失败)
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
 
# 2. 恢复之前的配置
sudo cp /etc/nginx/nginx.conf.backup /etc/nginx/nginx.conf
 
# 3. 检查配置
sudo nginx -t
 
# 4. 重载配置
sudo systemctl reload nginx

自动备份和回滚脚本

#!/bin/bash
# backup-and-rollback.sh
 
BACKUP_DIR="/backup/nginx"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
 
# 创建备份
backup_config() {
    echo "创建配置备份..."
    mkdir -p $BACKUP_DIR
    tar -czf $BACKUP_DIR/nginx_config_$TIMESTAMP.tar.gz \
        -C /etc/nginx .
    echo "备份完成: $BACKUP_DIR/nginx_config_$TIMESTAMP.tar.gz"
}
 
# 列出备份
list_backups() {
    echo "可用备份:"
    ls -la $BACKUP_DIR/*.tar.gz
}
 
# 回滚配置
rollback_config() {
    local backup_file=$1
    if [ -z "$backup_file" ]; then
        echo "请指定备份文件"
        list_backups
        exit 1
    fi
 
    echo "正在回滚配置: $backup_file"
 
    # 创建当前配置备份
    backup_config
 
    # 恢复配置
    cd /etc/nginx
    tar -xzf $backup_file
 
    # 检查配置
    nginx -t
    if [ $? -ne 0 ]; then
        echo "配置检查失败,自动恢复上次备份"
        # 恢复上次的备份
        # ...
        exit 1
    fi
 
    # 重载配置
    systemctl reload nginx
    echo "回滚完成"
}
 
# 主逻辑
case $1 in
    backup)
        backup_config
        ;;
    list)
        list_backups
        ;;
    rollback)
        rollback_config $2
        ;;
    *)
        echo "用法: $0 {backup|list|rollback <backup_file>}"
        exit 1
        ;;
esac

使用 Git 进行版本控制

# 1. 初始化 Git 仓库
cd /etc/nginx
sudo git init
 
# 2. 添加所有配置
sudo git add .
 
# 3. 提交初始版本
sudo git commit -m "Initial configuration"
 
# 4. 配置 git
sudo git config user.email "admin@example.com"
sudo git config user.name "Nginx Admin"
 
# 5. 修改配置后提交
sudo git add .
sudo git commit -m "Update virtual host configuration"
 
# 6. 查看历史
sudo git log
 
# 7. 回滚到指定版本
sudo git reset --hard <commit_id>
sudo nginx -t && sudo systemctl reload nginx

自动化部署

使用 CI/CD 自动部署

# .github/workflows/deploy-nginx.yml
name: Deploy Nginx Configuration
 
on:
  push:
    branches:
      - main
    paths:
      - 'nginx-configs/**'
 
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
 
      - name: Deploy to server
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          source: "nginx-configs/*"
          target: "/tmp/nginx-configs"
 
      - name: Reload Nginx
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            # 备份当前配置
            sudo cp -r /etc/nginx /etc/nginx.backup.$(date +%Y%m%d_%H%M%S)
 
            # 复制新配置
            sudo cp -r /tmp/nginx-configs/* /etc/nginx/
 
            # 检查配置
            sudo nginx -t
 
            # 如果检查通过,重载配置
            if [ $? -eq 0 ]; then
              sudo systemctl reload nginx
              echo "Nginx 配置部署成功"
            else
              echo "Nginx 配置检查失败"
              exit 1
            fi

Ansible 自动化部署

# ansible/deploy-nginx.yml
---
- name: Deploy Nginx Configuration
  hosts: webservers
  become: yes
 
  tasks:
    - name: Backup current configuration
      shell: |
        cp -r /etc/nginx /backup/nginx.$(date +%Y%m%d_%H%M%S)
      args:
        executable: /bin/bash
 
    - name: Copy nginx configuration
      copy:
        src: "{{ item }}"
        dest: "/etc/nginx/"
        owner: root
        group: root
        mode: '0644'
      with_fileglob:
        - "../nginx-configs/*"
 
    - name: Check nginx configuration
      command: nginx -t
      register: nginx_test
      failed_when: nginx_test.rc != 0
 
    - name: Reload nginx if configuration is valid
      service:
        name: nginx
        state: reloaded
      when: nginx_test.rc == 0

Docker + Nginx 热更新

#!/bin/bash
# docker-nginx-reload.sh
 
CONTAINER_NAME="nginx-web"
CONFIG_DIR="/path/to/nginx/config"
 
# 1. 检查配置(使用临时容器)
docker run --rm \
  -v $CONFIG_DIR:/etc/nginx:ro \
  nginx:latest nginx -t
 
if [ $? -ne 0 ]; then
  echo "配置检查失败"
  exit 1
fi
 
# 2. 复制新配置到运行中的容器
echo "复制配置到容器..."
docker cp $CONFIG_DIR/nginx.conf $CONTAINER_NAME:/etc/nginx/nginx.conf
docker cp $CONFIG_DIR/conf.d $CONTAINER_NAME:/etc/nginx/conf.d
 
# 3. 重载配置
echo "重载 Nginx 配置..."
docker exec $CONTAINER_NAME nginx -s reload
 
echo "热更新完成"

🔧 高级技巧

零停机部署策略

#!/bin/bash
# zero-downtime-deploy.sh
 
BACKUP_DIR="/backup/nginx"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
 
# 1. 创建备份
echo "创建备份..."
mkdir -p $BACKUP_DIR
tar -czf $BACKUP_DIR/nginx_before_$TIMESTAMP.tar.gz -C /etc/nginx .
 
# 2. 验证配置
echo "验证配置..."
sudo nginx -t
if [ $? -ne 0 ]; then
  echo "配置验证失败"
  exit 1
fi
 
# 3. 逐步更新(滚动更新)
echo "开始滚动更新..."
 
# 获取当前 worker 进程数
OLD_WORKERS=$(pgrep -f "nginx: worker process" | wc -l)
 
# 发送 USR2 信号(启动新 master)
sudo kill -USR2 $(cat /var/run/nginx.pid)
 
# 等待新 worker 启动
sleep 5
 
NEW_WORKERS=$(pgrep -f "nginx: worker process" | wc -l)
echo "Worker 进程数: $OLD_WORKERS -> $NEW_WORKERS"
 
# 4. 验证新版本
if [ $NEW_WORKERS -gt $OLD_WORKERS ]; then
  echo "新版本启动成功,正在测试..."
 
  # 测试请求
  for i in {1..10}; do
    curl -f http://localhost/health || {
      echo "健康检查失败,开始回滚"
      sudo kill -QUIT $(cat /var/run/nginx.pid.oldbin)
      exit 1
    }
  done
 
  echo "健康检查通过"
 
  # 优雅停止旧 worker
  sudo kill -WINCH $(cat /var/run/nginx.pid.oldbin)
 
  # 等待旧 worker 退出
  sleep 10
 
  # 停止旧 master
  sudo kill -QUIT $(cat /var/run/nginx.pid.oldbin)
 
  echo "零停机部署完成"
else
  echo "新版本启动失败"
  exit 1
fi

配置变更通知

#!/bin/bash
# config-change-notify.sh
 
# Slack 通知
notify_slack() {
  local message=$1
  local webhook="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
 
  curl -X POST -H 'Content-type: application/json' \
    --data "{\"text\":\"$message\"}" \
    $webhook
}
 
# 检查配置变更
LAST_CHECK=$(date +%s)
while true; do
  find /etc/nginx -name "*.conf" -newermt "@${LAST_CHECK}" | while read file; do
    echo "检测到配置变更: $file"
 
    # 检查配置
    if nginx -t 2>/dev/null; then
      # 自动重载
      systemctl reload nginx
 
      # 发送通知
      notify_slack "✅ Nginx 配置已自动更新: $(basename $file)"
    else
      notify_slack "❌ Nginx 配置检查失败: $(basename $file)"
    fi
  done
 
  LAST_CHECK=$(date +%s)
  sleep 60  # 每分钟检查一次
done

相关笔记