我把 Next.js 项目部署到了 Ubuntu 服务器,踩了这几个坑

0 阅读5分钟

实习一个月,第一次真正把项目部署到公网服务器上。

之前一直都是本地开发,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 线上控制台

最后

这次部署最大的几个坑:

  1. Next.js 默认监听 localhost
  2. Docker 端口未正确映射
  3. PostgreSQL 数据卷保留旧认证
  4. 环境变量遗漏
  5. Prisma migration 初始化顺序

不过整个流程跑通后,后面部署新项目会轻松很多。