本项目源代码和程序本站资源下载地址。
无论是对熟悉运维的开发者,还是初次尝试部署项目的爱好者,都能在本地环境中,顺利地将这个基于现代Web技术的游戏项目运行起来。
在开始之前,先快速浏览一下城堡的蓝图(项目目录结构),以便心中有数。

目录结构概览
.
├─ agent-ctx/ # 城堡的设计图纸(项目设计文档)
├─ bun.lock # 精确的材料清单(Bun 依赖锁文件)
├─ Caddyfile # 城门的守卫配置(Caddy 代理配置)
├─ components.json # 家具样式清单(Shadcn UI 组件配置)
├─ db/ # 城堡的仓库(SQLite 数据库文件)
├─ download/ # 宣传画册(项目演示截图、QA资源)
├─ eslint.config.mjs # 代码清洁工规则(ESLint配置)
├─ examples/ # 示例小工坊(WebSocket示例代码)
├─ keep-alive.sh # 可选的自愈脚本(守护脚本)
├─ mini-services/ # 城堡内的迷你游戏厅(小游戏服务)
├─ next.config.ts # Next.js 宫殿主配置
├─ package.json # 完整材料与施工脚本
├─ postcss.config.mjs # 样式加工规则(PostCSS配置)
├─ prisma/ # 仓库管理员工具(Prisma schema & 迁移)
├─ public/ # 对外开放的雕像与旗帜(静态资源)
├─ run-dev.sh # 开发模式自动修复脚本
├─ src/ # 宫殿的核心区域(React组件、API路由)
├─ start-dev.sh # (已弃用的示例脚本)
├─ tailwind.config.ts # 样式工具集配置(Tailwind CSS)
├─ tsconfig.json # TypeScript 编译配置
├─ watchdog.sh # 可选的监控脚本
└─ worklog.md # 建造日志
现在,蓝图已展开,让我们开始动工。
1️⃣ 环境准备:备齐建造工具
在开始搭建之前,需要确保您的"工具箱"里有所有必需的工具。这些工具各司其职,共同支撑起项目的运行。
核心工具说明:
| 工具 | 用途说明 |
|---|---|
| Bun | 不仅是包管理器(类似 npm),还是一个超快的 JavaScript 运行时。用于安装依赖、运行脚本和执行代码,堪称开发"瑞士军刀"。 |
| Node.js | 虽然主要使用 Bun,但许多工具链仍依赖 Node.js。建议安装较新版本作为兼容性"后援"。 |
| Git | 版本控制工具,用于从远程代码仓库克隆项目到本地。 |
| Caddy | 简单易用的 Web 服务器与反向代理,如同"城门守卫":接收外部请求并智能转发给内部的 Next.js 服务;还支持自动 HTTPS 证书管理,保障通信安全。 |
| SQLite3 | 默认使用的轻量级嵌入式数据库,无需独立服务,像一本直接存放在项目中的"账本",开箱即用。 |
| Prisma | 数据库"管家",提供类型安全的 ORM 功能,可轻松定义数据模型、创建表结构和执行查询,避免手写复杂 SQL。 |
如果您有特定风格偏好(如更技术化或更拟人化),也可以进一步调整语言风格。
1.1 检查与安装必要工具
| 工具 | 版本要求 | 安装方式(以Ubuntu/Debian为例) |
|---|---|---|
| Bun | >= 1.1.0 | `curl https://bun.sh/install |
| Node.js | >= 20 | `curl -fsSL https://deb.nodesource.com/setup_20.x |
| Git | 任意 | sudo apt install -y git |
| Caddy | >= 2.8 | `sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https && curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' |
| SQLite3 | >= 3.45 | sudo apt install -y sqlite3 |
| Make (可选) | 任意 | sudo apt install -y make |
小提示 :如果您更习惯使用
npm,当然也可以,但项目中的脚本命令默认是基于Bun的,使用Bun会获得更流畅的体验。
1.2 获取项目代码
如果还没有项目代码,现在需要通过Git把它"克隆"到您的计算机上。
bash
# 假设我们希望将项目放在 /home/tht/projects/tianmingsanguo 目录下
git clone https://github.com/your-repo/tianmingsanguo.git /home/tht/projects/tianmingsanguo
# 进入项目目录
cd /home/tht/projects/tianmingsanguo
1.3 环境变量 (.env)
项目运行时需要知道一些关键信息,比如"开哪个门(端口)?"、"仓库(数据库)在哪?"。这些信息通过一个名为 .env 的文件来提供。我们需在项目根目录下创建它。
dotenv
# -------------------
# 基础运行时配置
# -------------------
# 监听端口:Next.js 服务将在本机的哪个端口上启动。默认是3000。
PORT=3000
# 数据库地址:告诉 Prisma 我们的 SQLite 数据库文件存放在哪里。
DATABASE_URL="file:./db/custom.db"
# AI 服务接口(如适用):用于连接游戏可能需要的人工智能服务。
AI_ENDPOINT="http://localhost:8080/graph/stream"
AI_MODEL="Nnemotron-3-nano-omni-30b-a3b-reasoning"
# NextAuth 配置:用于身份验证,为您的城堡设置一把"安全锁"。
NEXTAUTH_URL="http://localhost:3000"
NEXTAUTH_SECRET="请生成一个随机的复杂字符串作为密钥"
深入理解 :
DATABASE_URL中的file:./db/custom.db是一个相对路径。这意味着您的数据库文件会直接存放在项目内的db文件夹下。如果您未来想使用更强大的 PostgreSQL 数据库,只需将这个地址改为 PostgreSQL 的连接串(如postgresql://user:password@localhost:5432/mydb),并调整Prisma配置即可。
2️⃣ 安装依赖:准备建筑材料
有了工具和蓝图,接下来就是根据"材料清单"(bun.lock 或 package.json)下载所有项目依赖的第三方库。这就像根据清单去采购木材、水泥和管件。
原理 :bun install 命令会读取 bun.lock 文件,确保下载的每个依赖库都是精确的版本,避免因为版本差异导致项目运行出错。然后,它会将所有依赖存放在 node_modules 目录中。
bash
# 使用 Bun 根据锁定文件安装所有依赖(强烈推荐)
bun install
如果您执意使用
npm,请运行npm ci(ci代表持续集成,它会严格按照package-lock.json安装,速度更快且更可靠)。
3️⃣ 布置"数据仓库":数据库准备
我们的游戏需要存储用户数据、游戏进度等信息。这个"仓库"就是数据库。我们通过"管家"Prisma来搭建它。
流程原理解释:
prisma generate:Prisma 会读取prisma/schema.prisma文件(里面定义了我们有哪些"货架"和"储物格"),然后生成一套专门用于操作这些数据的JavaScript代码(客户端)。这让我们的代码可以像操作普通对象一样读写数据库,既安全又高效。prisma db push:这个命令会将schema.prisma中定义的数据结构"推"到真实的数据库文件中,自动创建出对应的表格。这就像拿着设计图,直接在空地上建起一个个符合规格的仓库隔间。
#mermaid-svg-ZwyT50c2MqzRUNhs{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZwyT50c2MqzRUNhs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZwyT50c2MqzRUNhs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZwyT50c2MqzRUNhs .error-icon{fill:#552222;}#mermaid-svg-ZwyT50c2MqzRUNhs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZwyT50c2MqzRUNhs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZwyT50c2MqzRUNhs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZwyT50c2MqzRUNhs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZwyT50c2MqzRUNhs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZwyT50c2MqzRUNhs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZwyT50c2MqzRUNhs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZwyT50c2MqzRUNhs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZwyT50c2MqzRUNhs .marker.cross{stroke:#333333;}#mermaid-svg-ZwyT50c2MqzRUNhs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZwyT50c2MqzRUNhs p{margin:0;}#mermaid-svg-ZwyT50c2MqzRUNhs .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZwyT50c2MqzRUNhs .cluster-label text{fill:#333;}#mermaid-svg-ZwyT50c2MqzRUNhs .cluster-label span{color:#333;}#mermaid-svg-ZwyT50c2MqzRUNhs .cluster-label span p{background-color:transparent;}#mermaid-svg-ZwyT50c2MqzRUNhs .label text,#mermaid-svg-ZwyT50c2MqzRUNhs span{fill:#333;color:#333;}#mermaid-svg-ZwyT50c2MqzRUNhs .node rect,#mermaid-svg-ZwyT50c2MqzRUNhs .node circle,#mermaid-svg-ZwyT50c2MqzRUNhs .node ellipse,#mermaid-svg-ZwyT50c2MqzRUNhs .node polygon,#mermaid-svg-ZwyT50c2MqzRUNhs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZwyT50c2MqzRUNhs .rough-node .label text,#mermaid-svg-ZwyT50c2MqzRUNhs .node .label text,#mermaid-svg-ZwyT50c2MqzRUNhs .image-shape .label,#mermaid-svg-ZwyT50c2MqzRUNhs .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZwyT50c2MqzRUNhs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZwyT50c2MqzRUNhs .rough-node .label,#mermaid-svg-ZwyT50c2MqzRUNhs .node .label,#mermaid-svg-ZwyT50c2MqzRUNhs .image-shape .label,#mermaid-svg-ZwyT50c2MqzRUNhs .icon-shape .label{text-align:center;}#mermaid-svg-ZwyT50c2MqzRUNhs .node.clickable{cursor:pointer;}#mermaid-svg-ZwyT50c2MqzRUNhs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZwyT50c2MqzRUNhs .arrowheadPath{fill:#333333;}#mermaid-svg-ZwyT50c2MqzRUNhs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZwyT50c2MqzRUNhs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZwyT50c2MqzRUNhs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZwyT50c2MqzRUNhs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZwyT50c2MqzRUNhs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZwyT50c2MqzRUNhs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZwyT50c2MqzRUNhs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZwyT50c2MqzRUNhs .cluster text{fill:#333;}#mermaid-svg-ZwyT50c2MqzRUNhs .cluster span{color:#333;}#mermaid-svg-ZwyT50c2MqzRUNhs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZwyT50c2MqzRUNhs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZwyT50c2MqzRUNhs rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZwyT50c2MqzRUNhs .icon-shape,#mermaid-svg-ZwyT50c2MqzRUNhs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZwyT50c2MqzRUNhs .icon-shape p,#mermaid-svg-ZwyT50c2MqzRUNhs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZwyT50c2MqzRUNhs .icon-shape .label rect,#mermaid-svg-ZwyT50c2MqzRUNhs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZwyT50c2MqzRUNhs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZwyT50c2MqzRUNhs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZwyT50c2MqzRUNhs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} bun prisma
generate
bun prisma
db push
应用程序
调用
开发者定义
数据模型
prisma/schema.prisma
生成
Prisma Client
SQLite
数据库文件
通过 Prisma Client
读写数据
执行命令:
bash
# 1. 生成 Prisma 客户端代码
bun prisma generate
# 2. 将数据模型同步到 SQLite 数据库,创建表结构
bun prisma db push
小贴士 :如果您想对数据库结构的每一次改动都留下记录(便于版本管理和回滚),可以执行
bun prisma migrate dev --name init。这会创建一个"迁移"文件,而不是直接推送。
4️⃣ 本地开发:在沙盘上搭建和调试
在正式对外开放前,我们通常会在"沙盘"(本地开发环境)上反复调试。Next.js 框架提供了强大的"热模块替换"(HMR)功能,这意味着您修改代码后,浏览器页面会自动刷新,无需手动重启服务,大大提升了开发效率。
4.1 启动开发服务器
我们提供了一个名为 run-dev.sh 的智能启动脚本。它不仅会启动服务,还会在服务意外崩溃时尝试自动重启,就像一个忠诚的守卫。
bash
# 赋予脚本执行权限
chmod +x run-dev.sh
# 运行脚本
./run-dev.sh
脚本内部的核心命令就是 bun run dev。您也可以手动执行它来获得更直接的输出:
bash
bun run dev
现在,打开您的浏览器,访问 http://localhost:3000,您将看到《天命三国》的游戏界面。
4.2 开发调试小技巧
- 查看日志 :
run-dev.sh会将所有输出同时记录到dev.log文件中。如果控制台信息太多,可以随时tail -f dev.log来追踪最新日志。 - 直接操作数据库 :如果想快速查看或修改数据,可以使用命令行工具直接连接数据库:
sqlite3 db/custom.db。进入后,可以用.tables查看所有表,用SELECT * FROM User;查询数据。
5️⃣ 生产部署:城堡正式对外开放
当您在本地完成所有开发和测试后,就需要将项目部署到真正的服务器上,让所有玩家都能访问。这个过程包括"打包"、"运行"和"守卫"三个步骤。
5.1 打包构建:准备最终的可交付成果
bun run build 命令会启动一个复杂的优化流程。它会将您的源代码(React组件、TypeScript逻辑等)编译、压缩、合并成高效的、浏览器可以快速识别的静态文件(JS, CSS),并生成一个优化过的Node.js服务器文件。
bash
bun run build
构建产物 :所有生成的文件都会放在 .next 文件夹中。其中,.next/standalone 目录里包含了一个可以独立运行的服务器文件 server.js,以及它需要的所有Node.js代码。.next/static 则包含了所有的静态资源。
5.2 启动生产服务器:让服务跑起来
构建完成后,启动生产服务器非常简单,只需要用Bun执行那个独立的服务器文件即可。
bash
# 注意:您需要在项目根目录下运行此命令
bun .next/standalone/server.js
服务启动后会监听 PORT 环境变量指定的端口(默认3000)。这时,您的游戏服务已经在服务器本机上可访问了。
5.3 配置Caddy反向代理:设置安全的"城门"
直接对外暴露一个Node.js应用(端口3000)并非最佳实践。我们通常会在它前面加一个高效、稳定的Web服务器作为"反向代理"。我们选择 Caddy,因为它配置简单,并能自动为您的域名启用HTTPS。
Caddy 是如何工作的?
下面的Mermaid图展示了访问流程:
#mermaid-svg-LfQpHg0LZwf5VhFP{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LfQpHg0LZwf5VhFP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LfQpHg0LZwf5VhFP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LfQpHg0LZwf5VhFP .error-icon{fill:#552222;}#mermaid-svg-LfQpHg0LZwf5VhFP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LfQpHg0LZwf5VhFP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LfQpHg0LZwf5VhFP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LfQpHg0LZwf5VhFP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LfQpHg0LZwf5VhFP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LfQpHg0LZwf5VhFP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LfQpHg0LZwf5VhFP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LfQpHg0LZwf5VhFP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LfQpHg0LZwf5VhFP .marker.cross{stroke:#333333;}#mermaid-svg-LfQpHg0LZwf5VhFP svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LfQpHg0LZwf5VhFP p{margin:0;}#mermaid-svg-LfQpHg0LZwf5VhFP .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-LfQpHg0LZwf5VhFP .cluster-label text{fill:#333;}#mermaid-svg-LfQpHg0LZwf5VhFP .cluster-label span{color:#333;}#mermaid-svg-LfQpHg0LZwf5VhFP .cluster-label span p{background-color:transparent;}#mermaid-svg-LfQpHg0LZwf5VhFP .label text,#mermaid-svg-LfQpHg0LZwf5VhFP span{fill:#333;color:#333;}#mermaid-svg-LfQpHg0LZwf5VhFP .node rect,#mermaid-svg-LfQpHg0LZwf5VhFP .node circle,#mermaid-svg-LfQpHg0LZwf5VhFP .node ellipse,#mermaid-svg-LfQpHg0LZwf5VhFP .node polygon,#mermaid-svg-LfQpHg0LZwf5VhFP .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LfQpHg0LZwf5VhFP .rough-node .label text,#mermaid-svg-LfQpHg0LZwf5VhFP .node .label text,#mermaid-svg-LfQpHg0LZwf5VhFP .image-shape .label,#mermaid-svg-LfQpHg0LZwf5VhFP .icon-shape .label{text-anchor:middle;}#mermaid-svg-LfQpHg0LZwf5VhFP .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LfQpHg0LZwf5VhFP .rough-node .label,#mermaid-svg-LfQpHg0LZwf5VhFP .node .label,#mermaid-svg-LfQpHg0LZwf5VhFP .image-shape .label,#mermaid-svg-LfQpHg0LZwf5VhFP .icon-shape .label{text-align:center;}#mermaid-svg-LfQpHg0LZwf5VhFP .node.clickable{cursor:pointer;}#mermaid-svg-LfQpHg0LZwf5VhFP .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LfQpHg0LZwf5VhFP .arrowheadPath{fill:#333333;}#mermaid-svg-LfQpHg0LZwf5VhFP .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LfQpHg0LZwf5VhFP .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LfQpHg0LZwf5VhFP .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LfQpHg0LZwf5VhFP .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LfQpHg0LZwf5VhFP .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LfQpHg0LZwf5VhFP .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LfQpHg0LZwf5VhFP .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LfQpHg0LZwf5VhFP .cluster text{fill:#333;}#mermaid-svg-LfQpHg0LZwf5VhFP .cluster span{color:#333;}#mermaid-svg-LfQpHg0LZwf5VhFP div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-LfQpHg0LZwf5VhFP .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LfQpHg0LZwf5VhFP rect.text{fill:none;stroke-width:0;}#mermaid-svg-LfQpHg0LZwf5VhFP .icon-shape,#mermaid-svg-LfQpHg0LZwf5VhFP .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LfQpHg0LZwf5VhFP .icon-shape p,#mermaid-svg-LfQpHg0LZwf5VhFP .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LfQpHg0LZwf5VhFP .icon-shape .label rect,#mermaid-svg-LfQpHg0LZwf5VhFP .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LfQpHg0LZwf5VhFP .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LfQpHg0LZwf5VhFP .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LfQpHg0LZwf5VhFP :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 您的服务器
互联网
内部网络
- 发起 HTTPS 请求 (https://your-domain.com)
- 转发请求至内部服务
- 返回响应数据
- 返回 HTTPS 响应
用户浏览器
Caddy 反向代理
监听 80/443 端口
Next.js 生产服务器
监听 localhost:3000
配置步骤:
-
项目根目录已提供了
Caddyfile配置文件。您需要将它放置到Caddy可以找到的地方,通常是/etc/caddy/Caddyfile。 -
编辑
Caddyfile,将您的域名(例如game.yourdomain.com)和项目服务器的内部地址(localhost:3000)配置进去。一个更简明通用的
Caddyfile示例:caddy# 请将 your-domain.com 替换为您的真实域名 your-domain.com { # 将所有请求转发到本地的 Next.js 服务 reverse_proxy localhost:3000 { # 传递真实的客户端IP等头部信息 header_up Host {host} header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_addr} header_up X-Forwarded-Proto {scheme} } # 可选:开启日志记录 log { output file /var/log/caddy/tianmingsanguo-access.log } } -
启动或重载Caddy服务:
bash# 如果使用系统服务 sudo systemctl reload caddy # 或者,在项目目录下直接测试运行(会占用终端) sudo caddy run --config ./CaddyfileCaddy 会自动为
your-domain.com申请并续期免费的 Let's Encrypt SSL 证书,您的网站将自动支持HTTPS。
5.4 建议
为了保证服务长久稳定地运行,这里有一些专业建议:
| 项目 | 推荐方式与原因 |
|---|---|
| 进程守护 | 使用 systemd 服务。万一服务器重启或应用崩溃,systemd 会自动帮您重新启动它。创建一个 /etc/systemd/system/tianmingsanguo.service 文件,配置好启动命令(bun /path/to/.next/standalone/server.js)。 |
| 日志管理 | 如果使用 systemd,可以用 journalctl -u tianmingsanguo -f 查看实时日志。Caddy 的访问日志则单独配置,方便分析流量和排查问题。 |
| 环境变量 | 不要将 .env 文件放在项目目录下(会有被意外暴露的风险)。建议放在 /etc 目录下,如 /etc/tianmingsanguo.env,并在 systemd 服务文件中通过 EnvironmentFile=/etc/tianmingsanguo.env 来加载。 |
| 数据库备份 | SQLite 就是一个文件。设置一个定时任务(cron job),定期备份 db/custom.db 文件到安全的位置即可。例如:0 2 * * * cp /home/tht/projects/tianmingsanguo/db/custom.db /backup/db/custom_$(date +\%Y\%m\%d).db |