Add homelab documentation, update Dockerfile with healthcheck, update entrypoint for NAS compatibility, rewrite README for Homelab Edition

Co-authored-by: DocwatZ <227472400+DocwatZ@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-03-13 17:41:23 +00:00
parent 935d0ab22b
commit 7b207edbb3
10 changed files with 1584 additions and 134 deletions

View File

@ -1,7 +1,8 @@
FROM node:22-slim AS base
# Install bash & curl for entrypoint script compatibility, graphicsmagick for pdf2pic, and vips-dev & build-base for sharp
RUN apt-get update && apt-get install -y bash curl graphicsmagick libvips-dev build-essential
# Install bash & curl for entrypoint script compatibility, graphicsmagick for pdf2pic, and vips-dev & build-base for sharp
RUN apt-get update && apt-get install -y bash curl graphicsmagick libvips-dev build-essential \
&& rm -rf /var/lib/apt/lists/*
# All deps stage
FROM base AS deps
@ -29,14 +30,14 @@ ARG BUILD_DATE
ARG VCS_REF
# Labels
LABEL org.opencontainers.image.title="Project N.O.M.A.D" \
org.opencontainers.image.description="The Project N.O.M.A.D Official Docker image" \
LABEL org.opencontainers.image.title="Project N.O.M.A.D — Homelab Edition" \
org.opencontainers.image.description="Network Operations Monitoring and Automation Dashboard — Container-native homelab platform" \
org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.created="${BUILD_DATE}" \
org.opencontainers.image.revision="${VCS_REF}" \
org.opencontainers.image.vendor="Crosstalk Solutions, LLC" \
org.opencontainers.image.documentation="https://github.com/CrosstalkSolutions/project-nomad/blob/main/README.md" \
org.opencontainers.image.source="https://github.com/CrosstalkSolutions/project-nomad" \
org.opencontainers.image.documentation="https://github.com/DocwatZ/project-nomad-homelab-edition/blob/main/README.md" \
org.opencontainers.image.source="https://github.com/DocwatZ/project-nomad-homelab-edition" \
org.opencontainers.image.licenses="Apache-2.0"
ENV NODE_ENV=production
@ -47,5 +48,13 @@ COPY --from=build /app/build /app
COPY package.json /app/version.json
COPY admin/docs /app/docs
COPY README.md /app/README.md
# Create storage directory with proper permissions
RUN mkdir -p /app/storage && chown -R node:node /app/storage
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=5 \
CMD curl -f http://localhost:8080/api/health || exit 1
CMD ["node", "./bin/server.js"]

246
README.md
View File

@ -1,10 +1,10 @@
<div align="center">
<img src="https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/admin/public/project_nomad_logo.png" width="200" height="200"/>
# Project N.O.M.A.D.
### Node for Offline Media, Archives, and Data
# Project N.O.M.A.D. — Homelab Edition
### Network Operations Monitoring and Automation Dashboard
**Knowledge That Never Goes Offline**
**Knowledge That Never Goes Offline — Now Container-Native for Your Homelab**
[![Website](https://img.shields.io/badge/Website-projectnomad.us-blue)](https://www.projectnomad.us)
[![Discord](https://img.shields.io/badge/Discord-Join%20Community-5865F2)](https://discord.com/invite/crosstalksolutions)
@ -14,34 +14,94 @@
---
Project N.O.M.A.D. is a self-contained, offline-first knowledge and education server packed with critical tools, knowledge, and AI to keep you informed and empowered—anytime, anywhere.
Project N.O.M.A.D. Homelab Edition is a container-native fork of [Project N.O.M.A.D.](https://github.com/CrosstalkSolutions/project-nomad), optimized for NAS systems and homelab environments. It runs as a portable Docker Compose stack on **Unraid**, **TrueNAS SCALE**, and any standard Docker host.
## Installation & Quickstart
Project N.O.M.A.D. can be installed on any Debian-based operating system (we recommend Ubuntu). Installation is completely terminal-based, and all tools and resources are designed to be accessed through the browser, so there's no need for a desktop environment if you'd rather setup N.O.M.A.D. as a "server" and access it through other clients.
## Quick Start (Docker Compose)
*Note: sudo/root privileges are required to run the install script*
#### Quick Install
```bash
sudo apt-get update && sudo apt-get install -y curl && 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
# 1. Clone the repository
git clone https://github.com/DocwatZ/project-nomad-homelab-edition.git
cd project-nomad-homelab-edition
# 2. Configure environment
cp .env.example .env
sed -i "s/^APP_KEY=replaceme/APP_KEY=$(openssl rand -hex 32)/" .env
sed -i "s/^DB_PASSWORD=replaceme/DB_PASSWORD=$(openssl rand -base64 24)/" .env
sed -i "s/^MYSQL_ROOT_PASSWORD=replaceme/MYSQL_ROOT_PASSWORD=$(openssl rand -base64 24)/" .env
# 3. Create data directories
sudo mkdir -p /opt/project-nomad/{storage,redis,logs/nginx}
# 4. Start the stack
docker compose up -d
```
Project N.O.M.A.D. is now installed on your device! Open a browser and navigate to `http://localhost:8080` (or `http://DEVICE_IP:8080`) to start exploring!
Open `http://localhost:8080` to access the dashboard.
## How It Works
N.O.M.A.D. is a management UI ("Command Center") and API that orchestrates a collection of containerized tools and resources via [Docker](https://www.docker.com/). It handles installation, configuration, and updates for everything — so you don't have to.
## Container Architecture
**Built-in capabilities include:**
- **AI Chat with Knowledge Base** — local AI chat powered by [Ollama](https://ollama.com/), with document upload and semantic search (RAG via [Qdrant](https://qdrant.tech/))
- **Information Library** — offline Wikipedia, medical references, ebooks, and more via [Kiwix](https://kiwix.org/)
- **Education Platform** — Khan Academy courses with progress tracking via [Kolibri](https://learningequality.org/kolibri/)
- **Offline Maps** — downloadable regional maps via [ProtoMaps](https://protomaps.com)
- **Data Tools** — encryption, encoding, and analysis via [CyberChef](https://gchq.github.io/CyberChef/)
- **Notes** — local note-taking via [FlatNotes](https://github.com/dullage/flatnotes)
- **System Benchmark** — hardware scoring with a [community leaderboard](https://benchmark.projectnomad.us)
- **Easy Setup Wizard** — guided first-time configuration with curated content collections
| Service | Image | Purpose |
|---------|-------|---------|
| **nomad-app** | project-nomad | Web UI + API server |
| **nomad-worker** | project-nomad | Background job processing |
| **nomad-database** | mysql:8.0 | Persistent data storage |
| **nomad-cache** | redis:7-alpine | Cache + job queues |
| **nomad-nginx** | nginx:alpine | Reverse proxy |
N.O.M.A.D. also includes built-in tools like a Wikipedia content selector, ZIM library manager, and content explorer.
All services communicate over a private Docker network (`nomad-internal`).
## NAS Compatibility
| Platform | Storage Path | Guide |
|----------|-------------|-------|
| **Unraid** | `/mnt/user/appdata/project-nomad` | [Unraid Guide](docs/homelab/unraid-guide.md) |
| **TrueNAS SCALE** | `/mnt/pool/apps/project-nomad` | [TrueNAS Guide](docs/homelab/truenas-guide.md) |
| **Linux** | `/opt/project-nomad` | [Installation Guide](docs/homelab/installation-guide.md) |
### NAS Install Templates
- **Unraid**: [Community Apps XML template](homelab/unraid-template.xml)
- **TrueNAS SCALE**: [Helm chart](homelab/truenas/)
- **Any Docker host**: [docker-compose.yml](docker-compose.yml)
## Storage Layout
```
NOMAD_DATA_DIR/
├── storage/ # Content files (ZIM, maps, uploads) — NAS share OK
├── redis/ # Redis persistence
└── logs/
└── nginx/ # Nginx access/error logs
```
The MySQL database uses a **Docker named volume** for optimal I/O, avoiding NFS/SMB latency.
## Reverse Proxy Support
Works behind common homelab reverse proxies:
| Proxy | Configuration |
|-------|--------------|
| **Nginx Proxy Manager** | [Setup guide](homelab/reverse-proxy-examples/nginx-proxy-manager.md) |
| **Traefik** | [Traefik config](homelab/reverse-proxy-examples/traefik.yml) |
| **Caddy** | [Caddyfile](homelab/reverse-proxy-examples/caddy.Caddyfile) |
## Monitoring Agent
Deploy lightweight monitoring agents on homelab nodes:
```bash
docker run -d --name nomad-agent \
-p 9100:9100 \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v /proc:/host/proc:ro \
-e NODE_NAME=my-server \
nomad-agent
```
Features: CPU/RAM/disk metrics, Docker container monitoring, Prometheus `/metrics` endpoint.
See the [Agent Guide](docs/homelab/agent-guide.md) for details.
## What's Included
@ -56,113 +116,69 @@ N.O.M.A.D. also includes built-in tools like a Wikipedia content selector, ZIM l
| System Benchmark | Built-in | Hardware scoring, Builder Tags, and community leaderboard |
## Device Requirements
While many similar offline survival computers are designed to be run on bare-minimum, lightweight hardware, Project N.O.M.A.D. is quite the opposite. To install and run the
available AI tools, we highly encourage the use of a beefy, GPU-backed device to make the most of your install.
At it's core, however, N.O.M.A.D. is still very lightweight. For a barebones installation of the management application itself, the following minimal specs are required:
*Note: Project N.O.M.A.D. is not sponsored by any hardware manufacturer and is designed to be as hardware-agnostic as possible. The harware listed below is for example/comparison use only*
#### Minimum Specs
- Processor: 2 GHz dual-core processor or better
- RAM: 4GB system memory
- Storage: At least 5 GB free disk space
- OS: Debian-based (Ubuntu recommended)
- Stable internet connection (required during install only)
To run LLM's and other included AI tools:
- 2 GHz dual-core processor
- 4 GB RAM (8 GB recommended)
- 5 GB free disk space
- Docker 20.10+ and Docker Compose v2+
- Any Linux, Unraid, or TrueNAS SCALE host
#### Optimal Specs
- Processor: AMD Ryzen 7 or Intel Core i7 or better
- RAM: 32 GB system memory
- Graphics: NVIDIA RTX 3060 or AMD equivalent or better (more VRAM = run larger models)
- Storage: At least 250 GB free disk space (preferably on SSD)
- OS: Debian-based (Ubuntu recommended)
- Stable internet connection (required during install only)
- AMD Ryzen 7 / Intel Core i7 or better
- 32 GB RAM
- NVIDIA RTX 3060+ (for AI features)
- 250 GB SSD
- Stable internet connection (for initial content downloads)
**For detailed build recommendations at three price points ($200$800+), see the [Hardware Guide](https://www.projectnomad.us/hardware).**
## Documentation
Again, Project N.O.M.A.D. itself is quite lightweight - it's the tools and resources you choose to install with N.O.M.A.D. that will determine the specs required for your unique deployment
| Guide | Description |
|-------|-------------|
| [Installation Guide](docs/homelab/installation-guide.md) | Docker Compose setup |
| [Unraid Guide](docs/homelab/unraid-guide.md) | Unraid-specific installation |
| [TrueNAS Guide](docs/homelab/truenas-guide.md) | TrueNAS SCALE installation |
| [Agent Guide](docs/homelab/agent-guide.md) | Monitoring agent setup |
| [Architecture](docs/homelab/architecture.md) | System design and data flow |
| [Monitoring](docs/homelab/monitoring.md) | Monitoring stack and Prometheus integration |
## Configuration
All configuration is handled through environment variables in `.env`. See [`.env.example`](.env.example) for all options.
Key settings:
| Variable | Default | Description |
|----------|---------|-------------|
| `APP_KEY` | — | Encryption key (**required**) |
| `DB_PASSWORD` | — | Database password (**required**) |
| `URL` | http://localhost:8080 | External access URL |
| `NOMAD_DATA_DIR` | /opt/project-nomad | Host storage directory |
| `PORT` | 8080 | Application port |
| `LOG_LEVEL` | info | Log verbosity |
## Updating
```bash
docker compose pull
docker compose up -d
```
## About Internet Usage & Privacy
Project N.O.M.A.D. is designed for offline usage. An internet connection is only required during the initial installation (to download dependencies) and if you (the user) decide to download additional tools and resources at a later time. Otherwise, N.O.M.A.D. does not require an internet connection and has ZERO built-in telemetry.
To test internet connectivity, N.O.M.A.D. attempts to make a request to Cloudflare's utility endpoint, `https://1.1.1.1/cdn-cgi/trace` and checks for a successful response.
## About Security
By design, Project N.O.M.A.D. is intended to be open and available without hurdles - it includes no authentication. If you decide to connect your device to a local network after install (e.g. for allowing other devices to access it's resources), you can block/open ports to control which services are exposed.
**Will authentication be added in the future?** Maybe. It's not currently a priority, but if there's enough demand for it, we may consider building in an optional authentication layer in a future release to support uses cases where multiple users need access to the same instance but with different permission levels (e.g. family use with parental controls, classroom use with teacher/admin accounts, etc.). For now, we recommend using network-level controls to manage access if you're planning to expose your N.O.M.A.D. instance to other devices on a local network. N.O.M.A.D. is not designed to be exposed directly to the internet, and we strongly advise against doing so unless you really know what you're doing, have taken appropriate security measures, and understand the risks involved.
## Contributing
Contributions are welcome and appreciated! Please read this section fully to understand how to contribute to the project.
Contributions are welcome and appreciated! Please read the [Contributing Guide](CONTRIBUTING.md) for details.
### General Guidelines
- **Open an issue first**: Before starting work on a new feature or bug fix, please open an issue to discuss your proposed changes. This helps ensure that your contribution aligns with the project's goals and avoids duplicate work. Title the issue clearly and provide a detailed description of the problem or feature you want to work on.
- **Fork the repository**: Click the "Fork" button at the top right of the repository page to create a copy of the project under your GitHub account.
- **Create a new branch**: In your forked repository, create a new branch for your work. Use a descriptive name for the branch that reflects the purpose of your changes (e.g., `fix/issue-123` or `feature/add-new-tool`).
- **Make your changes**: Implement your changes in the new branch. Follow the existing code style and conventions used in the project. Be sure to test your changes locally to ensure they work as expected.
- **Add Release Notes**: If your changes include new features, bug fixes, or improvements, please see the "Release Notes" section below to properly document your contribution for the next release.
- **Conventional Commits**: When committing your changes, please use conventional commit messages to provide clear and consistent commit history. The format is `<type>(<scope>): <description>`, where:
- `type` is the type of change (e.g., `feat` for new features, `fix` for bug fixes, `docs` for documentation changes, etc.)
- `scope` is an optional area of the codebase that your change affects (e.g., `api`, `ui`, `docs`, etc.)
- `description` is a brief summary of the change
- **Submit a pull request**: Once your changes are ready, submit a pull request to the main repository. Provide a clear description of your changes and reference any related issues. The project maintainers will review your pull request and may provide feedback or request changes before it can be merged.
- **Be responsive to feedback**: If the maintainers request changes or provide feedback on your pull request, please respond in a timely manner. Stale pull requests may be closed if there is no activity for an extended period.
- **Follow the project's code of conduct**: Please adhere to the project's code of conduct when interacting with maintainers and other contributors. Be respectful and considerate in your communications.
- **No guarantee of acceptance**: The project is community-driven, and all contributions are appreciated, but acceptance is not guaranteed. The maintainers will evaluate each contribution based on its quality, relevance, and alignment with the project's goals.
- **Thank you for contributing to Project N.O.M.A.D.!** Your efforts help make this project better for everyone.
### Versioning
This project uses semantic versioning. The version is managed in the root `package.json`
and automatically updated by semantic-release. For simplicity's sake, the "project-nomad" image
uses the same version defined there instead of the version in `admin/package.json` (stays at 0.0.0), as it's the only published image derived from the code.
### Release Notes
Human-readable release notes live in [`admin/docs/release-notes.md`](admin/docs/release-notes.md) and are displayed in the Command Center's built-in documentation.
When working on changes, add a summary to the `## Unreleased` section at the top of that file under the appropriate heading:
- **Features** — new user-facing capabilities
- **Bug Fixes** — corrections to existing behavior
- **Improvements** — enhancements, refactors, docs, or dependency updates
Use the format `- **Area**: Description` to stay consistent with existing entries. When a release is triggered, CI automatically stamps the version and date, commits the update, and pushes the content to the GitHub release.
This project uses semantic versioning. The version is managed in the root `package.json`
and automatically updated by semantic-release.
## Community & Resources
- **Website:** [www.projectnomad.us](https://www.projectnomad.us) - Learn more about the project
- **Discord:** [Join the Community](https://discord.com/invite/crosstalksolutions) - Get help, share your builds, and connect with other NOMAD users
- **Benchmark Leaderboard:** [benchmark.projectnomad.us](https://benchmark.projectnomad.us) - See how your hardware stacks up against other NOMAD builds
- **Website:** [www.projectnomad.us](https://www.projectnomad.us)
- **Discord:** [Join the Community](https://discord.com/invite/crosstalksolutions)
- **Benchmark Leaderboard:** [benchmark.projectnomad.us](https://benchmark.projectnomad.us)
## License
Project N.O.M.A.D. is licensed under the [Apache License 2.0](LICENSE).
## Helper Scripts
Once installed, Project N.O.M.A.D. has a few helper scripts should you ever need to troubleshoot issues or perform maintenance that can't be done through the Command Center. All of these scripts are found in Project N.O.M.A.D.'s install directory, `/opt/project-nomad`
###
###### Start Script - Starts all installed project containers
```bash
sudo bash /opt/project-nomad/start_nomad.sh
```
###
###### Stop Script - Stops all installed project containers
```bash
sudo bash /opt/project-nomad/stop_nomad.sh
```
###
###### Update Script - Attempts to pull the latest images for the Command Center and its dependencies (i.e. mysql) and recreate the containers. Note: this *only* updates the Command Center containers. It does not update the installable application containers - that should be done through the Command Center UI
```bash
sudo bash /opt/project-nomad/update_nomad.sh
```
###### Uninstall Script - Need to start fresh? Use the uninstall script to make your life easy. Note: this cannot be undone!
```bash
curl -fsSL https://raw.githubusercontent.com/Crosstalk-Solutions/project-nomad/refs/heads/main/install/uninstall_nomad.sh -o uninstall_nomad.sh && sudo bash uninstall_nomad.sh
```
Project N.O.M.A.D. is licensed under the [Apache License 2.0](LICENSE).

146
docs/homelab/agent-guide.md Normal file
View File

@ -0,0 +1,146 @@
# Project N.O.M.A.D. — Agent Installation Guide
## Overview
The Nomad monitoring agent is a lightweight container that collects system metrics from remote homelab nodes and reports them to the Nomad server. It exposes a Prometheus-compatible `/metrics` endpoint.
## Features
- **System metrics**: CPU usage, memory, disk, network
- **Docker monitoring**: Container status, running/stopped counts
- **Prometheus endpoint**: Native `/metrics` output for scraping
- **Low resource usage**: ~20MB RAM, minimal CPU
- **Auto-reporting**: Sends metrics to Nomad server on configurable interval
## Quick Start
### Docker (Recommended)
```bash
docker run -d \
--name nomad-agent \
--restart unless-stopped \
-p 9100:9100 \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v /proc:/host/proc:ro \
-v /sys:/host/sys:ro \
-e NOMAD_SERVER_URL=http://your-nomad-server:8080 \
-e AGENT_SECRET=your-shared-secret \
-e NODE_NAME=my-server \
ghcr.io/docwatz/nomad-agent:latest
```
### Docker Compose
Add to your existing `docker-compose.yml` or create a new one:
```yaml
services:
nomad-agent:
build: ./agent
container_name: nomad-agent
restart: unless-stopped
ports:
- "9100:9100"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /proc:/host/proc:ro
- /sys:/host/sys:ro
environment:
- NOMAD_SERVER_URL=http://your-nomad-server:8080
- AGENT_SECRET=your-shared-secret
- NODE_NAME=my-server
- COLLECT_INTERVAL=30
```
### Build from Source
```bash
cd agent/
docker build -t nomad-agent .
```
## Configuration
| Variable | Default | Description |
|----------|---------|-------------|
| `AGENT_PORT` | 9100 | Metrics server port |
| `COLLECT_INTERVAL` | 30 | Collection interval in seconds |
| `NOMAD_SERVER_URL` | — | Nomad server URL for reporting |
| `AGENT_SECRET` | — | Shared secret for authentication |
| `NODE_NAME` | hostname | Display name for this node |
| `HOST_PROC` | /host/proc | Path to host /proc mount |
| `HOST_SYS` | /host/sys | Path to host /sys mount |
## API Endpoints
| Endpoint | Format | Description |
|----------|--------|-------------|
| `GET /health` | JSON | Health check |
| `GET /metrics` | Prometheus | Prometheus exposition format |
| `GET /api/metrics` | JSON | Full metrics as JSON |
## Prometheus Integration
Add the agent as a scrape target in your `prometheus.yml`:
```yaml
scrape_configs:
- job_name: 'nomad-agent'
static_configs:
- targets:
- 'server1:9100'
- 'server2:9100'
- 'nas:9100'
scrape_interval: 30s
```
### Available Metrics
| Metric | Type | Description |
|--------|------|-------------|
| `nomad_agent_cpu_usage_percent` | gauge | CPU usage percentage |
| `nomad_agent_cpu_count` | gauge | Number of CPU cores |
| `nomad_agent_memory_total_bytes` | gauge | Total memory |
| `nomad_agent_memory_used_bytes` | gauge | Used memory |
| `nomad_agent_memory_usage_percent` | gauge | Memory usage percentage |
| `nomad_agent_uptime_seconds` | gauge | System uptime |
| `nomad_agent_docker_containers` | gauge | Total Docker containers |
| `nomad_agent_docker_container_running` | gauge | Per-container running status |
## Security
- The agent runs as a non-root user inside the container
- Docker socket is mounted read-only
- Communication with the Nomad server uses a shared secret via `Authorization: Bearer` header
- For production use, place behind a TLS-terminating reverse proxy
## Resource Usage
| Metric | Value |
|--------|-------|
| RAM | ~15-25 MB |
| CPU | < 1% (idle) |
| Image size | ~60 MB |
| Network | ~1 KB per report |
## Deploying on Multiple Nodes
Deploy an agent on each homelab node:
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Server 1 │ │ Server 2 │ │ NAS │
│ nomad-agent │ │ nomad-agent │ │ nomad-agent │
│ :9100 │ │ :9100 │ │ :9100 │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└───────────────────┼───────────────────┘
┌──────▼──────┐
│ Nomad Server│
│ :8080 │
└─────────────┘
```
Each agent auto-registers with the Nomad server using `NODE_NAME` and begins sending telemetry at the configured interval.

View File

@ -0,0 +1,218 @@
# Project N.O.M.A.D. — Homelab Edition: Architecture
## System Overview
Project N.O.M.A.D. Homelab Edition is a container-native knowledge platform designed for NAS and homelab environments. The architecture prioritizes reliability, minimal resource usage, and compatibility with storage-backed systems.
## Container Stack
```
┌─────────────────────────────────────────────────────────────────┐
│ Docker Host / NAS │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ nomad-internal network │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │ │
│ │ │ nomad-nginx │ │ nomad-app │ │nomad-worker │ │ │
│ │ │ (Nginx) ├───►│ (AdonisJS) │ │ (Queue Jobs)│ │ │
│ │ │ :80/:443 │ │ :8080 │ │ │ │ │
│ │ └──────────────┘ └──────┬───────┘ └──────┬──────┘ │ │
│ │ │ │ │ │
│ │ ┌──────▼───────┐ ┌──────▼──────┐ │ │
│ │ │nomad-database│ │ nomad-cache │ │ │
│ │ │ (MySQL 8.0) │ │ (Redis 7) │ │ │
│ │ │ :3306 │ │ :6379 │ │ │
│ │ └──────────────┘ └─────────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ Volumes: │
│ ├── nomad-db-data (Docker volume - local SSD) │
│ ├── NOMAD_DATA_DIR/storage (bind mount - NAS share) │
│ ├── NOMAD_DATA_DIR/redis (bind mount) │
│ └── NOMAD_DATA_DIR/logs/nginx (bind mount) │
└─────────────────────────────────────────────────────────────────┘
```
## Service Roles
### nomad-app (Application Server)
- **Technology:** Node.js 22 + AdonisJS 6
- **Role:** Serves the web UI (React/Inertia), handles API requests, manages content
- **Port:** 8080
- **Dependencies:** nomad-database, nomad-cache
### nomad-worker (Background Worker)
- **Technology:** Same image as nomad-app
- **Role:** Processes background jobs — content downloads, AI model downloads, embeddings, benchmarks
- **Queues:** downloads, model-downloads, benchmarks, embeddings
- **Dependencies:** nomad-database, nomad-cache
### nomad-database (Database)
- **Technology:** MySQL 8.0
- **Role:** Persistent storage for services, content metadata, chat sessions, benchmarks, settings
- **Storage:** Docker named volume (optimized for I/O)
### nomad-cache (Cache / Queue Broker)
- **Technology:** Redis 7 Alpine
- **Role:** BullMQ job queues, session cache, real-time event transport
- **Config:** AOF persistence, 256MB max memory with LRU eviction
### nomad-nginx (Reverse Proxy)
- **Technology:** Nginx Alpine
- **Role:** TLS termination, request routing, static asset caching, WebSocket proxy
- **Ports:** 80 (HTTP), 443 (HTTPS)
## Data Flow
### Content Download Pipeline
```
User Request
nomad-app (API) ──► nomad-cache (Redis Queue)
nomad-worker
Downloads content
/app/storage/
(NAS bind mount)
```
### AI Chat Pipeline
```
User Message
nomad-app ──► Ollama (AI Model)
│ │
│ ▼
│ Response + RAG context
│ │
▼ ▼
nomad-database (Chat History)
```
### Real-Time Updates
```
nomad-worker ──► nomad-cache (Redis Pub/Sub)
nomad-app (Transmit SSE)
Browser (EventSource)
```
## Storage Architecture
### Design Principles
1. **Database on local volume** — Docker named volume for high-IOPS MySQL operations
2. **Content on NAS share** — Bind mount to NAS storage for large files (ZIM, maps, PDFs)
3. **Logs rotated automatically** — Nginx logs on bind mount, easily accessible
### Storage Tiers
| Tier | Type | Use Case | I/O Profile |
|------|------|----------|-------------|
| **Hot** | Docker named volume | MySQL database | High IOPS, small writes |
| **Warm** | Bind mount (SSD/cache) | Redis, temp files | Medium IOPS |
| **Cold** | Bind mount (NAS array) | Content library, backups | Sequential reads, large files |
### NAS Compatibility
| Platform | Storage Path | Notes |
|----------|-------------|-------|
| **Unraid** | `/mnt/user/appdata/project-nomad` | Uses cache drive for DB |
| **TrueNAS SCALE** | `/mnt/pool/apps/project-nomad` | ZFS dataset recommended |
| **Linux** | `/opt/project-nomad` | Standard filesystem |
| **Synology** | `/volume1/docker/project-nomad` | Btrfs volume |
## Network Architecture
### Internal Network
All services communicate over the `nomad-internal` bridge network. Only the following ports are exposed to the host:
| Port | Service | Purpose |
|------|---------|---------|
| 80 | nomad-nginx | HTTP (configurable) |
| 443 | nomad-nginx | HTTPS (configurable) |
| 8080 | nomad-app | Direct app access (optional) |
### Reverse Proxy Compatibility
The stack works behind external reverse proxies:
```
Internet/LAN
┌───────────────────┐
│ External Proxy │ Nginx Proxy Manager / Traefik / Caddy
│ (TLS termination) │
└─────────┬─────────┘
┌─────────────────────┐
│ nomad-nginx (:80) │ OR directly to nomad-app (:8080)
└─────────┬───────────┘
┌─────────────────────┐
│ nomad-app (:8080) │
└─────────────────────┘
```
When using an external reverse proxy, you can disable `nomad-nginx`:
```yaml
# In docker-compose.yml override
services:
nomad-nginx:
profiles: ["proxy"] # Only starts with --profile proxy
```
## Resource Requirements
### Minimum (8 GB RAM system)
| Service | RAM | CPU |
|---------|-----|-----|
| nomad-app | 256 MB | 0.25 cores |
| nomad-worker | 256 MB | 0.1 cores |
| nomad-database | 256 MB | 0.25 cores |
| nomad-cache | 64 MB | 0.05 cores |
| nomad-nginx | 16 MB | 0.01 cores |
| **Total** | **~850 MB** | **~0.66 cores** |
### Recommended (32 GB RAM system)
| Service | RAM | CPU |
|---------|-----|-----|
| nomad-app | 1 GB | 1 core |
| nomad-worker | 2 GB | 1 core |
| nomad-database | 1 GB | 0.5 cores |
| nomad-cache | 256 MB | 0.1 cores |
| nomad-nginx | 32 MB | 0.05 cores |
| **Total** | **~3.3 GB** | **~2.65 cores** |
## Security Model
- No authentication by default (network-level access control recommended)
- All inter-service communication on private Docker network
- Database and Redis not exposed to host by default
- Docker socket mounted read-only where possible
- Agent communication via shared secret (Bearer token)

View File

@ -0,0 +1,251 @@
# Project N.O.M.A.D. — Docker Compose Deployment Guide
## Overview
This guide covers deploying Project N.O.M.A.D. Homelab Edition using Docker Compose on any Linux host, VM, or NAS system.
## Prerequisites
- Docker 20.10+
- Docker Compose v2+ (comes with Docker Desktop or `docker compose` plugin)
- 4 GB RAM minimum
- 5 GB free disk space
### Verify Docker Installation
```bash
docker --version # Docker 20.10+
docker compose version # Docker Compose v2+
```
## Deployment
### Step 1: Get the Files
```bash
git clone https://github.com/DocwatZ/project-nomad-homelab-edition.git
cd project-nomad-homelab-edition
```
### Step 2: Configure Environment
```bash
cp .env.example .env
```
Generate secure credentials:
```bash
# Generate application key
APP_KEY=$(openssl rand -hex 32)
sed -i "s/^APP_KEY=replaceme/APP_KEY=$APP_KEY/" .env
# Generate database password
DB_PASS=$(openssl rand -base64 24)
sed -i "s/^DB_PASSWORD=replaceme/DB_PASSWORD=$DB_PASS/" .env
sed -i "s/^MYSQL_ROOT_PASSWORD=replaceme/MYSQL_ROOT_PASSWORD=$DB_PASS/" .env
```
Configure the external URL:
```bash
# Replace with your server IP or domain
sed -i "s|^URL=.*|URL=http://$(hostname -I | awk '{print $1}'):8080|" .env
```
### Step 3: Create Data Directories
```bash
NOMAD_DIR=$(grep NOMAD_DATA_DIR .env | cut -d= -f2)
sudo mkdir -p ${NOMAD_DIR}/{storage,redis,logs/nginx}
sudo chown -R $(id -u):$(id -g) ${NOMAD_DIR}
```
### Step 4: Launch
```bash
docker compose up -d
```
First launch takes 1-3 minutes for database initialization and migrations.
### Step 5: Verify
```bash
# Check all services are running
docker compose ps
# Check application health
curl -s http://localhost:8080/api/health
# View logs
docker compose logs -f nomad-app
```
## Service Management
### Start / Stop / Restart
```bash
# Stop all services
docker compose down
# Start all services
docker compose up -d
# Restart a specific service
docker compose restart nomad-app
# View logs
docker compose logs -f
docker compose logs -f nomad-app
```
### Update to Latest Version
```bash
docker compose pull
docker compose up -d
```
### Full Reset (Destroys Data)
```bash
docker compose down -v
sudo rm -rf /opt/project-nomad/*
docker compose up -d
```
## Customization
### Disable Nginx Proxy
If you already have a reverse proxy (Traefik, Nginx Proxy Manager, Caddy), you can skip the built-in Nginx:
```bash
# Start without nginx
docker compose up -d nomad-app nomad-worker nomad-database nomad-cache
```
Access the app directly on port 8080.
### Disable Worker (Lightweight Mode)
For minimal resource usage, you can run without the dedicated worker. The app will process jobs inline:
```bash
docker compose up -d nomad-app nomad-database nomad-cache
```
> Note: Background downloads and AI features may be slower without the worker.
### Custom Port
Edit `.env`:
```
PORT=9090
```
### Custom Storage Location
Edit `.env`:
```
NOMAD_DATA_DIR=/mnt/my-nas-share/project-nomad
```
## Compose File Structure
The `docker-compose.yml` defines five services:
```
docker-compose.yml
├── nomad-app # Web application (port 8080)
├── nomad-worker # Background job processor
├── nomad-database # MySQL 8.0 database
├── nomad-cache # Redis 7 cache/queue
└── nomad-nginx # Nginx reverse proxy (port 80/443)
```
### Override File
Create a `docker-compose.override.yml` for local customizations:
```yaml
services:
nomad-app:
# Add extra environment variables
environment:
- NOMAD_API_URL=https://api.projectnomad.io
# Add extra volumes
volumes:
- /mnt/nas-share/content:/app/storage/content:ro
```
## Monitoring
### Health Checks
All services include health checks. View status:
```bash
docker compose ps
```
### Resource Usage
```bash
docker stats --no-stream
```
### Prometheus Metrics
Deploy the monitoring agent for Prometheus-compatible metrics:
```bash
docker compose -f docker-compose.yml -f docker-compose.monitoring.yml up -d
```
See [Monitoring Architecture](./monitoring.md) for details.
## Troubleshooting
### Service Won't Start
```bash
# Check logs for the failing service
docker compose logs nomad-app
docker compose logs nomad-database
# Check if ports are in use
ss -tlnp | grep -E '(8080|3306|6379|80)'
```
### Database Connection Error
The app waits for the database health check. If it times out:
```bash
# Check database status
docker compose exec nomad-database mysqladmin ping -h localhost
# Check database logs
docker compose logs nomad-database
```
### Permission Denied on Volumes
```bash
sudo chown -R 1000:1000 /opt/project-nomad/storage
```
### Out of Disk Space
```bash
# Check Docker disk usage
docker system df
# Clean up unused images
docker system prune -a
```

View File

@ -0,0 +1,163 @@
# Project N.O.M.A.D. — Homelab Edition: Installation Guide
## Overview
Project N.O.M.A.D. Homelab Edition runs as a Docker Compose stack, making it compatible with any system that supports Docker — including NAS platforms like Unraid and TrueNAS SCALE.
## Prerequisites
- **Docker** 20.10+ and **Docker Compose** v2+
- **4 GB RAM** minimum (8 GB+ recommended)
- **5 GB** free disk space (more for content downloads)
- Network access to pull Docker images
## Quick Start
### 1. Clone or Download
```bash
git clone https://github.com/DocwatZ/project-nomad-homelab-edition.git
cd project-nomad-homelab-edition
```
Or download and extract the ZIP from the GitHub releases page.
### 2. Configure Environment
```bash
# Copy the example environment file
cp .env.example .env
# Generate a secure application key
APP_KEY=$(openssl rand -hex 32)
# Generate a secure database password
DB_PASS=$(openssl rand -base64 24)
# Update .env with generated values
sed -i "s/^APP_KEY=replaceme/APP_KEY=$APP_KEY/" .env
sed -i "s/^DB_PASSWORD=replaceme/DB_PASSWORD=$DB_PASS/" .env
sed -i "s/^MYSQL_ROOT_PASSWORD=replaceme/MYSQL_ROOT_PASSWORD=$DB_PASS/" .env
```
Edit `.env` to set your external URL:
```bash
# Set to your server's IP or domain
URL=http://192.168.1.100:8080
```
### 3. Create Data Directories
```bash
# Default location (or set NOMAD_DATA_DIR in .env)
sudo mkdir -p /opt/project-nomad/{storage,redis,logs/nginx}
sudo chown -R 1000:1000 /opt/project-nomad
```
### 4. Start the Stack
```bash
docker compose up -d
```
### 5. Access the Dashboard
Open your browser and navigate to the URL you configured (default: `http://localhost:8080`).
If using the Nginx proxy: `http://localhost` (port 80).
## Service Architecture
| Service | Container | Port | Purpose |
|---------|-----------|------|---------|
| **nomad-app** | Nomad application | 8080 | Web UI + API |
| **nomad-worker** | Background jobs | — | Queue processing |
| **nomad-database** | MySQL 8.0 | 3306 (internal) | Persistent data |
| **nomad-cache** | Redis 7 | 6379 (internal) | Cache + job queues |
| **nomad-nginx** | Nginx | 80, 443 | Reverse proxy |
## Volume Layout
```
NOMAD_DATA_DIR/
├── storage/ # Content files (ZIM, maps, uploads)
├── redis/ # Redis persistence
└── logs/
└── nginx/ # Nginx access/error logs
```
The MySQL database uses a Docker named volume (`nomad-db-data`) for optimal I/O performance. This avoids latency issues common with NFS/SMB-backed storage on NAS systems.
## Updating
```bash
# Pull latest images
docker compose pull
# Recreate containers with new images
docker compose up -d
```
## Stopping
```bash
docker compose down
```
To also remove data volumes:
```bash
docker compose down -v
```
## Configuration Reference
See `.env.example` for all available configuration options. Key settings:
| Variable | Default | Description |
|----------|---------|-------------|
| `PORT` | 8080 | Application port |
| `APP_KEY` | — | Encryption key (required) |
| `URL` | http://localhost:8080 | External access URL |
| `DB_PASSWORD` | — | Database password (required) |
| `NOMAD_DATA_DIR` | /opt/project-nomad | Host data directory |
| `LOG_LEVEL` | info | Logging verbosity |
| `NGINX_HTTP_PORT` | 80 | Nginx HTTP port |
| `NGINX_HTTPS_PORT` | 443 | Nginx HTTPS port |
## Troubleshooting
### Container won't start
```bash
# Check container logs
docker compose logs nomad-app
# Verify database is healthy
docker compose ps nomad-database
```
### Database connection errors
Ensure the database is healthy before the app starts. The compose file handles this with health checks, but on slow systems you may need to wait longer:
```bash
# Check database health
docker compose exec nomad-database mysqladmin ping -h localhost
```
### Permission issues on NAS
Ensure the storage directories are writable by the container user (UID 1000):
```bash
sudo chown -R 1000:1000 /path/to/your/storage
```
## Next Steps
- [Unraid Installation Guide](./unraid-guide.md)
- [TrueNAS SCALE Installation Guide](./truenas-guide.md)
- [Agent Installation Guide](./agent-guide.md)
- [Architecture Overview](./architecture.md)

225
docs/homelab/monitoring.md Normal file
View File

@ -0,0 +1,225 @@
# Project N.O.M.A.D. — Monitoring Architecture
## Overview
The Nomad Homelab Edition includes built-in monitoring capabilities and integrates with standard homelab monitoring stacks.
## Monitoring Layers
```
┌─────────────────────────────────────────────────────────────┐
│ Nomad Dashboard │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ NAS │ │ Server │ │Container │ │ Network │ │
│ │ Health │ │ Metrics │ │ Status │ │ Devices │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
│ ┌────▼────────────▼────────────▼────────────▼─────┐ │
│ │ Nomad App (Aggregator) │ │
│ └──────────────────────┬──────────────────────────┘ │
└─────────────────────────┼──────────────────────────────────┘
┌───────────────┼───────────────┐
│ │ │
┌─────▼─────┐ ┌────▼────┐ ┌──────▼──────┐
│ Agent 1 │ │ Agent 2 │ │ Agent N │
│ (Server) │ │ (NAS) │ │ (Remote) │
│ :9100 │ │ :9100 │ │ :9100 │
└───────────┘ └─────────┘ └─────────────┘
```
## Built-in Monitoring
### System Resource Monitoring
The Nomad application provides built-in system information through the system controller:
- **CPU**: Model, core count, usage
- **Memory**: Total, used, free, usage percentage
- **Disk**: Mount points, usage, filesystem types
- **Docker**: Container status, image versions, resource usage
### Docker Container Monitoring
Nomad monitors its own container stack and any Docker containers on the host via the Docker socket:
- Container health status
- Image versions and update availability
- Resource consumption
- Log access (via Dozzle integration in original install)
### Health Endpoints
| Endpoint | Service | Purpose |
|----------|---------|---------|
| `GET /api/health` | nomad-app | Application health |
| `GET /nginx-health` | nomad-nginx | Reverse proxy health |
| `GET /health` | nomad-agent | Agent health |
## Agent-Based Monitoring
### Architecture
The Nomad monitoring agent runs on remote homelab nodes and reports metrics via:
1. **Push model**: Agent sends JSON metrics to `POST /api/agent/report` on the Nomad server
2. **Pull model**: Prometheus scrapes the agent's `/metrics` endpoint
### Agent Metrics
```
nomad_agent_cpu_usage_percent - CPU utilization
nomad_agent_cpu_count - CPU core count
nomad_agent_memory_total_bytes - Total RAM
nomad_agent_memory_used_bytes - Used RAM
nomad_agent_memory_usage_percent - RAM utilization
nomad_agent_uptime_seconds - System uptime
nomad_agent_docker_containers - Docker container count
nomad_agent_docker_container_running - Per-container status
```
### Deployment
Deploy an agent on each node you want to monitor:
```bash
docker run -d --name nomad-agent \
--restart unless-stopped \
-p 9100:9100 \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v /proc:/host/proc:ro \
-v /sys:/host/sys:ro \
-e NOMAD_SERVER_URL=http://nomad-server:8080 \
-e NODE_NAME=$(hostname) \
nomad-agent
```
## Prometheus Integration
### Full Monitoring Stack
For a complete monitoring setup, add Prometheus and Grafana to your docker-compose:
```yaml
# docker-compose.monitoring.yml
services:
prometheus:
image: prom/prometheus:latest
container_name: nomad-prometheus
restart: unless-stopped
ports:
- "9090:9090"
volumes:
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
networks:
- nomad-internal
grafana:
image: grafana/grafana:latest
container_name: nomad-grafana
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
networks:
- nomad-internal
volumes:
prometheus-data:
grafana-data:
```
### Prometheus Configuration
```yaml
# monitoring/prometheus.yml
global:
scrape_interval: 30s
evaluation_interval: 30s
scrape_configs:
- job_name: 'nomad-agents'
static_configs:
- targets:
- 'nomad-agent:9100' # Local agent
- 'server2:9100' # Remote server
- 'nas:9100' # NAS agent
```
### Node Exporter (Optional)
For deeper host-level metrics, add the Prometheus Node Exporter alongside the Nomad agent:
```yaml
node-exporter:
image: prom/node-exporter:latest
container_name: nomad-node-exporter
restart: unless-stopped
ports:
- "9101:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--path.rootfs=/rootfs'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
```
## Observability
### Structured Logging
The Nomad application uses structured JSON logging:
```json
{
"level": "info",
"timestamp": "2026-03-13T12:00:00.000Z",
"msg": "HTTP request completed",
"method": "GET",
"url": "/api/health",
"status": 200,
"duration": "12ms"
}
```
Configure log level via `LOG_LEVEL` environment variable: `debug`, `info`, `warn`, `error`.
### Log Access
```bash
# Application logs
docker compose logs -f nomad-app
# Worker logs
docker compose logs -f nomad-worker
# All service logs
docker compose logs -f
# Nginx access logs (on host)
tail -f ${NOMAD_DATA_DIR}/logs/nginx/access.log
```
### Alerting Recommendations
For homelab alerting, integrate with:
| Tool | Use Case |
|------|----------|
| **Uptime Kuma** | Service uptime monitoring |
| **Grafana Alerting** | Metric-based alerts |
| **Ntfy** | Push notifications |
| **Gotify** | Self-hosted notifications |
Example Uptime Kuma monitor:
- **URL**: `http://nomad-app:8080/api/health`
- **Interval**: 60 seconds
- **Expected status**: 200

View File

@ -0,0 +1,185 @@
# Project N.O.M.A.D. — TrueNAS SCALE Installation Guide
## Overview
TrueNAS SCALE supports both Docker Compose (via custom app) and Helm charts for application deployment. This guide covers both methods.
## Method 1: Docker Compose via Custom App (Recommended)
TrueNAS SCALE Electric Eel (24.10+) supports Docker Compose as a custom app deployment method.
### Prerequisites
- TrueNAS SCALE 24.10+ (Electric Eel or newer)
- A dataset for application data
### Steps
#### 1. Create a Dataset
1. Go to **Storage** → **Pools**
2. Create a new dataset: `project-nomad`
- Path: `/mnt/pool/apps/project-nomad`
- Record Size: 128K
- Compression: LZ4
#### 2. Create Subdirectories
Open a TrueNAS shell:
```bash
mkdir -p /mnt/pool/apps/project-nomad/{storage,redis,logs/nginx,config}
```
#### 3. Deploy as Custom App
1. Go to **Apps****Discover Apps** → **Custom App**
2. Upload or paste the `docker-compose.yml` from this repository
3. Configure environment variables:
- `APP_KEY`: Generate with `openssl rand -hex 32`
- `DB_PASSWORD`: Set a secure password
- `MYSQL_ROOT_PASSWORD`: Same as DB_PASSWORD
- `URL`: `http://YOUR_TRUENAS_IP:8080`
- `NOMAD_DATA_DIR`: `/mnt/pool/apps/project-nomad`
#### 4. Start the Application
Click **Deploy** and wait for all services to start (first launch may take 2-3 minutes).
## Method 2: Helm Chart
### Prerequisites
- TrueNAS SCALE with Kubernetes enabled
- Helm CLI (if deploying manually)
### Steps
#### 1. Add the Chart
```bash
# Clone the repository
git clone https://github.com/DocwatZ/project-nomad-homelab-edition.git
cd project-nomad-homelab-edition/homelab/truenas
# Install with Helm
helm install project-nomad . \
--set app.appKey=$(openssl rand -hex 32) \
--set database.password=$(openssl rand -base64 24) \
--set database.rootPassword=$(openssl rand -base64 24) \
--set app.url=http://YOUR_TRUENAS_IP:8080 \
--set storage.data.hostPath=/mnt/pool/apps/project-nomad/storage
```
#### 2. Verify Deployment
```bash
helm status project-nomad
kubectl get pods -l app.kubernetes.io/instance=project-nomad
```
## TrueNAS-Specific Configuration
### Storage Best Practices
**ZFS Dataset Recommendations:**
| Dataset | Record Size | Compression | Purpose |
|---------|-------------|-------------|---------|
| `project-nomad/storage` | 1M | LZ4 | Large content files |
| `project-nomad/database` | 16K | LZ4 | MySQL data (if not using Docker volume) |
| `project-nomad/redis` | 128K | LZ4 | Redis persistence |
**Performance Tip:** Use a Docker named volume for the MySQL database (default in docker-compose.yml). Docker volumes on TrueNAS use the app pool, which typically has better I/O than network-accessed datasets.
### Network Configuration
TrueNAS SCALE apps run in an isolated network by default. To access Nomad from your LAN:
1. The compose file maps port 8080 to the host
2. Access via `http://YOUR_TRUENAS_IP:8080`
If using the Nginx proxy (port 80):
- Ensure port 80 isn't used by TrueNAS web UI
- Change `NGINX_HTTP_PORT` in `.env` if needed
### Permissions
TrueNAS uses ACLs for dataset permissions. Set the dataset owner:
```bash
# For Docker Compose deployments
chown -R 1000:1000 /mnt/pool/apps/project-nomad/storage
```
Or configure ACLs in the TrueNAS UI:
1. Go to **Storage** → select your dataset → **Edit Permissions**
2. Set User: `1000`, Group: `1000`
3. Apply recursively
## Updating on TrueNAS
### Docker Compose Method
```bash
cd /mnt/pool/apps/project-nomad
docker compose pull
docker compose up -d
```
### Helm Method
```bash
helm upgrade project-nomad ./homelab/truenas \
--reuse-values
```
## Monitoring on TrueNAS
TrueNAS SCALE includes built-in reporting. You can supplement it with the Nomad monitoring agent:
```bash
docker run -d --name nomad-agent \
--restart unless-stopped \
-p 9100:9100 \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v /proc:/host/proc:ro \
-v /sys:/host/sys:ro \
-e NOMAD_SERVER_URL=http://nomad-app:8080 \
-e NODE_NAME=truenas \
nomad-agent
```
## Troubleshooting
### App Won't Start
```bash
# Check container status
docker compose ps
# View logs
docker compose logs nomad-app
docker compose logs nomad-database
```
### Database Issues
If the database fails to initialize:
```bash
# Check MySQL logs
docker compose logs nomad-database
# Verify the database volume
docker volume inspect project-nomad_nomad-db-data
```
### Port Conflicts
TrueNAS web UI uses ports 80/443 by default. Adjust in `.env`:
```
NGINX_HTTP_PORT=8081
NGINX_HTTPS_PORT=8443
```

View File

@ -0,0 +1,194 @@
# Project N.O.M.A.D. — Unraid Installation Guide
## Overview
This guide covers installing Project N.O.M.A.D. Homelab Edition on Unraid using either Docker Compose or the Community Apps template.
## Method 1: Docker Compose (Recommended)
### Prerequisites
- Unraid 6.12+
- Docker enabled in Unraid settings
- Docker Compose plugin installed (available via Community Apps)
### Steps
#### 1. Create the Application Directory
Open an Unraid terminal (or SSH):
```bash
mkdir -p /mnt/user/appdata/project-nomad
cd /mnt/user/appdata/project-nomad
```
#### 2. Download Configuration Files
```bash
# Download docker-compose.yml
curl -fsSL https://raw.githubusercontent.com/DocwatZ/project-nomad-homelab-edition/main/docker-compose.yml -o docker-compose.yml
# Download .env.example
curl -fsSL https://raw.githubusercontent.com/DocwatZ/project-nomad-homelab-edition/main/.env.example -o .env
# Download nginx config
mkdir -p nginx
curl -fsSL https://raw.githubusercontent.com/DocwatZ/project-nomad-homelab-edition/main/nginx/default.conf -o nginx/default.conf
# Download entrypoint
mkdir -p install
curl -fsSL https://raw.githubusercontent.com/DocwatZ/project-nomad-homelab-edition/main/install/entrypoint.sh -o install/entrypoint.sh
chmod +x install/entrypoint.sh
```
#### 3. Configure Environment
```bash
# Generate secrets
APP_KEY=$(openssl rand -hex 32)
DB_PASS=$(openssl rand -base64 24)
# Update .env
sed -i "s/^APP_KEY=replaceme/APP_KEY=$APP_KEY/" .env
sed -i "s/^DB_PASSWORD=replaceme/DB_PASSWORD=$DB_PASS/" .env
sed -i "s/^MYSQL_ROOT_PASSWORD=replaceme/MYSQL_ROOT_PASSWORD=$DB_PASS/" .env
# Set Unraid storage path
sed -i "s|^NOMAD_DATA_DIR=.*|NOMAD_DATA_DIR=/mnt/user/appdata/project-nomad|" .env
# Set your server URL (replace with your Unraid IP)
sed -i "s|^URL=.*|URL=http://$(hostname -I | awk '{print $1}'):8080|" .env
```
#### 4. Create Storage Directories
```bash
mkdir -p /mnt/user/appdata/project-nomad/{storage,redis,logs/nginx}
```
#### 5. Start the Stack
```bash
docker compose up -d
```
#### 6. Access Nomad
Open your browser: `http://YOUR_UNRAID_IP:8080`
### Storage Layout on Unraid
```
/mnt/user/appdata/project-nomad/
├── docker-compose.yml
├── .env
├── nginx/
│ └── default.conf
├── install/
│ └── entrypoint.sh
├── storage/ # Content files (cache-only share recommended)
├── redis/ # Redis data
└── logs/
└── nginx/ # Nginx logs
```
**Tip:** For large content libraries (ZIM files, maps), consider storing them on a separate Unraid share with cache-preferred settings for better I/O performance.
## Method 2: Community Apps Template
### Steps
1. Install the **Docker Compose Manager** plugin from Community Apps
2. In Unraid web UI, go to **Docker** → **Add Container**
3. Click **Template** and paste the template URL:
```
https://raw.githubusercontent.com/DocwatZ/project-nomad-homelab-edition/main/homelab/unraid-template.xml
```
4. Configure the required fields:
- **APP_KEY**: Generate with `openssl rand -hex 32`
- **DB_PASSWORD**: Set a secure password
- **URL**: Your Unraid server URL
5. Click **Apply**
> **Note:** The Community Apps template creates only the Nomad application container. You still need separate MySQL and Redis containers. The Docker Compose method handles all services automatically.
## Unraid-Specific Tips
### Use Cache Drive for Database
For best performance, store the MySQL database on your Unraid cache drive:
```bash
# In .env, the database uses a Docker named volume by default
# This automatically stores on your cache drive
```
### Reverse Proxy with Unraid's SWAG/LSIO
If you use the SWAG (Secure Web Application Gateway) container:
1. Create a proxy config in `/mnt/user/appdata/swag/nginx/proxy-confs/`:
```nginx
# nomad.subdomain.conf
server {
listen 443 ssl;
server_name nomad.*;
include /config/nginx/ssl.conf;
location / {
proxy_pass http://nomad-app:8080;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
client_max_body_size 10G;
}
}
```
2. Ensure SWAG and Nomad share a Docker network.
### Auto-Start on Boot
Docker Compose stacks with `restart: unless-stopped` will automatically restart when Unraid boots and Docker starts.
## Updating on Unraid
```bash
cd /mnt/user/appdata/project-nomad
docker compose pull
docker compose up -d
```
## Troubleshooting
### Permission Issues
Unraid runs containers as root by default. If you encounter permission issues:
```bash
chown -R nobody:users /mnt/user/appdata/project-nomad/storage
chmod -R 755 /mnt/user/appdata/project-nomad/storage
```
### Network Conflicts
If port 8080 conflicts with another container, change the port in `.env`:
```
PORT=8088
```
### Logs
```bash
# View all container logs
docker compose logs -f
# View specific service logs
docker compose logs -f nomad-app
```

View File

@ -2,25 +2,68 @@
set -e
echo "Starting entrypoint script..."
echo "Running wait-for-it.sh to ensure MySQL is ready..."
echo "============================================"
echo " Project N.O.M.A.D. — Homelab Edition"
echo " Starting up..."
echo "============================================"
# Use wait-for-it.sh to wait for MySQL to be available
# wait-for-it.sh <host>:<port> [-t timeout] [-- command args]
/usr/local/bin/wait-for-it.sh ${DB_HOST}:${DB_PORT} -t 60 -- echo "MySQL is up and running!"
# ---------------------------------------------------------------------------
# Wait for database to be ready (no external dependencies like wait-for-it.sh)
# ---------------------------------------------------------------------------
DB_HOST="${DB_HOST:-localhost}"
DB_PORT="${DB_PORT:-3306}"
MAX_RETRIES=60
RETRY_INTERVAL=2
# Run AdonisJS migrations
echo "Running AdonisJS migrations..."
echo "Waiting for database at ${DB_HOST}:${DB_PORT}..."
retries=0
while [ $retries -lt $MAX_RETRIES ]; do
if curl -sf "http://${DB_HOST}:${DB_PORT}" >/dev/null 2>&1 || \
node -e "const net = require('net'); const s = new net.Socket(); s.setTimeout(2000); s.connect(${DB_PORT}, '${DB_HOST}', () => { s.destroy(); process.exit(0); }); s.on('error', () => process.exit(1)); s.on('timeout', () => { s.destroy(); process.exit(1); });" 2>/dev/null; then
echo "Database is ready!"
break
fi
retries=$((retries + 1))
echo " Waiting for database... (attempt ${retries}/${MAX_RETRIES})"
sleep $RETRY_INTERVAL
done
if [ $retries -eq $MAX_RETRIES ]; then
echo "ERROR: Database did not become ready in time. Continuing anyway..."
fi
# ---------------------------------------------------------------------------
# Ensure storage directories exist
# ---------------------------------------------------------------------------
STORAGE_PATH="${NOMAD_STORAGE_PATH:-/app/storage}"
echo "Ensuring storage directories exist at ${STORAGE_PATH}..."
mkdir -p "${STORAGE_PATH}" 2>/dev/null || true
# ---------------------------------------------------------------------------
# Run database migrations
# ---------------------------------------------------------------------------
echo "Running database migrations..."
node ace migration:run --force
# Seed the database if needed
# ---------------------------------------------------------------------------
# Seed the database
# ---------------------------------------------------------------------------
echo "Seeding the database..."
node ace db:seed
# Start background workers for all queues
echo "Starting background workers for all queues..."
node ace queue:work --all &
# ---------------------------------------------------------------------------
# Start background workers (only if not running as a dedicated worker)
# ---------------------------------------------------------------------------
if [ "${NOMAD_ROLE}" != "worker" ]; then
echo "Starting background workers for all queues..."
node ace queue:work --all &
fi
# Start the AdonisJS application
echo "Starting AdonisJS application..."
# ---------------------------------------------------------------------------
# Start the application
# ---------------------------------------------------------------------------
echo "============================================"
echo " N.O.M.A.D. is ready!"
echo " Listening on port ${PORT:-8080}"
echo "============================================"
exec node bin/server.js