文档版本 :v4.0(实战修订版) 编写日期 :2026-10-22 适用环境 :Windows 11(Docker Desktop)→ Rocky Linux 9.x(Docker CE) 操作对象 :MaxKB 一体容器(含大模型配置、知识库数据、自定义口令) 编写原则:本文档严格按实际操作顺序编写,包含每一步的命令、参数说明、校验方法与已知故障。
一、环境与资产总览
1.1 端点信息
| 项目 | 值 | 备注 |
|---|---|---|
| 源宿主机 | Windows 11 | Docker Desktop |
| 源容器名 | MaxKB |
一体镜像,内置 PostgreSQL |
| 容器内服务端口 | 8080 |
容器内部固定,不可改 |
| 目标宿主机 | Rocky Linux 9.x(VM) | IP 192.168.133.135 |
| 目标映射端口 | 28080:8080 |
宿主机 28080 对外 |
| frp 服务端 | 159.75.236.150:7000 |
云主机 Windows Server 2022 |
| frp 远程端口 | 28082 |
公网访问端口 |
1.2 端口三层模型(必须理解)
| 层级 | 示例 | 约束 |
|---|---|---|
| 容器内部 | 8080 |
各容器独立,可重复 |
| 宿主机映射 | -p 28080:8080 |
同一宿主机不可冲突 |
| frp 远程口 | remotePort=28082 |
服务端全局不可冲突 |
改宿主机端口不影响容器内部,MaxKB 始终监听 8080。
二、源环境打包(Windows 11)
2.1 确认容器与数据卷
docker ps -a --filter name=MaxKB --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"
docker inspect MaxKB --format='{{range .Mounts}}{{.Type}} -> {{.Destination}}{{"\n"}}{{end}}'
记录 Destination,MaxKB 一体镜像标准为 /opt/maxkb/data。
2.2 停止容器
docker stop MaxKB
PostgreSQL 运行时 commit 可能落半截事务。主动停止是严谨做法。
2.3 提交镜像
docker commit MaxKB maxkb:prod20261021
docker images maxkb
不使用
latest标签,便于版本追踪与回滚。
2.4 导出镜像
docker save -o D:\maxkb_prod_image.tar maxkb:prod20261021
Get-Item D:\maxkb_prod_image.tar | Select-Object Name, @{N='Size_GB';E={[math]::Round($_.Length/1GB,2)}}
约 3.65GB,属正常。
2.5 导出数据卷
docker run --rm --volumes-from MaxKB -v D:\export:/backup alpine:latest `
tar czf /backup/maxkb_vol.tar.gz -C /opt/maxkb data
校验:
docker run --rm -v D:\export:/backup alpine tar tzf /backup/maxkb_vol.tar.gz | Select-String "pgdata/base|pgdata/global/pg_control"
必须出现 data/postgresql/pgdata/base/ 与 data/postgresql/pgdata/global/pg_control。
2.6 原环境验证(不可省略)
docker run -d --name maxkb_verify -p 18080:8080 --volumes-from MaxKB maxkb:prod20261021
Start-Sleep -Seconds 30
docker logs --tail 50 maxkb_verify
浏览器访问 http://localhost:18080,验证:
- 修改后的口令可登录
- 大模型配置完整
- 知识库文档完整
docker rm -f maxkb_verify
三、文件传输(SCP)
scp D:\maxkb_prod_image.tar root@192.168.133.135:/opt/
scp D:\export\maxkb_vol.tar.gz root@192.168.133.135:/opt/
ssh root@192.168.133.135 "ls -lh /opt/maxkb_prod_image.tar /opt/maxkb_vol.tar.gz"
四、目标端部署(Rocky Linux)
4.1 加载镜像
docker load -i /opt/maxkb_prod_image.tar
docker images | grep maxkb
4.2 解压数据
mkdir -p /opt/maxkb_prod
tar xzf /opt/maxkb_vol.tar.gz -C /opt/maxkb_prod --strip-components=2
ls /opt/maxkb_prod/data/postgresql/pgdata
必须含 base、global、pg_wal。
4.3 权限与 SELinux(可略)
chown -R 999:999 /opt/maxkb_prod
chmod -R 755 /opt/maxkb_prod
chcon -R -t container_file_t /opt/maxkb_prod
4.4 拉起容器(映射新端口 28080)
docker run -d \
--name maxkb \
-p 28080:8080 \
-v /opt/maxkb_prod:/opt/maxkb:Z \
--restart=unless-stopped \
maxkb:prod20261021
只挂一处
-v。绝不可再加/var/lib/postgresql/data,会盖掉 MaxKB 自带 PG。
4.5 验证
docker ps --filter name=maxkb
docker logs --tail 60 maxkb
curl -I http://127.0.0.1:28080
firewall-cmd --permanent --add-port=28080/tcp && firewall-cmd --reload
浏览器 http://192.168.133.135:28080 验证通过。
五、frp 公网发布(本次最大故障点)
5.1 架构
MaxKB容器(8080) ← -p 28080:8080 ← VM(192.168.133.135:28080)
↑ netsh portproxy
Win11(127.0.0.1:28080) ← frpc ←→ 云主机 frps(7000) → 公网:28082
5.2 Win11 本地端口转发
frpc 运行在 Win11,其 localIP 只能填 127.0.0.1。虚拟机流量靠系统转发:
netsh interface portproxy add v4tov4 `
listenaddress=127.0.0.1 listenport=28080 `
connectaddress=192.168.133.135 connectport=28080
netsh interface portproxy show all
5.3 frpc.toml 完整配置
serverAddr = "159.75.***"
serverPort = 7000
[[proxies]]
name = "MaxKB"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8081
remotePort = 8082
[[proxies]]
name = "MaxKB-VM"
type = "tcp"
localIP = "127.0.0.1"
localPort = 28080
remotePort = 28082
[webServer]
addr = "127.0.0.1"
port = 7400
user = "admin"
password = "*****"
若服务端 frps.toml 配了
auth.token,客户端必须同步加:
auth.method = "token" auth.token = "与服务端一致"
⚠️ 5.4 本次真凶:frpc 读取的是旧配置(重点)
故障现象 :配置明明正确,frpc.exe -c frpc.toml 反复报 i/o deadline reached,持续约 2 小时无果。电脑重启多次仍无效。
根因 :frpc 实际加载的配置不是磁盘上的 frpc.toml ,而是上次通过 Web UI(http://127.0.0.1:7400)写入的内部配置 。本地 toml 新增的 28080/28082 段未被加载。
证据 :打开 http://127.0.0.1:7400/static/#/proxies,看到的代理列表只有旧的 8081/8082,缺少新增的 MaxKB-VM。
解决步骤:
-
浏览器打开
http://127.0.0.1:7400/static/#/proxies -
进入 Config 页面
-
将完整的
frpc.toml内容整段覆盖粘贴进配置框 -
点击 Update & Reload
-
回到 Proxies 页面,确认
MaxKB-VM已出现 -
此时公网
http://159.75.236.150:28082立即可用
原理说明:
-
frpc 启动时会将配置序列化进内存 ,Web UI 的
webServer模块操作的是内存中的配置副本 -
磁盘
frpc.toml只在进程首次启动时读取一次 -
若通过 Web UI 改过配置,后续 Reload 可能复用内存副本,导致磁盘新增大段不被感知
-
重启电脑不能解决:frpc 不是系统服务,重启后进程消失,但 Web UI 的 Reload 机制仍指向内存副本
结论 :凡通过 Web UI 管理 frpc 的场景,改完磁盘 toml 后必须到 Web UI 手动覆盖并重载,这是本次故障的唯一正确解法。
5.5 云主机侧检查
netstat -ano | findstr :7000
必须 0.0.0.0:7000 LISTENING。
netsh advfirewall firewall add rule name=frp7000 dir=in action=allow protocol=TCP localport=7000
netsh advfirewall firewall add rule name=frp28082 dir=in action=allow protocol=TCP localport=28082
云厂商安全组入方向放行 TCP 7000、28082。
5.6 网络拦截兜底(略)
若原网络(公司宽带/校园网)仍报 i/o deadline reached,改用 QUIC 协议(服务端需加 quicBindPort=7000,客户端加 transport.protocol="quic",并放行 UDP 7000)。
六、Nginx 反向代理与 HTTPS 发布
6.1 当前可访问地址(实测)
| 地址 | 协议 | 后端 | 状态 |
|---|---|---|---|
http://159.75.236.***:28082/chat/xxx |
HTTP | frp→VM:28080 | ✅ 可用 |
http://ai.dql5251.***:28082/chat/xxx |
HTTP | frp→VM:28080 | ✅ 可用(nginx 未配置 28080 亦可,因走 frp 直连) |
https://ai.dql5251.***:8083/chat/xxx |
HTTPS | nginx→Docker Desktop | ✅ 可用(网页嵌入场景) |
6.2 关键约束
-
MaxKB 容器内仅提供 HTTP(8080),本身无 HTTPS 能力
-
HTTPS 必须由外层终止:frp 或服务端 nginx 任一端做 TLS 卸载
-
网页嵌入必须用 HTTPS:浏览器对嵌入 iframe 有混合内容限制,HTTP 页面嵌入 HTTP 资源会被拦截
6.3 推荐架构(HTTPS 统一入口)
用户 HTTPS → nginx:443(TLS 终止)→ frp:28082 → VM:28080 → MaxKB:8080
6.4 nginx 配置示例
# /etc/nginx/conf.d/maxkb.conf
server {
listen 443 ssl http2;
server_name ai.dql5251.***;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://159.75.***:28082;
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 https;
# WebSocket 支持(MaxKB 对话流式输出需要)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 流式响应不缓冲
proxy_buffering off;
proxy_cache off;
}
}
# HTTP 强制跳转 HTTPS
server {
listen 80;
server_name ai.dql5251.***;
return 301 https://$host$request_uri;
}
6.5 验证
nginx -t && systemctl reload nginx
curl -I https://ai.dql5251.top/chat/02f58e0f0331edbf
6.6 协议混用故障说明
| 现象 | 原因 |
|---|---|
https://...:28082 打不开 |
frp 远程口只做 TCP 透传,不处理 TLS |
| HTTP 页面嵌入 MaxKB 失败 | 混合内容被浏览器拦截 |
| 嵌入页空白 | 前端站点 HTTPS,MaxKB 后端 HTTP |
统一原则:对外只暴露 443,内部全 HTTP,TLS 在 nginx 一层终止。
七、故障排查矩阵
| 现象 | 根因 | 解法 |
|---|---|---|
| 容器秒退,日志无输出 | commit 丢 CMD | 用原启动命令或 volumes-from 验证 |
| 登录后知识库为空 | 数据卷未挂载 | 确认 -v /opt/maxkb_prod:/opt/maxkb |
| PG 报 ownership error | 目录属主非 999 | chown -R 999:999 |
| SELinux 拒绝 | 挂载无标签 | :Z 或 chcon |
:28080 不通 |
firewalld | firewall-cmd add-port 28080 |
frpc 报 i/o deadline |
网络拦截或配置未重载 | 见 5.4 与 5.6 |
| Web UI 看不到新代理 | frpc 读的是内存旧配置 | Web UI 覆盖 + Update & Reload |
| HTTPS 地址打不开 | frp 不做 TLS | nginx 443 终止 |
| 嵌入页空白 | 协议混用 | 全站 HTTPS |
八、命令速查表
| 阶段 | 命令 |
|---|---|
| 停止容器 | docker stop MaxKB |
| 提交镜像 | docker commit MaxKB maxkb:prod20261021 |
| 导出镜像 | docker save -o D:\maxkb_prod_image.tar maxkb:prod20261021 |
| 导出数据 | docker run --rm --volumes-from MaxKB -v D:\export:/backup alpine tar czf /backup/maxkb_vol.tar.gz -C /opt/maxkb data |
| 本地验证 | docker run -d -p 18080:8080 --name maxkb_verify --volumes-from MaxKB maxkb:prod20261021 |
| SCP 传输 | scp D:\maxkb_prod_image.tar root@192.168.133.135:/opt/ |
| 加载镜像 | docker load -i /opt/maxkb_prod_image.tar |
| 解压数据 | tar xzf /opt/maxkb_vol.tar.gz -C /opt/maxkb_prod --strip-components=2 |
| 权限修正 | chown -R 999:999 /opt/maxkb_prod && chmod -R 755 /opt/maxkb_prod |
| 拉起容器 | docker run -d --name maxkb -p 28080:8080 -v /opt/maxkb_prod:/opt/maxkb:Z --restart=unless-stopped maxkb:prod20261021 |
| frp 重载 | Web UI Config 页覆盖 → Update & Reload |
| nginx 重载 | nginx -t && systemctl reload nginx |
九、附录:本次实战时间线
-
Windows 侧完成镜像与数据导出
-
SCP 推送至 Rocky Linux VM
-
目标端 load + 解压 + 拉起容器,映射 28080
-
配置 frp,反复报
i/o deadline reached约 2 小时 -
次日重启客户端,发现问题:Web UI 配置与本地 toml 不一致
-
Web UI 覆盖配置并执行 Update & Reload
-
公网
http://159.75.236.***:28082立即可用 -
补充 nginx HTTPS 反向代理,实现网页嵌入
文档结束
