Jesse A. Green / notebook

Project N.O.M.A.D. — User Guide

Generated April 2026 from Crosstalk-Solutions/project-nomad at 9cbf8c2

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Project N.O.M.A.D. (Network Outage Mitigation And Deployment) is a self-hosted offline knowledge appliance from Crosstalk Solutions. It bundles Wikipedia, encyclopedias, books, offline maps, an AI assistant, and a personal file knowledge base into a single Docker stack that runs on your own hardware and works without an internet connection. After the one-time content download, nothing in your library has to phone home to keep working.

1. Quick Start

Get a working N.O.M.A.D. installation in roughly fifteen minutes on a fresh Debian or Ubuntu machine:

curl -fsSL https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/install_nomad.sh -o install_nomad.sh
sudo bash install_nomad.sh

When the installer finishes, point a browser on the same LAN at the success URL it printed (typically http://<host-ip>:8080). On first visit you'll land on the Easy Setup wizard; follow the prompts to install the AI Assistant, download a Wikipedia tier, and grab the maps you want.

Tip

The installer accepts everything as defaults. The two values it generates for you — APP_KEY, MySQL root + user passwords — are written into /opt/project-nomad/compose.yml. Back that file up before you wipe the host.

What you get out of the box

  • Full-text Wikipedia (5 size tiers from a 100-article mini up to 100GB+)
  • Curated ZIM categories: medical, survival, agriculture, repair, education
  • Offline vector maps (Protomaps PMTiles) with custom region downloads
  • AI chat (Ollama, with optional RAG over your own files)
  • Personal Knowledge Base — drop PDFs, EPUBs, Markdown, and plain text in and the assistant cites them
  • Hardware benchmark with community comparison
  • Companion services (CyberChef, Flatnotes, Kolibri) installable from Settings
  • Web UI on port 8080, log viewer (Dozzle) on port 9999

Prerequisites

  • Debian-based Linux (Debian 12+, Ubuntu 22.04+) with sudo
  • Docker Engine + Docker Compose v2 plugin (the installer adds them if missing)
  • ≥ 8 GB RAM (16 GB+ recommended once you load Wikipedia and run AI)
  • ≥ 100 GB free disk for a useful library; SSD strongly preferred
  • An NVIDIA GPU is optional but unlocks much faster AI responses

First-run sanity check

docker ps --filter "name=^nomad_" --format "table {{.Names}}\t{{.Status}}"
NAMES                  STATUS
nomad_admin            Up 3 minutes (healthy)
nomad_mysql            Up 3 minutes (healthy)
nomad_redis            Up 3 minutes (healthy)
nomad_dozzle           Up 3 minutes
nomad_updater          Up 3 minutes
nomad_disk_collector   Up 3 minutes

If any container is missing or unhealthy see the Troubleshooting section.

2. Installation

2.1 System requirements

Component Minimum Recommended
OS Debian 12 / Ubuntu 22.04 Debian 12 / Ubuntu 24.04
CPU 4 cores 8+ cores
RAM 8 GB 32 GB
Disk 100 GB SSD 1 TB+ NVMe
GPU none (CPU-only AI) NVIDIA with CUDA 12+
Network LAN only required Internet for one-time downloads

Important

The AI Assistant runs much faster on an NVIDIA GPU. The installer will try to install the NVIDIA Container Toolkit automatically when it sees an NVIDIA card. Failures here are non-fatal — N.O.M.A.D. falls back to CPU inference.

2.2 Install methods

Automated (recommended)

curl -fsSL https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/install_nomad.sh -o install_nomad.sh
sudo bash install_nomad.sh

The script installs Docker if missing, sets up the NVIDIA runtime when a GPU is detected, generates a random APP_KEY plus MySQL passwords, drops a fully-wired compose.yml into /opt/project-nomad, and brings the stack up with docker compose up -d.

Manual compose

sudo mkdir -p /opt/project-nomad
cd /opt/project-nomad
sudo curl -fsSL https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/management_compose.yaml -o compose.yml
# Edit compose.yml and replace every "replaceme" placeholder
sudo docker compose -p project-nomad up -d

Use this when you need to customize ports, volume paths, or environment values before the first run.

2.3 Helper scripts the installer drops in /opt/project-nomad/

Script What it does
start_nomad.sh Starts every container whose name begins with nomad_
stop_nomad.sh Gracefully stops the same set
update_nomad.sh Pulls latest images and force-recreates containers
uninstall_nomad.sh Tears down the stack; optionally deletes /opt/project-nomad

Warning

uninstall_nomad.sh will offer to delete /opt/project-nomad. Accepting permanently removes your MySQL data, Redis cache, downloaded ZIMs, maps, uploaded knowledge-base files, and benchmark history. There is no undo.

2.4 Verifying the install

Open http://<host-ip>:8080 in any browser on the LAN. You should see the N.O.M.A.D. dashboard with the powered-by-Crosstalk badge in the footer. The URL bar will redirect from / to /home.

To verify the API is up:

curl http://localhost:8080/api/health
{"status":"ok"}

2.5 Post-install: Easy Setup wizard

The first time you load /easy-setup you'll be asked to:

  1. Install the AI Assistant (Ollama) container, or point N.O.M.A.D. at an existing remote Ollama / LM Studio / llama.cpp server you already run.
  2. Pick a Wikipedia size tier (or skip and add it later).
  3. Choose curated content tiers by category (medical, survival, repair, etc.) — each tier adds a coherent bundle of ZIM files.
  4. Download base map assets (Protomaps fonts, sprites, layer styles).

Everything chosen here runs as background download jobs you can monitor from the dashboard.

3. Configuration

Most users never need to touch compose.yml after install — every day-to-day setting is in the web UI under Settings → System and the per-feature settings pages. The full environment-variable reference lives in the Admin Guide; this section covers what an OSS user typically wants.

3.1 Where things live

Path Purpose
/opt/project-nomad/compose.yml Container definitions, env vars, ports
/opt/project-nomad/storage/ ZIMs, maps, uploads, logs, disk-info JSON
/opt/project-nomad/mysql/ MySQL data (users + sessions + settings)
/opt/project-nomad/redis/ Redis queue persistence

3.2 Common UI settings

Setting Where Notes
Theme (light/dark) Top-right toggle Persisted per-browser
AI Assistant custom name Settings → Models Renders everywhere "AI Assistant" appears
Chat suggestions Settings → Models Toggles the prompt-starter chips on the chat home
Remote Ollama URL Settings → Models Point at an existing LLM server instead of running one locally
Anonymous benchmark sharing Settings → Benchmark Strips builder-tag before submitting
Early-access flag Settings → System Enables in-development features

Tip

If you renamed the AI Assistant in Settings → Models, the new name propagates everywhere — page titles, system prompts, chat UI — within about sixty seconds (the name is cached for one minute server-side).

3.3 Changing the listening port

Edit the admin port mapping in compose.yml:

services:
  admin:
    ports:
      - "9090:8080"   # access at http://host:9090, container still uses 8080 internally

Then restart:

sudo /opt/project-nomad/update_nomad.sh

Note

Don't change PORT=8080 inside the environment: block — it's the in-container port and the health check is wired to it. Map it differently on the host instead.

4. Core Usage

4.1 Reading offline content

The Content Explorer (/home) lists every installed Wikipedia language pack, ZIM bundle, and curated tier. Click any tile to open it in the embedded Kiwix reader, which serves articles directly from the ZIM file under /opt/project-nomad/storage/zim/.

Search inside a ZIM uses the Kiwix full-text index. Cross-ZIM search isn't exposed in the UI; use the AI Assistant with Knowledge Base mode for that.

4.2 Chatting with the AI Assistant

Visit /chat (or click the chat bubble in the corner of any page).

1. Pick or download a model from the model dropdown at the top
2. Optionally turn on Knowledge Base for RAG over your uploaded files
3. Type a question — responses stream in real time

The assistant:

  • Streams tokens as they arrive (cancellable mid-stream)
  • Remembers conversation history for the active session
  • Auto-generates a session title from the first turn
  • Supports "thinking" models (deepseek-r1, qwen3, gpt-oss, etc.) and renders the thought stream in a collapsible panel
  • Honors model-size-aware RAG context limits so small models aren't drowned
Action How
New chat Click + New Chat in the sidebar
Switch model Top-right dropdown; choice persists per-browser
Stop generating Press the stop button while streaming
Delete one session Hover a session in the sidebar → trash icon
Clear all history Sidebar → trash-all icon → confirm modal
Knowledge Base toggle Switch in the chat header

Note

The first response with a freshly-downloaded model is slower than subsequent ones — Ollama warms its cache on the first generate call.

4.3 Building your knowledge base (RAG)

The Knowledge Base modal (chat → folder icon) is your file uploader. Drop in PDFs, EPUBs, Markdown, plain text, or HTML and they get chunked, embedded with nomic-embed-text (downloaded automatically), and stored in Qdrant.

Once a file finishes indexing it shows up in the Files list. Asking a chat question with Knowledge Base on:

  1. Rewrites your query using the conversation history (when you've had ≥ 3 user turns) so the search is context-aware.
  2. Searches Qdrant for the top-5 most similar chunks above a similarity score of 0.3.
  3. Trims results to fit the active model's context window (1B–3B models get 2 results / 1k tokens, 4–8B get 4 results / 2.5k tokens, 13B+ get 5 with no cap).
  4. Injects them as a system message and asks the model to cite them.

Supported formats and how they're handled:

Type Parser
.pdf pdf-parse text extraction; OCR via tesseract.js falls back if PDF is image-only
.epub Parses META-INF/container.xml → opf → spine, strips boilerplate
.md / .markdown Markdoc-aware so headings become chunk boundaries
.txt Direct chunking
.html / .htm DOM-aware extraction with cheerio, strips nav/footer/scripts

Tip

Configure a remote Ollama (Settings → Models → Remote Ollama URL) to keep your library on a small box and run the AI on a beefier GPU machine. Just remember to start that remote with OLLAMA_HOST=0.0.0.0 so it accepts LAN connections.

4.4 Maps

The Maps page renders a maplibre-gl base map from offline Protomaps tiles. Functions:

  • Pan/zoom the global low-zoom basemap.
  • Download high-detail PMTiles regions from the curated map collections list, or paste any .pmtiles URL into Download Custom.
  • Drop pins at any latitude/longitude with name + color (route support is scaffolded but UI-final in a future release).
  • Listed regions live under /opt/project-nomad/storage/maps/ and are served by the admin container on /storage/maps/... routes.

4.5 Installing companion apps

Settings → Apps lists the available services that ship as separate Docker containers. Click Install on any tile and N.O.M.A.D. pulls the image, wires it to the project network, and exposes its port through the admin UI's service catalog:

Service Default port Purpose
nomad_kiwix_server 8086 ZIM reader (always installed alongside any ZIM tier)
nomad_ollama 11434 Local LLM runtime
nomad_qdrant 6333 Vector DB powering the Knowledge Base
nomad_cyberchef 8000 The Cyber Swiss Army Knife
nomad_flatnotes 8200 Self-hosted markdown notes
nomad_kolibri 8080 (mapped) Open educational resource library

Warning

Service install pulls images from public registries (GHCR, Docker Hub). Make sure your host has internet access — the install will fail with "Pre-install action failed" otherwise.

4.6 Benchmarking

/settings/benchmark runs a calibrated 0–100 score combining sysbench (CPU, RAM, disk read, disk write) with an Ollama inference test on llama3.2:1b.

Full benchmark    System + AI (recommended)
System benchmark  CPU/RAM/disk only — works without AI Assistant
AI benchmark      Inference timing only — requires AI Assistant

The composite score uses these weights:

Component Weight
AI tokens/sec 30 %
CPU events/sec 25 %
Memory ops/sec 15 %
AI time-to-first-token 10 %
Disk read MB/s 10 %
Disk write MB/s 10 %

Submitting a Full benchmark to benchmark.projectnomad.us adds your hardware to the public comparison chart. Toggle anonymous in the submit modal to strip your builder-tag.

5. Common Tasks

5.1 Add Wikipedia after the wizard

  1. Go to Settings → ZIM.
  2. Click Wikipedia tab.
  3. Pick a size tier (Mini → Full); the size in MB is shown.
  4. Click Install — a download job starts.
  5. Watch progress on the dashboard's Active Downloads card.

5.2 Switch the AI Assistant to a remote server

  1. Stand up Ollama or LM Studio elsewhere with OLLAMA_HOST=0.0.0.0.
  2. Settings → Models → Remote Ollama URL → paste http://<remote>:11434.
  3. Click Test & Save. N.O.M.A.D. will probe /v1/models; on success it marks the local Ollama service as uninstalled and routes all chat traffic to the remote.
  4. To revert, clear the field and Save.

Important

Remote mode disables chat suggestions and does not auto-pull models for you — the remote box owns its own model library.

5.3 Re-index a single file in the knowledge base

  1. Chat → Knowledge Base → Files.
  2. Click the trash icon next to the file → confirm.
  3. Drag the file in again. The embedder rejects duplicates by SHA-256 hash, so the new copy must be different from the old one in some way (open it in an editor, save, retry) if you're testing.

5.4 Move N.O.M.A.D. to a bigger disk

  1. sudo /opt/project-nomad/stop_nomad.sh
  2. sudo rsync -aHAXxv /opt/project-nomad/ /mnt/newdisk/project-nomad/
  3. Edit compose.yml so every /opt/project-nomad/... volume points at /mnt/newdisk/project-nomad/....
  4. sudo docker compose -p project-nomad -f /mnt/newdisk/project-nomad/compose.yml up -d

5.5 Update to the latest version

In the UI: Settings → Update → Check for updates → Update Now. The sidecar updater rewrites the admin image tag in compose.yml, pulls fresh images, and recreates admin, mysql, redis, and dozzle one at a time. You can watch the progress bar live.

From the shell:

sudo /opt/project-nomad/update_nomad.sh

5.6 Open the container log viewer

Click Service Logs & Metrics under Settings → System (or browse to http://<host>:9999). Dozzle ships with N.O.M.A.D. for visual log access; it runs read-only — start/stop/exec actions are intentionally disabled.

5.7 Drop pins on the map

  1. Maps page → click anywhere on the map.
  2. The marker panel slides in from the right.
  3. Enter a name, pick a color, Save.
  4. Markers persist in MySQL and reappear on every visit.

5.8 Migrate from old disk-collector script

Older installs ran collect_disk_info.sh as a nohup background process on the host that wrote to /tmp/nomad-disk-info.json. The new architecture uses a sidecar container. To migrate:

curl -fsSL https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/migrate-disk-collector.sh -o migrate.sh
sudo bash migrate.sh

The script stops the old PID, removes the old /tmp/nomad-disk-info.json bind-mount from compose.yml, adds the disk-collector service, and brings the stack back up.

6. Troubleshooting

Error: Container nomad_mysql is unhealthy

Cause: Stale MySQL data directory from a previous install attempt — the MYSQL_*_PASSWORD values in compose.yml no longer match what's in the on-disk databases. (See issue #630.)

Solution:

  1. sudo /opt/project-nomad/stop_nomad.sh
  2. sudo rm -rf /opt/project-nomad/mysql
  3. sudo /opt/project-nomad/start_nomad.sh

This forces MySQL to reinitialize with the credentials currently in compose.yml.

Prevention: Use the official installer; if you customize, never delete just compose.yml without also wiping the MySQL data directory.

Error: Failed to load the XML library file '/data/kiwix-library.xml'

Cause: The Kiwix container started with an empty library (no ZIM files yet) — Kiwix can refuse to boot until it has at least one ZIM. Tracked as issue #710.

Solution: Install at least one ZIM tier from Settings → ZIM and the admin container will rebuild kiwix-library.xml and restart Kiwix automatically. The KiwixMigrationProvider handles legacy configs on every admin startup as well.

Error: Ollama is not running or not accessible (ECONNREFUSED)

Cause: Either the AI Assistant container isn't installed, has crashed, or your remote Ollama URL is unreachable.

Solution:

  1. Settings → Apps — confirm "AI Assistant" shows as installed and running.
  2. If running, check docker logs nomad_ollama for crash details.
  3. For remote mode, confirm the remote is up: curl http://<remote>:11434/v1/models. If that fails, the issue is network or the remote isn't bound to 0.0.0.0.

Prevention: Pin a stable Ollama image tag in compose.yml and don't prune Docker volumes named nomad_ollama_* blindly.

Error: GPU is not detected by Nomad

Cause: NVIDIA Container Toolkit not installed or Docker daemon not configured for the nvidia runtime. Open as issue #727.

Solution:

nvidia-smi                                # Confirms host sees the GPU
docker info | grep -i nvidia              # Confirms Docker can use it

If the second command finds nothing:

sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
sudo /opt/project-nomad/update_nomad.sh   # Recreate containers with the runtime

Prevention: Run the official installer on a host where nvidia-smi already works; the installer handles the rest.

Error: Flatnotes not working both locally and remotely. ERR_CONNECTION_REFUSED on port 8200

Cause: Flatnotes container failed to start, or its port mapping conflicts with another service. See issue #709.

Solution:

docker logs nomad_flatnotes
docker compose -p project-nomad restart flatnotes

If it loops, Settings → Apps → Flatnotes → Force Reinstall rebuilds the container from scratch with default config.

Error: nomad_qdrant may fail and never come back online

Cause: Qdrant data corruption or insufficient disk during a write, documented in issue #673.

Solution:

  1. docker logs nomad_qdrant — look for "WAL", "snapshot", or panic lines.
  2. If the WAL is corrupt, the safe fix is to delete the qdrant data directory and re-embed your files: docker compose -p project-nomad stop qdrant && sudo rm -rf /opt/project-nomad/qdrant && docker compose -p project-nomad up -d qdrant.

Prevention: Watch the Storage gauge on the dashboard — Qdrant gets unhappy when free disk drops below ~1 GB.

Error: Storage bar graph does not correctly reflect size and space available on custom partition

Cause: The disk-collector sidecar reads from the host's mount table via /host/proc/1/mounts. If you moved /opt/project-nomad to a non-default mount that isn't visible in the host's namespace, the gauge can be wrong. Tracked as issue #716.

Solution: Bind the actual storage partition into the disk-collector at its real host mount path or run the migration script from §5.8 again after moving directories.

Error: Installing a AI model, removing, and attempting to reinstall fails

Cause: Ollama keeps a tombstone for recently-deleted models for a short window. Issue #690.

Solution: Wait ~60 seconds and retry the download, or docker exec nomad_ollama ollama list to verify the model is fully gone before reinstalling.

Diagnostic decision tree

Web UI won't load?
├── docker ps shows nomad_admin?
│    ├── No  → docker compose up -d in /opt/project-nomad
│    └── Yes → curl http://localhost:8080/api/health
│              ├── Returns {"status":"ok"} → check firewall / reverse proxy
│              └── Errors                  → docker logs nomad_admin
└── Containers all up but UI 502s?
     └── nomad_admin healthy? (docker ps STATUS column)
          ├── No  → check MySQL/Redis dependencies, see "unhealthy" entries above
          └── Yes → clear browser cache / try incognito

Warning

Do not run docker system prune -a --volumes on the N.O.M.A.D. host. It will delete the named volumes that hold MySQL data, Redis state, and the shared update channel between admin and the updater sidecar.

Caution

The MySQL MYSQL_ROOT_PASSWORD and the admin APP_KEY are written into compose.yml in plain text. Anyone with shell access to the host can read them. Don't expose /opt/project-nomad/compose.yml over a public file share.

7. FAQ

Q: Does N.O.M.A.D. need an internet connection to run?

Only for the one-time content downloads, container image pulls, and update checks. Once everything is local, the entire stack works on a fully air-gapped LAN. The dashboard's "Internet Status" indicator just tells you whether outgoing connectivity is available — it never gates functionality.

Q: Can I run it without a GPU?

Yes. AI inference falls back to CPU. Expect single-digit tokens/sec on small models (1B–3B parameters) and very slow responses on anything larger. The benchmark gives you a concrete number for your hardware.

Q: Where are my uploaded knowledge-base files actually stored?

/opt/project-nomad/storage/kb_uploads/. Embeddings live in Qdrant under /opt/project-nomad/qdrant/. Deleting one without the other leaves the system in a confused state — use the UI Delete button instead, which clears both.

Q: How do I back up my N.O.M.A.D. data?

Stop the stack first to ensure consistent MySQL and Qdrant state, then archive /opt/project-nomad:

sudo /opt/project-nomad/stop_nomad.sh
sudo tar czf nomad-backup-$(date +%F).tar.gz -C / opt/project-nomad
sudo /opt/project-nomad/start_nomad.sh

ZIM files and PMTiles are big — exclude storage/zim and storage/maps if you don't need them in the backup; they can be re-downloaded.

Q: Can I run two N.O.M.A.D. instances on the same host?

Not without significant rework — the install script hardcodes the project name project-nomad and the install path /opt/project-nomad. Different ports alone won't avoid container-name collisions.

Q: How do I disable the AI Assistant entirely?

Settings → Apps → AI Assistant → Uninstall. Or, in compose.yml, never install the Ollama service. The chat icon in the UI will redirect to a "Service not installed" page.

Q: Which models are recommended?

The fallback recommendations are llama3.1, deepseek-r1, and llama3.2. The full Available Models picker pulls a live, sortable catalog from Ollama's registry. For the Knowledge Base, ensure qwen2.5:3b is installed — it's the default query-rewriter and the chat will just skip rewriting if it's missing.

Q: How do I unblock submitting a benchmark?

Run a Full benchmark (not System-only or AI-only) on a host where the AI Assistant is installed and reachable. Only Full benchmarks with non-zero AI data are accepted by the public repository.

Q: Does N.O.M.A.D. send telemetry?

No analytics, ads, or telemetry. The only outbound calls are explicit user-initiated actions: downloading content from your chosen sources, checking GitHub for new releases, optionally submitting your benchmark to benchmark.projectnomad.us, and pulling images during updates.

Q: How do I file a bug?

github.com/Crosstalk-Solutions/project-nomad/issues. The Settings → Support → Generate Debug Info button bundles a sanitized state dump you can attach.