20 KiB
20 KiB
PandaWiki Ubuntu 22.04 内网部署指南
本文档涵盖从源码传输、构建 Docker 镜像到部署运行的完整流程。
一、整体部署架构
┌──────────────────────────────────────────────────┐
│ Ubuntu 22.04 Server │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Nginx/Caddy │ │ Admin 前端 │ │
│ │ (反向代理) │ │ (Nginx) │ │
│ │ 端口: 80/443│ │ 端口: 5000 │ │
│ └──────┬──────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ API 服务 (Go) │ 端口: 8000 │
│ │ Consumer 服务 (Go) │ 后台异步任务 │
│ └──────────┬───────────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ PG │ │Redis │ │ NATS │ │MinIO │ │
│ │ :5432│ │:6379 │ │:4222 │ │:9000 │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
│ ┌──────────────────────┐ │
│ │ RAG 向量检索服务 │ 端口: 5050 │
│ └──────────────────────┘ │
│ │
│ ┌──────────────────────┐ │
│ │ AI 大模型 API │ 外部配置 │
│ └──────────────────────┘ │
└──────────────────────────────────────────────────┘
二、服务器环境准备
2.1 系统要求
# 确认系统版本
lsb_release -a
# Ubuntu 22.04.x LTS
# 建议配置
# CPU: 4 核以上
# 内存: 8 GB 以上 (AI 相关功能需要更多)
# 磁盘: 50 GB 以上
2.2 安装 Docker
# 卸载旧版本 (如果有)
sudo apt-get remove docker docker-engine docker.io containerd runc
# 安装依赖
sudo apt-get update
sudo apt-get install -y \
ca-certificates \
curl \
gnupg \
lsb-release
# 添加 Docker 官方 GPG 密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 添加 Docker 仓库
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装 Docker Engine
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
# 验证安装
sudo docker --version
sudo docker compose version
# 将当前用户加入 docker 组 (免 sudo)
sudo usermod -aG docker $USER
newgrp docker
# 设置 Docker 开机自启
sudo systemctl enable docker
2.3 安装 Docker Compose (独立版,可选)
Docker 新版已内置 docker compose 插件。如需独立版:
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" \
-o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
2.4 安装 Git (用于获取源码)
sudo apt-get install -y git
三、传输源码到服务器
方式 A:Git 仓库 (服务器有网络)
# 在服务器上
git clone https://github.com/chaitin/PandaWiki.git
cd PandaWiki
# 然后将你 Windows 上修改过的文件传输到服务器覆盖对应文件
# 需要覆盖的文件:
# backend/domain/license.go
# backend/usecase/stat.go
# backend/repo/pg/auth.go
# web/admin/src/constant/version.ts
方式 B:直接 SCP 传输整个项目 (推荐)
在 Windows 上使用 PowerShell 或 WSL:
# 在 Windows 上执行,将整个项目传到服务器
scp -r "E:\code project\PandaWiki-3.85.0" user@your-server-ip:/home/user/
# 或者用 rsync (WSL/Linux)
rsync -avz --progress \
"/mnt/e/code project/PandaWiki-3.85.0/" \
user@your-server-ip:/home/user/PandaWiki/
方式 C:打包传输
# 在 Windows 上打包 (Git Bash / WSL)
cd "E:\code project\PandaWiki-3.85.0"
tar --exclude='.git' -czf panda-wiki.tar.gz .
# 传输到服务器
scp panda-wiki.tar.gz user@your-server-ip:/home/user/
# 在服务器上解压
mkdir -p ~/PandaWiki && cd ~/PandaWiki
tar -xzf ~/panda-wiki.tar.gz
四、创建 Docker Compose 配置
在项目根目录创建 docker-compose.yml:
cd ~/PandaWiki
# docker-compose.yml
version: '3.8'
services:
# ========== 基础设施 ==========
postgres:
image: postgres:16-alpine
container_name: panda-wiki-postgres
restart: unless-stopped
environment:
POSTGRES_USER: panda-wiki
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-ChangeMe123!}
POSTGRES_DB: panda-wiki
volumes:
- pg_data:/var/lib/postgresql/data
ports:
- "127.0.0.1:5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U panda-wiki"]
interval: 5s
timeout: 5s
retries: 5
networks:
- panda-wiki
redis:
image: redis:7-alpine
container_name: panda-wiki-redis
restart: unless-stopped
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-ChangeMe123!}
volumes:
- redis_data:/data
ports:
- "127.0.0.1:6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
interval: 5s
timeout: 5s
retries: 5
networks:
- panda-wiki
nats:
image: nats:2-alpine
container_name: panda-wiki-nats
restart: unless-stopped
command: >
-js
-m 8222
--user ${NATS_USER:-panda-wiki}
--pass ${NATS_PASSWORD:-ChangeMe123!}
ports:
- "127.0.0.1:4222:4222"
- "127.0.0.1:8222:8222"
networks:
- panda-wiki
minio:
image: minio/minio:latest
container_name: panda-wiki-minio
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${S3_ACCESS_KEY:-s3panda-wiki}
MINIO_ROOT_PASSWORD: ${S3_SECRET_KEY:-ChangeMe123!}
volumes:
- minio_data:/data
ports:
- "127.0.0.1:9000:9000"
- "127.0.0.1:9001:9001"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 10s
timeout: 5s
retries: 5
networks:
- panda-wiki
# ========== 业务服务 ==========
api:
build:
context: ./backend
dockerfile: Dockerfile.api
image: panda-wiki-api:latest
container_name: panda-wiki-api
restart: unless-stopped
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-ChangeMe123!}
NATS_PASSWORD: ${NATS_PASSWORD:-ChangeMe123!}
REDIS_PASSWORD: ${REDIS_PASSWORD:-ChangeMe123!}
JWT_SECRET: ${JWT_SECRET:-your-jwt-secret-change-me}
S3_SECRET_KEY: ${S3_SECRET_KEY:-ChangeMe123!}
ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123}
LOG_LEVEL: ${LOG_LEVEL:-0}
ENV: ${ENV:-production}
SENTRY_ENABLED: "false"
PG_DSN: "host=panda-wiki-postgres user=panda-wiki password=${POSTGRES_PASSWORD:-ChangeMe123!} dbname=panda-wiki port=5432 sslmode=disable TimeZone=Asia/Shanghai"
MQ_NATS_SERVER: "nats://panda-wiki-nats:4222"
REDIS_ADDR: "panda-wiki-redis:6379"
S3_ENDPOINT: "panda-wiki-minio:9000"
RAG_CT_RAG_BASE_URL: ${RAG_BASE_URL:-http://host.docker.internal:5050}
ports:
- "127.0.0.1:8000:8000"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
nats:
condition: service_started
minio:
condition: service_healthy
networks:
- panda-wiki
consumer:
build:
context: ./backend
dockerfile: Dockerfile.consumer
image: panda-wiki-consumer:latest
container_name: panda-wiki-consumer
restart: unless-stopped
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-ChangeMe123!}
NATS_PASSWORD: ${NATS_PASSWORD:-ChangeMe123!}
REDIS_PASSWORD: ${REDIS_PASSWORD:-ChangeMe123!}
JWT_SECRET: ${JWT_SECRET:-your-jwt-secret-change-me}
S3_SECRET_KEY: ${S3_SECRET_KEY:-ChangeMe123!}
LOG_LEVEL: ${LOG_LEVEL:-0}
ENV: ${ENV:-production}
SENTRY_ENABLED: "false"
PG_DSN: "host=panda-wiki-postgres user=panda-wiki password=${POSTGRES_PASSWORD:-ChangeMe123!} dbname=panda-wiki port=5432 sslmode=disable TimeZone=Asia/Shanghai"
MQ_NATS_SERVER: "nats://panda-wiki-nats:4222"
REDIS_ADDR: "panda-wiki-redis:6379"
S3_ENDPOINT: "panda-wiki-minio:9000"
RAG_CT_RAG_BASE_URL: ${RAG_BASE_URL:-http://host.docker.internal:5050}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
nats:
condition: service_started
minio:
condition: service_healthy
networks:
- panda-wiki
# Nginx 反向代理 (可选,用于统一入口)
nginx:
image: nginx:alpine
container_name: panda-wiki-nginx
restart: unless-stopped
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
ports:
- "80:80"
depends_on:
- api
networks:
- panda-wiki
volumes:
pg_data:
redis_data:
minio_data:
networks:
panda-wiki:
driver: bridge
创建 Nginx 反向代理配置
cat > nginx.conf << 'EOF'
server {
listen 80;
server_name _;
client_max_body_size 100M;
# API 服务
location /api/ {
proxy_pass http://panda-wiki-api:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /share/ {
proxy_pass http://panda-wiki-api:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 健康检查
location /health {
proxy_pass http://panda-wiki-api:8000;
}
}
EOF
创建环境变量文件
cat > .env << 'EOF'
# 数据库密码
POSTGRES_PASSWORD=ChangeMe123!
# Redis 密码
REDIS_PASSWORD=ChangeMe123!
# NATS 密码
NATS_USER=panda-wiki
NATS_PASSWORD=ChangeMe123!
# MinIO/S3
S3_ACCESS_KEY=s3panda-wiki
S3_SECRET_KEY=ChangeMe123!
# JWT 密钥 (务必修改为随机字符串)
JWT_SECRET=your-jwt-secret-change-me-to-random-string
# 管理员初始密码 (首次登录后修改)
ADMIN_PASSWORD=admin123
# 日志级别: -4=debug, 0=info, 4=warn, 8=error
LOG_LEVEL=0
# RAG 向量检索服务地址
RAG_BASE_URL=http://host.docker.internal:5050
EOF
五、构建并启动
5.1 构建后端 Docker 镜像
cd ~/PandaWiki
# 构建 API 镜像 (包含数据库迁移)
docker build -f backend/Dockerfile.api -t panda-wiki-api:latest ./backend
# 构建 Consumer 镜像
docker build -f backend/Dockerfile.consumer -t panda-wiki-consumer:latest ./backend
5.2 构建前端 (可选)
如果需要在服务器上运行前端:
# 安装 Node.js 22 (管理员前端构建)
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs
# 安装 pnpm
sudo npm install -g pnpm
# 构建管理员前端
cd ~/PandaWiki/web
pnpm install
pnpm --filter panda-wiki-admin build
# 构建用户端前端
pnpm --filter panda-wiki-app build
# 管理员前端会输出到 web/admin/dist/
# 用户端前端会输出到 web/app/dist/
# 可以用 Nginx 托管这些静态文件
5.3 启动全部服务
cd ~/PandaWiki
# 先启动基础设施
docker compose up -d postgres redis nats minio
# 等待基础设施就绪
sleep 15
# 启动业务服务
docker compose up -d api consumer nginx
# 查看所有容器状态
docker compose ps
# 查看日志
docker compose logs -f api
5.4 验证部署
# 检查 API 是否正常
curl http://localhost:8000/api/v1/health
# 查看容器日志
docker compose logs api | tail -50
docker compose logs consumer | tail -50
# 确认数据库迁移成功
docker compose logs api | grep -i migrate
六、AI 模型配置
首次登录管理后台后,需要配置 AI 大模型才能使用 AI 创作、AI 问答等功能。
支持的模型接入方式
| 方式 | 说明 |
|---|---|
| OpenAI 兼容 API | 任何兼容 OpenAI 接口的模型服务 |
| 本地 Ollama | 在内网服务器上自建 Ollama 服务 |
| DeepSeek API | DeepSeek 官方 API |
| Gemini API | Google Gemini |
内网环境推荐:自建 Ollama
# 在服务器上安装 Ollama
curl -fsSL https://ollama.com/install.sh | sh
# 拉取模型 (根据服务器配置选择)
ollama pull qwen2.5:7b # 7B 参数,需要约 8GB 显存/内存
ollama pull qwen2.5:14b # 14B 参数
ollama pull llama3.1:8b # 8B 参数
# Ollama API 默认监听 11434 端口
# 在 PandaWiki 管理后台配置模型时,填写:
# API 地址: http://host.docker.internal:11434/v1
# 模型名称: qwen2.5:7b
七、Nginx 前端托管 (可选)
将构建好的前端静态文件用 Nginx 托管:
# 创建前端部署目录
sudo mkdir -p /var/www/panda-wiki/{admin,app}
# 复制构建产物
sudo cp -r ~/PandaWiki/web/admin/dist/* /var/www/panda-wiki/admin/
sudo cp -r ~/PandaWiki/web/app/dist/* /var/www/panda-wiki/app/
# Nginx 配置
sudo tee /etc/nginx/sites-available/panda-wiki << 'EOF'
server {
listen 80;
server_name your-domain.com;
client_max_body_size 100M;
# 管理后台
location /admin {
alias /var/www/panda-wiki/admin;
index index.html;
try_files $uri $uri/ /admin/index.html;
}
# Wiki 用户端
location / {
root /var/www/panda-wiki/app;
index index.html;
try_files $uri $uri/ /index.html;
}
# API 代理
location /api/ {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /share/ {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
EOF
sudo ln -s /etc/nginx/sites-available/panda-wiki /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
八、内网完全离线部署
如果服务器完全无法访问外网,需要在有网络的机器上预先准备所有材料。
8.1 准备阶段 (在有网络的机器上)
# 1. 拉取所有基础 Docker 镜像
docker pull postgres:16-alpine
docker pull redis:7-alpine
docker pull nats:2-alpine
docker pull minio/minio:latest
docker pull nginx:alpine
docker pull golang:1.24.3-alpine
docker pull alpine:3.21
# 2. 导出镜像为 tar 文件
docker save -o postgres-16.tar postgres:16-alpine
docker save -o redis-7.tar redis:7-alpine
docker save -o nats-2.tar nats:2-alpine
docker save -o minio-latest.tar minio/minio:latest
docker save -o nginx-alpine.tar nginx:alpine
docker save -o golang-1.24.tar golang:1.24.3-alpine
docker save -o alpine-3.21.tar alpine:3.21
# 3. 下载 Go 依赖 (可选,Docker 构建时会自动处理)
# 如果有网络,直接 Docker build 即可
# 如果完全离线,需要预先 go mod download 并复制缓存
# 4. 打包项目源码
cd ~/PandaWiki
tar czf panda-wiki-source.tar.gz \
--exclude='.git' \
--exclude='node_modules' \
--exclude='web/.pnpm-store' \
.
# 5. 将镜像 tar 和源码 tar 传输到内网服务器
scp *.tar user@internal-server:/home/user/
8.2 部署阶段 (在内网服务器上)
# 1. 导入 Docker 镜像
cd /home/user
for f in *.tar; do
docker load -i "$f"
done
# 2. 解压项目源码
mkdir -p ~/PandaWiki && cd ~/PandaWiki
tar xzf ~/panda-wiki-source.tar.gz
# 3. 修改 docker-compose.yml 中的 build 部分
# 将 BUILDKIT 缓存挂载移除 (离线环境不支持)
# 将 Dockerfile 中的 --mount=type=cache 替换为普通 COPY
# 4. 创建离线版 Dockerfile
cat > backend/Dockerfile.api.offline << 'DOCKERFILE'
FROM golang:1.24.3-alpine AS builder
WORKDIR /src
ENV CGO_ENABLED=0
COPY backend/go.mod backend/go.sum ./
RUN go mod download
COPY backend/ .
ARG TARGETOS TARGETARCH VERSION
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build \
-ldflags "-s -w -extldflags '-static'" \
-o /build/panda-wiki-api \
cmd/api/main.go cmd/api/wire_gen.go \
&& GOOS=$TARGETOS GOARCH=$TARGETARCH go build \
-ldflags "-s -w -extldflags '-static'" \
-o /build/panda-wiki-migrate \
cmd/migrate/main.go cmd/migrate/wire_gen.go
FROM alpine:3.21 AS api
RUN apk update && apk upgrade && apk add --no-cache ca-certificates tzdata \
&& update-ca-certificates 2>/dev/null || true && rm -rf /var/cache/apk/*
WORKDIR /app
COPY --from=builder /build/panda-wiki-api /app/panda-wiki-api
COPY --from=builder /build/panda-wiki-migrate /app/panda-wiki-migrate
COPY --from=builder /src/store/pg/migration /app/migration
CMD ["sh", "-c", "/app/panda-wiki-migrate && /app/panda-wiki-api"]
DOCKERFILE
# 5. 使用离线 Dockerfile 构建
docker build -f backend/Dockerfile.api.offline -t panda-wiki-api:latest .
# 6. 启动服务
docker compose up -d
九、常用运维命令
# 查看所有服务状态
docker compose ps
# 查看某个服务的实时日志
docker compose logs -f api
docker compose logs -f consumer
# 重启某个服务
docker compose restart api
# 进入容器调试
docker exec -it panda-wiki-api sh
# 数据库备份
docker exec panda-wiki-postgres pg_dump -U panda-wiki panda-wiki > backup.sql
# 数据库恢复
docker exec -i panda-wiki-postgres psql -U panda-wiki panda-wiki < backup.sql
# 更新代码后重新构建
docker compose build api consumer
docker compose up -d api consumer
# 查看资源占用
docker stats
# 完全停止
docker compose down
# 停止并删除数据卷 (危险!会丢失所有数据)
docker compose down -v
十、访问地址
部署完成后:
| 地址 | 说明 |
|---|---|
http://服务器IP:8000 |
后端 API (通过 Nginx 代理则为 80 端口) |
http://服务器IP:2443 |
管理后台 (如使用官方 Caddy 配置) |
http://服务器IP:9001 |
MinIO 管理控制台 |
首次登录使用 .env 中配置的 ADMIN_PASSWORD 密码,用户名为 admin。
十一、故障排查
数据库连接失败
# 检查 postgres 是否就绪
docker compose logs postgres
# 手动连接测试
docker exec -it panda-wiki-postgres psql -U panda-wiki -d panda-wiki
API 启动失败
# 查看详细日志
docker compose logs api
# 常见原因:
# 1. 数据库迁移失败 - 检查 PG_DSN 配置
# 2. NATS 连接失败 - 检查 MQ_NATS_SERVER 配置
# 3. Redis 连接失败 - 检查 REDIS_ADDR 配置
前端页面空白
# 检查 API 是否可达
curl http://localhost:8000/api/v1/health
# 检查浏览器控制台是否有 CORS 或 API 404 错误
# 确保前端配置的 API 地址正确
容器之间网络不通
# 检查网络
docker network inspect panda-wiki_panda-wiki
# 容器间通信测试
docker exec panda-wiki-api ping panda-wiki-postgres