World Monitor Self-Hosting Guide: Docker, Ollama, PMTiles, and Offline Intelligence

Self-host World Monitor from source or Docker, connect Ollama, serve offline PMTiles, audit external data dependencies, configure caching, and troubleshoot deployment failures.

World Monitor is a real-time dashboard that aggregates news, markets, aviation, geo-risk, infrastructure and public intelligence data. It added about 13,231 stars in GitHub Trending in a week, but “can open the front end” and “run completely offline” are two different deployment goals. This article first separates components and network dependencies, and then provides three verifiable paths for source code development, container front-end and local AI summary.

Decide how much of the stack must work offline

The project documentation describes three deployment modes with different privacy boundaries. The simplest is to open the app locally, but continue to request the public API and cloud LLM. The second runs the desktop app with Ollama, LM Studio, llama.cpp, or vLLM, keeping news summaries local while other data sources remain online. The third category is isolated networks: local models, local PMTiles, pre-prepared data snapshots, and disabling live external sources. A Docker container alone cannot deliver the third mode because flight, market, RSS, and risk feeds still require data updates. Before starting, document the allowed domains, freshness requirements, and whether cloud-based summarization is permitted.

World Monitor is more than a web frontend

The front-end is a Vanilla TypeScript application, and the map is rendered by components such as MapLibre GL, deck.gl, and globe.gl. The server part includes Edge handler, RPC gateway, cache and data seeding tasks. AIS Relay is responsible for some real-time streaming and periodic data. Redis is used for caching, throttling, and preventing multiple requests from refreshing the same data at the same time. Desktop uses Tauri with Node.js sidecar. PMTiles can put basemaps into object storage or LAN HTTP services. Therefore, self-hosting needs to clarify which components are run by themselves and which continue to borrow upstream services.

Review the license before choosing a deployment model

The repository is AGPL-3.0 with additional instructions for commercial use. Personal, research and educational use may be self-hosted subject to attribution and license conditions. Commercial SaaS, debranding, or repackaging requires checking the project’s commercial licensing requirements. Don’t understand “the code can be publicly downloaded” to mean that it can be sold unconditionally as a closed source. When planning to provide external services, first read the LICENSE and README permission forms in the repository.

Prepare Node 22 and basic tools

The project change log has fixed Node 22 as the development baseline. It is recommended to use WSL2 Ubuntu on Windows, Linux and macOS can operate directly.

1
2
3
4
node --version
npm --version
git --version
make --version

When the main version of Node is not 22, use nvm to switch:

1
2
3
nvm install 22
nvm use 22
node --version

Do not mix global packages between system nodes and nvm nodes.

Launch the complete development panel from source code

First fork or directly clone the official repository:

1
2
3
git clone https://github.com/koala73/worldmonitor.git
cd worldmonitor
git rev-parse HEAD

Save the commit SHA, and subsequent document and configuration changes can be traced back to the specific version. The official contribution document provides a unified installation target:

1
make install

It will prepare buf, sebuf plugin, npm dependencies and Playwright browser. To only view help run:

1
make help

Development server for full variant:

1
npm run dev

The default address is http://localhost:3000.

Variants are configurations, not separate repositories

World Monitor controls panels, map layers, refresh cycles, and default data sources via variant. Technology, Finance and Complete panels can be launched separately:

1
2
npm run dev:tech
npm run dev:finance

The production build also has a corresponding command:

1
2
3
npm run build
npm run build:tech
npm run build:finance

Switching variants will reset some settings. Do not treat localStorage of different browser variants as the same configuration.

Enable environment variables one data source at a time

Copy the sample file:

1
cp .env.example .env.local

Don’t fill in all the API keys at once. Start with the panel that doesn’t require credentials and confirm that the frontend, map, and basic RPC are working. Add News, Markets, Flights or LLM Suppliers one by one. Each time a variable is added, the service is restarted and network requests are checked. .env.local does not enter Git:

1
2
git status --short
git check-ignore .env.local

If the second item is not output, check .gitignore first and do not continue to fill in the real key.

Use Docker to host the frontend

docker/Dockerfile in the repository builds a multi-architecture image, nginx provides SPA, and proxies API requests to the upstream. Build locally first:

1
2
docker build -f docker/Dockerfile -t worldmonitor:local .
docker image inspect worldmonitor:local

Check the Dockerfile exposed port and nginx configuration before running. Do not guess the port:

1
2
docker image inspect worldmonitor:local \
  --format '{{json .Config.ExposedPorts}}'

Assuming image exposure 80, loopback-only mapping test available:

1
2
3
docker run --rm --name worldmonitor-test \
  -p 127.0.0.1:8080:80 \
  worldmonitor:local

If the actual ports are different, the mirroring check result shall prevail.

A containerized frontend does not make every API local

Open the Network panel of your browser’s developer tools. Refresh the page and group requests by domain name. Any request to access Vercel, Railway, Upstash, third-party news or market interfaces indicates that there is still a current cloud dependency. Don’t use “the webpage comes from your own server” to deduce “the data does not leave the LAN”. When isolation is required, replace API endpoints item by item, or disable panels that don’t work locally.

Use Ollama for local summaries

with Ollama World Monitor’s native LLM route supports OpenAI-compatible services and can discover Ollama, LM Studio, llama.cpp, and vLLM models. Confirm the service after installing Ollama:

1
2
3
ollama --version
ollama list
curl http://127.0.0.1:11434/api/tags

Pull a command model suitable for native resources:

1
ollama pull qwen3:8b

Retest OpenAI compatible endpoint:

1
curl http://127.0.0.1:11434/v1/models

In the application, point the base URL to the loopback address and select the actual model ID.

Local LLM fallback chain requires active verification

The project documentation describes a summary fallback sequence that includes native LLM, Groq, OpenRouter, and browser T5. If the goal is to prevent data from leaving the network, simply configuring Ollama is not enough. Also remove the cloud key, block related domain names, and confirm that the browser does not silently roll back after a local timeout. Stop the Ollama service:

1
sudo systemctl stop ollama

Trigger summary again. A strictly offline configuration should clearly indicate that the local service is unavailable rather than produce a cloud summary.

PMTiles solves the basemap dependency

Traditional maps will continuously request online tiles per viewport. PMTiles organizes tiles into individual archives that can be placed on local disk, NAS, object storage, or a normal HTTP service. After preparing the file, do the minimum HTTP service first:

1
python3 -m http.server 9000 --directory /srv/pmtiles

Access the PMTiles file from your browser and confirm that Range requests are supported. Without Range support, the map might try to download the entire large file or fail to locate the tile. The reverse proxy needs to retain the headers related to Range and Accept-Ranges.

How to choose between Cloudflare R2 and LAN storage

R2 is suitable for public network services, can reduce origin site bandwidth and provide object-level access. LAN MinIO, NAS or nginx are more suitable for isolated environments. Basemap files can be large, record size and hash before publishing:

1
2
sha256sum world.pmtiles
du -h world.pmtiles

After the client configures the URL, use the browser to confirm the request and return 206 Partial Content.

Redis is not a hard threshold for local trial

Single-person development does not require the deployment of a complete cache system. Multi-person or public network services require Redis to control refresh storms, cache seed results, and limit traffic. Start local Redis:

1
2
docker run --rm --name worldmonitor-redis \
  -p 127.0.0.1:6379:6379 redis:7-alpine

Verification:

1
docker exec worldmonitor-redis redis-cli ping

PONG should be returned. Redis should not be directly exposed to the public network, and do not rely on the default passwordless configuration for cross-host access.

Locate failures across external data sources

Start by checking the URL, status code, and response time of the browser request. 401 or 403 is usually a key, quota or authorization range. 429 indicates rate limiting. Adding retries may make the problem more serious. 5xx needs to distinguish its own proxy, upstream service and cache layer. An empty array is not necessarily a fault, it may be that there is no data for the region and time range. Save the request ID and response header, don’t just take a screenshot of the blank panel.

Static builds cannot replace AIS and real-time feeds

Shipping AIS, flight and GPS interference layers rely on continuous data streams or periodic seeds. Pure nginx SPA can only display existing data and call upstream interfaces. When you need to self-host related flows, read scripts/ais-relay.cjs and Deployment Configuration to confirm data provider permissions. Do not unconditionally mirror and republish data sources seen on public web pages.

Turn on health check and data freshness monitoring

The application can return 200, which does not mean that the data is being updated. Monitoring is divided into at least three levels: static pages, API endpoints and seed freshness. Record the last success time and the number of consecutive failures for each data source. The entire site should not be marked as fully healthy when the news is still being updated and the market is down.

Run project’s own checks before building

1
2
3
4
npm run typecheck
npm run test:data
npm run test:e2e
npm run build:full

The existence of the command is based on the current repository package.json and make help. When the data test fails, do not delete the failure source to make the CI turn green. First confirm whether the format has changed. E2E requires browser dependencies and stable test data, and container CI requires reserved shared memory.

Expose only the required reverse-proxy endpoints

The public network deployment uses HTTPS and leaves the management end, Redis, Ollama and internal seed endpoints in the private network. Ollama should not be directly exposed to the Internet by default. If the front end and API are in separate domains, explicitly set the CORS allow list. Do not use a combination that allows any origin to also carry credentials.

Run a clean offline test

Disconnecting from the internet after loading a panel is prone to false positives because the service worker, browser cache, and IndexedDB still hold old data. First clear the test profile, block external domain names, and then reopen the application. Record which panels are normal, which ones show old cache, and which ones report errors. Check that the timestamp clearly identifies that the data has expired. Offline mode should degrade gracefully rather than disguise old information as real-time information.

Preserve variant and map configuration when upgrading

Save the commit, .env.local variable name, PMTiles URL, Redis schema, and reverse proxy configuration before upgrading.

1
2
3
git fetch --tags
git log --oneline --decorate -10
git diff -- .env.example docker/ deploy/

Build in the new working tree first, do not directly overwrite the running directory. The setting format of the front-end localStorage may change. Check the variant, layer and refresh cycle after the upgrade.

Self-hosting completion checklist

  • The page with the required variant can be built.
  • Docker image ports come from inspect, not guesswork.
  • All API keys are outside of Git.
  • Does not silently go to the cloud when on-premises LLM fails.
  • PMTiles returns a Range request.
  • Redis, Ollama and internal services are not exposed to the public network.
  • Each real-time data source has a last updated time.
  • The offline test can distinguish between cache and real availability.
  • License checked for commercial use.

World Monitor’s self-hosting boundaries depend on how many live data sources you retain. Drawing the network dependencies clearly first, and then deciding whether to use a local front end, privacy summary or complete isolation is more reliable than directly pursuing “one Docker command”.

Project resources