worldmonitor v2.11.4 Docker Compose 部署指南
从源码构建并部署 worldmonitor v2.11.4 官方自托管全栈:四个必需密钥、镜像构建、种子数据灌入、MCP 密钥与 CLI 接线全流程,含数据持久化、运维命令与七个实测排障问题。
worldmonitor v2.11.4 Docker Compose 部署指南
目标:用 Docker Compose 在一台 Linux 服务器上从源码构建并部署 worldmonitor v2.11.4 官方自托管全栈(nginx+Node API + Redis + Redis REST 代理 + AIS 中继),完成必需密钥生成、种子数据灌入、MCP 密钥配置与 CLI 接线,实现「浏览器打开仪表盘 +
worldmonitor命令行直连自家栈」的完整可用状态。本文全部命令与回显已在 Docker Engine 29.9.2(Compose v5.6.1)、Alpine 3.24.3 服务器环境实测通过,部署版本为 v2.11.4 快照(main 分支 commitd8ba38d,2026-10-24)。
一、环境信息
- 操作系统:Alpine Linux 3.24.3(x86_64,自带 git 2.54.0 / OpenSSL 3.5.9,另安装 Node.js v24.22.1 + npm 11.12.1 用于宿主侧种子脚本)
- Docker Engine:29.9.2,Docker Compose 插件 v5.6.1
- worldmonitor 版本:v2.11.4(2026-10-24 发布;无官方 registry 镜像,本篇从源码构建,见第二章)
- 镜像清单(构建产物实测体积):
worldmonitor:latest787MB、worldmonitor-ais-relay:latest562MB、worldmonitor-redis-rest:latest255MB、docker.io/redis:7-alpine57.8MB - 端口规划:仪表盘宿主端口
8140(服务内端口 8080,经.env的WM_PORT指定);Redis REST 代理127.0.0.1:8079(仅回环);AIS 中继 3004 与 Redis 6379 仅栈内互通不对外发布。生产环境建议WM_PORT=3000直接对外或置于反代之后,本文取值仅为与实测环境保持一致,可按需替换 - 编排目录:
/opt/worldmonitor/(git clone 产物,含docker-compose.yml、Dockerfile、SELF_HOSTING.md、.env) - 编排项目名:
worldmonitor-2-11-4-stack(经docker compose -p显式指定,栈内自动生成同名_defaultbridge 网络与worldmonitor-2-11-4-stack_redis-data数据卷)
二、镜像选型说明
worldmonitor 不发布官方 registry 镜像,官方自托管路径就是「源码构建」(docker-compose.yml 的三个服务均带 build: 段,README Quick Start 与 SELF_HOSTING.md 均以 docker compose up -d --build 为标准动作)。选型要点集中在构建产物与基础镜像两点:
| 项目 | 取值 | 说明 |
|---|---|---|
| 主服务镜像 | worldmonitor:latest(源码 Dockerfile 构建) | 多阶段构建:builder 装依赖并产出 Vite 前端 + 编译 TS API 处理器 → runtime-deps 只装运行时依赖 → final 由 nginx(静态+反代)+ Node API(supervisord 托管)组成,以非 root 用户 appuser 运行,内置健康检查探针 /api/sidecar-health |
| AIS 中继镜像 | worldmonitor-ais-relay:latest(源码 Dockerfile.relay 构建) | WebSocket → AISStream 实时船舶流中继 |
| REST 代理镜像 | worldmonitor-redis-rest:latest(源码 docker/Dockerfile.redis-rest 构建) | Upstash 兼容 REST 代理,只放行固定 Redis 命令白名单 |
| Redis 基础镜像 | docker.io/redis:7-alpine(官方上游) | 以 --requirepass + --maxmemory 256mb --maxmemory-policy allkeys-lru 运行 |
💡 说明:基础镜像
node:24-alpine在 Dockerfile 中按 sha256 摘要锁定(node:24-alpine@sha256:feb766…),保证构建可复现;主镜像内 nginx、supervisord、gettext(envsubst 用)来自 Alpine 包管理器。镜像标签统一为:latest——如需版本化,可在docker compose build后自行docker tag标注构建日期。
⚠️ 网络说明:构建过程需要访问 npm registry 与 Docker Hub。本实测环境直连境外源不稳定(同一环境跑官方 CLI 曾实测报
Error: fetch failed),故构建时给 BuildKit 传入预定义代理参数--build-arg HTTP_PROXY=… --build-arg HTTPS_PROXY=…走代理完成,docker pull redis:7-alpine由守护进程代理拉取。可直连官方源的服务器无需传任何代理参数;若npm ci仍超时,可改走国内 npm 镜像源后重试。
三、前置条件
- 服务器已安装 Docker Engine 与 Compose 插件,验证:
docker version --format 'Engine {{.Server.Version}}'
实测输出:
Engine 29.9.2
docker compose version
实测输出:
Docker Compose version v5.6.1
- 宿主侧安装 Node.js 22+ 与 OpenSSL(种子脚本在宿主机运行,不在栈内跑):
apk add --no-cache git nodejs npm openssl bash 2>&1 | tail -3
实测输出(Alpine 服务器;Debian/Ubuntu 用 apt install -y git nodejs npm openssl bash,Node 需 ≥22):
OK: 101.6 MiB in 65 packages
node -v && openssl version
实测输出:
v24.22.1
OpenSSL 3.5.9 29 Sep 2026 (Library: OpenSSL 3.5.9 29 Sep 2026)
- 克隆源码(浅克隆即可):
cd /opt && git clone --depth 1 https://github.com/koala73/worldmonitor.git && cd worldmonitor && git log -1 --format='%h %cd' --date=short
实测输出:
Cloning into 'worldmonitor'...
d8ba38d8246fac3035b3eacc68d1e4dd9193a69f 2026-10-24
du -sh /opt/worldmonitor
实测输出:
253.3M /opt/worldmonitor
- 端口确认:规划仪表盘端口(本篇取 8140)未被占用:
ss -ltn | grep -c ':8140 ' || echo '端口 8140 空闲'
实测输出:
0
端口 8140 空闲
四、部署步骤
4.1 生成四个必需密钥
自托管栈的四个密钥没有安全默认值——缺任何一个,对应服务直接拒绝启动(.env.example 与 SELF_HOSTING.md 均强调;wm-local-token 旧默认值已因 #3804 安全问题移除)。一次性写入 .env:
cd /opt/worldmonitor
printf "RELAY_SHARED_SECRET=%s\nREDIS_PASSWORD=%s\nREDIS_TOKEN=%s\nWM_SESSION_SECRET=%s\n" \
"$(openssl rand -hex 32)" "$(openssl rand -hex 32)" \
"$(openssl rand -hex 32)" "$(openssl rand -hex 32)" > .env
printf "WM_PORT=8140\n" >> .env
wc -l .env
实测输出:
5 .env
四个密钥的用途(来源:SELF_HOSTING.md「Required Environment Variables」表,实测与之一致):
| 变量 | 用途 | 缺失后果(实测) |
|---|---|---|
RELAY_SHARED_SECRET | 认证仪表盘发给 AIS 中继的一切非公开请求 | 中继拒绝启动 |
REDIS_PASSWORD | Redis AUTH 密码(--requirepass) | Redis 拒绝启动 |
REDIS_TOKEN | REST 代理(redis-rest)每请求 Bearer 令牌,应用侧即 UPSTASH_REDIS_REST_TOKEN | 代理与应用拒绝启动 |
WM_SESSION_SECRET | 给自托管 API 路由的匿名浏览器会话签名 | 应用拒绝启动 |
WM_PORT | 仪表盘对外端口(compose 里 ${WM_PORT:-3000}:8080) | 不设则用默认 3000 |
缺密钥时的报错形态(实测,用于排障对照):
REDIS_TOKEN= docker compose -p worldmonitor-2-11-4-stack config
实测输出:
error while interpolating services.redis-rest.environment.SRH_TOKEN: required variable REDIS_TOKEN is missing a value: REDIS_TOKEN required — generate with: openssl rand -hex 32
error while interpolating services.worldmonitor.environment.UPSTASH_REDIS_REST_TOKEN: required variable REDIS_TOKEN is missing a value: REDIS_TOKEN required — generate with: openssl rand -hex 32
4.2 构建镜像
首次构建包含 npm ci 依赖安装、TS API 处理器编译、/pro 页面构建与 Vite 前端构建,本实测约 15 分钟:
docker compose -p worldmonitor-2-11-4-stack build \
--build-arg HTTP_PROXY=http://192.168.1.62:7897 \
--build-arg HTTPS_PROXY=http://192.168.1.62:7897 \
--build-arg NO_PROXY=localhost,127.0.0.1
实测输出(输出节选,实测首尾;代理参数按自身网络替换,可直连则省略):
#38 [runtime-deps 3/3] RUN npm ci --omit=dev --omit=optional --ignore-scripts
#38 DONE 51.9s
...
#56 [final 6/8] COPY docker/nginx.conf /etc/nginx/nginx.conf.template
#56 DONE 0.2s
...
=> => naming to docker.io/library/worldmonitor:latest
构建完成后确认三个自建镜像与一个上游镜像:
docker images --format '{{.Repository}}:{{.Tag}}\t{{.Size}}'
实测输出:
worldmonitor:latest 787MB
worldmonitor-ais-relay:latest 562MB
worldmonitor-redis-rest:latest 255MB
redis:7-alpine 57.8MB
4.3 启动全栈
docker compose -p worldmonitor-2-11-4-stack up -d
实测输出:
Container worldmonitor-redis Starting
Container worldmonitor-redis Started
Container worldmonitor-redis-rest Starting
Container worldmonitor-redis-rest Started
Container worldmonitor-ais-relay Starting
Container worldmonitor-ais-relay Started
Container worldmonitor Starting
Container worldmonitor Started
docker compose -p worldmonitor-2-11-4-stack ps --format 'table {{.Name}}\t{{.Status}}\t{{.Ports}}'
实测输出(启动约半分钟后健康检查转 healthy):
NAME STATUS PORTS
worldmonitor Up 8 seconds (healthy) 0.0.0.0:8140->8080/tcp, [::]:8140->8080/tcp
worldmonitor-ais-relay Up 4 minutes (healthy) 3004/tcp
worldmonitor-redis Up 4 minutes 6379/tcp
worldmonitor-redis-rest Up 4 minutes 127.0.0.1:8079->80/tcp
主服务启动日志(docker compose -p worldmonitor-2-11-4-stack logs worldmonitor,输出节选,实测首部)——可见 supervisord 拉起 nginx 与 Node API、API 共 184 条路由、健康检查探针已通:
worldmonitor | 2026-10-25 02:03:20,692 INFO supervisord started with pid 1
worldmonitor | 2026-10-25 02:03:21,693 INFO spawned: 'nginx' with pid 30
worldmonitor | 2026-10-25 02:03:21,698 INFO spawned: 'worldmonitor-api' with pid 31
worldmonitor | [local-api] listening on http://127.0.0.1:46123 (apiDir=/app/api, routes=184, cloudFallback=false)
worldmonitor | 2026-10-25 02:03:22,778 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
worldmonitor | 127.0.0.1 - [25/Oct/2026:02:03:25 +0000] "GET /api/sidecar-health HTTP/1.1" 200 55
4.4 验证仪表盘与健康端点
curl -s -o /dev/null -w 'GET http://localhost:8140/ -> HTTP %{http_code}\n' http://localhost:8140/
curl -s http://localhost:8140/ | grep -oE '<title>[^<]*</title>' | head -1
curl -s http://localhost:8140/api/sidecar-health
实测输出:
GET http://localhost:8140/ -> HTTP 200
<title>World Monitor - Real-Time Global Intelligence Dashboard</title>
{"status":"ok","mode":"docker","port":46123}
再确认前端资源、/pro 页面与 dashboard 路由(SPA 回退目标)均可达:
curl -s -o /dev/null -w 'main.js HTTP %{http_code} bytes=%{size_download}\n' http://localhost:8140/assets/main-CDZonSH6.js
curl -s -o /dev/null -w '/pro/ HTTP %{http_code}\n' http://localhost:8140/pro/
curl -s -o /dev/null -w '/dashboard.html HTTP %{http_code}\n' http://localhost:8140/dashboard.html
实测输出:
main.js HTTP 200 bytes=134478
/pro/ HTTP 200
/dashboard.html HTTP 200
此时打开浏览器访问 http://<服务器IP>:8140/ 即见完整仪表盘(世界地图、新闻、市场等面板)。数据健康总览端点在灌数前会显示大量 EMPTY(详见 4.5):
curl -s 'http://localhost:8140/api/health?compact=1' | head -c 220
实测输出(灌数前;crit:210 即种子数据未灌入):
{"status":"UNHEALTHY","summary":{"total":335,"ok":23,"warn":33,"containedWarn":1,"onDemandWarn":69,"staleContent":0,"rolloutPending":0,"crit":210},"checkedAt":"2026-10-25T02:01:46.112Z","problems":{"earthquakes":{"status":"EMPTY","records":0,"maxStaleMin":30},"outages":{"status":"EMPTY","records":0,"maxStaleMin":30},"sectors":{"status":"EMPTY","records":0,"maxStaleMin":30},"etfFlows":{"status":"EMPTY","records":0,"maxStaleMin":60},"climateAnomalies":{"status":"EMPTY","records":0,"maxStaleMin":540},"climateDisasters":{"status":"EMPTY","records":0,"maxStaleMin":720},"climateAirQuality":{"status"
4.5 灌入种子数据
仪表盘的缓存型面板(地震、天气、经济指标等)由种子脚本从上游抓数写入 Redis。脚本在宿主机运行(不在栈内),需 Redis REST 代理已启动;run-seeders.sh 会自动从 .env 读 REDIS_TOKEN:
cd /opt/worldmonitor && ./scripts/run-seeders.sh
实测输出(输出节选,实测首部;仓库共 226 个 scripts/seed-*.mjs,独立脚本逐个输出 OK/FAIL,bundle 脚本输出 SKIP 并附内部统计——FAIL/SKIP 均为优雅降级,不中断整体流程):
→ seed-aaii-sentiment.mjs ... FAIL (=== Failed gracefully (1458ms) ===)
→ seed-alberta-emergency-alert.mjs ... OK
→ seed-aviation.mjs ... FAIL (Node.js v24.22.1)
→ seed-bc-emergency-info.mjs ... OK
→ seed-bigmac.mjs ... FAIL (=== Done (5002ms, RETRY FAILED) ===)
→ seed-bis-data.mjs ... OK
→ seed-bis-extended.mjs ... OK
→ seed-bis-lbs.mjs ... OK
→ seed-boc-valet.mjs ... OK
→ seed-bundle-canada.mjs ...
跑一段时间后复查健康总览(本实测跑至约 20 个脚本后,ok 从 23 升至 79、crit 从 210 降至 169):
curl -s 'http://localhost:8140/api/health?compact=1' | head -c 200
实测输出(节选,实测首部):
{"status":"UNHEALTHY","summary":{"total":335,"ok":79,"warn":32,"containedWarn":1,"onDemandWarn":55,"staleContent":0,"rolloutPending":0,"crit":169},"checkedAt":"2026-10-25T02:09:15.262Z",
💡 说明:全量 226 个脚本按默认每脚本 30 分钟超时上限跑完需要较长时间,生产建议交给 cron 定时补数(SELF_HOSTING.md 给出
*/30 * * * *示例);部分脚本无对应 API key 或上游被墙时永远 FAIL,属预期行为,不影响其余面板。每个独立脚本受SEED_TIMEOUT秒级墙钟上限保护(默认 1800,SEED_TIMEOUT=0关闭),防止单个挂起的上游拖死整轮灌数。
4.6 配置 MCP 密钥并接通 CLI
自托管栈自带 MCP 服务器(/api/mcp),用 X-WorldMonitor-Key 头认证,合法 key 由 .env 的 WORLDMONITOR_VALID_KEYS 定义(OAuth 仅官方托管版提供)。生成 key 并重建应用:
cd /opt/worldmonitor
KEY="wm_$(openssl rand -hex 20)"
echo "WORLDMONITOR_VALID_KEYS=$KEY" >> .env
docker compose -p worldmonitor-2-11-4-stack up -d
实测输出:
Container worldmonitor Recreated
Container worldmonitor Starting
Container worldmonitor Started
裸协议验证 MCP(tools/list):
curl -s -X POST http://localhost:8140/api/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H "X-WorldMonitor-Key: $KEY" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | head -c 220
实测输出(节选,实测首部):
{"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"get_country_history","title":"Country daily history","description":"Read cached daily country CII, resilience and linked headlines. Account depth: Pro 90 days; API/Enterprise 365. ...
再用官方 CLI 直连自家栈(CLI 安装见 《worldmonitor v2.11.4 常用 CLI 命令与工具详解》):
worldmonitor call get_sources --mcp-url http://localhost:8140/api/mcp --api-key "$KEY" 2>&1 | head -10
实测输出(节选,实测首部):
{
"content": [
{
"type": "text",
"text": "{\"view\":\"summary\",\"summary\":{\"providerCount\":790,\"excludedProviderCount\":171,\"outletCount\":531,\"providersByKind\":{\"feed\":406,\"structured\":291,\"operational-status\":30,\"feed+structured\":63},...
到此部署闭环完成:浏览器访问 http://<服务器IP>:8140/ 看仪表盘,CLI/MCP 客户端经 http://<服务器IP>:8140/api/mcp 编程取数。
五、数据持久化说明
自托管栈只有一仞需要持久化的状态——Redis 种子数据,落在 compose 自动创建的命名卷中:
docker volume ls --format '{{.Name}}' | grep worldmonitor
实测输出:
worldmonitor-2-11-4-stack_redis-data
- 重启不丢:
docker compose restart/ 服务器重启(restart: unless-stopped自动拉起)后 Redis 数据仍在,面板无需重灌; down不带-v不丢:docker compose down保留卷;down -v会删卷,所有种子数据清零,需重新执行./scripts/run-seeders.sh(SELF_HOSTING.md 原文警告);- 种子数据有时效:种子内容按 TTL 过期,靠 cron 定时补数保持新鲜;看到面板 stale/EMPTY 先跑一轮 seeders 再排查;
- 用户偏好(面板顺序、监视关键词等)存在浏览器 LocalStorage/IndexedDB,不在服务端,换浏览器需重新配置。
六、环境变量表
docker-compose.yml 从 .env 插值。必填 4 项缺失即拒绝启动;其余可选项按功能开启(值留空 = 对应功能关闭,核心功能不受影响)。
6.1 必填项(本篇实测全部设置)
| 变量 | 示例来源 | 用途 |
|---|---|---|
RELAY_SHARED_SECRET | openssl rand -hex 32 | AIS 中继鉴权共享密钥 |
REDIS_PASSWORD | openssl rand -hex 32 | Redis AUTH 密码(--requirepass,并用于 redis-rest 上游连接串) |
REDIS_TOKEN | openssl rand -hex 32 | redis-rest 的 Bearer 令牌(SRH_TOKEN)与应用侧 UPSTASH_REDIS_REST_TOKEN |
WM_SESSION_SECRET | openssl rand -hex 32 | 匿名浏览器会话签名密钥 |
6.2 高频可选项(值留空功能即隐藏)
| 变量 | 用途 | 获取途径 |
|---|---|---|
WM_PORT | 仪表盘对外端口(默认 3000) | 自定 |
WORLDMONITOR_VALID_KEYS | 自托管 MCP/REST 的 operator key(wm_ 前缀) | wm_$(openssl rand -hex 20) |
OPENROUTER_API_KEY | 云端 LLM(免费档 50 次/天) | openrouter.ai |
LLM_API_URL / LLM_API_KEY / LLM_MODEL | 自托管 LLM(任意 OpenAI 兼容端点,如 Ollama http://<内网主机>:11434/v1/chat/completions) | 自建 |
FINNHUB_API_KEY | 股票行情主源(配额缺口 + 符号搜索) | finnhub.io(免费档) |
AISSTREAM_API_KEY | 实时船舶 AIS(app 与 ais-relay 两个服务都要给) | aisstream.io(免费) |
EIA_API_KEY | 石油分析 | eia.gov/opendata(免费) |
FRED_API_KEY | 美联储经济数据 | fred.stlouisfed.org(免费) |
ACLED_EMAIL / ACLED_PASSWORD | 冲突与抗议数据(OAuth 自动刷新,优于静态 token) | acleddata.com(研究者免费) |
NASA_FIRMS_API_KEY | 卫星火点(seed-fire-detections 脚本必需) | firms.modaps.eosdis.nasa.gov(免费) |
CLOUDFLARE_API_TOKEN | 断网监测(需 Radar 访问权限,付费) | dash.cloudflare.com |
OPENSKY_CLIENT_ID / OPENSKY_CLIENT_SECRET | 军航追踪(经中继) | opensky-network.org(免费) |
WM_TRUSTED_PROXY_CIDRS | 前置反代时声明可信代理网段(逗号分隔,非法值拒绝启动;直连勿设) | 自定 |
完整可配置项超过 250 个(api/、scripts/、前端 VITE_ 特性开关等),全集见仓库 .env.example(1297 行)与本专栏配置详解篇。
七、配置参数说明
docker-compose.yml 内写死的关键运行参数(自托管一般不动,理解含义即可):
| 参数 | 值 | 说明 |
|---|---|---|
LOCAL_API_MODE | docker | 启用 Docker 自托管模式:无 Clerk/Convex 权益后端,/api/local- 管理路由一律 403,运维改动走 Compose 环境变量重建 |
LOCAL_API_PORT | 46123 | 栈内 Node API 监听端口(nginx 把 /api/* 反代过去,不对外发布) |
LOCAL_API_CLOUD_FALLBACK | false | 关闭云端回退,纯本地模式 |
WS_RELAY_URL | http://ais-relay:3004 | 应用侧连 AIS 中继的栈内地址 |
UPSTASH_REDIS_REST_URL | http://redis-rest:80 | 应用/中继经 REST 代理访问 Redis |
UPSTASH_ALLOW_INSECURE_HTTP | true(仅 ais-relay) | 允许中继容器走纯 HTTP 代理(默认要求 https,自托管代理是 http) |
--maxmemory 256mb / allkeys-lru | Redis 启动参数 | 缓存上限 256MB,满了按 LRU 淘汰 |
mem_limit: 512m | redis-rest | REST 代理会整体缓冲请求体(默认上限 16MB),限 512MB 内存防并发大请求放大 |
💡 说明:Docker 模式下仅
GET /api/intelligence/v1/get-country-intel-brief接受匿名会话,且每日每 IP 限 50 次直连 LLM 调用(nginx 以$remote_addr打X-Real-IP,轮换头或会话都无法重置配额);其余 premium 路由仍需 API key。若在栈前另加反代,必须设WM_TRUSTED_PROXY_CIDRS指向该反代,否则限流可被伪造转发头绕过或误伤。
八、配置文件挂载与密钥注入
本栈不挂载配置文件,配置全部经环境变量注入;推荐用 gitignore 的 docker-compose.override.yml 注入 API key(不污染主文件、不进版本库)。创建 /opt/worldmonitor/docker-compose.override.yml:
services:
worldmonitor:
environment:
OPENROUTER_API_KEY: "${OPENROUTER_API_KEY}"
FINNHUB_API_KEY: "${FINNHUB_API_KEY}"
LLM_API_URL: "http://192.168.1.100:11434/v1/chat/completions"
LLM_MODEL: "qwen3:8b"
ais-relay:
environment:
AISSTREAM_API_KEY: "${AISSTREAM_API_KEY}"
同目录 .env 追加对应值后重建生效(override 里的 ${VAR} 从 .env 插值,密钥不落命令行历史):
echo "FINNHUB_API_KEY=${FINNHUB_API_KEY}" >> .env # 实际值由运维在 .env 中填入
docker compose -p worldmonitor-2-11-4-stack up -d
💡 说明:除 override 文件外,compose 还预留了 Docker secrets 注入形态(主文件注释段:
secrets/目录每 key 一个文件,如echo "sk-or-abc123" > secrets/openrouter_api_key.txt),适合不想让 key 出现在docker inspect输出的场景,两种方式二选一即可。自托管 LLM 若主机名不可解析,在 override 里加extra_hosts: ["your-host:192.168.1.100"](SELF_HOSTING.md 原文示例)。
九、等价 docker run
理解 compose 拓扑后,可用单条 docker run 把构建好的 worldmonitor:latest 跑成一个独立验证实例(挂到栈内网络、指向 redis-rest,对外 8141),验证后即删:
cd /opt/worldmonitor && set -a && . ./.env && set +a
docker run -d --name worldmonitor-run-eq -p 8141:8080 \
-e UPSTASH_REDIS_REST_URL=http://redis-rest:80 \
-e UPSTASH_REDIS_REST_TOKEN=$REDIS_TOKEN \
-e WM_SESSION_SECRET=$WM_SESSION_SECRET \
-e LOCAL_API_PORT=46123 \
-e LOCAL_API_MODE=docker \
-e LOCAL_API_CLOUD_FALLBACK=false \
-e WS_RELAY_URL=http://ais-relay:3004 \
-e RELAY_SHARED_SECRET=$RELAY_SHARED_SECRET \
--network worldmonitor-2-11-4-stack_default worldmonitor:latest
sleep 10 && curl -s http://localhost:8141/api/sidecar-health
docker rm -f worldmonitor-run-eq
实测输出:
{"status":"ok","mode":"docker","port":46123}
💡 说明:正式运行请回到 compose 管理(
restart: unless-stopped、健康检查、与 redis/中继的编排关系都由 compose 提供),docker run仅用于快速验证镜像与密钥是否正常。
十、常用运维命令
以下命令均在 /opt/worldmonitor/ 目录内执行(-p worldmonitor-2-11-4-stack 与部署时保持一致):
docker compose -p worldmonitor-2-11-4-stack ps # 四服务状态与健康检查
docker compose -p worldmonitor-2-11-4-stack logs -f worldmonitor # 跟踪主服务日志(Ctrl+C 退出)
docker compose -p worldmonitor-2-11-4-stack restart worldmonitor # 只重启主服务
docker compose -p worldmonitor-2-11-4-stack down # 停栈(保留数据卷)
docker compose -p worldmonitor-2-11-4-stack up -d # 依 .env/override 重建启动
重启主服务实测输出:
Container worldmonitor Restarting
Container worldmonitor Started
curl -s -o /dev/null -w '重启后 GET / -> HTTP %{http_code}\n' http://localhost:8140/
实测输出:
重启后 GET / -> HTTP 200
升级到新版本(官方发布极快,四天三个补丁版;升级 = 换源码 → 重建镜像 → 重灌种子):
cd /opt/worldmonitor
git pull --ff-only # 或 git fetch --tags && git checkout v2.11.5
docker compose -p worldmonitor-2-11-4-stack build # 依赖不变时命中层缓存,只重跑变更层
docker compose -p worldmonitor-2-11-4-stack up -d
./scripts/run-seeders.sh # 新版本新增面板需要补数
回滚:git checkout v2.11.3 切回上一版源码后重复 build + up -d 即可;Redis 数据卷与新版本向后兼容,无需删除。
密钥轮换:重写 .env 中对应项后 docker compose up -d 重建(必填密钥无默认值,全部可随时轮换;WORLDMONITOR_VALID_KEYS 轮换后客户端需同步换 key)。
十一、常见问题(FAQ)
Q1:up -d 直接报 required variable ... is missing a value?
四个必填密钥(RELAY_SHARED_SECRET/REDIS_PASSWORD/REDIS_TOKEN/WM_SESSION_SECRET)至少缺一。按 4.1 用 openssl rand -hex 32 补齐到 .env 再 up -d。实测报错形态见 4.1 节。老克隆升级到新版本尤其要补——旧版默认 wm-local-token 已被移除(#3804)。
Q2:构建阶段 npm ci 报错或卡死?
先确认代理/直连渠道(见第二章 ⚠️ 网络说明)。SELF_HOSTING.md 给出的官方解法:锁文件与构建机 npm 版本不匹配时,用容器重建锁文件后再构建:
docker run --rm -v "$(pwd)":/app -w /app node:24-alpine npm install --package-lock-only
Q3:仪表盘打开但大量面板空白/显示 stale?
种子数据未灌或已过期。先跑 ./scripts/run-seeders.sh,再用 curl 'http://localhost:8140/api/health?compact=1' 复查 ok/crit 计数(本实测灌数前 ok:23/crit:210,灌数中 ok:79/crit:169,随 seeders 推进持续改善)。上游需要 API key 的面板(船舶、军航、断网等)无 key 时永远为空,属预期。
Q4:seeders 大量 FAIL / SKIP?
独立脚本 FAIL、bundle 脚本 SKIP 都是设计内的优雅降级:无对应 API key、上游临时不可达时该脚本跳过,其余继续。按需在 docker-compose.override.yml/.env 补 key 后重跑即可。单脚本挂死由 SEED_TIMEOUT(默认 1800 秒)强制截断。
Q5:管理接口全部 403?
Docker 模式(LOCAL_API_MODE=docker)下 /api/local- 管理路由一律 403,内部 sidecar 令牌不授予管理员权限——这是 SELF_HOSTING.md 明文设计。运维改动一律走 Compose 环境变量/override 重建,或使用桌面端原生管理功能。
Q6:服务器带出网代理时,官方 CLI 报 Error: fetch failed?
Node 24 的 fetch 默认不读代理环境变量。实测在命令前加 NODE_USE_ENV_PROXY=1(Node 24 内置开关)即可让 CLI 走 HTTP_PROXY/HTTPS_PROXY 访问官方端点;连自家栈(--mcp-url http://localhost:8140/api/mcp)则无需代理。
Q7:redis-rest 报 413 Payload Too Large?
代理默认接受 16MB 请求体(SRH_MAX_BODY_BYTES),种子负载上限 5MB/键。调大上限时需同步上调 redis-rest 的 mem_limit(代理整体缓冲请求体,实测注释:64 个并发 16MB POST 可达约 933MB RSS)。
十二、参考链接
- 官方自托管指南(仓库内,本文主要依据):https://github.com/koala73/worldmonitor/blob/main/SELF_HOSTING.md
- 仓库根 docker-compose.yml:https://github.com/koala73/worldmonitor/blob/main/docker-compose.yml
- 仓库根 Dockerfile(多阶段构建细节):https://github.com/koala73/worldmonitor/blob/main/Dockerfile
- 环境变量全集:https://github.com/koala73/worldmonitor/blob/main/.env.example
- 项目仓库与版本发布:https://github.com/koala73/worldmonitor 、https://github.com/koala73/worldmonitor/releases
- 官方 Getting Started(安装三通道与 API 依赖表):https://www.worldmonitor.app/docs/getting-started
- 官方托管站:https://www.worldmonitor.app
- 本专栏部署后的参数详解与 CLI 使用:见 worldmonitor 专栏后续各篇