前端到上线全流程:从买服务器到 Nginx 反向代理,搞懂全栈部署
写完代码
npm run dev跑通了,然后呢?如何让全世界都能访问你的网站?本文以一个 React + TS 前端 + Node.js 后端的前后端分离项目为例,完整拆解从购买服务器、域名备案、DNS 解析、安全组防火墙、Nginx 反向代理到项目构建上线的全流程。不止讲"怎么做",更讲"为什么"------为什么 80 端口是 HTTP 默认端口,为什么 Nginx 反向代理能解决跨域,为什么开发环境和生产环境的数据库要分开。建议收藏后跟着实操。
一、部署的两个选择:Vercel vs 自建服务器
1.1 Vercel 云端部署
ini
Vercel = Next.js 的母公司
适合场景:
→ Next.js + Supabase 项目
→ 部署方式比较固定
→ push 代码 → 自动构建 → 自动部署
→ 免费二级域名 xxx.vercel.app
局限:
→ 部署自由度受限(Vercel 的规则)
→ Java、Go、Python 等非 JS 栈支持有限
→ 国内访问速度不稳定
→ 定制化需求难以满足
1.2 自建服务器部署
自建服务器 = 完全掌控
适合场景:
→ 任何技术栈(Node.js / Java / Go / Python)
→ 部署自由度极高
→ 国内支持好(腾讯云、阿里云)
→ 可以完全控制 Nginx、数据库、SSL 等配置
成本:
→ 轻量云服务器约 35 元/月起
→ 域名 + 备案 10-20 天
→ 需要一定的 Linux 运维知识
本文重点:自建服务器 + 宝塔面板 + Nginx
1.3 对比
| 维度 | Vercel | 自建服务器 |
|---|---|---|
| 部署方式 | push 自动部署 | 手动配置 |
| 自由度 | 受 Vercel 约束 | 完全自由 |
| 技术栈 | JS 生态为主 | 任意技术栈 |
| 国内访问 | 不稳定 | 腾讯云/阿里云快 |
| 运维成本 | 零运维 | 需要基础运维 |
| 适合项目 | Next.js 全栈 | 前后端分离任意栈 |
二、部署全流程概览
2.1 完整流程图
arduino
┌──────────────────────────────────────────────────────────────┐
│ 全栈部署完整流程 │
│ │
│ ① 购买服务器 │
│ → 轻量云服务器(Linux) │
│ → 获得公网 IP │
│ → 安装宝塔面板 │
│ │ │
│ ▼ │
│ ② 购买域名 + 备案 │
│ → 域名绑定服务器 IP │
│ → ICP 备案(10-20 天) │
│ │ │
│ ▼ │
│ ③ 配置 HTTPS │
│ → SSL 证书 │
│ → 更安全的 HTTP │
│ │ │
│ ▼ │
│ ④ 服务器环境搭建 │
│ → 安装 Nginx(Web 服务器) │
│ → 安装 Node.js(nvm 版本管理) │
│ → 安装 MySQL(dev/production 双库) │
│ │ │
│ ▼ │
│ ⑤ 项目构建 │
│ → 前端:npm run build → dist/ 静态资源 │
│ → 后端:npm run build → dist/ 编译后的 JS │
│ │ │
│ ▼ │
│ ⑥ Nginx 配置 │
│ → 静态资源路由(返回 HTML/CSS/JS) │
│ → 动态资源路由(反向代理到 Node 后端) │
│ → 跨域问题自动解决 │
│ │ │
│ ▼ │
│ ⑦ 启动服务 │
│ → node dist/app.js(后端启动) │
│ → Nginx 常驻(前端服务) │
│ → 用户访问域名 → 看到网站 │
└──────────────────────────────────────────────────────────────┘
2.2 前后端分离项目的产出
arduino
前后端分离 = 两套独立的项目
前端项目(React + TypeScript):
├── 开发:npm run dev → Vite 开发服务器(localhost:5173)
├── 构建:npm run build → dist/ 静态资源文件
│ ├── index.html
│ ├── assets/
│ │ ├── index.js(打包后的 JS)
│ │ └── index.css(打包后的 CSS)
│ └── ...
└── 部署:dist/ 放到 Nginx 静态资源目录
后端项目(Node.js + TypeScript):
├── 开发:npm run dev → ts-node-dev 热更新
├── API:/api/todos → 返回 JSON
├── 构建:npm run build → dist/ 编译后的 JS
│ └── dist/app.js
└── 部署:node dist/app.js(正式启动)
三、购买服务器与宝塔面板
3.1 购买轻量云服务器
选择轻量云服务器:
→ Linux 系统(Ubuntu / CentOS)
→ 获得公网 IP(如 175.27.132.28)
→ 全量 Linux 部署,命令行成本较高
痛点:
→ Linux 命令行操作门槛高
→ 配置 Nginx、MySQL、Node 都需要命令行
→ 对前端开发者不友好
解决方案:宝塔面板
3.2 宝塔面板
ruby
宝塔(BT Panel)= 服务器管理面板
核心价值:
→ 给服务器装了一个"控制台/操作系统后台"
→ 可视化操作,点击完成部署
→ 不用记 Linux 命令
┌──────────────────────────────────────────────────────┐
│ 宝塔面板的核心能力 │
│ │
│ ├── 可视化管理 │
│ │ → 文件管理(上传、编辑、删除) │
│ │ → 软件管理(一键安装 Nginx、MySQL、Node) │
│ │ → 网站管理(添加站点、配置域名、SSL) │
│ │ → 数据库管理(创建库、用户、权限) │
│ │ → 防火墙管理(开放/关闭端口) │
│ │ → 进程管理(查看运行状态、日志) │
│ │ │
│ ├── 自由度高 │
│ │ → 想怎么部署就怎么部署 │
│ │ → 不受平台限制 │
│ │ → 适合任意技术栈 │
│ │ │
│ └── 服务器默认端口 │
│ → 宝塔面板:8888 │
│ → 通过 http://公网IP:8888 访问 │
└──────────────────────────────────────────────────────┘
项目根目录:
/www/wwwroot/ → 宝塔默认的网站根目录
→ 前端 dist/ 文件放在这里
→ 后端项目也放在这里
四、用户访问网站到底发生了什么?
4.1 完整链路图
bash
用户在浏览器输入域名 → 网站显示内容
这个过程中发生了什么?
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ │ │ │ │ │ │ │ │ │
│ 浏览器 │ ─→ │ DNS │ ─→ │ 安全组 │ ─→ │ 防火墙 │ ─→ │ Nginx │
│ 输入域名 │ │ 域名解析 │ │ 保安 │ │ 门卫 │ │ 分流器 │
│ │ │ │ │ │ │ │ │ │
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
│
┌───────────────┼───────────────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ │ │ │
│ 静态资源 │ │ Node.js │
│ dist/ │ │ 后端服务 │
│ HTML/CSS │ │ /api/* │
│ │ │ │
└──────────┘ └──────────┘
4.2 DNS 域名解析
ini
DNS = Domain Name System(域名系统)
作用:域名 → IP 地址的映射
用户输入 www.example.com
│
│ ① 浏览器 DNS 缓存
│ → 浏览器自己缓存过?
│
│ ② 操作系统 DNS 缓存
│ → 本机系统缓存过?
│
│ ③ 局域网 DNS 服务器
│ → 路由器/公司内网缓存?
│
│ ④ 城域网 DNS 服务器
│ → 电信/联通运营商缓存?
│
│ ⑤ 根 DNS 服务器
│ → .com / .cn 顶级域名服务器
│ → 权威 DNS 服务器返回最终 IP
│
▼
DNS 返回服务器公网 IP(如 175.27.132.28)
DNS 查询会缓存在本地(每一层都可能缓存)
→ 所以第二次访问同域名会更快
→ 这就是 DNS Prefetch 提前解析的意义
4.3 安全组与防火墙
yaml
请求到达服务器前,要过两道关卡:
┌──────────────────────────────────────────────────────────┐
│ 第一道关卡:安全组(Security Group) │
│ │
│ 位置:云厂商网络层(如腾讯云控制台) │
│ 作用:控制哪些端口可以被外网访问 │
│ 类比:小区大门保安 ------ 不让外人进 │
│ │
│ 常见端口策略: │
│ ├── 80 → HTTP 默认端口 → 放行 │
│ ├── 443 → HTTPS 默认端口 → 放行 │
│ ├── 8888 → 宝塔面板端口 → 限制 IP(只允许管理员) │
│ ├── 3306 → MySQL 端口 → 不放行(或限制 IP) │
│ └── 其他 → 尽量少开放端口 │
│ │
│ 安全组规则: │
│ → IP 限流:恶意 IP 封禁 │
│ → 端口管控:只开放必要端口 │
│ → dev/production 区分:只开放给特定 IP │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│ 第二道关卡:防火墙(Firewall) │
│ │
│ 位置:服务器操作系统层(Linux 内核) │
│ 作用:控制哪些端口可以被进程监听 │
│ 类比:大楼门卫 ------ 检查进入楼内的人 │
│ │
│ 常见工具: │
│ → iptables(Linux 原生防火墙) │
│ → ufw(Ubuntu 简化防火墙) │
│ → firewalld(CentOS 防火墙) │
│ → 宝塔面板可视化配置 │
└──────────────────────────────────────────────────────────┘
安全组 vs 防火墙:
→ 安全组在云厂商网络层(先拦截)
→ 防火墙在操作系统层(后拦截)
→ 两层防护,双重保险
4.4 Nginx:真正的入口
javascript
Nginx = 高性能的 Web 服务器
请求通过安全组和防火墙后,到达 Nginx
Nginx 做三件事:
┌──────────────────────────────────────────────────────────┐
│ Nginx 的三大职责 │
│ │
│ ① 接受请求 │
│ → 监听 80(HTTP)和 443(HTTPS)端口 │
│ → 接收所有来自浏览器的 HTTP 请求 │
│ │
│ ② 返回静态资源 │
│ → 请求 http://175.27.132.28/ │
│ → 匹配静态路由 │
│ → 返回 dist/index.html │
│ → 前端页面、CSS、JS、图片等静态文件 │
│ │
│ ③ 反向代理(动态资源转发) │
│ → 请求 http://175.27.132.28/api/todos │
│ → 匹配 /api 路由 │
│ → 转发到 http://127.0.0.1:3001/todos │
│ → Node.js 后端处理 │
│ → 返回 JSON │
│ → Nginx 把 JSON 返回给前端 │
└──────────────────────────────────────────────────────────┘
五、Nginx 反向代理:跨域问题的终极解法
5.1 开发环境的跨域问题
arduino
开发环境(npm run dev):
前端:localhost:5173(Vite 开发服务器)
后端:localhost:3001(Node.js API 服务器)
前端发送请求:
fetch('http://localhost:3001/api/todos')
│
│ 浏览器检查:
│ → 请求源:localhost:5173
│ → 目标源:localhost:3001
│ → 端口不同 → 跨域!
│ → 浏览器拦截(CORS 策略)
│
✗ 跨域错误
开发环境的解决方式:
→ Vite 配置 proxy 代理
→ vite.config.js 中 proxy: { '/api': 'http://localhost:3001' }
→ Vite 拦截 /api 请求,转发到后端
→ 浏览器以为请求是发给 5173 的 → 不跨域
5.2 生产环境:Nginx 反向代理
javascript
生产环境(Nginx 部署后):
前端:Nginx 提供静态资源(端口 80)
后端:Node.js 运行在 localhost:3001
前端发送请求:
fetch('/api/todos')
│
│ 请求发到 Nginx(同源,端口 80)
│ → 浏览器检查:
│ → 请求源:http://example.com(端口 80)
│ → 目标源:http://example.com/api/todos(端口 80)
│ → 同源!不跨域!
│
▼
Nginx 收到 /api/todos 请求
│
│ Nginx 配置了反向代理:
│ location /api {
│ proxy_pass http://127.0.0.1:3001;
│ }
│
│ Nginx 把请求转发到 Node.js 后端
│ → http://127.0.0.1:3001/todos
│
▼
Node.js 处理请求,返回 JSON
│
▼
Nginx 把 JSON 返回给浏览器
跨域?不存在的!
→ 浏览器只跟 Nginx(80 端口)通信
→ Nginx 内部转发到 Node.js(3001 端口)
→ 浏览器不知道后端的存在
→ 同源策略不触发 → 没有跨域问题
5.3 反向代理的本质
正向代理 vs 反向代理:
正向代理(VPN / 代理服务器):
→ 客户端知道要访问的目标
→ 代理帮客户端去访问
→ 服务器不知道真正的客户端是谁
→ 类比:你找代购帮你买海外商品
反向代理(Nginx):
→ 客户端不知道真正的后端是谁
→ Nginx 帮服务器接收请求
→ 客户端以为 Nginx 就是服务器
→ 类比:你拨打客服电话,接线员帮你转接到具体部门
┌──────────────────────────────────────────────────────────┐
│ Nginx 反向代理解决跨域的本质 │
│ │
│ 没有 Nginx: │
│ → 前端(80 端口)→ 后端(3001 端口) │
│ → 端口不同 → 跨域 │
│ │
│ 有 Nginx: │
│ → 前端 → Nginx(80 端口)→ 后端(3001 端口) │
│ → 前端只跟 Nginx(80 端口)通信 │
│ → Nginx 内部转发 → 浏览器无感知 │
│ → 同源 → 不跨域 │
│ │
│ 一句话:Nginx 把前后端统一到同一个端口下 │
└──────────────────────────────────────────────────────────┘
5.4 Nginx 配置示例
nginx
# /www/server/nginx/conf/vhost/example.conf
server {
listen 80; # 监听 HTTP 80 端口
server_name example.com; # 绑定域名
root /www/wwwroot/dist; # 前端静态资源目录
# ① 静态资源路由
location / {
try_files $uri $uri/ /index.html;
# React Router 的 history 模式需要回退到 index.html
}
# ② 动态资源路由(反向代理)
location /api {
proxy_pass http://127.0.0.1:3001; # 转发到 Node.js 后端
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# ③ HTTPS 配置(可选)
# listen 443 ssl;
# ssl_certificate /path/to/cert.pem;
# ssl_certificate_key /path/to/key.pem;
}
bash
请求分流逻辑:
http://example.com/ → Nginx 返回 dist/index.html(静态)
http://example.com/assets/x.js → Nginx 返回 dist/assets/x.js(静态)
http://example.com/api/todos → Nginx 转发到 Node:3001/todos(动态)
http://example.com/api/users → Nginx 转发到 Node:3001/users(动态)
六、服务器环境搭建
6.1 Node.js 版本管理:nvm
css
nvm = Node Version Manager(Node 版本管理器)
为什么需要 nvm?
→ 不同项目依赖不同的 Node 版本
→ 项目 A 需要 Node 18
→ 项目 B 需要 Node 20
→ nvm 可以同时安装多个版本,通过指针切换
┌──────────────────────────────────────────────┐
│ nvm 工作原理 │
│ │
│ nvm install 18 → 安装 Node 18 │
│ nvm install 20 → 安装 Node 20 │
│ nvm use 18 → 切换到 Node 18(指针) │
│ nvm use 20 → 切换到 Node 20(指针) │
│ nvm current → 查看当前使用的版本 │
│ │
│ 本质:指针指向不同版本的 Node 安装目录 │
└──────────────────────────────────────────────┘
6.2 MySQL 数据库
bash
安装 MySQL 后,建立开发和生产两个数据库:
┌──────────────────────────────────────────────────────────┐
│ dev / production 双库隔离 │
│ │
│ time_capsule_dev(开发库) │
│ → 本地开发时连接 │
│ → 可以随意修改、删除数据 │
│ → 密码独立管理 │
│ │
│ time_capsule_production(生产库) │
│ → 线上运行时连接 │
│ → 严格保护,不能随意操作 │
│ → 密码独立管理 │
│ │
│ 为什么要分开? │
│ → 开发时改数据不影响线上 │
│ → 线上数据不会被误删 │
│ → 密码隔离,安全独立 │
└──────────────────────────────────────────────────────────┘
安全建议:
→ 数据库密码不要提交到 Git
→ 使用 .env 环境变量管理
→ production 密码要足够复杂
→ 3306 端口不对外开放(只允许本机 127.0.0.1 访问)
6.3 HTTPS 配置
ini
HTTPS = HTTP + SSL/TLS
HTTP(明文传输):
→ 数据在传输过程中是明文
→ 中间人可以截获、篡改
→ 不安全
HTTPS(加密传输):
→ 数据在传输过程中加密
→ 中间人无法读取内容
→ 更安全
SSL 证书:
→ 证明网站身份的数字证书
→ Let's Encrypt 提供免费证书
→ 宝塔面板一键申请 SSL
默认端口:
→ HTTP → 80
→ HTTPS → 443
七、项目构建与启动
7.1 前端构建
arduino
前端项目(React + TypeScript):
开发环境:
→ npm run dev
→ Vite 启动开发服务器(localhost:5173)
→ 热更新(HMR)
→ 实际案例:瀑布流布局(小红书风格)
→ 经典复杂的前端用户体验
→ 无限滚动(滚动到底部自动加载)
生产构建:
→ npm run build
→ Vite 打包编译
→ 输出 dist/ 静态资源文件
→ 将 dist/ 上传到服务器 /www/wwwroot/dist
→ Nginx 提供静态资源服务
7.2 后端构建
arduino
后端项目(Node.js + TypeScript):
TypeScript 是大型项目的标配:
→ 类型安全,减少运行时错误
→ 代码可维护性高
→ IDE 智能提示更好
但 Node.js 不能直接运行 TypeScript:
→ 需要 TS → JS 的编译过程
┌──────────────────────────────────────────────────────────┐
│ 三种运行方式 │
│ │
│ ① 开发环境:ts-node-dev │
│ → npm run dev │
│ → ts-node-dev 实时编译 TS → JS → 热更新运行 │
│ → 修改代码自动重启 │
│ → 开发体验好,但性能差(每次编译) │
│ │
│ ② 生产构建:tsc │
│ → npm run build │
│ → TypeScript 编译器将 TS → JS │
│ → 输出到 dist/ 目录 │
│ → 一次性编译,性能好 │
│ │
│ ③ 生产启动:node │
│ → npm run start │
│ → node dist/app.js │
│ → 直接运行编译后的 JS │
│ → 无需编译,性能最佳 │
└──────────────────────────────────────────────────────────┘
7.3 .env 环境变量配置
ini
.env 文件管理不同环境的配置:
开发环境(.env.development):
DATABASE_URL=postgresql://user:password@localhost:5432/time_capsule_dev
PORT=3001
NODE_ENV=development
生产环境(.env.production):
DATABASE_URL=postgresql://user:password@localhost:5432/time_capsule_production
PORT=3001
NODE_ENV=production
常见问题:数据库连接失败
→ 检查 .env 中的 DATABASE_URL 是否正确
→ 检查数据库是否启动
→ 检查密码是否正确
→ 检查数据库名是否存在
安全:
→ .env 文件不提交到 Git(.gitignore 排除)
→ 生产环境密码与开发环境不同
→ 服务器上手动创建 .env 文件
八、完整部署流程串讲
8.1 从零到上线
sql
完整部署时间线:
Day 1:购买服务器
→ 腾讯云/阿里云购买轻量云服务器
→ 选择 Linux 系统
→ 获得公网 IP
→ 安装宝塔面板
→ 通过 http://公网IP:8888 访问面板
Day 1-20:域名备案
→ 购买域名
→ 提交 ICP 备案(10-20 个工作日)
→ 备案期间可以用 IP 访问
Day 2:服务器环境搭建
→ 宝塔面板安装 Nginx
→ 宝塔面板安装 MySQL
→ nvm 安装 Node.js
→ 创建 dev / production 两个数据库
→ 配置安全组(开放 80、443 端口)
Day 3:项目部署
→ 前端:npm run build → dist/ 上传到 /www/wwwroot/dist
→ 后端:npm run build → dist/ 上传到 /www/wwwroot/api
→ 后端:创建 .env 文件配置生产数据库
→ 后端:node dist/app.js 启动(用 PM2 守护进程)
→ Nginx:配置静态资源 + 反向代理
→ Nginx:重启 nginx -s reload
Day 20+:域名解析 + HTTPS
→ 备案通过
→ DNS 解析域名 → 服务器 IP
→ 宝塔面板申请 SSL 证书
→ 配置 HTTPS
→ 用户通过域名访问网站
8.2 用 PM2 守护 Node 进程
bash
直接用 node dist/app.js 启动的问题:
→ 终端关闭后进程就停了
→ 进程崩溃后不会自动重启
→ 没有日志管理
PM2 解决方案:
→ pm2 start dist/app.js # 启动并守护
→ pm2 list # 查看所有进程
→ pm2 logs # 查看日志
→ pm2 restart app # 重启
→ pm2 stop app # 停止
→ pm2 startup # 开机自启
→ pm2 save # 保存进程列表
PM2 的价值:
→ 进程崩溃自动重启
→ 终端关闭不影响
→ 开机自动启动
→ 日志管理
→ 零停机重载(pm2 reload)
8.3 请求完整链路
javascript
用户访问 http://example.com/api/todos 的完整链路:
① 浏览器输入域名
│
▼
② DNS 解析
→ example.com → 175.27.132.28(公网 IP)
│
▼
③ 安全组检查(云厂商网络层)
→ 80 端口是否开放?→ 是
│
▼
④ 防火墙检查(操作系统层)
→ 80 端口是否放行?→ 是
│
▼
⑤ Nginx 接收请求
→ 匹配 location /api
→ proxy_pass http://127.0.0.1:3001/todos
│
▼
⑥ Node.js 处理请求
→ 路由匹配 /api/todos
→ 查询数据库(MySQL / Supabase)
→ 返回 JSON
│
▼
⑦ Nginx 返回响应
→ JSON → 浏览器
│
▼
⑧ 浏览器渲染
→ 前端 JS 解析 JSON
→ 更新 UI
→ 用户看到数据
九、部署知识速查
9.1 端口速查表
| 端口 | 服务 | 说明 | 安全策略 |
|---|---|---|---|
| 80 | HTTP | Nginx 默认端口 | 放行 |
| 443 | HTTPS | SSL 加密端口 | 放行 |
| 8888 | 宝塔面板 | 服务器管理 | 限制 IP |
| 3001 | Node.js | 后端 API 服务 | 不放行(仅内部) |
| 3306 | MySQL | 数据库 | 不放行(仅内部) |
| 22 | SSH | 远程登录 | 限制 IP |
9.2 关键概念表
| 概念 | 本质 | 类比 |
|---|---|---|
| DNS | 域名 → IP 映射 | 查通讯录找地址 |
| 安全组 | 云厂商网络层端口管控 | 小区大门保安 |
| 防火墙 | 操作系统层端口管控 | 大楼门卫 |
| Nginx | Web 服务器 + 反向代理 | 前台接线员 |
| 反向代理 | Nginx 转发请求到后端 | 接线员转接到具体部门 |
| HTTPS | HTTP + SSL 加密 | 密信传输 |
| nvm | Node 版本管理器 | 多版本切换器 |
| PM2 | Node 进程守护 | 进程保姆 |
| 宝塔面板 | 服务器可视化管理面板 | 服务器控制台 |
9.3 Nginx 路由速查
nginx
# 静态资源
location / {
root /www/wwwroot/dist;
try_files $uri $uri/ /index.html;
}
# API 反向代理
location /api {
proxy_pass http://127.0.0.1:3001;
}
# 静态文件缓存
location ~* \.(js|css|png|jpg|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
十、总结
10.1 知识体系图
bash
全栈部署全流程
│
├── 部署选择
│ ├── Vercel(Next.js 专用,零运维)
│ └── 自建服务器(任意栈,完全掌控)
│
├── 服务器准备
│ ├── 购买轻量云服务器(Linux)
│ ├── 安装宝塔面板(可视化,端口 8888)
│ ├── 域名 + ICP 备案(10-20 天)
│ └── 配置 HTTPS(SSL 证书)
│
├── 用户访问全链路
│ ├── DNS 解析(域名 → IP,多级缓存)
│ ├── 安全组(云厂商网络层,端口管控)
│ ├── 防火墙(操作系统层,端口管控)
│ └── Nginx(真正的入口,请求分流)
│
├── Nginx 三大职责
│ ├── 接受请求(监听 80/443 端口)
│ ├── 静态资源(返回 dist/ HTML/CSS/JS)
│ └── 反向代理(转发 /api 到 Node 后端)
│ └── 解决跨域:前后端统一到同端口
│
├── 服务器环境
│ ├── nvm(Node 版本管理,多版本切换)
│ ├── MySQL(dev/production 双库隔离)
│ ├── PM2(Node 进程守护,崩溃自重启)
│ └── .env(环境变量,密码不提交 Git)
│
├── 项目构建
│ ├── 前端:npm run dev → npm run build → dist/
│ ├── 后端:ts-node-dev → tsc → node dist/app.js
│ └── TypeScript:大型项目标配,TS → JS 编译
│
└── 关键认知
├── 80 = HTTP 默认端口,443 = HTTPS 默认端口
├── Nginx 反向代理 = 跨域终极解法
├── 安全组(云层)vs 防火墙(系统层)= 双重防护
└── dev/production 数据库隔离 = 安全底线
10.2 一句话总结
全栈部署的本质是一条请求链路:浏览器 → DNS 解析域名拿到 IP → 安全组放行端口 → 防火墙放行端口 → Nginx 接收请求并分流(静态资源直接返回,动态请求反向代理到 Node.js 后端)→ 后端查询数据库返回 JSON。其中 Nginx 反向代理是核心------它把前后端统一到同一个端口下,从根本上消灭了跨域问题。宝塔面板让 Linux 命令行操作变成可视化点击,nvm 管理多版本 Node,PM2 守护后端进程,.env 隔离环境配置。掌握这条链路,你就具备了把任何项目从本地搬到线上的能力。
如果这篇文章对你有帮助,欢迎点赞 和收藏!