一、故事的开头:本地跑通了,然后呢?
前段时间,我做完了一个 AI 项目—— 学面通AI。前端、后端、数据库、向量库都已经在本地跑得好好的:打开 localhost,功能一切正常。但是要怎样才把这个项目上线?让其他人也能在线上访问
我把这条路走了一遍,发现可以拆成三块:
- 基础设施:服务器、域名、证书,先把“地基”打好;
- 工程化改造:容器化、网关、数据持久化,让项目具备“上线的资格”;
- 部署执行:真正把代码送上去,让服务跑起来。
这篇文章是整个部署系列的总览,先带你把全局地图看清楚,后面的章节再逐个动手实操。
二、第一步:先有一台“永不关机的电脑”——云服务器
本地电脑要关机、要断网、没有公网地址,显然不能拿来对外提供服务。
所以第一件事是购买一台云服务器:它本质上就是一台放在云端、24 小时开机的 Linux 电脑,用来存放代码、运行程序。
小提醒:买完之后记得到安全组里只放行必要端口(通常是 80、443,以及用于登录的 22)。数据库、Redis 等端口不要对公网开放,后面我们会专门处理。
三、第二步:给服务器起个好记的名字——域名与 DNS
服务器买好后,会得到一个公网 IP,比如 47.xx.xx.xx。理论上用 IP 就能访问,但一长串数字既不好记,也不专业。
这就是域名存在的意义:方便用户记忆和访问。
不过这里有个底层原理要搞清楚:互联网通信靠的是 IP 地址,不是域名。浏览器拿到域名后,要先经过 DNS 解析,把域名翻译成服务器的公网 IP,才能真正找到你的机器。
所以这一步的完整动作是:购买域名 → 添加 DNS 解析记录,指向服务器公网 IP。
小提醒:如果服务器在中国大陆,域名需要先完成 ICP 备案才能正常对外提供网站服务,建议尽早办理,因为备案需要时间。
四、第三步:给访问加把锁——HTTPS 证书
现在用户已经能通过域名访问网站了,但浏览器地址栏可能还显示“不安全”。原因是数据在浏览器和服务器之间是明文传输的。
HTTPS 证书的作用,就是让这段传输过程被加密,保障数据安全。
这里有一个容易踩的顺序坑:
⚠️ 证书是和域名绑定的,所以必须先拥有域名,才能申请对应的证书。
到这里,“地基”就打好了:服务器 + 域名 + 证书。接下来,轮到项目本身“动手术”了。
五、第四步:把一堆服务装进“集装箱”——Docker + Docker Compose
我们来数一数学面通在跑的服务:
- FastAPI:后端业务服务
- MySQL:关系型数据
- Redis:缓存
- MinIO:文件存储
- Qdrant:向量数据库
如果在服务器上一个个手动安装、配置、启动,光是环境差异就够折腾一整天:版本冲突、依赖缺失、“我本地明明是好的”……
解决办法是容器化:用 Docker 把每个服务封装成独立的容器,一个服务一个容器;再用 Docker Compose 写一份 docker-compose.yml,把所有容器的启动方式统一编排好。
编排完成后,只需要一条命令,就能把整套服务一起拉起来:
docker compose up -d
除了省事,容器化还有个很重要的安全收益:Docker 内置了私有内网,容器之间在内网中互相通信,里面的服务不会直接暴露在公网。比如外网根本访问不到你的 MySQL,这就等于给数据库加了一层天然的保护。
一个精简版的编排骨架大概长这样(仅作示意,实际配置会在后续章节展开):
services:
nginx:
image: nginx:stable
ports:
- "80:80"
- "443:443"
volumes:
- ./frontend/dist:/usr/share/nginx/html:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- backend
backend: # FastAPI
build: ./backend
env_file: .env
depends_on:
- mysql
- redis
- minio
- qdrant
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:7
volumes:
- redis_data:/data
minio:
image: minio/minio
command: server /data --console-address ":9001"
volumes:
- minio_data:/data
qdrant:
image: qdrant/qdrant
volumes:
- qdrant_data:/qdrant/storage
volumes:
mysql_data:
redis_data:
minio_data:
qdrant_data:
注意:只有 nginx 对外暴露了端口,其余服务都藏在内网里。
六、第五步:给所有请求装一个“前台”——Nginx 统一网关
服务都在内网里了,用户的请求怎么进来?
答案是:所有请求都先经过 Nginx。它就像公司的前台,统一接待所有访客,再按需求分流:
| 用户请求 | Nginx 的处理方式 |
|---|---|
| 前端静态资源(页面、JS、CSS) | 直接返回,速度快 |
| 后端 API 调用 | 反向代理,转发到内网的后端服务 |
| 文件请求 | 同样转发处理 |
同时,Nginx 还会读取服务器上的证书,完成 HTTPS 的加解密。也就是说,加密、分流、转发这些“共同操作”,都在统一入口一次性解决,既方便管理,也提升了安全性。
核心配置的思路大致如下:
server {
listen 80;
server_name your-domain.com;
return 301 https://$host$request_uri; # HTTP 自动跳转 HTTPS
}
server {
listen 443 ssl;
server_name your-domain.com;
ssl_certificate /etc/nginx/certs/your-domain.com.pem;
ssl_certificate_key /etc/nginx/certs/your-domain.com.key;
# 前端静态资源
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
# 后端 API 反向代理
location /api/ {
proxy_pass http://backend:8000;
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;
}
}
这里的 backend 就是 Compose 里的服务名——容器在同一个内网中,可以直接用服务名互相访问。
七、第六步:容器删了,数据可不能丢——数据持久化
容器化带来一个新问题:容器是“可丢弃”的。一旦容器被删除重建,里面的数据也会跟着消失,MySQL 里的用户数据、Qdrant 里的向量,岂不是全没了?
解决方案是命名数据卷(named volume)。回头看上面的 Compose 骨架,你会发现每个有状态的服务都挂了一个卷,比如 mysql_data、redis_data。
这样一来,数据实际保存在 Linux 服务器的磁盘上,而不是容器内部。即使容器重启、甚至被删除重建,原有数据依然完好。
八、真正的部署:把代码送上云端
“装备”都备齐了,终于可以动手部署了。整个执行流程如下:
- 配置
.gitignore:把 node_modules、本地缓存、密钥等不需要上传的文件忽略掉; - 前端打包:运行打包命令,生成 dist 目录,交给 Nginx 托管;
- 准备环境变量文件:把数据库密码、各类密钥等配置到
.env(注意不要提交到 Git); - 上传代码到云服务器:可以通过 Git 拉取,或用 scp / rsync 上传;
- 构建并启动容器:在服务器上执行 Compose 命令,自动拉取镜像、安装依赖:
docker compose up -d --build
- 数据库迁移:容器启动后,MySQL 里还是一片空白。通过 Alembic 迁移命令,自动在 MySQL 容器中创建所需的数据表:
docker compose exec backend alembic upgrade head
到这一步,访问你的域名,就能看到线上的学面通了。
九、串起来看:一个请求的完整旅程
当用户在浏览器输入域名并发起操作,整个链路是这样的:
用户 → 输入域名访问
↓ DNS 解析为服务器公网 IP
Nginx(统一入口,HTTPS 解密)
↓
┌─────┴──────────────┐
静态资源 API 请求
直接返回 转发给 FastAPI 后端
↓
MySQL / Redis / MinIO / Qdrant
(分工完成不同任务)
↓
结果原路返回浏览器
- 静态资源:Nginx 直接返回;
- API 请求:转发给后端,后端连接 MySQL、Redis、MinIO、Qdrant,各司其职完成任务;
- 响应:结果沿原路返回给用户。
十、总结:部署的三个重点
回头看,整条链路可以浓缩成三件事:
- 基础设施先到位:购买服务器、域名并解析、申请 HTTPS 证书(先有域名,再申请证书);
- Docker + Docker Compose 容器化编排:多个服务统一写进一份配置文件,一条命令启动全部服务,依赖自动下载,不用手动逐个安装;
- Nginx 统一网关 + 数据卷持久化:统一入口做 HTTPS、分流与代理,保障安全;命名数据卷保证数据不丢失。