- 新增管理端板块管理页面与后端接口(admin_board) - 新增旧版数据导入:legacyimport 服务、导入面板、importusers 命令行工具 - 聊天用户卡片、板块图标等 UI 组件与界面优化 - 补充 about/公告/1Panel 部署等文档 - gitignore 排除 dist/ 构建产物与 .agents/ 本地工具目录
184 lines
6.3 KiB
Markdown
184 lines
6.3 KiB
Markdown
# 姜十三论坛(jiang13-bbs)Docker 部署教程
|
||
|
||
> 前置条件:应用镜像(`jiang13-api`、`jiang13-web`)已推送到你的私有镜像仓库。本教程只讲如何在服务器上用 1Panel 部署、反代与运维。
|
||
>
|
||
> 项目架构:Next.js 前端(web)+ Go 后端(api)+ PostgreSQL 17,三者为独立容器。
|
||
|
||
---
|
||
|
||
## 一、镜像说明
|
||
|
||
| 服务 | 镜像 | 来源 |
|
||
|---|---|---|
|
||
| api | `<你的用户名>/jiang13-api` | 你的私有仓库 |
|
||
| web | `<你的用户名>/jiang13-web` | 你的私有仓库 |
|
||
| postgres | `postgres:17-alpine` | Docker Hub 官方公共镜像,直接拉取 |
|
||
|
||
> 安全说明:api / web 镜像为多阶段构建产物,**最终镜像不含源码**,密钥运行时注入,不烤进镜像。部署前请确认这两个仓库在 Docker Hub 上已设为 **Private**。
|
||
|
||
---
|
||
|
||
## 二、1Panel 部署
|
||
|
||
### 1. 配置私有仓库认证(关键)
|
||
私有镜像必须先认证,否则拉取报 `denied`。
|
||
|
||
1Panel 左侧 **容器 → 「仓库」标签 → 创建**:
|
||
- 仓库地址:`docker.io`
|
||
- 用户名:你的 Docker Hub 用户名
|
||
- 密码:Docker Hub 密码或 Access Token(推荐 Token)
|
||
|
||
### 2. 用编排一键部署
|
||
**容器 → 「编排」标签 → 创建编排**,名称 `jiang13`,粘贴以下内容:
|
||
|
||
```yaml
|
||
name: jiang13
|
||
|
||
services:
|
||
postgres:
|
||
image: postgres:17-alpine
|
||
restart: unless-stopped
|
||
environment:
|
||
POSTGRES_USER: jiang13
|
||
POSTGRES_PASSWORD: 改成你的强密码
|
||
POSTGRES_DB: jiang13
|
||
volumes:
|
||
- pgdata:/var/lib/postgresql/data
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "pg_isready -U jiang13 -d jiang13"]
|
||
interval: 5s
|
||
timeout: 5s
|
||
retries: 10
|
||
|
||
api:
|
||
image: <你的用户名>/jiang13-api:0.1.0
|
||
restart: unless-stopped
|
||
depends_on:
|
||
postgres:
|
||
condition: service_healthy
|
||
environment:
|
||
HTTP_PORT: "3001"
|
||
DEV_MODE: "false"
|
||
JIANG13_WORK_PATH: /var/lib/jiang13
|
||
DATA_DIR: /var/lib/jiang13/data
|
||
DB_DSN: postgres://jiang13:改成上面同一个密码@postgres:5432/jiang13?sslmode=disable
|
||
JWT_SECRET: ""
|
||
SITE_URL: https://改成你的域名
|
||
SETTINGS_MASTER_KEY: ""
|
||
volumes:
|
||
- appdata:/var/lib/jiang13/data
|
||
|
||
web:
|
||
image: <你的用户名>/jiang13-web:0.1.0
|
||
restart: unless-stopped
|
||
depends_on:
|
||
api:
|
||
condition: service_healthy
|
||
environment:
|
||
BACKEND_URL: http://api:3001
|
||
SITE_URL: https://改成你的域名
|
||
NODE_ENV: production
|
||
DEV_MODE: "false"
|
||
PORT: "3000"
|
||
HOSTNAME: 0.0.0.0
|
||
ports:
|
||
- "13000:3000"
|
||
|
||
volumes:
|
||
pgdata:
|
||
appdata:
|
||
```
|
||
|
||
**只需改 3 处**:
|
||
1. `POSTGRES_PASSWORD` 的值
|
||
2. `DB_DSN` 里的密码(**必须与第 1 处完全一致**)
|
||
3. 两处 `SITE_URL` 的域名
|
||
|
||
保存后,在编排列表点 **▶ 启动**。会自动:拉镜像 → 起 postgres → 健康后起 api → 健康后起 web。
|
||
|
||
> 容器名固定为 `postgres` / `api`,因为服务间通过容器名互访(`@postgres:5432`、`http://api:3001`)。
|
||
|
||
### 3. 验证启动
|
||
「容器」标签确认三个容器状态:
|
||
- postgres Up (healthy)
|
||
- api Up (healthy) ← 健康才说明连库成功
|
||
- web Up
|
||
|
||
接口检查:
|
||
```bash
|
||
curl http://127.0.0.1:13000/healthz # web,返回 ok
|
||
docker exec jiang13-api-1 wget -qO- http://127.0.0.1:3001/health # api
|
||
```
|
||
|
||
---
|
||
|
||
## 三、Nginx 反向代理 + HTTPS
|
||
|
||
`DEV_MODE=false` 启用了 `__Host-` 前缀 cookie,**必须 HTTPS**。
|
||
|
||
1Panel **网站 → 创建网站 → 反向代理**:
|
||
- 目标地址:`http://127.0.0.1:13000`
|
||
- 申请并开启 SSL(1Panel 可一键 Let's Encrypt)
|
||
- 域名 DNS 解析到服务器
|
||
|
||
访问 `https://你的域名`,空库下**第一个注册的账号自动成为站长(管理员)**。
|
||
|
||
---
|
||
|
||
## 四、配置说明
|
||
|
||
### 环境变量
|
||
| 变量 | 说明 | 建议 |
|
||
|---|---|---|
|
||
| `POSTGRES_PASSWORD` | 数据库密码 | 强密码,与 DB_DSN 一致 |
|
||
| `DB_DSN` | 后端连库串 | 密码须与上者一致 |
|
||
| `JWT_SECRET` | 登录 token 签名密钥 | **留空**,自动生成并持久化到 data/.jwt_secret;自填须 ≥32 字符强随机 |
|
||
| `SETTINGS_MASTER_KEY` | 加密邮件/S3 凭据(32字节Base64) | **留空**=禁用保存凭据功能;需要时用 `openssl rand -base64 32` 生成 |
|
||
| `SITE_URL` | 对外公开 origin | 前后端一致,与浏览器地址栏完全相同(含 https、无尾斜杠)。运行时读取,可后改重启生效 |
|
||
|
||
> `JWT_SECRET` 与 `SETTINGS_MASTER_KEY` **不要填同一个值**(密钥复用是安全大忌,且两者格式/生命周期不同)。
|
||
|
||
### 端口被占用怎么办
|
||
- 容器内端口(3000/3001)写死不能改;只改映射的**宿主机端口**(冒号左边),如 `"13000:3000"`。
|
||
- 用 Nginx 反代时 **api 无需暴露端口**(web 通过容器名内部访问)。
|
||
- 查占用:`ss -tlnp | grep -E ':3000|:3001'`
|
||
|
||
### 数据卷
|
||
- `pgdata`:数据库数据
|
||
- `appdata`:上传文件 / `.jwt_secret`
|
||
|
||
删除编排时**不要勾选删除数据卷**,否则数据丢失。若换过数据库密码,需先删除旧 `pgdata` 卷重建(Postgres 只在空数据目录初始化密码)。
|
||
|
||
---
|
||
|
||
## 五、更新与运维
|
||
|
||
### 更新版本
|
||
修改编排中镜像的 tag(如 `:0.1.0` → `:0.2.0`),或使用 `:latest` 标签后点「重新拉取镜像」再重启容器:
|
||
```bash
|
||
docker compose pull
|
||
docker compose up -d
|
||
```
|
||
> `:latest` 不会自动更新,需手动重新拉取才生效;建议同时保留版本号标签以便回滚。
|
||
|
||
### 常用命令
|
||
```bash
|
||
docker compose ps # 查看状态
|
||
docker compose logs -f # 看日志
|
||
docker compose logs api --tail 50
|
||
docker compose down # 停止(保留数据)
|
||
docker compose down -v # 停止并清空数据(慎用)
|
||
```
|
||
|
||
---
|
||
|
||
## 六、排障速查
|
||
|
||
| 现象 | 原因 | 解决 |
|
||
|---|---|---|
|
||
| api 反复 restart,日志 `password authentication failed` | 密码不一致 / pgdata 残留旧密码 | 统一两处密码;删 pgdata 卷重建 |
|
||
| api 日志 `JWT_SECRET 过弱` | 填了 change-me 或过短 | 留空自动生成,或换 ≥32 字符强随机值 |
|
||
| 拉私有镜像 `denied` | 未配置仓库认证 | 1Panel 仓库里添加 Docker Hub 凭证 |
|
||
| web 不启动 | 等不到 api healthy | 先把 api 弄健康(解决上面问题) |
|
||
| 能打开页面但登录异常 | HTTP 下 __Host- cookie 不生效 | 必须走 HTTPS 反代 |
|