V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
Yangsh853
V2EX  ›  程序员

分享一个遇到的 Nginx 命令引发的故障

  •  
  •   Yangsh853 · 6 小时 30 分钟前 · 261 次点击

    提到 nginx -t 命令,绝大多数人的第一反应是 “测试 Nginx 配置文件语法是否正确”—— 毕竟执行后看到 “syntax is ok” 和 “test is successful”,就默认它只是个 “语法检查工具”。

    图片

    但最近一次线上故障,让我彻底刷新了对这条命令的认知:它居然会悄悄修改服务器目录权限,甚至直接导致业务卡顿崩溃!

    一、突发故障:页面频繁卡顿,日志报满 “权限拒绝”

    某天突然收到业务反馈:某页面多次加载卡顿、频繁报 “502 Bad Gateway”,用户无法正常操作。

    图片

    第一时间查看 Nginx 错误日志,发现大量类似报错,核心信息全是 “权限拒绝”:

    [crit] 421611#421611: *429 open() "/var/lib/nginx/tmp/proxy/664/02/0000000027" failed (13: Permission denied) while reading upstream, client: 
    
    16:48:57 [crit] 421611#421611: *399 open() "/var/lib/nginx/tmp/proxy/666/02/0000000026" failed (13: Permission denied) while reading upstream, client: , server: _, request: "GET /hp-prod/js/dist/block-editor.min.js?ver=b3b0b55b35e04df52f7c HTTP/1.1", upstream: "http://:9080/hp-prod/js/dist/block-editor.min.js?ver=b3b0b55b35e04df52f7c", host: "8.153.203.10", referrer: "http://hppd-admin/post.php"
    

    日志指向很明确:Nginx 要读取 / 写入代理临时文件(/var/lib/nginx/tmp/proxy/)时,没有权限—— 这些临时文件是 Nginx 转发上游服务(如 WordPress 、后端 API )时,用来缓存大响应的关键文件,没权限操作就会导致请求中断。

    二、紧急修复:麻溜恢复业务

    既然是权限问题,先定位 Nginx 的运行用户:

    ps aux | grep nginx
    

    输出显示,Nginx worker 进程的运行用户是 app-u(这是我们之前为了安全,专门创建的低权限账号)。

    再检查临时目录权限:

    ls -ld /var/lib/nginx/tmp/proxy/
    

    结果出乎意料:proxy 目录及所有子文件的属主 / 属组,居然变成了 nobody( Linux 默认的匿名用户)——app-u 对这些文件没有读写权限,自然会报错。

    紧急执行权限修复命令:

    # 递归将临时目录的属主/属组改为 app-u
    chown -R app-u:app-u /var/lib/nginx/tmp/
    # 确保目录有读写执行权限
    chmod -R 755 /var/lib/nginx/tmp/
    

    修复后通知用户重试,页面加载恢复正常,故障暂时解决。

    三、溯源:是谁 “偷偷” 改了权限?

    业务恢复后,核心问题来了:/var/lib/nginx/tmp/ 原本是 app-u 权限,为什么会变成 nobody

    我们翻了故障前 1 小时的服务器操作日志(通过操作记录日志文件),发现一个关键操作:**故障前 2 分钟,有同事用 root 账号执行了 nginx -t -c /path/to/nginx.conf**。

    “不就是测试个配置吗?怎么会改权限?” 带着疑问,去看了当时执行的 nginx.conf,发现配置文件里有一行:

    user nobody;  # 指定 Nginx 运行用户为 nobody
    

    但这里有个矛盾:我们实际启动 Nginx 时,用的是 app-u 账号,且启动命令里没指定配置文件(默认加载 /etc/nginx/nginx.conf,其中 user app-u;)—— 那同事手动指定的这个配置文件,为什么会影响目录权限?

    四、测试验证:nginx -t 居然真的会改权限!

    为了验证猜想,我在测试环境复现了整个过程:

    1. 初始状态:用 app-u 启动 Nginx ,/var/lib/nginx/tmp/ 属主是 app-u,权限正常;
    2. 执行命令:切换到 root 账号,执行 nginx -t -c /path/to/test.conf(这个 test.conf 里配置了 user nobody;);
    3. 检查结果:执行后立即查看 tmp 目录权限 ——proxyclient_body 等子目录的属主,果然从 app-u 变成了 nobody

    至此真相大白: nginx -t 不仅会检查配置语法,还会根据配置文件中的 user 指令,自动创建 / 修复 Nginx 所需的临时目录(如 tmp/proxytmp/client_body),并将这些目录的属主改为 user 指令指定的用户

    之前同事用 root 执行 nginx -t -c 错误配置文件 时,配置里的 user nobody; 触发了 Nginx 的 “目录权限修复” 逻辑 —— 直接把原本 app-u 权限的临时目录,改成了 nobody 权限,最终导致业务故障。

    五、后续整改

    这次故障完全是 “认知盲区” 导致的,后续我们做了 3 项整改,彻底杜绝同类问题:

    1. 规范配置文件:user 指令与运行用户强一致

    所有 Nginx 配置文件的 user 指令,必须与实际启动 Nginx 的账号保持一致 —— 比如用 app-u 启动,就统一写 user app-u;,禁止出现 nobodyroot 等不匹配的用户。

    同时将核心配置文件(如 /etc/nginx/nginx.conf)设为只读,避免误修改:

    chmod 444 /etc/nginx/nginx.conf
    

    2. 平时变更类相关操作禁止使用 root 账号

    3. 日志监控告警:提前发现权限问题

    通过写脚本监控错误日志中的错误关键字,错误次数,一旦触发阈值就告警

    最后:

    以前总觉得 nginx -t 是 “安全无害” 的命令,这次故障才意识到:任何看似简单的命令,都可能藏着你不知道的细节

    尤其是 Nginx 这类高频使用的工具,建议多翻官方文档(比如 nginx -t 的官方说明里其实提到了 “会验证配置相关的目录权限”),避免因 “想当然” 踩坑

    图片

    图片

    mimiphp
        1
    mimiphp  
       5 小时 46 分钟前
    wget -c https://nginx.org/download/nginx-1.27.5.tar.gz
    tar zxvf nginx-1.27.5.tar.gz
    cd nginx-1.27.5 && ls
    make clean
    ./configure \
    --prefix=/usr/local/nginx \
    --user=www \
    --group=www \
    --sbin-path=/usr/local/nginx/sbin/nginx \
    --conf-path=/usr/local/nginx/nginx.conf \
    --error-log-path=/usr/local/nginx/error.log \
    --http-log-path=/usr/local/nginx/access.log \
    --pid-path=/usr/local/nginx/nginx.pid \
    --lock-path=/usr/local/nginx/nginx.lock \
    --http-client-body-temp-path=/usr/local/nginx/client_temp \
    --http-proxy-temp-path=/usr/local/nginx/proxy_temp \
    --http-fastcgi-temp-path=/usr/local/nginx/fastcgi_temp \
    --http-uwsgi-temp-path=/usr/local/nginx/uwsgi_temp \
    --http-scgi-temp-path=/usr/local/nginx/scgi_temp \
    --with-file-aio \
    --with-threads \
    --with-http_addition_module \
    --with-http_auth_request_module \
    --with-http_dav_module \
    --with-http_flv_module \
    --with-http_gunzip_module \
    --with-http_gzip_static_module \
    --with-http_mp4_module \
    --with-http_random_index_module \
    --with-http_realip_module \
    --with-http_secure_link_module \
    --with-http_slice_module \
    --with-http_ssl_module \
    --with-http_stub_status_module \
    --with-http_sub_module \
    --with-http_v2_module \
    --with-mail \
    --with-mail_ssl_module \
    --with-stream \
    --with-stream_realip_module \
    --with-stream_ssl_module \
    --with-stream_ssl_preread_module

    make -j $(nproc)
    make install
    cat <<EOF > /etc/systemd/system/nginx.service
    [Unit]
    Description=nginx
    After=network.target

    [Service]
    Type=forking
    ExecStart=/usr/local/nginx/sbin/nginx
    ExecReload=/usr/local/nginx/sbin/nginx -s reload
    ExecStop=/usr/local/nginx/sbin/nginx -s quit
    PrivateTmp=false

    [Install]
    WantedBy=multi-user.target
    EOF

    mkdir -p /usr/local/nginx/rewrite
    mkdir -p /usr/local/nginx/ssl
    mkdir -p /usr/local/nginx/ssl/default
    mkdir -p /usr/local/nginx/vhost


    这是我编写的编译安装 nginx 的代码片段。。。。我恰恰相反。web 服务器核心组件安装,比如就是 nginx 这个软件安装,必须用 root 权限来安装。执行权限交给 www ,并且是 nologin 账户。。。。普通用户就不应该可以操作修改重启核心组件。

    这里我特别强调就是多用户维护服务器,最好是开放 SSH ,或者 nginx 配置 webdav ,不要再用 FTP 这种明文传输的协议。
    yuedingwangji
        2
    yuedingwangji  
       2 小时 22 分钟前
    既然你专门配置了 app-u 的账号运行 ng 了, 你都不改 ng 配置里面的账号么
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   925 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 21:45 · PVG 05:45 · LAX 14:45 · JFK 17:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.