我们在个人帐号目录下进行日常的开发工作,通常使用弱权限帐号(如:nobody)运行 Web 服务器(如:nginx)。
nginx 配置 Web 服务器的根目录为个人用户目录,这样修改代码后刷新浏览器就可以看到效果。
user nobody; server { listen 80; server_name www.example.com; location / { root /home/tangxinfa/projects/www.example.com; index index.html index.htm; } }
然而 linux 的用户权限系统禁止 Web 服务器用户(nobody)访问个人用户(tangxinfa)的数据。
使用浏览器访问,会得到一个错误页面
403 Forbidden
使用 linux 命令确认问题是由用户权限系统引起
$ sudo -u nobody -g nobody ls -la /home/tangxinfa/projects/www.example.com ls: cannot access '/home/tangxinfa/projects/www.example.com': Permission denied
解决方法有以下几种:
使用软链接
很多人都会下意识地想到通过软链接来解决
sudo ln -s /home/tangxinfa/projects/www.example.com /var/www/ sudo chown -R nobody:nobody /var/www/www.example.com sudo chown -R nobody:nobody /home/tangxinfa/projects/www.example.com
将个人用户目录链到 Web 服务器用户目录下是没有用的,linux 按原始路径(/home/tangxinfa/projects/www.example.com)来检查权限。
可以反过来,将项目从个人用户目录移到 Web 服务器用户目录下,然后反向建一个软链接,即可以让 Web 服务器工作正常,又不影响日常开发。
sudo mv /home/tangxinfa/projects/www.example.com /var/www/ ln -s /var/www/www.example.com /home/tangxinfa/projects/
但是,如果项目是版本控制系统(如:git)仓库的一个子项目(目录),将目录变成软链接后 git 会认为目录被删除了。
用户目录给 Web 服务帐号开放权限
按 linux 的帐号权限系统要求,修改(chmod)用户目录的属性,每一级目录的权限都要修改,容易过渡放开权限,引入安全问题。
设置 Web 服务帐号为用户帐号
user tangxinfa;
由于 Web 服务器(nginx)通常配有多个服务,Web 服务帐号是全局共用的,其它服务的目录权限也要进行调整。如果 nginx 只运行这一个服务的话,还是可行的。
设置 Web 服务帐号为 root 帐号
user root;
使用 root 帐号会引入安全隐患,一般不推荐,但很少会遇到目录权限方面的问题,可以应急使用。
将用户目录挂载到 Web 帐号目录下
mount 命令支持将一个目录重新挂载到其它位置
sudo mkdir /var/www/www.example.com sudo chown nobody:nobody /var/www/www.example.com sudo mount --bind -o ro,username=nobody /home/tangxinfa/projects/www.example.com /var/www/www.example.com
Web 服务器和日常开发可以兼顾,两全其美的方案。
bind 形式的挂载放到 /etc/fstab 会挂载失败(估计是挂载时相关依赖还没有准备好),影响开机。
创建挂载脚本 /usr/sbin/bind-mounts 并添加可执行权限,内容如下
#!/bin/bash mount --bind -o ro,username=nobody /home/tangxinfa/projects/www.example.com /var/www/www.example.com
创建 systemd 服务文件 /usr/lib/systemd/system/bind-mounts.service
[Unit] Description=Bind Mounts After=local-fs.target [Service] Type=simple ExecStart=/usr/sbin/bind-mounts [Install] WantedBy=multi-user.target
启用 bind-mounts 服务
sudo systemctl enable bind-mounts