权限被拒绝 - nginx 和 uwsgi socket

61

目前我正在尝试使用nginx和uwsgi提供django应用程序服务。我目前正在使用虚拟环境安装了uwsgi。然而,当我尝试访问页面时,目前出现502错误网关。

我遇到的错误。

2014/02/27 14:20:48 [crit] 29947#0: *20 connect() to unix:///tmp/uwsgi.sock failed (13: Permission denied) while connecting to upstream, client: 144.136.65.176, server: domainname.com.au, request: "GET /favicon.ico HTTP/1.1", upstream: "uwsgi://unix:///tmp/uwsgi.sock:", host: "www.domainname.com.au"

这是我的nginx.conf文件

    # mysite_nginx.conf

# the upstream component nginx needs to connect to
upstream django {
    server unix:///tmp/uwsgi.sock; # for a file socket
    #server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}

# configuration of the server
server {
    # the port your site will be served on
    listen      80;
    # the domain name it will serve for
    server_name .domainname.com.au; # substitute your machine's IP address or FQDN
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste

    # Django media
    location /media  {
        alias /home/deepc/media;  # your Django project's media files - amend as required
    }

    location /static {
        alias /home/deepc/static; # your Django project's static files - amend as required
    }

    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        include     /home/deepc/.virtualenvs/dcwebproj/dcweb/uwsgi_params; # the uwsgi_params file you installed
    }
}

这是我的uwsgi.ini文件

[uwsgi]
socket=/tmp/uwsgi.sock
chmod-socket=644
uid = www-data
gid = www-data

chdir=/home/deepc/.virtualenvs/dcwebproj/dcweb
module=dcweb.wsgi:application
pidfile=/home/deepc/.virtualenvs/dcwebproj/dcweb.pid
vacuum=true
根据我在 Google 上的阅读,这似乎是与 www-data 组和 /tmp/ 目录的权限问题有关。然而,我对此还很陌生,并尝试更改文件夹的权限级别,但无济于事。请问是否有人可以指点一下方向?这是权限问题吗?
另外,将 sock 文件放在 tmp 目录中是否可行?
谢谢。

尝试将 chmod-socket=644 更改为 666?我不确定。 - Hunger
1
原因是nginx无法访问sock文件。确保启动uwsgi的用户组与nginx组(默认为www-data)相同,以便nginx可以访问sock文件,然后一切都会正常。usermod -g www-data username。希望有所帮助。 - Jiangshi Fresh
11个回答

66
我认为你只需要将你的 socket 文件更改为 666(664 对于 www-data 来说也可以),或者删除它并重新运行 uwsgi 服务器。
在我的 uwsgi.ini 中:
chmod-socket = 664
uid = www-data
gid = www-data

1
我已经设置了这个,并尝试在二进制文件上使用标志(--uid www-data --gid www-data),但它似乎忽略了它们。有什么想法为什么会这样? - Chockomonkey
2
@Chockomonkey,你在命令行中运行了uwsgi(带有--uid www-data --gid www-data)吗?它将仅使用当前用户启动进程。在我的项目中,我只是按照http://uwsgi-docs.readthedocs.org/en/latest/Upstart.html的说明进行操作,init脚本将作为服务器运行我的uwsgi,进程/套接字/pid上的用户将是www-data。如果有不清楚的地方,请告诉我,谢谢。 - gzerone
1
感谢您的澄清。您是正确的,当我通过命令行运行它时,它会忽略--uid和--gid标志。所以至少这部分现在有意义了,耶!然而,我仍然无法正确地使用Upstart运行Emperor。请参见https://dev59.com/7onca4cB1Zd3GeqP5QvA - Chockomonkey
先生,您真是位绅士和学者。我不得不在我的uwsgi.ini文件中添加uid/gid标志。 - skift
1
真是个传奇,谢谢!如何调试这种问题最好的方法是什么?不像nginx在其日志中抱怨缺少权限一样。 - tonysepia
显示剩余2条评论

40

哇,这个问题花了我一整天的时间!

我使用的是 uwsgi 2.0.14, nginx 1.10.1, django 1.10

总之,最重要的是确保以下两个用户都对socket文件有rwx权限:

  1. nginx用户;
  2. uWSGI用户;

所以,您可以逐一检查它们。


首先,您可以在不运行uwsgi的情况下刷新url:http://192.168.201.210:8024/morning/,并检查web服务器nginx是否具有权限。如果您看到类似于/var/log/nginx/error.log No such file or directory的内容:

2016/10/14 16:53:49 [crit] 17099#0: *19 connect() to unix:///usr/share/nginx/html/test/helloworld.sock failed (2: No such file or directory) while connecting to upstream, client: 192.168.201.140, server: belter-tuesday.com, request: "GET /morning/ HTTP/1.1", upstream: "uwsgi://unix:///usr/share/nginx/html/test/helloworld.sock:", host: "192.168.201.210:8024"

只需创建一个名为 helloworld.sock 的文件,然后刷新URL并再次检查日志文件,如果您在日志文件中看到 Permission denied ,就像这样:

只需要创建一个名为helloworld.sock的文件,然后刷新URL并再次检查日志文件,如果您在日志文件中看到Permission denied,就像这样:

2016/10/14 17:00:45 [crit] 17099#0: *22 connect() to unix:///usr/share/nginx/html/test/helloworld.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.201.140, server: belter-tuesday.com, request: "GET /morning/ HTTP/1.1", upstream: "uwsgi://unix:///usr/share/nginx/html/test/helloworld.sock:", host: "192.168.201.210:8024"

这意味着Web服务器nginx没有读取、写入和执行所有的权限。因此,您可以授予该文件权限:

sudo chmod 0777 helloworld.sock

然后,刷新URL并再次检查日志文件,如果在日志文件中看到连接被拒绝,就像这样:

2016/10/14 17:09:28 [error] 17099#0: *25 connect() to unix:///usr/share/nginx/html/test/helloworld.sock failed (111: Connection refused) while connecting to upstream, client: 192.168.201.140, server: belter-tuesday.com, request: "GET /morning/ HTTP/1.1", upstream: "uwsgi://unix:///usr/share/nginx/html/test/helloworld.sock:", host: "192.168.201.210:8024"

这是一个好的信号,它意味着您的Web服务器nginx从现在开始有使用helloworld.sock文件的权限。


接下来运行uwsgi并检查uwsgi用户是否有使用helloworld.sock的权限。首先删除我们之前创建的helloworld.sock文件。

运行uwsgi:uwsgi --socket /usr/share/nginx/html/test/helloworld.sock --wsgi-file wsgi.py

如果您看到bind(): Permission denied [core/socket.c line 230],这意味着uwsgi无权绑定helloworld.sock。这是目录test的问题,即helloworld.sock的父目录。

sudo chmod 0777 test/

现在,您已经成功运行了uwsgi

但是,也许你仍然看到了502 Bad Gateway,这太可怕了,我整天都在看到它。如果您再次检查error.log文件,您会再次看到以下内容:

2016/10/14 17:33:00 [crit] 17099#0: *28 connect() to unix:///usr/share/nginx/html/test/helloworld.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.201.140, server: belter-tuesday.com, request: "GET /morning/ HTTP/1.1", upstream: "uwsgi://unix:///usr/share/nginx/html/test/helloworld.sock:", host: "192.168.201.210:8024"

有什么问题吗?

检查helloworld.sock文件的详细信息,您可以看到:

srwxr-xr-x. 1 belter mslab       0 Oct 14 17:32 helloworld.sock

uWSGI会自动给这个文件赋予755权限。

您可以通过添加 --chmod-socket 来更改它:

uwsgi --socket /usr/share/nginx/html/test/helloworld.sock --wsgi-file wsgi.py --chmod-socket=777

好的!最后,您可以看到:

成功查看网页信息


要点:

  1. uwsgi_params文件的位置不重要;
  2. 由于我的nginx用户和uwsgi用户不同甚至不在同一组中,因此我需要给helloworld.sock及其父目录test/赋予777权限;
  3. 如果将helloworld.sock文件放在您的主目录中,您将始终收到拒绝访问的错误消息。
  4. 有两个地方需要设置socket文件路径,一个是nginx配置文件,对我而言是helloworld_nginx.conf;另一个是运行uwsgi时。
  5. 检查SELinux

这是我的helloworld_nginx.conf文件:

# helloworld_nginx.conf
upstream django {
    server unix:///usr/share/nginx/html/test/helloworld.sock; # for a file socket
    # server 127.0.0.1:5902; # for a web port socket (we'll use this first)
}

# configuration of the server
server {
    # the port your site will be served on
    listen      8024;
    # the domain name it will serve for
    server_name .belter-tuesday.com; # substitute your machine's IP address or FQDN
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste

    # Finally, send all non-media requests to the Django server.
    location /morning {
        include     uwsgi_params;
        uwsgi_pass  django;
    }
}

2
虽然我认为0777太宽松了,你应该找到更好的方法来给予正确的用户权限,而不是向所有用户开放,但是你的解释非常好,帮助我追踪问题。 - shanemgrey
当我运行uwsgi --socket /tmp/mysite.sock --wsgi-file wsgi.py时,它显示 !!! no internal routing support, rebuild with pcre support !!! *** 警告:您正在运行没有主进程管理器的uWSGI *** 锁引擎:pthread鲁棒互斥锁 thunder lock:已禁用(您可以使用--thunder-lock启用它) 错误删除unix套接字,unlink():操作不允许[core/socket.c line 198] bind():地址已在使用中[core/socket.c line 230] - Arti Berde
你可以更改目录,而不是使用/tmp作为你的套接字文件,请再试一次。 - Belter
我的套接字文件内容为 helloworld.sock: 没有这样的设备或地址,而且我的网页无响应。 - darth vader

12

在CentOS上,我尝试了所有这些方法,但仍然没有起作用。最终,我找到了这篇文章:

https://www.nginx.com/blog/nginx-se-linux-changes-upgrading-rhel-6-6/

对于开发机器,我们只需运行:

semanage permissive -a httpd_t

但对于真正的生产服务器,我还没有想出解决方案。 您可能需要尝试上文提到的其他方法。


这个命令解决了我为之奋斗了整整一周的问题,谢谢! - Shaig Khaligli
3
谢谢,这解决了我在CentOS 7上的问题。我需要使用yum install policycoreutils-python来安装semanage。 - Gerg

8
这让我花了很多时间去找权限问题。当然,问题就在权限上。默认用户是nginx。 我做了什么: 在/etc/nginx/nginx.conf中更改用户:
user  www-data;

下一步将您的用户加入到www-data组中:
usermod -a -G www-data yourusername

接下来配置uwsgi:

[uwsgi]
uid = yourusername
gid = www-data
chmod-socket = 660

接着重新启动nginx:

sudo systemctl restart nginx

最后重新启动uwsgi。


3
我曾经为这个问题苦苦挣扎,后来发现我的uwsgi.ini文件中的uid和gid标志没有应用到.sock文件上。
你可以通过运行uwsgi,然后使用Linux命令ls -l检查你的.sock文件的权限来进行测试。
对我来说,解决方法是以sudo身份运行uwsgi:
sudo uwsgi --ini mysite_uwsgi.ini

使用包含标志的.ini文件:

chmod-socket = 664
uid = www-data
gid = www-data

然后,.sock文件的权限是正确的,502 Bad Gateway错误最终消失了!

希望这可以帮到您 :)


2
这个问题让我很疯狂。我的环境是centos7+nginx+uwsgi,使用unix socket连接。 被接受的答案非常好,只需要添加一些要点即可。
ROOT用户,快速测试
首先,关闭selinux,然后将chmod-socket更改为666,最后使用root启动uwsgi。
像这样:
setenforce 0 #turn off selinux
chmod-socket = 666
uwsgi --ini uwsgi.ini

其他用户

如果您使用创建的其他用户启动uwsgi,请确保主目录下的用户文件夹的权限为755,并且所有者和组相对应。

例如:

chmod-socket = 666
usermod -a -G nginx webuser #add webuser to nginx's group
cd /home/
chmod -R 755 webuser
chown -R webuser:webuser webuser
uwsgi --ini uwsgi.ini --gid webuser --uid webuser

1

对于CentOS用户来说,又有一篇很棒的文章:

https://axilleas.me/en/blog/2013/selinux-policy-for-nginx-and-gitlab-unix-socket-in-fedora-19/

尽管CentOS的答案很有用,但问题在于SELinux。
我按照整篇文章的步骤操作了,但解决问题的命令如下:
yum install -y policycoreutils-{python,devel}
grep nginx /var/log/audit/audit.log | audit2allow -M nginx
semodule -i nginx.pp
usermod -a -G user nginx
chmod g+rx /home/user/

请使用实际用户代替“user”以授予权限。对于chmod命令下的目录也适用相同规则。

0

uwsgi.ini

[uwsgi]
uid = yourusername
gid = www-data
chmod-socket = 664

为什么?因为有时应用程序需要读取或写入超出Web服务器可访问范围的文件系统。我不想改变所有权和权限来适应每种情况。我宁愿让我的应用程序以我的身份运行并执行所需操作。将组设置为www-data并将套接字的chmod设置为664允许该组对其进行写入,从而提供Web服务器和应用程序之间唯一必要的通信窗口。

0

只需在nginx配置文件中添加用户名即可正常工作 添加 /etc/nginx/nginx.conf

user user_name www-data;


0
在开发模式下,如果使用root用户,只需按照以下方式设置wsgi.ini或emperor.ini:
uid=root
gid=root

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接