实习一个月,第一次真正把项目部署到公网服务器上。
之前一直都是本地开发,npm run dev 一把梭,感觉项目“能跑”就结束了。结果最近开始做微信支付、支付宝这些功能,才发现很多东西本地根本没法调。
公司在入职的时候就给了一台 Ubuntu 服务器,我第一次正式开始折腾:
- Docker Compose
- Next.js 部署
- Prisma migration
- PostgreSQL
- 环境变量
- 端口映射
- 公网访问
- Cloudflare Tunnel
中间真的踩了很多坑。
比如:
- Next.js 默认监听
127.0.0.1 - Docker 映射了端口但外网还是访问不了
- Postgres 数据卷保留旧密码导致认证失败
.env.production少配一个变量整个服务直接起不来
尤其是数据库那个问题,我改了半天密码都不生效,最后才发现是 Docker volume 里的旧数据还在。
最后看到:
Ready
还有:
HTTP/1.1 307 Temporary Redirect
Location: /login
那一刻感觉很好。
虽然只是“把项目跑起来”,但和以前只在本地开发的感觉完全不一样。
第一次开始真正接触:
- 线上环境
- 服务部署
- 容器化
- 网络
- 运维
- 生产环境配置
也终于理解为什么很多人说:
“会写业务代码”和“能把项目真正上线”是两回事。
感觉这一个月学到的东西,比之前自己做 demo 的时候多太多了。
这篇文章把完整部署过程记录下来,后面自己再部署新项目时也能直接复用。
一、SSH 登录服务器
先从本地连接服务器:
ssh 名字@服务器名
作用:
- 从本地电脑连接到 Ubuntu 云服务器
二、进入项目目录
cd ~/你的项目目录
作用:
- 进入项目根目录
- 后续 Docker、环境变量、启动命令都在这里执行
三、检查 Docker 环境
先确认服务器已经安装 Docker。
docker --version
docker compose version
作用:
- 检查 Docker 是否安装成功
- 检查 Docker Compose 是否可用
四、检查生产环境变量文件
ls -la .env.production .env.production.example
作用:
- 确认生产环境配置文件存在
一般生产环境会单独维护:
.env.production
五、检查关键环境变量是否为空
生产环境最怕漏配置。
我这里用了 awk 做快速检查:
awk -F= '/^(POSTGRES_USER|POSTGRES_PASSWORD|POSTGRES_DB|BETTER_AUTH_SECRET|BETTER_AUTH_URL|ROOT_DOMAIN|APP_URL|AI_MODEL_ID|AI_BASE_URL|AI_API_KEY)=/ { if ($2 == "") print $1 " is empty"; else print $1 " is set" }' .env.production
作用:
- 检查关键变量是否为空
- 不直接打印密钥
- 避免敏感信息泄露
这个在生产环境里非常实用。
六、编辑生产环境变量
nano .env.production
主要修改:
APP_URL=http://服务器地址:3000
BETTER_AUTH_URL=http://服务器地址:3000
ROOT_DOMAIN=服务器地址
保存方式:
Ctrl + O
Enter
Ctrl + X
七、修改 Docker Compose 配置
编辑:
nano compose.yaml
这里有两个关键配置。
1. 暴露端口
ports:
- "3000:3000"
作用:
- 把容器内部 3000 端口映射到服务器公网
否则外部无法访问。
2. 让 Next.js 监听公网地址
environment:
HOSTNAME: 0.0.0.0
PORT: 3000
这是这次部署里最容易踩坑的地方之一。
很多 Node.js / Next.js 应用默认只监听:
127.0.0.1
这会导致:
- 容器内部能访问
- 外部浏览器无法访问
设置:
HOSTNAME=0.0.0.0
之后才能被 Docker 正常映射到公网。
八、清空旧数据库并停止旧容器
docker compose down -v
作用:
- 停止并删除容器
- 删除网络
- 删除数据卷
这里要特别注意:
-v
会删除 PostgreSQL 数据。
为什么这次必须删除?
因为之前的 Postgres 数据卷里保留了旧账号密码。
即使修改了:
POSTGRES_USER
POSTGRES_PASSWORD
旧数据库仍然使用历史认证信息。
最后直接导致:
password authentication failed
所以最后直接删除旧 volume 重建。
九、重新构建并启动项目
docker compose --env-file .env.production up -d --build
参数解释:
--env-file
--env-file .env.production
指定生产环境变量文件。
up
启动 compose 服务。
-d
后台运行。
--build
重新构建镜像。
代码有修改时必须带上。
这个命令会启动什么?
整个项目包含:
db PostgreSQL
migrate Prisma migration
seed 初始化数据
app Next.js 应用
cloudflared Cloudflare Tunnel
其中:
- db:数据库
- migrate:执行 Prisma migration
- seed:初始化数据
- app:主应用
- cloudflared:Cloudflare Tunnel
十、查看容器状态
docker compose ps
正常情况下会看到:
0.0.0.0:3000->3000/tcp
说明:
- 容器端口已经成功映射到公网
十一、查看日志排查问题
查看 migration 日志:
docker compose logs --tail=100 migrate
如果看到:
All migrations have been successfully applied.
说明:
- Prisma 数据库迁移成功
查看 app 日志:
docker compose logs --tail=100 app
如果看到:
Ready
说明:
- Next.js 已成功启动
十二、服务器本机测试
curl -I http://localhost:3000
返回:
HTTP/1.1 307 Temporary Redirect
Location: /login
这是正常现象。
说明:
- 服务已经启动
- 首页自动跳转登录页
十三、以后如何启动项目?
如果代码没变
cd ~/你的项目
docker compose --env-file .env.production up -d
如果代码更新了
cd ~/你的项目
docker compose --env-file .env.production up -d --build
查看状态
docker compose ps
停止项目
docker compose down
实时查看日志
docker compose logs -f app
这个命令非常常用。
基本等于:
- Next.js 线上控制台
最后
这次部署最大的几个坑:
- Next.js 默认监听 localhost
- Docker 端口未正确映射
- PostgreSQL 数据卷保留旧认证
- 环境变量遗漏
- Prisma migration 初始化顺序
不过整个流程跑通后,后面部署新项目会轻松很多。