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 GatewayPermission 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 安全策略,无权限错误