我们来深入且系统地探讨如何将一个 React 项目部署到 VPS(Virtual Private Server),并重点讲解如何实现自动化部署。
整个过程可以分为两大核心部分:
-
手动部署的基础设施搭建:这是实现自动化的前提。你必须先成功手动部署一次,理解其中的每一个环节。
-
自动化部署的实现:在手动部署成功的基础上,配置工作流,将“重复劳动”交给机器。
第一部分:核心基础 - 手动部署
手动部署的本质是:在你的本地电脑上将 React 代码打包成一堆静态文件(HTML, CSS, JavaScript),然后将这些静态文件上传到你的 VPS 上,并使用一个 Web 服务器(如 Nginx)来托管它们,让用户可以通过域名访问。
前置条件
-
一台 VPS:已经购买并可以通过 SSH 登录。通常是 Linux 系统,例如 Ubuntu 22.04。
-
一个域名:已经购买并解析到了你的 VPS IP 地址。
-
一个可运行的 React 项目:在本地可以通过
npm start正常运行。 -
SSH 客户端:macOS 和 Linux 自带终端,Windows 可以使用 WSL、PowerShell 或 PuTTY。
步骤 1: 在本地构建 React 项目
在你的 React 项目根目录下,执行构建命令:
Bash
npm run build
# 或者
# yarn build
这个命令会在你的项目根目录下创建一个 build 或 dist 文件夹。这个文件夹里包含了所有你的网站需要的静态资源,这就是我们要部署到服务器上的全部内容。
步骤 2: 连接并准备你的 VPS
通过 SSH 登录到你的 VPS:
Bash
ssh your_user@your_vps_ip
登录后,首先更新系统并安装 Nginx。Nginx 是一款高性能的 Web 服务器,非常适合用来托管静态文件。
Bash
# 更新软件包列表
sudo apt update && sudo apt upgrade -y
# 安装 Nginx
sudo apt install nginx -y
# 验证 Nginx 是否安装成功并正在运行
sudo systemctl status nginx
如果看到 active (running) 字样,说明 Nginx 安装成功。
步骤 3: 上传构建好的文件
现在,你需要将本地的 build 文件夹内容上传到 VPS。我们将它上传到 Nginx 的默认网站根目录 /var/www/html。
在本地电脑的终端中执行以下 scp 命令(Secure Copy Protocol):
Bash
# 注意:命令末尾有一个点 "." 表示目标目录
# -r 表示递归复制整个文件夹
scp -r ./build/* your_user@your_vps_ip:/var/www/html/
这会要求你输入 VPS 的登录密码。完成后,你的所有静态文件就都位于 VPS 的 /var/www/html 目录下了。
权限注意:
/var/www/html目录默认可能需要sudo权限才能写入。一个更规范的做法是为你的项目创建一个专门的目录,例如/var/www/my-react-app,并调整其所有权,但为了简化初始步骤,我们先用默认目录。如果遇到权限问题,可以先上传到用户主目录,再在 VPS 上用sudo mv移动。
步骤 4: 配置 Nginx
这是最关键的一步。我们需要告诉 Nginx 如何处理访问你网站的请求。特别是对于 React 这样的单页面应用(SPA),我们需要确保无论用户访问哪个路径(例如 your_domain.com/about),Nginx 都返回 index.html,然后由 React Router 来处理前端路由。
-
在 VPS 上,创建一个新的 Nginx 配置文件:
Bash
sudo nano /etc/nginx/sites-available/your_domain -
将以下配置粘贴进去,并替换
your_domain和www.your_domain:Nginx
server { listen 80; listen [::]:80; # 网站文件的根目录 root /var/www/html; index index.html index.htm; # 你的域名 server_name your_domain www.your_domain; location / { # 这一行是单页面应用(SPA)配置的核心 # 它会尝试查找完全匹配的文件 ($uri) # 或目录 ($uri/),如果都找不到, # 就返回 /index.html 文件,让 React Router 接管。 try_files $uri $uri/ /index.html; } } -
保存并退出编辑器 (在
nano中是Ctrl+X->Y->Enter)。 -
启用这个配置,通过创建一个从
sites-available到sites-enabled的符号链接:Bash
sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/ -
测试 Nginx 配置是否有语法错误:
Bash
sudo nginx -t如果显示
syntax is ok和test is successful,则说明配置无误。 -
重启 Nginx 使配置生效:
Bash
sudo systemctl restart nginx
现在,通过浏览器访问你的域名 http://your_domain,应该就能看到你的 React 应用了!
步骤 5 (强烈推荐): 配置 HTTPS
目前你的网站是 HTTP 的,不安全。我们可以使用 Let's Encrypt 提供的免费 SSL 证书来启用 HTTPS。
Bash
# 安装 Certbot,它是 Let's Encrypt 的客户端
sudo apt install certbot python3-certbot-nginx -y
# 自动获取证书并配置 Nginx
sudo certbot --nginx -d your_domain -d www.your_domain
Certbot 会引导你完成一些设置,包括输入邮箱、同意服务条款,以及是否将所有 HTTP 请求重定向到 HTTPS(推荐选择重定向)。完成后,Certbot 会自动更新你的 Nginx 配置文件,并设置证书的自动续期。
至此,你已经完成了完整的手动部署流程。
第二部分:自动化部署
每次更新代码后都重复上述“构建 -> 上传”的流程非常繁琐。自动化部署的目标是:当你将代码推送到 Git 仓库(如 GitHub)的特定分支时,服务器能自动拉取最新代码、构建并部署。
我们介绍两种主流的自动化方法,从简单到专业。
方法 A: 简单直接 - 使用 Git Hooks
这种方法是在你的 VPS 上创建一个裸的(bare)Git 仓库。当你从本地 git push 到这个 VPS 上的仓库时,会触发一个服务器端的钩子脚本(hook script),这个脚本负责执行构建和部署的命令。
工作流程: 本地开发 -> git push vps main -> VPS 上的 Git Hook 触发 -> 自动构建和部署
实现步骤:
-
在 VPS 上安装 Git 和 Node.js/npm
Bash
# 安装 Git sudo apt install git -y # 安装 Node.js (推荐使用 nvm 或 nodesource) curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - sudo apt-get install -y nodejs -
在 VPS 上创建裸 Git 仓库
Bash
# 在一个合适的位置创建裸仓库 sudo git init --bare /var/repo/my-react-app.git # 更改仓库所有权,使其属于你的登录用户,避免权限问题 sudo chown -R your_user:your_user /var/repo/my-react-app.git -
创建 post-receive 钩子
这是自动化的核心。这个脚本在仓库接收到推送后执行。
Bash
# 创建并编辑钩子文件 sudo nano /var/repo/my-react-app.git/hooks/post-receive将以下脚本内容粘贴进去:
Bash
#!/bin/bash # # The production directory TARGET="/var/www/my-react-app" # The git repo REPO="/var/repo/my-react-app.git" # A temporary directory for the checkout TEMP_CLONE="/tmp/my-react-app-clone" # ---- echo "-----> Deploying React App..." # Remove old temporary clone and create a new one rm -rf $TEMP_CLONE mkdir -p $TEMP_CLONE # Checkout the repository into the temporary directory git --work-tree=$TEMP_CLONE --git-dir=$REPO checkout main -f # Navigate into the temporary directory cd $TEMP_CLONE # Install dependencies and build the project echo "-----> Installing dependencies (npm install)..." npm install echo "-----> Building project (npm run build)..." npm run build # Create the production directory if it doesn't exist mkdir -p $TARGET # Deploy by copying the build files to the production directory echo "-----> Deploying to $TARGET..." # 使用 rsync 可以更高效地同步文件 rsync -a --delete build/ $TARGET/ # Cleanup rm -rf $TEMP_CLONE echo "-----> Deployment finished successfully." exit 0注意:
-
这个脚本假定你的部署目录是
/var/www/my-react-app。你需要相应地更新你的 Nginx 配置中的root指令。 -
确保你的主分支是
main,如果不是,请修改脚本中的checkout main。
-
-
给钩子脚本添加执行权限
Bash
sudo chmod +x /var/repo/my-react-app.git/hooks/post-receive -
在本地电脑上配置 Git remote
在你的本地 React 项目中,添加一个新的远程仓库,指向你的 VPS。
Bash
# "vps" 是你给这个远程仓库起的名字 git remote add vps your_user@your_vps_ip:/var/repo/my-react-app.git -
推送部署
现在,当你完成了新的开发,只需执行:
Bash
git push vps main你会在终端看到服务器端
post-receive脚本输出的日志,显示安装、构建和部署的过程。
优点:
-
设置相对简单,不依赖第三方服务。
-
非常直观,易于理解。
缺点:
-
安全风险:构建过程(
npm install)直接在生产服务器上进行,可能会引入不安全的依赖包。 -
资源消耗:构建过程会消耗 VPS 的 CPU 和内存资源,可能影响线上服务的稳定性。
-
环境污染:需要在生产服务器上安装 Node.js、npm 等构建工具。
方法 B: 现代专业方案 - 使用 CI/CD (以 GitHub Actions 为例)
这是目前业界最推荐的做法。构建过程在一个隔离、干净的环境(由 GitHub 提供)中进行,只有最终的产物(build 文件夹)被传送到你的 VPS 上。
工作流程: 本地开发 -> git push github main -> GitHub Actions 触发 -> 在 GitHub 的服务器上构建 -> 将构建产物安全地部署到 VPS
实现步骤:
-
准备 VPS
与方法 A 不同,你的 VPS 不再需要安装 Node.js 或 npm。它只需要 Nginx 和一个能被远程访问的用户即可。
-
生成 SSH 密钥对,用于免密登录
为了让 GitHub Actions 能够自动登录到你的 VPS,我们需要设置 SSH 密钥。
-
在你的本地电脑上生成一个新的密钥对:
Bash
# -f 指定文件路径,-N "" 表示不设置密码 ssh-keygen -t rsa -b 4096 -f github-actions-key -C "github-actions-deploy" -N ""这会生成两个文件:
github-actions-key(私钥) 和github-actions-key.pub(公钥)。 -
将公钥添加到 VPS 的授权列表:
首先,查看并复制公钥内容:
Bash
cat github-actions-key.pub然后,SSH 登录到你的 VPS,将复制的公钥内容追加到
~/.ssh/authorized_keys文件中:Bash
# 在 VPS 上执行 echo "PASTE_PUBLIC_KEY_CONTENT_HERE" >> ~/.ssh/authorized_keys # 确保文件权限正确 chmod 600 ~/.ssh/authorized_keys
-
-
在 GitHub 仓库中设置 Secrets
私钥非常敏感,绝不能直接写在代码或配置文件里。我们需要把它作为加密的 Secret 存储在 GitHub 仓库中。
-
打开你的 GitHub 仓库页面 ->
Settings->Secrets and variables->Actions。 -
点击
New repository secret,创建以下几个 Secret:-
VPS_SSH_PRIVATE_KEY: 值是私钥文件github-actions-key的全部内容 (用cat github-actions-key查看)。 -
VPS_HOST: 值为你的 VPS IP 地址。 -
VPS_USER: 值为你用于 SSH 登录的用户名(如root或ubuntu)。 -
DEPLOY_PATH: 值为你希望部署文件的 VPS 上的绝对路径,例如/var/www/my-react-app。
-
-
-
创建 GitHub Actions Workflow 文件
在你的 React 项目根目录下,创建 .github/workflows/deploy.yml 文件:
Bash
mkdir -p .github/workflows touch .github/workflows/deploy.yml将以下 YAML 内容粘贴到
deploy.yml文件中:YAML
name: Deploy React App to VPS on: # 当推送到 main 分支时触发 push: branches: - main jobs: build-and-deploy: runs-on: ubuntu-latest # 使用最新的 Ubuntu 运行环境 steps: # 步骤 1: Checkout 代码 - name: Checkout Code uses: actions/checkout@v4 # 步骤 2: 设置 Node.js 环境 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' # 指定 Node.js 版本 cache: 'npm' # 缓存 npm 依赖,加快后续构建速度 # 步骤 3: 安装依赖并构建 - name: Install Dependencies and Build run: | npm install npm run build # 步骤 4: 部署到 VPS - name: Deploy to VPS uses: appleboy/ssh-action@master with: host: ${{ secrets.VPS_HOST }} username: ${{ secrets.VPS_USER }} key: ${{ secrets.VPS_SSH_PRIVATE_KEY }} script: | # 使用 rsync 高效、安全地将 build 目录内容同步到服务器的部署路径 # -r 递归, -a 归档模式, -v 输出详情, -z 压缩, --delete 删除目标目录多余的文件 rsync -ravz --delete ./build/ ${{ secrets.DEPLOY_PATH }} -
提交并推送
将你做的所有修改(包括 .github/workflows/deploy.yml 文件)提交到你的 GitHub 仓库。
Bash
git add . git commit -m "feat: Add GitHub Actions CI/CD for deployment" git push origin main推送到
main分支后,会自动触发 Action。你可以在 GitHub 仓库的Actions标签页看到实时的工作流日志。
优点:
-
高安全性:构建环境与生产服务器隔离,只有构建产物被传输。私钥等敏感信息被加密存储。
-
环境纯净:生产服务器只需 Nginx,无需安装 Node.js 等开发工具,更加稳定和安全。
-
标准化和可扩展:这是行业标准实践,工作流可以轻松扩展,加入单元测试、代码扫描等步骤。
-
性能:GitHub 的服务器性能强劲,构建速度通常比在普通 VPS 上快。
缺点:
-
初始设置比 Git Hooks 复杂。
-
依赖于第三方服务(GitHub)。
结论与最终推荐
对于任何严肃的、长期的项目,我毫无疑问地推荐使用方法 B:GitHub Actions (或类似的 CI/CD 工具)。
虽然初始设置需要多花一些时间来理解 SSH 密钥和 YAML 配置,但它带来的安全性、稳定性、标准化和可扩展性是 Git Hooks 方案无法比拟的。它将构建环境和生产环境彻底分离,这是现代软件工程中一个至关重要的原则。一旦设置完成,你的开发体验会变得极其流畅:只需 git push,剩下的事情就交给一个健壮、可靠的自动化流程来完成。
Git Hooks 方法更像是一个优秀的学习工具,它可以帮助你深入理解自动化部署的基本原理。对于个人小型项目或者在没有外部网络访问的内网环境中,它依然是一个有效且轻量的选择。
最终,选择哪种方法取决于你的项目规模、团队协作需求以及你对稳定性和安全性的要求。但面向未来和专业实践,投资时间学习并实施 CI/CD 流程是绝对值得的。