CentOS不再维护,换用Alma Linux 来部署了 Flask 应用,一切看起来都很顺畅,可访问 URL 时却报了——502 Bad Gateway!从头检查了配置、权限、日志,全都无济于事。于是尝试输入 sudo setenforce 0,应用居然能正常访问了!
是不是觉得SELinux就是没事找事的东西,但实际上它是在执行它的安全职责,禁用只是你放开了安全策略。今天我们就来看看这个问题。
默认情况下SELinux会拦截Nginx连接Gunicorn的Unix套接字;systemd从/home目录启动Gunicorn,应用通过SMTP发送邮件。上面这些他都拦。那么怎么来判断是不是SELinux干的活的?通过两个命令定位问题
# 查看 SELinux 拦截的操作sudo ausearch -m avc -ts recent# 查看服务日志sudo journalctl -u your-service -n 50 --no-pager
如果日志重出现"Permission denied with code 203/EXEC",那就是SELinux在拦截。
接下来我们看看解决方案,首先将Web迁移到/var/www目录,SELinux对Web应用放在/home目录非常的敏感
sudo systemctl stop your-service # 停止应用服务sudo mkdir -p /var/www # 创建目标目录sudo mv /home/user/my-app /var/www/my-app # 迁移应用sudo chown -R user:user /var/www/my-app # 设置目录权限sudo restorecon -Rv /var/www/my-app # SELinux 权限重置(关键一步)
然后编辑systemd服务文件/etc/systemd/system/your-service.service,替换为以下内容:
[Unit]Description=Gunicorn for Flask app # 服务描述After=network.target # 网络启动后再启动该服务[Service]User=your-user # 运行服务的用户Group=your-group # 运行服务的用户组WorkingDirectory=/var/www/my-app # 应用工作目录# 启动前准备:创建套接字目录、设置权限ExecStartPre=/usr/bin/mkdir -p /var/run/my-appExecStartPre=/usr/bin/chown your-user:nginx /var/run/my-appExecStartPre=/usr/bin/chmod 755 /var/run/my-appEnvironment="PATH=/var/www/my-app/venv/bin" # 虚拟环境路径# Gunicorn 启动命令ExecStart=/var/www/my-app/venv/bin/gunicorn \ --workers 4 \ # 工作进程数(根据服务器配置调整) --bind unix:/var/run/my-app/my-app.sock \ # 绑定 Unix 套接字 --umask 007 \ # 设定文件创建权限掩码 wsgi:app # 应用入口(wsgi.py 中的 app 实例)Restart=always # 服务异常时自动重启[Install]WantedBy=multi-user.target # 多用户模式下启动
配置完成后重载systemd配置
sudo systemctl deamon-reload
配置SELinux上下文,告诉哪些是合法操作,避免被误拦截:
# 配置套接字目录的 SELinux 上下文(标记为合法的 Web 服务运行目录)sudo semanage fcontext -a -t httpd_var_run_t "/var/run/my-app(/.*)?"sudo restorecon -Rv /var/run/my-app# 允许 Nginx 进行网络连接sudo setsebool -P httpd_can_network_connect 1
创建定义专属放行策略:
# 临时切换到宽容模式(让应用正常运行以生成拦截记录)sudo setenforce 0# 重启应用,触发可能的 SELinux 拦截(生成日志)sudo systemctl restart your-servicesleep 5 # 等待 5 秒,让应用稳定运行curl http://localhost # 访问应用,触发相关操作# 根据拦截日志生成自定义策略(my_policy 是策略名称,可自定义)sudo ausearch -m avc -ts recent | audit2allow -M my_policy# 安装自定义策略sudo semodule -i my_policy.pp# 切回强制模式(恢复 SELinux 安全防护)sudo setenforce 1# 重启服务,验证效果sudo systemctl restart your-service
audit2allow工具会分析所有SELinux的拦截记录,生成一个允许这些操作的策略文件,安装后,SELinux就知道哪些是合法操作了。
接下来编辑Nginx反向代理,修改/etc/nginx/conf.d下的.conf文件:
upstream app_server { # 连接 Gunicorn 的 Unix 套接字(与 systemd 配置中的路径一致) server unix:/var/run/my-app/my-app.sock fail_timeout=0;}server { listen 80; # 监听 80 端口 server_name my-domain.com; # 你的域名或服务器 IP location / { proxy_pass http://app_server; # 反向代理到 Gunicorn proxy_set_header Host $host; # 传递主机头信息 proxy_set_header X-Real-IP $remote_addr; # 传递真实客户端 IP }}
配置完成后,验证并重载Nginx
sudo nginx -t # 验证配置是否正确sudo systemctl reload nginx # 重载 Nginx 配置
以下是一些常见问题的快速修复方式
无法发送邮件:执行 sudo setsebool -P httpd_can_sendmail 1外部数据库连接被拦截:sudo setsebool -P httpd_can_network_connect_db 1API 调用失败:sudo setsebool -P httpd_can_network_connect 1
# 检查 SELinux 模式(应显示 "Enforcing",即强制模式)getenforce# 检查应用服务状态(应显示 "active (running)")sudo systemctl status your-service# 检查是否还有 SELinux 拦截记录(无输出即正常)sudo ausearch -m avc -ts recent# 测试应用访问(应返回 200 OK)curl -I http://your-domain.com
总之,遇到问题,千万别甩锅给SELinux,它在生产环境中起到关键的作用,遇到问题找到原因,解决它才是我们的目的。