Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

服务器部署

方法论: 部署不是玄学,理解架构原理后,所有问题都能迎刃而解。


📖 本节目标

学完本节,你将理解:

  • ✅ 云服务器和安全组配置
  • ✅ Nginx反向代理的原理和配置
  • ✅ PM2进程管理器的使用
  • ✅ HTTPS证书配置
  • ✅ 域名解析和DNS配置

预计用时: 40分钟


1. 部署架构全景图

1.1 从用户访问到服务器响应

用户浏览器 www.yoursite.com
    │
    ▼
域名解析(DNS)  → 将域名转换为IP地址
    │
    ▼
云服务器安全组  → 防火墙,检查是否允许访问
    │
    ▼
Nginx反向代理  → 前台接待员,路由请求
    │
    ├─→ 静态文件  → 直接返回HTML/CSS/JS
    │
    └─→ 后端API  → PM2管理的Node.js/Python应用
           │
           └─→ 数据库  → 读取/写入数据

1.2 核心概念类比

组件生活类比作用
云服务器商场大楼24小时营业的电脑
安全组/防火墙门禁系统控制谁能进来
域名商场地址www.yoursite.com
DNS导航地图域名→IP地址
Nginx前台接待分流访客到不同部门
PM2部门经理管理员工(进程),自动重启
应用进程员工处理具体业务

2. 云服务器和安全组

2.1 什么是云服务器?

云服务器 = 远程的24小时开机电脑

你的笔记本云服务器
在你家里在机房里
你关机就停止24小时不停机
只有你能访问全世界都能访问(如果配置正确)
断网就用不了多条网络线路,高可用

2.2 安全组配置 ⚠️ 新手必看!

最常见的部署失败原因: 忘记配置安全组!

安全组 = 云服务器的门禁系统

                     云安全组
用户 ─────────────> │端口80?  允许│ ────> Nginx
                    │端口443? 允许│
                    │端口3000? 拒绝│ ✗  你的应用访问不了!

2.3 必须开放的端口

端口协议用途是否必需
22SSH远程登录服务器✅ 必需
80HTTP网站访问(HTTP)✅ 必需
443HTTPS网站访问(HTTPS)✅ 强烈推荐
3000/8000自定义应用直接访问❌ 不推荐暴露

2.4 配置安全组(各云平台)

阿里云:

  1. 登录控制台
  2. 云服务器ECS → 网络与安全 → 安全组
  3. 配置规则 → 添加入方向规则
  4. 添加端口: 22, 80, 443

腾讯云:

  1. 登录控制台
  2. 云服务器 → 安全组 → 修改规则
  3. 入站规则 → 添加规则
  4. 添加端口: 22, 80, 443

AWS:

  1. EC2 → Security Groups
  2. Edit inbound rules
  3. Add Rule → 添加端口

验证配置:

# 在本地测试端口是否开放
telnet your-server-ip 80
telnet your-server-ip 443

# 或使用curl
curl http://your-server-ip

3. Nginx反向代理

3.1 为什么需要Nginx?

场景: 你有一个前端(React)和一个后端(Node.js)

不用Nginx的问题:

前端: http://your-ip:3000   ← 用户要记端口
后端: http://your-ip:8000   ← 两个地址,跨域问题

用Nginx后:

用户访问: https://www.yoursite.com

Nginx自动分流:
- www.yoursite.com/      → 前端静态文件
- www.yoursite.com/api/  → 后端API

一个域名,无跨域! ✅

3.2 Nginx的三大作用

作用说明类比
反向代理隐藏真实服务器,统一入口前台接待,分流访客
负载均衡分发请求到多个服务器开多个窗口,排队均匀
静态资源服务高效提供HTML/CSS/JS自助服务区,不用麻烦后厨

3.3 安装Nginx

Ubuntu/Debian:

sudo apt update
sudo apt install nginx

# 启动Nginx
sudo systemctl start nginx

# 开机自启
sudo systemctl enable nginx

# 检查状态
sudo systemctl status nginx

CentOS/RHEL:

sudo yum install nginx

sudo systemctl start nginx
sudo systemctl enable nginx

验证安装:

打开浏览器,访问 http://your-server-ip

看到“Welcome to nginx!“说明成功!

3.4 Nginx配置文件

主配置文件位置:

# Ubuntu/Debian
/etc/nginx/nginx.conf
/etc/nginx/sites-available/default

# CentOS/RHEL
/etc/nginx/nginx.conf
/etc/nginx/conf.d/default.conf

基础配置示例:

# /etc/nginx/sites-available/mysite

server {
    listen 80;                          # 监听80端口
    server_name www.yoursite.com;       # 你的域名

    # 前端静态文件
    location / {
        root /var/www/mysite/dist;      # 前端build后的文件夹
        index index.html;
        try_files $uri $uri/ /index.html;  # 解决SPA刷新404
    }

    # 后端API代理
    location /api/ {
        proxy_pass http://localhost:3000;  # 转发到后端
        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;
    }
}

配置说明:

指令作用
listen 80监听HTTP请求(80端口)
server_name域名或IP
location /处理根路径请求
root静态文件目录
try_filesSPA应用防404
proxy_pass反向代理到后端

3.5 启用配置

# 创建软链接(Ubuntu/Debian)
sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/

# 测试配置是否正确
sudo nginx -t

# 重载配置
sudo nginx -s reload

# 或重启Nginx
sudo systemctl restart nginx

3.6 解决SPA刷新404问题

问题: React/Vue应用刷新页面后404

原因: Nginx找不到物理文件/about.html

解决: 使用try_files

location / {
    root /var/www/mysite/dist;
    index index.html;
    try_files $uri $uri/ /index.html;  # 关键配置!
}

原理: 找不到文件时,返回index.html,让前端路由处理


4. PM2进程管理

4.1 为什么需要PM2?

问题: 直接运行node app.js

node app.js
# 程序崩溃了 → 应用停止! ✗
# 关闭终端 → 应用停止! ✗
# 服务器重启 → 应用不会自动启动! ✗

PM2解决方案:

  • ✅ 自动崩溃重启
  • ✅ 后台运行(关闭终端也不停)
  • ✅ 服务器重启后自动启动
  • ✅ 集群模式(多核CPU利用)
  • ✅ 日志管理
  • ✅ 零停机部署

4.2 安装PM2

# 全局安装PM2
sudo npm install -g pm2

# 验证安装
pm2 --version

4.3 PM2基础命令

启动应用:

# 启动应用
pm2 start app.js --name my-app

# 启动Python应用
pm2 start app.py --interpreter python3

# 集群模式(利用所有CPU核心)
pm2 start app.js -i max

管理应用:

# 查看所有应用
pm2 list
pm2 status

# 查看详细信息
pm2 show my-app

# 查看日志
pm2 logs my-app

# 实时监控
pm2 monit

重启和停止:

# 重启应用
pm2 restart my-app

# 重载应用(零停机)
pm2 reload my-app

# 停止应用
pm2 stop my-app

# 删除应用
pm2 delete my-app

# 重启所有应用
pm2 restart all

4.4 开机自启配置 ⚠️ 重要!

必须执行的两个命令:

# 1. 生成启动脚本
pm2 startup

# 会输出类似这样的命令,复制执行:
# sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u username --hp /home/username

# 2. 保存当前应用列表
pm2 save

为什么两个都要?

  • pm2 startup: 让系统启动时启动PM2
  • pm2 save: 告诉PM2启动时要运行哪些应用

验证:

# 重启服务器
sudo reboot

# 重新登录后检查
pm2 list
# 你的应用应该自动运行了!

4.5 使用ecosystem.config.js

创建配置文件:

pm2 init

编辑ecosystem.config.js:

module.exports = {
  apps: [
    {
      name: 'my-app',                    // 应用名称
      script: './server.js',             // 启动文件
      instances: 2,                      // 进程数量(或'max')
      exec_mode: 'cluster',              // 集群模式
      env: {                             // 环境变量
        NODE_ENV: 'development',
        PORT: 3000
      },
      env_production: {
        NODE_ENV: 'production',
        PORT: 8000
      },
      error_file: './logs/err.log',     // 错误日志
      out_file: './logs/out.log',       // 输出日志
      log_date_format: 'YYYY-MM-DD HH:mm:ss',
      merge_logs: true,
      autorestart: true,                 // 自动重启
      watch: false,                      // 文件变化重启(开发用)
      max_memory_restart: '1G'           // 内存超限重启
    }
  ]
};

使用配置文件:

# 启动
pm2 start ecosystem.config.js

# 生产环境启动
pm2 start ecosystem.config.js --env production

# 更新配置后重启
pm2 restart ecosystem.config.js

5. HTTPS和SSL证书

5.1 为什么需要HTTPS?

HTTP的问题:

  • ❌ 数据明文传输,容易被窃听
  • ❌ 浏览器显示“不安全“
  • ❌ 小程序/PWA必须HTTPS
  • ❌ SEO排名更低

HTTPS的好处:

  • ✅ 数据加密传输
  • ✅ 浏览器显示安全锁
  • ✅ 提升用户信任
  • ✅ SEO更好

5.2 使用Let’s Encrypt免费证书

Let’s Encrypt = 免费、自动化、开放的证书颁发机构

安装Certbot:

# Ubuntu/Debian
sudo apt update
sudo apt install certbot python3-certbot-nginx

# CentOS/RHEL
sudo yum install certbot python3-certbot-nginx

自动配置Nginx:

# Certbot会自动修改Nginx配置
sudo certbot --nginx -d www.yoursite.com -d yoursite.com

# 按提示输入邮箱,同意协议
# 选择是否重定向HTTP到HTTPS(推荐选Yes)

Certbot做了什么:

  1. 验证你拥有这个域名
  2. 下载SSL证书
  3. 自动修改Nginx配置
  4. 设置HTTPS监听
  5. 设置HTTP→HTTPS重定向

配置自动续期:

# Let's Encrypt证书90天过期,需要自动续期

# 测试续期
sudo certbot renew --dry-run

# 设置自动续期(已自动配置,无需手动)
# Certbot会创建systemd定时器或cron任务

验证HTTPS:

打开浏览器,访问 https://www.yoursite.com

看到🔒安全锁,说明成功!

5.3 手动配置HTTPS(高级)

如果使用自己的证书:

server {
    listen 443 ssl http2;
    server_name www.yoursite.com;

    # SSL证书配置
    ssl_certificate /etc/nginx/ssl/cert.pem;        # 证书
    ssl_certificate_key /etc/nginx/ssl/key.pem;    # 私钥

    # SSL优化配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # 其他配置...
    location / {
        root /var/www/mysite;
        index index.html;
    }
}

# HTTP自动跳转HTTPS
server {
    listen 80;
    server_name www.yoursite.com;
    return 301 https://$server_name$request_uri;
}

6. 域名和DNS配置

6.1 域名解析原理

用户输入: www.yoursite.com
    │
    ▼
DNS服务器: "这个域名对应IP是 123.45.67.89"
    │
    ▼
浏览器访问: http://123.45.67.89

6.2 DNS记录类型

记录类型作用示例
A记录域名→IPv4地址www.yoursite.com → 123.45.67.89
AAAA记录域名→IPv6地址www.yoursite.com → 2001:db8::1
CNAME记录域名→域名(别名)blog.yoursite.com → www.yoursite.com
MX记录邮件服务器邮箱相关
TXT记录文本信息域名验证

6.3 配置DNS解析

常见域名服务商:

  • 阿里云(万网)
  • 腾讯云DNSPod
  • Cloudflare
  • GoDaddy
  • Namecheap

配置步骤 (以阿里云为例):

  1. 登录域名控制台
  2. 找到你的域名 → 解析
  3. 添加记录

示例配置:

记录类型主机记录记录值TTL
Awww123.45.67.89600
A@123.45.67.89600
CNAMEblogwww.yoursite.com600

记录说明:

  • www: 访问www.yoursite.com
  • @: 访问yoursite.com(根域名)
  • *: 泛解析(所有子域名)

TTL: 缓存时间(秒)

  • 600 = 10分钟
  • 3600 = 1小时

6.4 验证DNS解析

# 查询域名的A记录
nslookup www.yoursite.com

# 或使用dig(更详细)
dig www.yoursite.com

# 查看解析到的IP
ping www.yoursite.com

DNS生效时间: 通常5分钟到24小时


7. 完整部署流程

7.1 前端打包详解

7.1.1 为什么要打包?

打包 = 把开发代码变成浏览器能高效运行的代码

开发环境代码生产环境代码(打包后)
多个JS文件合并成几个文件
有注释、有空格压缩、混淆
完整的错误提示最小化体积
React JSX语法转换成纯JS
ES6+新语法转换成ES5兼容代码
图片原始大小压缩优化

打包前后对比:

开发环境:
src/
├── App.jsx           (5KB, JSX语法)
├── Header.jsx        (3KB)
├── Footer.jsx        (2KB)
├── utils.js          (4KB)
└── ...50个文件

打包后:
dist/
├── index.html        (2KB)
├── main.abc123.js    (120KB, 压缩混淆)
└── main.abc123.css   (15KB, 压缩)

体积减少60%+, 文件数量减少90%+
加载速度提升3-5倍! ⚡

7.1.2 打包前的准备

检查package.json的scripts:

{
  "scripts": {
    "dev": "vite",              // 开发服务器
    "build": "vite build",      // 生产打包
    "preview": "vite preview"   // 预览打包结果
  }
}

常见框架的打包命令:

框架打包命令输出目录
Create React Appnpm run buildbuild/
Vite (React/Vue)npm run builddist/
Next.jsnpm run build.next/
Vue CLInpm run builddist/

7.1.3 环境变量配置

为什么需要环境变量?

开发环境和生产环境的API地址不同:

开发: http://localhost:3000/api
生产: https://api.yoursite.com/api

创建环境变量文件:

# .env.development (开发环境)
VITE_API_URL=http://localhost:3000
VITE_APP_NAME=MyApp Dev

# .env.production (生产环境)
VITE_API_URL=https://api.yoursite.com
VITE_APP_NAME=MyApp

在代码中使用:

// Vite项目
const apiUrl = import.meta.env.VITE_API_URL;

// Create React App项目
const apiUrl = process.env.REACT_APP_API_URL;

⚠️ 重要:

  • 环境变量必须以 VITE_REACT_APP_ 开头才会暴露给前端
  • 不要在前端环境变量中存储密钥!

7.1.4 执行打包

标准打包流程:

# 1. 安装依赖(如果还没装)
npm install

# 2. 执行打包
npm run build

# 打包过程输出示例:
# vite v4.3.0 building for production...
# ✓ 123 modules transformed.
# dist/index.html                  2.15 kB
# dist/assets/index-abc123.js      142.35 kB │ gzip: 45.23 kB
# dist/assets/index-abc123.css     15.67 kB  │ gzip: 4.12 kB
# ✓ built in 3.45s

# 3. 检查打包结果
ls dist/
# index.html  assets/  favicon.ico

打包成功的标志:

  • ✅ 没有报错
  • ✅ 生成了 dist/build/ 文件夹
  • ✅ 文件夹里有 index.html
  • ✅ 有打包后的 JS 和 CSS 文件

7.1.5 本地预览打包结果

为什么要预览?

打包后的代码可能和开发环境表现不同,需要本地测试!

# Vite项目
npm run preview
# ➜  Local:   http://localhost:4173/

# 或使用http-server
npx http-server dist -p 8080

# 或使用serve
npx serve -s dist -p 8080

打开浏览器访问,检查:

  • ✅ 页面能正常显示
  • ✅ 路由跳转正常(SPA应用)
  • ✅ API请求正常
  • ✅ 打开控制台,没有错误

7.1.6 常见打包错误

错误1: 内存溢出

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory

解决:

# 增加Node.js内存限制
NODE_OPTIONS=--max_old_space_size=4096 npm run build

错误2: 环境变量未定义

ReferenceError: process is not defined

原因: 直接使用了 process.env 而不是框架提供的方式

解决:

// ❌ 错误
const apiUrl = process.env.API_URL;

// ✅ 正确(Vite)
const apiUrl = import.meta.env.VITE_API_URL;

// ✅ 正确(CRA)
const apiUrl = process.env.REACT_APP_API_URL;

错误3: 路径引用错误

Failed to load resource: net::ERR_FILE_NOT_FOUND
/assets/logo.png 404

原因: 静态资源路径不对

解决:

// vite.config.js
export default {
  base: '/',  // 或 '/your-subpath/'
}

// 确保图片放在public/文件夹
public/
  └── logo.png

// 代码中引用
<img src="/logo.png" />

错误4: 打包体积过大

(!) Some chunks are larger than 500kb after minification

解决 - 代码分割:

// 使用动态导入
const MyComponent = React.lazy(() => import('./MyComponent'));

// 路由懒加载
const About = lazy(() => import('./pages/About'));

7.1.7 打包优化建议

1. 分析打包体积:

# Vite项目
npm run build -- --report

# 或使用rollup-plugin-visualizer
npm install --save-dev rollup-plugin-visualizer

2. 代码分割:

  • ✅ 路由懒加载
  • ✅ 组件懒加载
  • ✅ 第三方库分离

3. 压缩优化:

  • ✅ 图片压缩(TinyPNG)
  • ✅ 启用Gzip压缩(Nginx配置)
  • ✅ 移除console.log

4. CDN加速:

// vite.config.js
export default {
  build: {
    rollupOptions: {
      external: ['react', 'react-dom'],
      output: {
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM'
        }
      }
    }
  }
}

7.2 前端部署

# 1. 本地构建
npm run build
# 生成dist/文件夹

# 2. 上传到服务器
scp -r dist/* user@your-server:/var/www/mysite/

# 或使用rsync
rsync -avz dist/ user@your-server:/var/www/mysite/

# 3. 设置权限
sudo chown -R www-data:www-data /var/www/mysite
sudo chmod -R 755 /var/www/mysite

# 4. 配置Nginx
sudo vim /etc/nginx/sites-available/mysite

# 5. 测试并重载
sudo nginx -t
sudo nginx -s reload

7.3 后端部署

# 1. 上传代码到服务器
git clone https://github.com/yourname/yourproject.git
cd yourproject

# 2. 安装依赖
npm install --production
# 或 pip install -r requirements.txt

# 3. 配置环境变量
cp .env.example .env
vim .env

# 4. 用PM2启动
pm2 start server.js --name my-api

# 5. 配置开机自启
pm2 startup
pm2 save

# 6. 查看日志
pm2 logs my-api

7.4 完整Nginx配置

# /etc/nginx/sites-available/mysite

server {
    listen 80;
    server_name www.yoursite.com yoursite.com;

    # 重定向到HTTPS
    return 301 https://www.yoursite.com$request_uri;
}

server {
    listen 443 ssl http2;
    server_name www.yoursite.com;

    # SSL证书(Certbot自动配置)
    ssl_certificate /etc/letsencrypt/live/www.yoursite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.yoursite.com/privkey.pem;

    # 前端静态文件
    location / {
        root /var/www/mysite/dist;
        index index.html;
        try_files $uri $uri/ /index.html;
    }

    # 后端API
    location /api/ {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        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;
    }

    # 静态资源缓存
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        root /var/www/mysite/dist;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

8. 常见问题排查

Q1: 访问域名显示502 Bad Gateway

原因: Nginx无法连接到后端

排查步骤:

# 1. 后端应用是否运行?
pm2 list

# 2. 端口是否正确?
netstat -tuln | grep 3000

# 3. 防火墙是否阻止?
sudo ufw status

# 4. 查看Nginx错误日志
sudo tail -f /var/log/nginx/error.log

# 5. 查看应用日志
pm2 logs my-app

Q2: 域名无法访问

排查步骤:

# 1. DNS是否解析正确?
nslookup www.yoursite.com

# 2. 服务器IP是否正确?
ping www.yoursite.com

# 3. 云安全组是否开放80/443?
# 登录云控制台检查

# 4. Nginx是否运行?
sudo systemctl status nginx

# 5. Nginx配置是否正确?
sudo nginx -t

Q3: HTTPS证书错误

排查:

# 1. 证书是否过期?
sudo certbot certificates

# 2. 手动续期
sudo certbot renew

# 3. 强制重新获取
sudo certbot --nginx -d www.yoursite.com --force-renew

Q4: PM2应用重启后停止

原因: 没有配置开机自启

# 重新配置
pm2 startup
# 复制输出的命令执行

pm2 save

# 验证
sudo reboot
# 重启后检查
pm2 list

9. 部署检查清单

部署前

  • ✅ 代码在本地测试通过
  • ✅ 环境变量配置正确
  • ✅ package.json依赖完整
  • ✅ .gitignore配置正确

服务器配置

  • ✅ 云安全组开放80/443/22端口
  • ✅ Node.js/Python环境已安装
  • ✅ npm/pip镜像源已配置
  • ✅ Nginx已安装并运行

应用部署

  • ✅ 代码已上传到服务器
  • ✅ 依赖已安装(npm install/pip install)
  • ✅ PM2应用已启动
  • ✅ PM2开机自启已配置(startup+save)
  • ✅ 应用日志无错误

Nginx配置

  • ✅ 静态文件路径正确
  • ✅ 反向代理配置正确
  • ✅ SPA应用try_files配置
  • ✅ nginx -t测试通过
  • ✅ 配置已重载

HTTPS配置

  • ✅ SSL证书已配置
  • ✅ HTTP自动跳转HTTPS
  • ✅ 浏览器显示安全锁

DNS配置

  • ✅ A记录已添加
  • ✅ DNS解析生效
  • ✅ 域名可以访问

10. 总结

核心要点

  1. 部署三件套:

    • Nginx: 前台接待(反向代理)
    • PM2: 部门经理(进程管理)
    • 云安全组: 门禁系统(防火墙)
  2. HTTPS是必需的:

    • 使用Let’s Encrypt免费证书
    • Certbot自动配置
    • 自动续期
  3. DNS解析:

    • A记录指向服务器IP
    • 等待5分钟-24小时生效
  4. PM2必须配置开机自启:

    • pm2 startup
    • pm2 save
    • 两个都要!

典型错误

错误原因解决
502 Bad Gateway后端没运行检查PM2
403 Forbidden权限不对chown+chmod
无法访问安全组没开开放端口
证书错误证书过期certbot renew
重启后应用停止没保存PM2pm2 save

下一步

恭喜!你已经掌握了完整的部署流程。

继续深入:

  • 学习Docker容器化部署
  • 学习CI/CD自动化部署
  • 学习Kubernetes集群管理
  • 学习监控和日志分析

记住: 部署出问题是正常的,重要的是学会看日志排查!