项目部署文档 - Red Hat Enterprise Linux 10.1 虚拟机部署
项目概述
本项目包含两个部分:
- 前端: Vue 3 + Vite + Vant 移动端新闻应用 (端口: 5173)
- 后端: FastAPI + MySQL 新闻API服务 (端口: 8000)
一、环境准备
1.1 系统配置
| 项目 | 最低配置 | 推荐配置 |
|---|---|---|
| CPU | 2核 | 4核 |
| 内存 | 4GB | 8GB |
| 磁盘 | 40GB | 80GB |
| 操作系统 | Red Hat Enterprise Linux 10.1 | RHEL 10.1 |
1.3 安装基础软件
bash
# 安装基础依赖 (Python 3.12 已预装)
sudo dnf install -y python3-pip git curl unzip nginx redis
1.4 创建项目用户
bash
sudo useradd -m -s /bin/bash deploy
sudo mkdir -p /root/xwzx-news
sudo chown -R deploy:deploy /root/xwzx-news
1.5 关闭 SELinux 和配置 Firewalld (可选)
bash
# 临时关闭 SELinux (生产环境建议配置策略)
sudo setenforce 0
# 永久关闭 (需重启)
sudo sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
# 配置防火墙
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-port=8000/tcp
sudo firewall-cmd --reload
二、数据库安装与配置 (MySQL 8.4.8)
2.1 安装 MySQL 8.4.8 (RHEL 10 官方仓库)
RHEL 10 默认仓库没有 mysql-server,需要添加 MySQL 官方 YUM 仓库:
bash
# 1. 下载 MySQL 8.4.8 Yum 仓库 RPM 包
dnf install -y https://dev.mysql.com/get/mysql84-community-release-el10-2.noarch.rpm
# 2. 安装 MySQL 8.4.8
yum install mysql-community-server -y
# 3. 启动并设置开机启动
sudo systemctl start mysqld
sudo systemctl enable mysqld
# 4. 获取临时密码 (首次安装会生成临时密码)
sudo grep 'temporary password' /var/log/mysqld.log
# 5. 登录mysql
mysql -uroot -p".+ky6+LEL<qv"
# 6. 更改root默认密码
alter user 'root'@'localhost' identified by 'MySQL@123';
2.2 导入数据库表结构
bash
# 把前后端的项目代码源文件上传到服务器
[root@localhost ~]# ll
total 208
-rw-------. 1 root root 752 Apr 18 15:36 anaconda-ks.cfg
-rw-r--r--. 1 root root 208012 May 2 16:17 database.sql
drwxr-xr-x. 12 root root 184 May 2 16:05 toutiao_backend
drwxr-xr-x. 5 root root 136 May 2 16:06 xwzx-news
# 导入数据库 (先创建数据库用户)
mysql -uroot -p'MySQL@123' -e "CREATE DATABASE IF NOT EXISTS news_app CHARACTER SET utf8mb4;"
# 导入表结构和数据
mysql -uroot -p'MySQL@123' news_app < database.sql
2.3 数据库表说明
导入的表结构:
user- 用户信息表user_token- 用户令牌表news_category- 新闻分类表news- 新闻表related_news- 相关新闻关联表favorite- 收藏表history- 浏览历史表
三、缓存服务 (Redis)
3.1 安装 Redis (源码编译)
Redis 不在 RHEL 10 默认仓库中,采用源码编译安装:
bash
# 1. 安装编译依赖
sudo dnf install -y gcc make
# 2. 下载 Redis 7.4.2 源码,直接去浏览器下载,然后上传
https://github.com/redis/redis/archive/refs/tags/7.4.2.tar.gz
# 3. 编译安装
tar xzf redis-7.4.2.tar.gz
cd redis-7.4.2
make -j$(nproc)
sudo make install
# 4. 创建配置目录并复制配置文件
sudo mkdir -p /etc/redis
sudo cp redis.conf /etc/redis/
# 5. 修改配置以守护进程运行
sudo sed -i 's/^daemonize no/daemonize yes/' /etc/redis/redis.conf
sudo sed -i 's/^bind 127.0.0.1/bind 0.0.0/' /etc/redis/redis.conf
3.2 启动 Redis
bash
# 直接运行 Redis 服务器
/usr/local/bin/redis-server /etc/redis/redis.conf
# 验证
redis-cli ping
# 应返回: PONG
四、后端部署 (FastAPI)
4.1 安装 Python 虚拟环境依赖
bash
# 进入后端目录
cd toutiao_backend/
# 创建虚拟环境 (RHEL 10 使用 python3)
python3 -m venv venv
# 激活虚拟环境
source venv/bin/activate
# 安装依赖
pip install fastapi uvicorn sqlalchemy aiomysql python-jose passlib==1.7.4 python-multipart pydantic pydantic-settings bcrypt==3.2.2 redis
4.2 修改数据库配置
编辑 config/db_config.py,修改数据库连接信息:
python
# 数据库URL - 使用 localhost,如果密码包含特殊字符需要 URL 编码
# 例如 @ 编码为 %40
ASYNC_DATABASE_URL = "mysql+aiomysql://root:MySQL%40123@localhost:3306/news_app?charset=utf8mb4"
注意:如果 MySQL 允许远程连接,可以使用服务器 IP,但需确保 MySQL 用户有对应主机的权限。
4.3 使用 systemd 管理后端服务
bash
# 创建 systemd 服务文件
sudo cat > /etc/systemd/system/xwzx-news-backend.service << 'EOF'
[Unit]
Description=XWZX News API Backend
After=network.target mysqld.service
[Service]
User=root
Group=root
WorkingDirectory=/root/toutiao_backend
ExecStart=/root/toutiao_backend/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
Restart=always
RestartSec=5
Environment="PYTHONPATH=/root/toutiao_backend"
[Install]
WantedBy=multi-user.target
EOF
# 重新加载 systemd 配置
sudo systemctl daemon-reload
# 启动服务
sudo systemctl start xwzx-news-backend
# 设置开机启动
sudo systemctl enable xwzx-news-backend
# 查看服务状态
sudo systemctl status xwzx-news-backend
4.4 验证后端服务
bash
# 检查服务状态
sudo systemctl status xwzx-news-backend
# 测试 API
curl http://localhost:8000/
# 应返回: {"message":"Hello World"}
五、前端部署 (Vue + Vite)
5.1 安装 Node.js (RHEL 10)
bash
# 使用 NodeSource 仓库安装 Node.js 20 LTS
curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -
sudo dnf install -y nodejs
5.2 前端 API 配置
修改 src/config/api.js,必须使用空字符串:
javascript
// API基础URL配置 - 必须为空字符串
export const apiConfig = {
baseURL: ''
}
注意 :
baseURL不能为/,否则拼接后变成//api/user/register被浏览器当成协议相对 URL,导致请求失败。
5.3 构建前端
bash
cd /root/xwzx-news
# 安装依赖
npm install
# 构建生产版本
npm run build
# 复制到 Nginx 目录
sudo rm -rf /usr/share/nginx/html/xwzx-news
sudo cp -r /root/xwzx-news/dist /usr/share/nginx/html/xwzx-news
# 启动 Nginx
sudo systemctl start nginx
sudo systemctl enable nginx
5.4 nginx反向代理配置
bash
[root@localhost ~]# cat /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name _;
root /usr/share/nginx/html/xwzx-news;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location /api/ {
proxy_pass http://127.0.0.1:8000/api/;
proxy_http_version 1.1;
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;
}
}
}
六、部署检查清单
6.1 服务启动顺序
bash
# 1. 确保 MySQL 运行
sudo systemctl status mysqld
# 2. 启动 Redis
/usr/local/bin/redis-server /etc/redis/redis.conf
# 3. 启动后端 API
sudo systemctl start xwzx-news-backend
# 4. 检查后端是否正常
curl http://localhost:8000/
# 5. 确保 Nginx 运行
sudo systemctl status nginx
6.2 常见问题排查
| 问题 | 解决方法 |
|---|---|
| 后端无法连接数据库 | 检查 MySQL 服务状态 (sudo systemctl status mysqld) 和密码配置 |
| 前端 API 请求失败 | 检查 api.js 中的 baseURL 配置 |
| 502 Bad Gateway | Nginx 无法连接后端,检查后端服务是否运行 |
| 静态资源加载失败 | 检查 Nginx root 路径是否正确 |
| SELinux 拒绝访问 | 执行 sudo setenforce 0 临时关闭,或配置正确的安全上下文 |
6.3 日志查看
bash
# 后端日志
sudo journalctl -u xwzx-news-backend -f
# MySQL 日志
sudo journalctl -u mysqld -f
sudo tail -f /var/log/mysqld.log
# Nginx 日志
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/nginx/access.log
七、安全配置 (生产环境必做)
7.1 修改数据库密码
编辑 config/db_config.py 使用强密码
7.2 配置 CORS
编辑 main.py,将 allow_origins=["*"] 改为具体的前端域名:
python
app.add_middleware(
CORSMiddleware,
allow_origins=["https://your-domain.com"], # 只允许指定域名
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
7.3 配置 Firewalld (RHEL 10)
bash
# 只开放必要端口
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
# 查看当前规则
sudo firewall-cmd --list-all
7.4 SELinux 配置 (RHEL 10 推荐)
建议不要完全关闭 SELinux,而是配置正确的安全上下文:
bash
# 允许 Nginx 访问网络
sudo setsebool -P httpd_can_network_connect 1
# 允许 Nginx 访问后端端口
sudo setsebool -P nhttpd_can_network_connect 1
# 如果需要访问特定目录
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/root/xwzx-news(/.*)?"
sudo restorecon -R /root/xwzx-news
八、快速部署脚本 (RHEL 10)
将以下脚本保存为 deploy.sh 并执行:
bash
#!/bin/bash
set -e
PROJECT_DIR="/root"
DB_NAME="news_app"
DB_ROOT_PASS="MySQL@123"
REDIS_VER="7.4.2"
echo "=== XWZX News 部署脚本 (RHEL 10) ==="
# 1. 安装系统依赖
echo "[1/9] 安装系统依赖..."
sudo dnf install -y python3-pip git curl unzip nginx gcc make
# 2. 安装 MySQL 8.4.8
echo "[2/9] 安装 MySQL 8.4.8..."
curl -fsSL https://dev.mysql.com/get/mysql84-community-release-el10-2.noarch.rpm -o mysql84-community.rpm
sudo dnf install -y mysql84-community.rpm
sudo dnf install -y mysql-community-server
sudo systemctl start mysqld
sudo systemctl enable mysqld
# 3. 配置 MySQL
echo "[3/9] 配置 MySQL..."
echo "等待 MySQL 启动..."
until mysql -e "SELECT 1" &>/dev/null; do
sleep 2
done
sudo mysql -e "CREATE DATABASE IF NOT EXISTS ${DB_NAME} CHARACTER SET utf8mb4;"
sudo mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '${DB_ROOT_PASS}';"
# 4. 导入数据库
echo "[4/9] 导入数据库..."
mysql -uroot -p"${DB_ROOT_PASS}" ${DB_NAME} < /root/database.sql
# 5. 安装 Redis (源码编译)
echo "[5/9] 安装 Redis..."
cd /tmp
curl -fsSL https://github.com/redis/redis/archive/refs/tags/${REDIS_VER}.tar.gz -o redis-${REDIS_VER}.tar.gz
tar xzf redis-${REDIS_VER}.tar.gz
cd redis-${REDIS_VER}
make -j$(nproc)
sudo make install
sudo mkdir -p /etc/redis
sudo cp redis.conf /etc/redis/
sudo sed -i 's/^daemonize no/daemonize yes/' /etc/redis/redis.conf
sudo sed -i 's/^bind 127.0.0.1/bind 0.0.0/' /etc/redis/redis.conf
/usr/local/bin/redis-server /etc/redis/redis.conf
# 6. 创建 Python 虚拟环境
echo "[6/9] 创建 Python 虚拟环境..."
cd ${PROJECT_DIR}/toutiao_backend
python3 -m venv venv
# 创建 requirements.txt
cat > requirements.txt << 'EOF'
fastapi==0.115.0
uvicorn[standard]==0.30.6
sqlalchemy==2.0.35
aiomysql==0.2.0
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4
python-multipart==0.0.12
pydantic==2.9.2
pydantic-settings==2.5.2
bcrypt==3.2.2
redis
EOF
${PROJECT_DIR}/toutiao_backend/venv/bin/pip install -r ${PROJECT_DIR}/toutiao_backend/requirements.txt
# 7. 创建 systemd 服务
echo "[7/9] 创建后端服务..."
sudo cat > /etc/systemd/system/xwzx-news-backend.service << 'EOF'
[Unit]
Description=XWZX News API Backend
After=network.target mysqld.service
[Service]
User=root
Group=root
WorkingDirectory=/root/toutiao_backend
ExecStart=/root/toutiao_backend/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
Restart=always
RestartSec=5
Environment="PYTHONPATH=/root/toutiao_backend"
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable xwzx-news-backend
sudo systemctl start xwzx-news-backend
# 8. 安装 Node.js 并构建前端
echo "[8/9] 构建前端..."
curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -
sudo dnf install -y nodejs
cd ${PROJECT_DIR}/xwzx-news
npm install
npm run build
sudo rm -rf /usr/share/nginx/html/xwzx-news
sudo cp -r ${PROJECT_DIR}/xwzx-news/dist /usr/share/nginx/html/xwzx-news
# 9. 配置 Nginx
echo "[9/9] 配置 Nginx..."
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
sudo cat > /etc/nginx/nginx.conf << 'NGINXCONF'
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name _;
root /usr/share/nginx/html/xwzx-news;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location /api/ {
proxy_pass http://127.0.0.1:8000/api/;
proxy_http_version 1.1;
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;
}
}
}
NGINXCONF
sudo systemctl enable nginx
sudo nginx -t && sudo systemctl restart nginx
echo ""
echo "=== 部署完成 ==="
echo "后端API: http://localhost:8000"
echo "前端访问: http://服务器IP"
九、访问地址汇总
| 服务 | 地址 |
|---|---|
| 后端 API | http://localhost:8000 |
| API 文档 | http://localhost:8000/docs |
| 前端应用 | http://服务器IP:80 |
如有问题,请检查日志:
bash
# 后端
sudo journalctl -u xwzx-news-backend -n 50
# Nginx
sudo tail -20 /var/log/nginx/error.log