在 Rocky Linux 9 上部署 Vue 应用并配合 Nginx 反向代理后端 API(如 localhost:5000)时,SELinux 是关键的安全机制,若忽略其策略,即使配置正确也会因权限拒绝导致 403 或 502 错误。
下面是一份 完整、安全、考虑 SELinux 的部署教程,涵盖:
- 将 Vue 静态文件部署到自定义目录(非
/usr/share/nginx/html) - 配置 Nginx 提供前端访问
- 代理
/api请求到本地后端服务(127.0.0.1:5000) - 正确设置 SELinux 上下文和布尔值
🔧 前提条件
- 已构建好 Vue 项目(有
dist/目录) - 后端服务正在运行并监听
127.0.0.1:5000 - 服务器可联网,具备
sudo权限
步骤 1:安装必要软件
# 安装 EPEL(提供额外工具)
sudo dnf install -y epel-release
# 安装 Nginx
sudo dnf install -y nginx
# 安装 SELinux 管理工具(用于设置文件上下文和端口)
sudo dnf install -y policycoreutils-python-utils
# 启动 Nginx 并设为开机自启
sudo systemctl enable --now nginx
步骤 2:部署 Vue 静态文件到自定义目录(例如 /var/www/vue-app)
# 创建目录
sudo mkdir -p /var/www/vue-app
# 假设你的 dist 在 ~/my-vue-project/dist
sudo cp -r ~/my-vue-project/dist/* /var/www/vue-app/
# 设置属主(推荐使用 nginx 用户)
sudo chown -R nginx:nginx /var/www/vue-app
⚠️ 注意:不要用 root 拥有 Web 内容,避免安全风险。
步骤 3:修复 SELinux 文件上下文(关键!)
默认情况下,/var/www/vue-app 的 SELinux 上下文不是 httpd_sys_content_t,Nginx(即 httpd)无法读取。
# 查看当前上下文(可选)
ls -Z /var/www/vue-app
# 设置正确的 SELinux 上下文(递归)
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/vue-app(/.*)?"
# 应用上下文
sudo restorecon -Rv /var/www/vue-app
✅ 执行后,Nginx 才能合法读取该目录下的静态文件。
步骤 4:配置 Nginx 站点(支持前端 + API 代理)
创建配置文件:
sudo vi /etc/nginx/conf.d/vue-app.conf
内容如下:
server {
listen 80;
server_name _; # 匹配任意主机名,或替换为你的域名
root /var/www/vue-app;
index index.html;
# 前端路由支持(Vue Router history 模式)
location / {
try_files $uri $uri/ /index.html;
}
# 代理 API 请求到本地后端(如 Flask/FastAPI 运行在 5000)
location /api {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 强制禁止缓存(覆盖后端可能遗漏的情况)
add_header Cache-Control "no-store, no-cache, must-revalidate, private" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
}
}
📌 注意:
proxy_pass末尾不要加/,除非你明确需要路径重写。
测试并重载:
sudo nginx -t
sudo systemctl reload nginx
步骤 5:配置 SELinux 允许 Nginx 连接后端端口(关键!)
默认 SELinux 禁止 Nginx 向任意端口发起网络连接(包括 127.0.0.1:5000)。
启用布尔值:
# 永久允许 Nginx 发起网络连接
sudo setsebool -P httpd_can_network_connect on
✅ 这一步是解决
502 Bad Gateway或Permission denied while connecting to upstream的关键!
验证:
getsebool httpd_can_network_connect
# 应输出:httpd_can_network_connect --> on
步骤 6:开放防火墙(仅需 80 端口)
因为 API 是本地回环通信(127.0.0.1:5000),不需要对外暴露 5000 端口。
只需开放 HTTP:
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload
🔒 后端服务应绑定
127.0.0.1:5000(而非0.0.0.0),确保不被外网直接访问。
步骤 7:验证部署
1. 访问前端:
curl http://localhost
# 应返回 Vue 的 index.html
2. 测试 API 代理:
curl http://localhost/api/health
# 应返回后端服务的响应(假设你有 /api/health 接口)
3. 检查日志(如有问题):
# Nginx 错误日志
sudo tail -f /var/log/nginx/error.log
# SELinux 拒绝日志(关键!)
sudo ausearch -m avc -ts recent
# 或
sudo grep nginx /var/log/audit/audit.log | audit2why
🛡️ 安全建议总结
| 项目 | 推荐做法 |
|---|---|
| 静态文件目录 | 使用/var/www/your-app,非默认目录也可 |
| 文件权限 | 属主为nginx:nginx,权限 644/755 |
| SELinux 文件上下文 | httpd_sys_content_t |
| SELinux 网络连接 | 启用httpd_can_network_connect |
| 后端绑定地址 | 127.0.0.1:5000(禁止公网访问) |
| 防火墙 | 仅开放 80/443 |
✅ 最终效果
- 用户访问
http://your-server-ip/→ 显示 Vue 前端 - 前端请求
POST /api/login→ 被 Nginx 代理到http://127.0.0.1:5000/login - 全程符合 SELinux 安全策略,无权限错误