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
相关产品推荐
相关产品推荐

