--- title: "14.3.2 部署 Next.js 应用" --- # 14.3.2 部署 Next.js 应用 > **本节目标**:通过 1Panel 的运行环境功能,把你的 Next.js 项目部署到服务器上并成功访问。 小明打开 1Panel 的运行环境配置页面,看到表单字段不多——"比 Vercel 还简单?" 老师傅说:"差不多。在自己的服务器上部署,就是把 Vercel 帮你做的事情手动走一遍——填几个关键字段就行。" ## 前置准备 确保你已经完成: - 服务器上安装了 1Panel(参考 [14.2](./02-vps-setup.md)) - 通过应用商店安装了 **OpenResty** 和 **PostgreSQL**(如果项目需要数据库) - 项目代码已推送到 GitHub ## 第一步:上传代码到服务器 创建运行环境时需要指定「项目目录」,所以你需要先把项目代码上传到服务器。常见方式: - **Git Clone**:SSH 登录服务器,`git clone` 你的仓库到指定目录 - **1Panel 文件管理**:通过面板的「文件」功能上传压缩包并解压 ```bash # SSH 登录后,克隆代码到指定目录 cd /opt git clone https://github.com/你的用户名/你的项目.git # 进入项目目录,先把依赖装好 cd 你的项目 pnpm install ``` 如果是私有仓库,需要配置 GitHub 的访问凭证(Personal Access Token)或 SSH Key。 ::: tip 公开仓库更省事 如果你的项目不涉及敏感信息(敏感信息应该放在环境变量里,不在代码中),把仓库设为 Public 可以省去配置凭证的步骤。 ::: ## 第二步:理解端口映射 在创建运行环境之前,先理解一个关键概念:**端口映射**。 你的 Next.js 应用运行在 Docker 容器里,默认监听 3000 端口。但容器是隔离的——外部用户访问服务器 IP 时,根本碰不到容器内部的 3000。你需要配置**端口映射**,在服务器上开一个外部端口,把流量转发到容器的 3000。 ``` 用户访问 → 服务器IP:3001 → 转发到 → 容器内部:3000 → Next.js 应用 ``` ::: tip 端口映射是什么? 一栋楼只有一个地址,但有很多房间。服务器只有一个 IP,但通过端口号区分不同的应用——3001 号房间是你的网站,3002 号房间是 API,5432 号房间是数据库。端口映射就是把楼外的门牌号(外部端口)和楼内的房间号(容器端口)对应起来。 ::: 小明听到这里有点懵:"所以我要填两个端口?"老师傅说:"对。容器内部端口是 3000(Next.js 默认),服务器外部端口你自己定,比如 3001。用户访问 3001,流量就转发到容器的 3000。" ![image-20260303151924020](/images/Advanced/image-20260303151924020.png) ## 前置准备:内存不足的解决方案 如果你的 VPS 内存只有 1-2GB,构建 Next.js 项目时可能会遇到内存不足错误(`JavaScript heap out of memory`)。解决方案是创建 Swap 分区(虚拟内存): ```bash # 创建 2GB Swap 文件 sudo fallocate -l 2G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile # 设置开机自动挂载 echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab # 验证 Swap 是否生效 free -h ``` 创建 Swap 后,即使物理内存不足,系统也能用硬盘空间顶上,避免构建失败。 ::: tip 什么时候需要 Swap? - 1GB 内存:强烈建议创建 2GB Swap - 2GB 内存:建议创建 1-2GB Swap - 4GB 及以上:通常不需要 ::: ## 第三步:创建运行环境 ::: tip 运行环境的本质 1Panel 的「运行环境」本质上就是一个 Docker 容器。你在表单里填的配置项——项目目录、启动命令、端口映射——最终都会变成 `docker-compose.yml` 的参数。理解了这一点,下面的配置就不会觉得陌生了。 ::: 在 1Panel 面板中,进入「网站 > 运行环境」,点击「创建运行环境」。表单分为基础配置和高级配置两部分。 **基础配置**(重点关注): - **名称**:给这个运行环境起个名字(如 `my-nextjs-app`) - **项目目录**:选择你的代码所在路径(右侧有文件夹图标可以可视化选择) - **版本**:Node.js 版本,默认是较新的版本,一般不需要改。如果你本地用的是特定版本,选择和本地一致的即可 - **启动命令**:`git pull && pnpm build && pnpm start`(见下方说明) - **容器名称**:默认与运行环境名称相同,用于容器间通信——后端容器要连数据库时,就是通过容器名找到对方的 **高级配置**(展开后可见): - **端口映射**:把容器的 3000 映射到服务器的 3001(见下方说明) - **环境变量**:把 `.env` 里的变量逐一添加(见下方说明) ![image-20260302235637992](/images/Advanced/image-20260302235637992.png) ### 端口映射怎么配置 在创建运行环境时,展开「高级配置」区域,找到端口映射部分: 1. 点击「添加」按钮新增一行端口映射 2. **主机端口**填 `3001`(服务器外部端口,你自己定) 3. **容器端口**填 `3000`(Next.js 默认端口) ``` 服务器外部端口 3001 → 容器内部端口 3000 ``` 这样,用户访问 `http://服务器IP:3001`,流量就会被转发到容器里的 3000 端口,也就是你的 Next.js 应用。如果你的项目需要暴露多个端口,可以继续点「添加」配置更多映射。 配置完成后,记得在云厂商的安全组中**开放对应的外部端口**(如 3001)。 ![image-20260303151929448](/images/Advanced/image-20260303151929448.png) ### 启动命令怎么填 这是整个表单最关键的一项。1Panel 提供两种模式: - **自动解析模式**(默认):1Panel 会读取你项目的 `package.json`,解析出 `scripts` 里定义的命令(如 `dev`、`build`、`start`),显示在下拉框中供你选择。 - **自定义模式**:打开「自定义启动命令」开关,手动输入任意命令。适合需要串联多个步骤的场景。 对于 Next.js 项目,`pnpm start` 只负责启动——它要求项目已经构建好。所以推荐使用自定义模式,把拉代码、构建和启动串起来: ```bash git pull && pnpm build && pnpm start ``` 这样每次重启时会自动拉取最新代码并重新构建,更新部署只需要在面板点「重启」就行,不用 SSH 登录服务器手动操作。 依赖安装(`pnpm install`)建议在上传代码后通过 SSH 提前完成(第一步已经做了),不需要放进启动命令里——每次重启都重新装一遍依赖既慢又没必要。如果后续新增了依赖包,SSH 上去跑一次 `pnpm install` 即可。 小明填到"启动命令"时犹豫了一下——本地开发用的是 `pnpm dev`,但生产环境应该用 `pnpm start`。老师傅提醒:"dev 是开发模式,会开启热更新和调试工具,性能差而且不安全。生产环境永远用 start。" ### 环境变量怎么填 ::: tip 环境变量的安全管理 环境变量中通常包含敏感信息(数据库密码、API 密钥等)。关于如何安全地管理这些敏感信息,详见第 8 章《认证与安全》中的"环境变量与密钥管理"部分。 ::: 表单里的环境变量区域是一个键值对列表——每行一个"键"和"值",点「添加」新增一行,点红色垃圾桶图标删除。把你本地 `.env` 里的变量逐一添加: ```bash # PostgreSQL 连接(注意主机名是容器名) DATABASE_URL="postgresql://用户名:密码@1Panel-postgresql-xxxx:5432/数据库名" # Redis 连接(如果使用 Redis) # 有密码的情况 REDIS_URL="redis://:你的密码@1Panel-redis-xxxx:6379" # 无密码的情况 REDIS_URL="redis://1Panel-redis-xxxx:6379" # 其他环境变量 BETTER_AUTH_SECRET="你的密钥" BETTER_AUTH_URL="http://你的IP:端口" NODE_ENV="production" ``` ::: warning 容器名的命名规则 1Panel 创建的数据库容器名遵循 `1Panel-{数据库类型}-{随机4位字母}` 的格式: - PostgreSQL: `1Panel-postgresql-ukow`(后4位随机) - Redis: `1Panel-redis-w94p`(后4位随机) - MySQL: `1Panel-mysql-abcd`(后4位随机) 你可以在「容器」页面查看实际的容器名,或者在创建数据库时自定义容器名。 ::: ::: tip Redis 连接字符串格式 Redis 连接字符串的格式取决于是否设置了密码: - **有密码**:`redis://:密码@容器名:6379`(注意 `:` 后面是密码) - **无密码**:`redis://容器名:6379`(直接省略密码部分) - **指定数据库**:`redis://容器名:6379/0`(末尾的 `/0` 表示使用 0 号数据库) ::: 小明把本地 `.env` 文件里的变量一个个复制过去。填到 `DATABASE_URL` 时,他差点又写 `localhost`——想起上一节的教训,赶紧改成了 PostgreSQL 的容器名。他去「容器」页面确认了一下,容器名是 `1Panel-postgresql-ukow`。 ![image-20260302235711891](/images/Advanced/image-20260302235711891.png) ### 点击确认,等待启动 所有配置填好后,点击「确认」。1Panel 会按照你的启动命令依次执行拉取代码、构建、启动。第一次启动会比较慢——构建 Next.js 可能需要几分钟,毕竟服务器只有 2GB 内存。 小明点击确认后,日志开始滚动——拉取代码、构建、启动,跑了将近两分钟,最终状态变成了绿色的"运行中"。 查看运行日志可以在「网站 > 运行环境」列表中点击对应环境的「日志」按钮。 ![image-20260302235748925](/images/Advanced/image-20260302235748925.png) ## 第四步:访问你的应用 应用启动成功后,在浏览器中输入 `http://服务器IP:3001`(你配置的外部端口),就能看到你的应用了。 小明在浏览器中输入地址,看到了自己的应用页面——"它真的跑在我自己的服务器上了!"他试着注册了一个账号、发了一条数据,刷新页面,数据还在。前端、后端、数据库,三个部分在自己的服务器上协同工作。 ## 容器名 vs localhost:数据库连接 这是部署过程中最容易出错的地方,值得再强调一遍: | 你的代码运行在哪里 | DATABASE_URL 里填什么 | |------------------|---------------------| | Docker 容器里(1Panel 运行环境) | 填**容器名**,如 `postgresql` | | 服务器主机上(SSH 手动运行) | 填 `localhost` 或 `127.0.0.1` | 老师傅说:"记住一句话就行——**容器找邻居用名字,主机找容器用 localhost**。" ## 常见问题排查 | 现象 | 可能原因 | 解决方案 | |------|---------|---------| | 启动后立刻退出 | 环境变量缺失 | 检查日志,补全环境变量 | | 页面打不开 | 安全组没开端口 | 去云厂商控制台开放端口 | | 数据库连接失败 | 主机名填错了 | 用容器名替代 localhost | | 构建失败 | 内存不足或 Node 版本不匹配 | 参考上文"前置准备:内存不足的解决方案"创建 Swap,或选择和本地一致的 Node 版本 | ## 更新部署 代码更新后,你不需要重新走一遍流程。因为启动命令里已经有 `git pull`,直接在「网站 - 运行环境」列表中点击「重启」,面板就会自动拉取最新代码、重新构建并启动。如果遇到问题需要彻底重建,可以在「已安装」页面对应用执行「重建」——面板会删除容器并基于当前配置重新创建,持久化数据会保留。 小明第一次更新代码时,还傻傻地想着要不要 SSH 上去手动操作。老师傅说:"启动命令里已经有 `git pull` 了,直接在面板点'重启'就行。如果新增了依赖包,才需要 SSH 上去跑一次 `pnpm install`。"整个过程不到一分钟,新版本就上线了。 ::: tip 部署失败怎么办? 如果重建或重启后应用起不来,先看日志——在「网站 - 运行环境」列表点击「日志」按钮查看运行日志。最常见的原因是新代码引入了新的环境变量但没有在面板里配置,或者依赖包版本冲突。日志里通常会有明确的报错信息。 ::: --- ::: info 下一步 Next.js 应用部署搞定了。如果你的项目是纯前端(没有后端),可以用更简单的方式部署——[14.3.3 部署静态网站](./03-3-deploy-static.md)。 :::