如何在 Ubuntu 上使用 Nginx 部署 React 应用

本文详细介绍了如何在 Ubuntu 服务器上使用 Nginx 部署 React 应用。内容涵盖了从创建 React 项目、构建生产版本、配置 Nginx 实现性能优化与 React Router 兼容性、设置 SSL 证书、集成后端 API 反向代理,到 CI/CD 自动化部署和生产环境监控调试等关键步骤。旨在帮助开发者构建高效、安全且易于维护的生产级 React 应用部署方案。

阅读时长: 19 分钟
共 9309字
作者: eimoon.com

引言

使用 Create React App 默认的构建工具,您可以快速将 React 应用部署到服务器。build 脚本会将应用编译到一个包含所有 JavaScript 代码、图片、样式和 HTML 文件的单独目录中。将所有资源集中到一处,您只需进行最少的配置即可部署到 Web 服务器。

在本综合教程中,您将学习如何将本地机器上的 React 应用部署到运行 Nginx 的 Ubuntu 服务器。您将使用 Create React App 构建一个应用,配置 Nginx 以实现最佳性能,设置反向代理,实施 SSL 证书,并学习生产环境优化技术。我们还将涵盖现代部署策略,包括 CI/CD 自动化 和适用于 Ubuntu 的容器化方法。

核心要点

在深入技术实现之前,以下是您将掌握的关键概念:

  • 生产构建优化 (Production Build Optimization):学习如何创建优化的 React 构建,包括资产压缩和缓存策略。
  • Nginx 配置精通 (Nginx Configuration Mastery):理解服务器块 (server blocks)、位置指令 (location directives) 和 React 应用的反向代理设置。
  • SSL/TLS 安全 (SSL/TLS Security):使用 Let’s Encrypt 证书并配置 HTTPS 重定向以确保安全部署。
  • 性能调优 (Performance Tuning):配置 Gzip 压缩、浏览器缓存和静态资源优化以加快加载时间。
  • CI/CD 集成 (CI/CD Integration):使用 GitHub Actions 或 GitLab CI 设置自动化部署管道以简化更新流程。
  • 容器化部署 (Container Deployment):探索基于 Docker 的部署策略,以实现可扩展、可移植的 React 应用。
  • 监控与调试 (Monitoring & Debugging):为生产环境实施日志记录、错误追踪和性能监控。

前置条件

本教程兼容 Ubuntu 18.04, 20.04, 22.04, 24.0425.04 版本。如果您使用 Ubuntu 16.04 或更早版本,建议您升级到更新的版本,因为 Ubuntu 不再提供对这些版本的支持。您可以参考官方 Ubuntu LTS 升级指南 获取更多信息。

要完成本教程,您需要:

第一步:创建 React 项目并生成生产构建

在本步骤中,您将使用 Create React App 创建一个应用程序,并构建一个具有生产优化功能的样板应用的部署版本。

首先,在您的本地环境中创建一个新的 React 应用。在终端中,运行以下命令来构建应用。在本教程中,项目将命名为 react-deploy

npx create-react-app react-deploy

npx 命令将在不下载 Node 包到您的机器上的情况下运行它。create-react-app 脚本将安装您的 React 应用所需的所有依赖项,并在 react-deploy 目录中构建一个基础项目。有关 Create React App 的更多信息,请查阅教程 如何使用 Create React App 设置 React 项目

现代 React 开发提示:虽然 Create React App 非常适合学习,但对于新项目,请考虑使用 Vite,因为它提供更快的构建时间和更好的开发体验。本教程为了简化和广泛采用,将使用 Create React App。

代码将运行几分钟,因为它会下载并安装依赖项。完成后,您将收到一条成功消息。如果您使用 yarn 而不是 npm,您的版本可能会略有不同:

Success! Created react-deploy at your_file_path/react-deploy
Inside that directory, you can run several commands:

  npm start
    Starts the development server.

  npm build
    Bundles the app into static files for production.

  npm test
    Starts the test runner.

  npm eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you cant go back!

We suggest that you begin by typing:

  cd react-deploy
  npm start

Happy hacking!

按照输出中的建议,首先进入项目文件夹:

cd react-deploy

现在您有了一个基础项目,在本地运行它以测试它在服务器上的显示效果。使用 npm start 脚本运行项目:

npm start

当命令运行时,您将收到包含本地服务器信息的输出:

Compiled successfully!

You can now view react-deploy in the browser.

  Local:            `http://localhost:3000`
  On Your Network:  `http://192.168.1.110:3000`

Note that the development build is not optimized.
To create a production build, use npm build.

打开浏览器并导航到 http://localhost:3000。您将能够访问样板 React 应用。

在终端中输入 CTRL+C⌘+C 停止项目。

现在您有了一个可以在浏览器中成功运行的项目,您需要创建一个生产构建。使用以下命令运行 create-react-app 构建脚本:

npm run build

此命令将把 JavaScript 和资产编译到 build 目录中。命令完成后,您将收到一些包含构建数据信息的输出。请注意,文件名包含哈希值,因此您的输出会略有不同:

Creating an optimized production build...
Compiled successfully.

File sizes after gzip:

  41.21 KB  build/static/js/2.82f639e7.chunk.js
  1.4 KB    build/static/js/3.9fbaa076.chunk.js
  1.17 KB   build/static/js/runtime-main.1caef30b.js
  593 B     build/static/js/main.e8c17c7d.chunk.js
  546 B     build/static/css/main.ab7136cd.chunk.css

The project was built assuming it is hosted at /.
You can control this with the homepage field in your package.json.

The build folder is ready to be deployed.
You may serve it with a static server:

  serve -s build

Find out more about deployment here:

  https://cra.link/deployment

build 目录现在将包含您项目所需的所有文件的编译和最小化版本。此时,您无需担心 build 目录之外的任何内容。您所要做的就是将该目录部署到服务器。

在本步骤中,您创建了一个新的 React 应用。您验证了应用在本地运行成功,并使用 Create React App 的 build 脚本构建了生产版本。在下一步中,您将登录到服务器以了解要将 build 目录复制到何处。

第二步:确定 Ubuntu 服务器上的部署文件位置

在本步骤中,您将开始将 React 应用部署到服务器。但在上传文件之前,您需要确定部署服务器上的正确文件位置。本教程使用 Nginx 作为 Web 服务器,但使用 Apache 的方法是相同的(Ubuntu 22.04 / Ubuntu 20.04 / Ubuntu 18.04)。主要区别在于配置文件将在不同的目录中。

要找到 Web 服务器将用作项目根目录的目录,请使用 ssh 登录到您的服务器:

ssh username@server_ip

登录服务器后,在 /etc/nginx/sites-enabled 中查找您的 Web 服务器配置。还有一个名为 sites-allowed 的目录;此目录包含未激活的配置。找到配置文件后,使用以下命令在终端中显示输出:

cat /etc/nginx/sites-enabled/your_domain

如果您的站点没有 HTTPS 证书,您将收到类似以下结果:

server {
        listen 80;
        listen [::]:80;

        root /var/www/your_domain/html;
        index index.html index.htm index.nginx-debian.html;

        server_name your_domain www.your_domain;

        location / {
                try_files $uri $uri/ =404;
        }
}

如果您遵循了 Let’s Encrypt 前置条件来保护您的 Ubuntu 服务器,您将收到此输出:

server {

        root /var/www/your_domain/html;
        index index.html index.htm index.nginx-debian.html;

        server_name your_domain www.your_domain;

        location / {
                try_files $uri $uri/ =404;
        }

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
    if ($host = www.your_domain) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    if ($host = your_domain) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

        listen 80;
        listen [::]:80;

        server_name your_domain www.your_domain;
    return 404; # managed by Certbot
}

无论是哪种情况,部署 React 应用最重要的字段是 root。它将 HTTP 请求指向 /var/www/your_domain/html 目录。这意味着您将把文件复制到该位置。在下一行中,您可以看到 Nginx 将查找 index.html 文件。如果您查看本地 build 目录,您将看到一个将作为主入口点的 index.html 文件。

从 Ubuntu 服务器注销并返回到您的本地开发环境。

现在您知道了 Nginx 将提供文件的位置,您可以上传您的构建。

第三步:使用 scp 上传构建文件

此时,您的 build 文件已准备就绪。您只需将它们复制到服务器。一个快速的方法是使用 scp 将文件复制到正确的位置。scp 命令是一种从终端安全地将文件复制到远程服务器的方法。如果您的 ssh 密钥已配置,该命令将使用它。否则,系统将提示您输入用户名和密码。

命令格式为 scp files_to_copy username@server_ip:path_on_server。第一个参数是您要复制的文件。在本例中,您要复制 build 目录中的所有文件。第二个参数是您的凭据和目标路径的组合。目标路径将与您的 Nginx 配置中的 root 相同:/var/www/your_domain/html

使用 * 通配符将所有 build 文件复制到 /var/www/your_domain/html

scp -r ./build/* username@server_ip:/var/www/your_domain/html

当您运行该命令时,您将收到显示文件正在上传的输出。您的结果会略有不同:

asset-manifest.json                                                                                          100% 1092    22.0KB/s   00:00
favicon.ico                                                                                                  100% 3870    80.5KB/s   00:00
index.html                                                                                                   100% 3032    61.1KB/s   00:00
logo192.png                                                                                                  100% 5347    59.9KB/s   00:00
logo512.png                                                                                                  100% 9664    69.5KB/s   00:00
manifest.json                                                                                                100%  492    10.4KB/s   00:00
robots.txt                                                                                                   100%   67     1.0KB/s   00:00
main.ab7136cd.chunk.css                                                                                      100%  943    20.8KB/s   00:00
main.ab7136cd.chunk.css.map                                                                                  100% 1490    31.2KB/s   00:00
runtime-main.1caef30b.js.map                                                                                 100%   12KB  90.3KB/s   00:00
3.9fbaa076.chunk.js                                                                                          100% 3561    67.2KB/s   00:00
2.82f639e7.chunk.js.map                                                                                      100%  313KB 156.1KB/s   00:02
runtime-main.1caef30b.js                                                                                     100% 2372    45.8KB/s   00:00
main.e8c17c7d.chunk.js.map                                                                                   100% 2436    50.9KB/s   00:00
3.9fbaa076.chunk.js.map                                                                                      100% 7690   146.7KB/s   00:00
2.82f639e7.chunk.js                                                                                          100%  128KB 226.5KB/s   00:00
2.82f639e7.chunk.js.LICENSE.txt                                                                              100% 1043    21.6KB/s   00:00
main.e8c17c7d.chunk.js                                                                                       100% 1045    21.7KB/s   00:00
logo.103b5fa1.svg                                                                                            100% 2671    56.8KB/s   00:00

命令完成后,您就完成了。由于 React 项目由只包含浏览器的静态文件组成,因此您无需配置任何进一步的服务器端语言。打开浏览器并导航到您的域名。届时,您将看到您的 React 项目。

在本步骤中,您将 React 应用部署到服务器。您学习了如何识别服务器上的根 Web 目录,并使用 scp 复制文件。文件上传完成后,您就可以在 Web 浏览器中查看您的项目了。

第四步:Nginx 生产环境优化配置

虽然您的 React 应用现在可以访问了,但默认的 Nginx 配置并未针对生产环境的 React 应用进行优化。在本步骤中,您将配置 Nginx 以获得更好的性能、安全性和 React Router 兼容性。

理解 React Router 与 Nginx 配置

使用客户端路由 (React Router) 的 React 应用需要特殊的 Nginx 配置。当用户导航到 /about/contact 等路由时,浏览器会向服务器请求这些路径,但 Nginx 不知道这些客户端路由,并会返回 404 错误。

解决方案是配置 Nginx 为所有不对应实际文件的路由提供 index.html 文件。这被称为“回退 (fallback)”配置。

创建优化后的 Nginx 配置

为您的 React 应用创建一个新的 Nginx 配置文件:

sudo nano /etc/nginx/sites-available/your_domain

用这个优化后的版本替换现有配置:

server {
    listen 80;
    listen [::]:80;
    server_name your_domain www.your_domain;

    root /var/www/your_domain/html;
    index index.html;

    # 安全头部
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_proxied expired no-cache no-store private must-revalidate auth;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/javascript
        application/xml+rss
        application/json;

    # 静态资源缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # React Router 回退 - 这对 SPA 至关重要
    location / {
        try_files $uri $uri/ /index.html;
    }

    # API 代理 (如果您有后端 API)
    location /api/ {
        proxy_pass http://localhost:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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;
        proxy_cache_bypass $http_upgrade;
    }
}

简而言之,此配置执行以下操作:

  • try_files $uri $uri/ /index.html:这是 React Router 的回退。它首先尝试提供请求的文件,然后是目录,最后回退到 index.html 以进行客户端路由。
  • Gzip 压缩:将文件大小减少 60-80%,显著提高加载时间。
  • 静态资源缓存:为静态文件设置长期缓存,并使用不可变缓存控制。
  • 安全头部:防止常见的 Web 漏洞。
  • API 代理:将 /api/ 请求路由到您的后端服务器(如果适用)。

理解配置组件

此 Nginx 配置专门针对 React 应用程序进行了优化。让我们分解每个部分以了解其作用以及为何重要:

1. 基本服务器配置

listen 80;
listen [::]:80;
server_name your_domain www.your_domain;
root /var/www/your_domain/html;
index index.html;
  • 双重监听 (Dual listening):处理 IPv4 (listen 80) 和 IPv6 (listen [::]:80) 连接以实现最大兼容性。
  • 域名处理 (Domain handling):从同一配置中提供 your-domain.comwww.your-domain.com
  • 文档根目录 (Document root):指向您的 React 构建文件所在的位置。
  • 默认文件 (Default file):在未请求特定文件时提供 index.html

2. 安全头部

add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

这些头部保护免受常见的 Web 漏洞:

  • X-Frame-Options:通过控制您的站点是否可以嵌入到框架中来防止点击劫持攻击。
  • X-Content-Type-Options:防止 MIME 类型嗅探攻击,这些攻击可能执行恶意代码。
  • X-XSS-Protection:启用浏览器的内置 XSS (跨站脚本) 保护。
  • Referrer-Policy:控制随请求发送的 referrer 信息量,保护用户隐私。

3. Gzip 压缩

gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private must-revalidate auth;
gzip_types
    text/plain
    text/css
    text/xml
    text/javascript
    application/javascript
    application/xml+rss
    application/json;

此部分显著提高了性能:

  • 文件大小减少 (File size reduction):将文本文件压缩 60-80%,显著减少带宽使用。
  • 更快的加载时间 (Faster load times):尤其对于移动用户和较慢的连接至关重要。
  • 智能压缩 (Smart compression):仅压缩大于 1KB 的文件,以避免小型文件上的 CPU 开销。
  • 有针对性的压缩 (Targeted compression):专注于最受益于压缩的文件类型 (CSS, JS, JSON)。

4. 静态资源缓存

location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    access_log off;
}

此配置优化了静态资源的缓存:

  • 长期缓存 (Long-term caching):静态资源缓存 1 年,减少重复下载。
  • 不可变缓存 (Immutable cache)immutable 指令告诉浏览器文件不会改变(因为 React 会在文件名中添加哈希值,如 main.abc123.js,所以这是安全的)。
  • 减少服务器负载 (Reduced server load)access_log off 防止记录静态资源请求,减少 I/O 开销。
  • 更快的重复访问 (Faster repeat visits):用户无需重新下载未更改的文件。

5. React Router 回退(对 SPA 至关重要)

location / {
    try_files $uri $uri/ /index.html;
}

这是 React 应用程序最重要的配置:

  • 客户端路由支持 (Client-side routing support):对 React Router 正常工作至关重要。
  • 回退机制 (Fallback mechanism):如果请求的文件不存在,Nginx 将提供 index.html
  • 防止 404 错误 (Prevents 404 errors):用户可以书签并共享到 React 路由的直接链接,例如 /about/contact
  • SPA 兼容性 (SPA compatibility):启用正确的单页应用程序行为。

工作原理:

  1. 首先尝试提供请求的文件 ($uri)。
  2. 然后尝试提供目录 ($uri/)。
  3. 最后回退到 index.html 以进行客户端路由。

6. API 反向代理

location /api/ {
    proxy_pass http://localhost:3001;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    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;
    proxy_cache_bypass $http_upgrade;
}

此部分处理后端 API 集成:

  • API 路由 (API routing):将所有 /api/ 请求路由到运行在端口 3001 的后端服务器。
  • WebSocket 支持 (WebSocket support):处理 WebSocket 升级以实现实时功能。
  • 头部转发 (Header forwarding):保留客户端信息以进行正确的日志记录和安全性。
  • 消除 CORS (CORS elimination):从同一域提供所有内容,消除跨域问题。
  • 负载均衡就绪 (Load balancing ready):可以轻松扩展以代理到多个后端服务器。

性能影响总结

此优化配置比基本的 Nginx 设置提供了显著的改进:

  • 通过 Gzip 压缩将文件大小减少 60-80%
  • 静态资源缓存 1 年,消除重复下载。
  • 通过多个保护头部增强安全性
  • 通过 React Router 回退配置完美支持 SPA
  • 通过反向代理设置无缝 API 集成
  • 通过优化日志记录和缓存减少服务器负载

此配置已可用于生产环境,并处理 React 单页应用 (SPA) 的独特要求,同时提供企业级的性能和安全优化。

测试与重新加载配置

测试您的 Nginx 配置是否存在语法错误:

sudo nginx -t

如果测试通过,重新加载 Nginx:

sudo systemctl reload nginx

第五步:设置 API 反向代理

许多 React 应用需要与后端 API 通信。Nginx 可以充当 反向代理,将 API 请求路由到您的后端服务器,同时从同一域名提供 React 应用。

设置后端 API

如果您有 Node.js/Express 后端,以下是设置方法:

# 安装 PM2 用于进程管理
sudo npm install -g pm2

# 创建一个简单的 Express 服务器
mkdir /var/www/api
cd /var/www/api
npm init -y
npm install express cors

创建一个简单的 API 服务器:

// /var/www/api/server.js
const express = require('express');
const cors = require('cors');
const app = express();
const PORT = process.env.PORT || 3001;

app.use(cors());
app.use(express.json());

app.get('/api/health', (req, res) => {
    res.json({ status: 'OK', timestamp: new Date().toISOString() });
});

app.get('/api/users', (req, res) => {
    res.json([
        { id: 1, name: 'John Doe', email: 'john@example.com' },
        { id: 2, name: 'Jane Smith', email: 'jane@example.com' }
    ]);
});

app.listen(PORT, () => {
    console.log(`API server running on port ${PORT}`);
});

使用 PM2 启动 API 服务器:

pm2 start server.js --name "react-api"
pm2 save
pm2 startup

更新 Nginx 配置

第四步 中的 Nginx 配置已包含 API 代理。/api/ 位置块将请求路由到运行在端口 3001 的后端服务器。

第六步:实现 SSL/HTTPS 安全

SSL 证书 对于生产应用至关重要。让我们为您的域名设置 Let’s Encrypt 证书

安装 Certbot

sudo apt update
sudo apt install certbot python3-certbot-nginx

获取 SSL 证书

sudo certbot --nginx -d your_domain -d www.your_domain

Certbot 将自动更新您的 Nginx 配置以包含 SSL 设置并将 HTTP 重定向到 HTTPS。

验证 SSL 配置

安装后,您的 Nginx 配置将包含 SSL 设置:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name your_domain www.your_domain;

    ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # 您的现有配置...
}

server {
    listen 80;
    listen [::]:80;
    server_name your_domain www.your_domain;
    return 301 https://$server_name$request_uri;
}

设置自动续订

sudo crontab -e

添加此行以自动续订证书:

0 12 * * * /usr/bin/certbot renew --quiet

第七步:配置性能优化

Nginx 高级性能调优

通过编辑主配置文件创建性能优化的 Nginx 配置:

# /etc/nginx/nginx.conf
worker_processes auto;
worker_rlimit_nofile 65535;

events {
    worker_connections 4096;
    use epoll;
    multi_accept on;
}

http {
    # 基本设置
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    # 缓冲区大小
    client_body_buffer_size 128k;
    client_max_body_size 10m;
    client_header_buffer_size 1k;
    large_client_header_buffers 4 4k;

    # 超时设置
    client_body_timeout 12;
    client_header_timeout 12;
    keepalive_timeout 15;
    send_timeout 10;

    # Gzip 设置
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/javascript
        application/xml+rss
        application/json
        application/atom+xml
        image/svg+xml;

    # 速率限制
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;

    # 包含您的站点配置
    include /etc/nginx/sites-enabled/*;
}

理解高级性能配置

此配置在系统级别优化了 Nginx,以实现高性能的 React 应用服务。让我们分解每个部分以了解其作用:

1. Worker 进程配置

worker_processes auto;
worker_rlimit_nofile 65535;
  • worker_processes auto:自动将 worker 进程数设置为与您的 CPU 核心数匹配,以最大化并行处理。
  • worker_rlimit_nofile 65535:增加每个 worker 的文件描述符限制,允许更多并发连接(默认通常为 1024)。

2. 事件处理优化

events {
    worker_connections 4096;
    use epoll;
    multi_accept on;
}
  • worker_connections 4096:每个 worker 最多可以处理 4,096 个并发连接(总数 = worker 数 × 4096)。
  • use epoll:在 Linux 系统上使用最高效的事件处理方法。
  • multi_accept on:允许 worker 一次接受多个连接,减少上下文切换。

3. HTTP 性能设置

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
  • sendfile on:使用内核的 sendfile() 系统调用进行高效的文件服务,绕过用户空间复制。
  • tcp_nopush on:通过等待数据包填满后再发送来优化 TCP 数据包传输。
  • tcp_nodelay on:立即发送小数据包以获得更好的实时性能。
  • keepalive_timeout 65:保持连接活跃 65 秒,减少连接开销。
  • types_hash_max_size 2048:增加哈希表大小以加快 MIME 类型查找。

4. 缓冲区大小优化

client_body_buffer_size 128k;
client_max_body_size 10m;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
  • client_body_buffer_size 128k:为请求体分配 128KB 缓冲区,减少小型上传的磁盘 I/O。
  • client_max_body_size 10m:允许文件上传最大 10MB(根据您的 React 应用需求调整)。
  • client_header_buffer_size 1k:HTTP 头的标准缓冲区。
  • large_client_header_buffers 4 4k:使用 4 个 4KB 缓冲区处理大型头部(cookies、自定义头部)。

5. 超时配置

client_body_timeout 12;
client_header_timeout 12;
keepalive_timeout 15;
send_timeout 10;
  • client_body_timeout 12:给客户端 12 秒钟发送请求体数据。
  • client_header_timeout 12:给客户端 12 秒钟发送完整的头部。
  • keepalive_timeout 15:保持空闲连接活跃 15 秒。
  • send_timeout 10:给客户端 10 秒钟发送响应数据。

6. 高级 Gzip 配置

gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
    text/plain
    text/css
    text/xml
    text/javascript
    application/javascript
    application/xml+rss
    application/json
    application/atom+xml
    image/svg+xml;
  • gzip_comp_level 6:平衡压缩比(6)与 CPU 使用率(1-9 级)。
  • gzip_proxied any:压缩所有代理请求的响应。
  • gzip_vary on:添加 “Vary: Accept-Encoding” 头部以帮助缓存理解压缩。
  • 扩展文件类型:包含 SVG 和 Atom 订阅以实现全面的压缩覆盖。

7. 速率限制保护

limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
  • API 速率限制 (API rate limiting):允许每个 IP 每秒 10 个 API 端点请求。
  • 登录速率限制 (Login rate limiting):将每个 IP 每秒登录尝试限制为 1 个请求。
  • 内存分配 (Memory allocation):使用 10MB 内存来跟踪速率限制状态。
  • DDoS 保护 (DDoS protection):防止滥用同时允许合法流量。

高级性能配置的性能影响总结

此高级配置提供了:

  • 比默认设置多 4 倍的并发连接
  • 通过优化的事件处理减少 CPU 使用率
  • 通过 sendfile 和 TCP 优化加快文件服务
  • 通过调优的 Gzip 设置更好的压缩效果
  • 通过智能速率限制DDoS 保护
  • 通过适当的缓冲区大小优化的内存使用率

应用配置

要应用这些更改:

sudo nano /etc/nginx/nginx.conf

将现有配置替换为上面优化的版本,然后测试并重新加载:

sudo nginx -t
sudo systemctl reload nginx

注意:这些设置针对生产环境进行了优化。对于开发环境,您可能希望减少某些值以节省资源。

优化您的 React 构建

为生产环境优化您的 React 构建:

// package.json
{
  "scripts": {
    "build": "GENERATE_SOURCEMAP=false npm run build",
    "build:analyze": "npm run build && npx serve -s build"
  }
}

创建特定环境的构建

创建特定环境的构建:

# .env.production
REACT_APP_API_URL=https://your-domain.com/api
REACT_APP_ENVIRONMENT=production

第八步:设置 CI/CD 自动化

设置 GitHub Actions 工作流

创建 .github/workflows/deploy.yml

name: Deploy React App to Ubuntu

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18'
        cache: 'npm'

    - name: Install dependencies
      run: npm ci

    - name: Run tests
      run: npm test -- --coverage --watchAll=false

    - name: Build React app
      run: npm run build
      env:
        REACT_APP_API_URL: ${{ secrets.REACT_APP_API_URL }}

    - name: Deploy to server
      uses: appleboy/ssh-action@v0.1.5
      with:
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        key: ${{ secrets.SSH_KEY }}
        script: |
          cd /var/www/your-domain/html
          rm -rf *
          # 文件将通过 rsync 上传

    - name: Upload files
      run: |
        rsync -avz --delete ./build/ ${{ secrets.USERNAME }}@${{ secrets.HOST }}:/var/www/your-domain/html/

    - name: Restart Nginx
      uses: appleboy/ssh-action@v0.1.5
      with:
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        key: ${{ secrets.SSH_KEY }}
        script: |
          sudo systemctl reload nginx

这个自动化部署管道通过在您推送更改到 main 分支时自动构建、测试和部署您的 React 应用程序来简化您的工作流程。以下是该过程的逐步工作原理:

  1. 代码检出 (Code Checkout):工作流从仓库中检出您最新的代码。
  2. Node.js 设置 (Node.js Setup):它设置 Node.js 环境并启用 npm 缓存以加快构建速度。
  3. 依赖安装 (Dependency Installation):使用 npm ci 安装所有依赖项,以实现可靠和可重现的构建。
  4. 测试 (Testing):运行您的测试套件并生成覆盖率报告,以确保代码质量,然后再进行部署。
  5. 生产构建 (Production Build):使用 GitHub Secrets 中的环境变量编译您的 React 应用程序以进行生产,从而创建优化的静态文件。
  6. 服务器准备 (Server Preparation):通过 SSH 连接到您的 Ubuntu 服务器并清空现有的 Web 目录。
  7. 文件上传 (File Upload):使用 rsync 有效地仅上传更改的文件,最大限度地减少传输时间和带宽使用。
  8. Nginx 重载 (Nginx Reload):重新加载 Nginx 以提供更新后的应用程序,而无需停机。
  9. 隔离环境 (Isolated Environment):整个过程在 GitHub 服务器上的干净、隔离的环境中运行,确保无论您的本地设置如何,部署都保持一致。
  10. 即时反馈 (Immediate Feedback):如果任何步骤失败,您会收到即时反馈,使您能够快速识别和修复问题,然后它们再到达生产环境。

第九步:监控与调试生产问题

设置日志记录

配置 Nginx 日志以进行更好的调试:

# 在您的站点配置中
access_log /var/log/nginx/react-app.access.log;
error_log /var/log/nginx/react-app.error.log;

# 详细分析的日志格式
log_format detailed '$remote_addr - $remote_user [$time_local] '
                   '"$request" $status $body_bytes_sent '
                   '"$http_referer" "$http_user_agent" '
                   '$request_time $upstream_response_time';

使用 PM2 监控

# 安装 PM2 监控
pm2 install pm2-logrotate
pm2 monit

设置健康检查端点

在您的 React 应用中添加一个健康检查:

// 在您的 React 应用中
const HealthCheck = () => {
  const [status, setStatus] = useState('checking');

  useEffect(() => {
    fetch('/api/health')
      .then(res => res.json())
      .then(data => setStatus(data.status))
      .catch(() => setStatus('error'));
  }, []);

  return <div>API Status: {status}</div>;
};

监控性能

安装和配置监控工具:

# 安装 htop 进行系统监控
sudo apt install htop

# 监控 Nginx 状态
sudo systemctl status nginx

# 检查磁盘使用情况
df -h

# 监控内存使用情况
free -h

常见问题 (FAQ)

1. 如何在 Ubuntu 上使用 Nginx 部署 React 应用?

在 Ubuntu 上使用 Nginx 部署 React 应用涉及几个关键步骤:

  1. 使用 npm run build 构建您的 React 应用程序,以创建优化的生产文件。
  2. 使用 try_files $uri $uri/ /index.html 配置 Nginx,设置适当的服务器块和 React Router 回退。
  3. 将构建文件上传到服务器的 Web 目录(通常是 /var/www/your-domain/html)。
  4. 使用 Let’s Encrypt 设置 SSL 证书以实现安全的 HTTPS 连接。
  5. 通过 Gzip 压缩、静态资源缓存和安全头部优化性能。

React Router 兼容性的关键配置是 try_files 指令,它确保所有客户端路由都回退到 index.html 以实现正确的单页应用程序功能。

2. 我应该将 React 构建文件放在 Nginx 的哪个位置?

React 构建文件应放置在 Nginx 服务器的文档根目录中。在 Ubuntu 系统上,标准位置是 /var/www/your-domain/html/

典型的结构如下:

/var/www/your-domain/html/
├── index.html          # 主入口点
├── static/
   ├── css/           # 编译后的 CSS 文件
   ├── js/            # 编译后的 JavaScript 文件
   └── media/         # 图片和其他资源
├── manifest.json      # PWA 清单文件
└── robots.txt         # SEO 机器人文件

确保您的 Nginx 配置使用 root 指令指向此目录,并且 Web 服务器具有适当的读取权限。

3. 如何修复 React Router 路由在 Nginx 中不工作的问题?

React Router 路由在 Nginx 中失效,因为服务器不知道客户端路由。当用户导航到 /about/contact 时,Nginx 会尝试查找这些文件并返回 404 错误。

解决方案:使用回退到 index.html 的方式配置 Nginx:

location / {
    try_files $uri $uri/ /index.html;
}

此配置告诉 Nginx:

  1. 首先尝试提供请求的文件 ($uri)。
  2. 然后尝试提供目录 ($uri/)。
  3. 最后回退到 index.html 以进行客户端路由。

此外,请确保您的 React 应用使用 BrowserRouter 而不是 HashRouter 来获得不带哈希片段的干净 URL。

4. 我可以在同一个 Nginx 服务器上部署前端和后端吗?

是的,您可以使用反向代理配置在同一个 Nginx 服务器上部署前端和后端。这对于全栈应用程序来说是一种常见且高效的设置。

配置示例

server {
    listen 80;
    server_name your-domain.com;

    # 为除 API 之外的所有路由提供 React 应用
    location / {
        root /var/www/your-domain/html;
        try_files $uri $uri/ /index.html;
    }

    # 将 API 请求代理到后端
    location /api/ {
        proxy_pass http://localhost:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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;
        proxy_cache_bypass $http_upgrade;
    }
}

此设置允许您的 React 应用向 /api/endpoint 发出 API 调用,这些调用将被代理到运行在端口 3001 的后端服务器。

5. 如何为使用 Nginx 部署的 React 应用启用 HTTPS?

使用 Let’s Encrypt 免费 SSL 证书为您的 React 应用启用 HTTPS:

  1. 安装 Certbot
    sudo apt update
    sudo apt install certbot python3-certbot-nginx
    
  2. 获取 SSL 证书
    sudo certbot --nginx -d your-domain.com -d www.your-domain.com
    
  3. 验证自动续订
    sudo certbot renew --dry-run
    

Certbot 会自动配置 Nginx,包含:

  • SSL 证书路径
  • HTTP 到 HTTPS 的重定向
  • 现代 SSL 安全设置
  • 自动证书续订

然后,您的 React 应用将通过 https://your-domain.com 访问,并带有有效的 SSL 证书。

6. 使用 Nginx 缓存 React 静态资源的最佳实践是什么?

通过以下 Nginx 配置优化 React 静态资源缓存:

静态资源的长期缓存

location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    access_log off;
}

更新文件的缓存失效: React 的构建过程会自动向文件名添加哈希值(例如 main.abc123.js),因此您可以安全地长期缓存这些文件。

Gzip 压缩

gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types
    text/plain
    text/css
    text/javascript
    application/javascript
    application/json;

HTML 的浏览器缓存

location ~* \.html$ {
    expires 1h;
    add_header Cache-Control "public, must-revalidate";
}

此配置可将带宽使用量减少 60-80%,并显著缩短回访用户的页面加载时间。

总结

您已成功在 Ubuntu 上使用 Nginx 部署了一个生产就绪的 React 应用程序,并集成了企业级优化、强大的安全配置和全面的监控功能。

这种方法通过 Gzip 压缩、静态资源缓存和高级 Nginx 调优等功能,确保了优化的性能,从而实现更快的加载时间。通过 SSL 证书、安全头部和适当的访问控制加强了安全性,而通过支持 API 集成和微服务的反向代理设置实现了可伸缩性。

本教程中概述的技术与最新的 Ubuntu 版本兼容,确保您的部署在当前和未来的 Ubuntu LTS 版本中保持可靠和面向未来。

后续步骤

推荐学习教程:

如果您想阅读更多 React 教程,请查看我们的 React 主题页面,或返回 React.js 编程系列教程页面

关于

关注我获取更多资讯

公众号
📢 公众号
个人号
💬 个人号
使用 Hugo 构建
主题 StackJimmy 设计