You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nginx子进程打开父进程创建文件时遇errno=13权限拒绝问题

Nginx主进程创建文件后子进程权限拒绝问题解决

问题根源

Nginx的主进程通常以root用户启动(绑定80/443端口需要root权限),但子进程会自动切换到Nginx配置文件中user指令指定的普通用户(默认一般是www-data或nginx)运行,这是Nginx的安全设计。你在主进程中创建的文件属主是root,即使权限设为0766,普通用户身份的子进程也没有读写该文件的权限,因此会返回errno=13(Permission denied)。

而普通父子进程案例中,父子进程默认使用同一用户身份运行,所以不会出现这个权限问题。

解决方案

1. 修改文件属主为Nginx子进程运行用户(推荐)

在主进程创建文件后、关闭文件描述符前,调用fchown()将文件的属主和属组修改为Nginx子进程的运行用户。这样子进程就能正常读写文件。

示例修改后的主进程代码:

#include <unistd.h>
#include <pwd.h>

u_char* shared_addr = NULL; 
int map_my_file(const char* path)
{
    extern int errno;
    umask(0);
    int fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0766);
    if (fd < 0)
    {
        ngx_log_stderr(0, "open file failed %s, %d", path, errno);
        return -1;
    }

    // 获取Nginx子进程运行用户的uid和gid,替换为你配置中的用户(比如nginx/www-data)
    struct passwd *pw = getpwnam("www-data");
    if (pw != NULL) {
        if (fchown(fd, pw->pw_uid, pw->pw_gid) < 0) {
            ngx_log_stderr(0, "fchown failed %d", errno);
            close(fd);
            unlink(path); // 清理创建失败的文件
            return -1;
        }
    }

    if (ftruncate(fd, 1024 * 1024) < 0)
    {
        ngx_log_stderr(0, "ftruncate %d failed", fd);
        close(fd);
        unlink(path);
        return -1;
    }
    shared_addr = (u_char*)mmap(NULL, 1024 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    close(fd);
    return 0;
}

2. 调整文件权限(不推荐,存在安全风险)

如果不想修改属主,可以将文件权限设为0777,让所有用户都能读写。但这种方式会带来严重的安全隐患,生产环境禁止使用。

修改主进程中的open调用:

int fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0777);

3. 取消Nginx子进程降权(强烈不推荐)

将Nginx配置文件中的user指令改为root,让子进程以root身份运行。这种方式完全违背了Nginx的安全设计,可能导致服务器被入侵,绝对不建议使用。

额外注意事项

子进程中使用相对路径./t.log可能存在工作目录不一致的问题,建议改为绝对路径(比如/var/tmp/t.log),避免因路径找不到导致的权限类错误混淆排查。

内容的提问来源于stack exchange,提问作者Klen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 18:22:46