# GeoIntel Unraid all-in-one container GeoIntel can run on Unraid as one DockerMan-native container. Inside that single container: - embedded PostGIS stores the application database - Alembic migrations run at startup - FastAPI runs on internal `127.0.0.1:8000` - nginx serves the React/MapLibre frontend on container port `80` - nginx proxies `/api` and `/health` to the internal backend The browser entrypoint is: ```text http://:${GEOINTEL_FRONTEND_PORT} ``` The app icons are served from the same container: ```text http://:${GEOINTEL_FRONTEND_PORT}/geointel-icon.svg http://:${GEOINTEL_FRONTEND_PORT}/geointel-icon.png ``` ## Files - `docker-compose.unraid.yml`: config validation reference for the all-in-one image. - `deploy/unraid/Dockerfile.all-in-one`: builds the single container. - `deploy/unraid/all-in-one-start.sh`: starts embedded PostGIS, backend and nginx. - `deploy/unraid/run-dockerman-container.sh`: starts/replaces the running container with DockerMan labels and editable Unraid metadata. - `deploy/unraid/nginx-all-in-one.conf`: frontend and API proxy config for one container. - `deploy/unraid/geointel.env.example`: copy to `.env` and edit ports/paths. - `deploy/unraid/geointel-unraid-template.xml`: Unraid/DockerMan metadata for editable fields. - `deploy/unraid/geointel-icon.svg`: frontend favicon source. - `deploy/unraid/geointel-icon.png`: DockerMan/Unraid icon source. - `frontend/public/geointel-icon.svg`: frontend-served SVG icon. - `frontend/public/geointel-icon.png`: frontend-served PNG icon. The Tower deploy scripts also copy the editable DockerMan template to: ```text /boot/config/plugins/dockerMan/templates-user/my-geointel.xml ``` and copy the PNG icon to: ```text /boot/config/plugins/dockerMan/images/geointel-icon.png ``` The template name is `geointel` so it matches the running all-in-one container name. If the Unraid Docker page was already open, refresh it after deploy so DockerMan reloads the template/icon metadata. `docker-compose.unraid.yml` also applies DockerMan labels to the running container: ```text net.unraid.docker.managed=dockerman net.unraid.docker.webui=http://[IP]:[PORT:80]/ net.unraid.docker.icon=/boot/config/plugins/dockerMan/images/geointel-icon.png ``` These labels are required because a plain Compose container can run correctly while still missing the normal Unraid edit/icon controls. ## First setup from the repo From the Unraid shell: ```bash cd /mnt/user/appdata git clone gitea-widefrog:NuklearRabbit/geointel.git geointel cd /mnt/user/appdata/geointel cp deploy/unraid/geointel.env.example .env nano .env docker compose -f docker-compose.unraid.yml config docker build --build-arg GEOINTEL_INSTALL_AI=${GEOINTEL_INSTALL_AI:-false} -f deploy/unraid/Dockerfile.all-in-one -t geointel-all-in-one:latest . bash deploy/unraid/run-dockerman-container.sh ``` The repository deploy scripts run the same flow automatically. They validate the Compose reference, build the image with the `GEOINTEL_INSTALL_AI` build arg, install the DockerMan template/icon, remove any old Compose-owned `geointel` container, preserve/migrate the PostGIS data path and start the final container with DockerMan labels. `scripts/deploy_tower.sh` and `scripts/deploy_tower.ps1` source the remote `.env` before building the image. That means `GEOINTEL_INSTALL_AI=true` in `/mnt/user/appdata/geointel/.env` is enough for the automatic deploy to build the AI-enabled image. Set `GEOINTEL_INSTALL_AI` in the local shell or pass `-InstallAi true/false` to the PowerShell wrapper only when you intentionally want to override the remote `.env` for that deploy. Database credentials are runtime configuration, not image metadata. The all-in-one image does not bake `GEOINTEL_POSTGRES_PASSWORD` into the Dockerfile; set it through `.env`, the Unraid template or `docker run -e`. AI dependencies are opt-in. Leave `GEOINTEL_INSTALL_AI=false` for the default GIS-only image. Set `GEOINTEL_INSTALL_AI=true`, mount models through `GEOINTEL_MODELS_PATH` and configure `YOLO_ENABLED=true` plus `YOLO_MODELS_DIR=/app/models` and `YOLO_MODEL_PATH=/app/models/.pt` only when you have a local model file. The AI-enabled image installs PyTorch/Ultralytics plus the native OpenCV runtime libraries needed for Ultralytics imports; it still never downloads model weights. The documented CPU runtime installs pinned `torch==2.13.0` and `torchvision==0.28.0` from `https://download.pytorch.org/whl/cpu`, avoiding the unused CUDA runtime wheels included by the general Linux package index. The Dockerfile copies dependency metadata before backend source, so normal code-only redeploys can reuse the expensive dependency layer. `YOLO_CONFIG_DIR` defaults to `/app/storage/ultralytics`, a writable persistent path, so Ultralytics settings do not fall back to root user config directories. To safely configure an existing local YOLO model on Tower, place one supported model file (`.pt`, `.onnx` or `.engine`) under: ```text /mnt/user/appdata/geointel/models ``` Then run a dry-run first: ```bash cd /mnt/user/appdata/geointel python scripts/configure_yolo_model.py \ --models-dir /mnt/user/appdata/geointel/models \ --env-file .env ``` Apply only after the selected host and container paths are correct: ```bash python scripts/configure_yolo_model.py \ --models-dir /mnt/user/appdata/geointel/models \ --env-file .env \ --apply bash deploy/unraid/run-dockerman-container.sh ``` If multiple model files are present, add `--model-file /mnt/user/appdata/geointel/models/.pt`. The helper does not download weights, does not load a model and does not run inference; it only updates the env file for the mounted local model. Validate liveness, dependency readiness and the canonical API: ```bash curl -fsS "http://192.168.10.150:${GEOINTEL_FRONTEND_PORT:-1202}/health/live" curl -fsS "http://192.168.10.150:${GEOINTEL_FRONTEND_PORT:-1202}/health/ready" curl -fsS "http://192.168.10.150:${GEOINTEL_FRONTEND_PORT:-1202}/api/v1/system/capabilities" curl -fsS "http://192.168.10.150:${GEOINTEL_FRONTEND_PORT:-1202}/api/v1/projects" curl -I "http://192.168.10.150:${GEOINTEL_FRONTEND_PORT:-1202}/geointel-icon.svg" curl -I "http://192.168.10.150:${GEOINTEL_FRONTEND_PORT:-1202}/geointel-icon.png" ``` The live migration smoke also checks PostgreSQL database collation metadata. When reusing a PostGIS volume created by an older Debian/glibc runtime, it may print `COLLATION_VERSION_MISMATCH`. This is a maintenance warning, not an app startup failure. Review backups first, then acknowledge the new runtime collation version inside the running container: ```bash docker exec -it geointel psql -U "${GEOINTEL_POSTGRES_USER:-geointel}" -d "${GEOINTEL_POSTGRES_DB:-geointel}" ALTER DATABASE "geointel" REFRESH COLLATION VERSION; ``` If you rely on text indexes with locale-specific ordering, plan a maintenance window and rebuild the affected indexes before acknowledging the version. The current GeoIntel V1 spatial workflows primarily use UUIDs, JSON metadata and PostGIS geometry indexes, but the warning should still be tracked explicitly. ## Change the browser port Edit `.env`: ```env GEOINTEL_FRONTEND_PORT=1203 GEOINTEL_CORS_ORIGINS=http://localhost:1203,http://127.0.0.1:1203,http://192.168.10.150:1203 ``` Apply: ```bash docker build --build-arg GEOINTEL_INSTALL_AI=${GEOINTEL_INSTALL_AI:-false} -f deploy/unraid/Dockerfile.all-in-one -t geointel-all-in-one:latest . bash deploy/unraid/run-dockerman-container.sh ``` ## Persistent paths Recommended Unraid paths: ```env GEOINTEL_STORAGE_PATH=/mnt/user/appdata/geointel/storage GEOINTEL_POSTGIS_DATA_PATH=/mnt/user/appdata/geointel/postgres-data ``` `GEOINTEL_STORAGE_PATH` contains uploads, tiles, masks, reports and exports. `GEOINTEL_POSTGIS_DATA_PATH` contains the embedded PostGIS database files. ## Local Ollama assistant The repository Compose file, DockerMan template and automatic deployment all map `host.docker.internal` to the Unraid host and enable the source-grounded assistant by default. Ollama must already listen on host port `11434`; GeoIntel does not install or expose Ollama itself. ```env OLLAMA_ENABLED=true OLLAMA_BASE_URL=http://host.docker.internal:11434 OLLAMA_DEFAULT_MODEL=qwen3.5:9b OLLAMA_TIMEOUT_SECONDS=120 OLLAMA_MAX_OUTPUT_TOKENS=1200 OLLAMA_CONTEXT_TOKENS=16384 ``` `/health/live` proves only that FastAPI is serving. `/health/ready` returns HTTP 503 when PostgreSQL, PostGIS, the migration head or persistent storage is not ready, and is the container healthcheck. The all-in-one startup also marks work left in `running` by a previous process as failed with `PROCESS_INTERRUPTED`; synchronous work cannot survive a container restart. The model dropdown comes from Ollama `/api/tags`, so changing the installed models requires no frontend rebuild. Verify after deployment with: ```bash curl http://127.0.0.1:1202/api/v1/assistant/status curl http://127.0.0.1:1202/api/v1/assistant/models ``` ## Update from Gitea ```bash cd /mnt/user/appdata/geointel git fetch origin main git reset --hard origin/main docker build --build-arg GEOINTEL_INSTALL_AI=${GEOINTEL_INSTALL_AI:-false} -f deploy/unraid/Dockerfile.all-in-one -t geointel-all-in-one:latest . bash deploy/unraid/run-dockerman-container.sh ``` ## Safe cleanup Safe cache cleanup if Docker build cache fills the Unraid Docker image: ```bash docker builder prune -af ``` Avoid broad volume pruning unless you explicitly intend to remove persisted PostGIS data or GeoIntel artifacts. ## Multi-container development stack The root `docker-compose.yml` remains available for development and CI-like validation with separate `db`, `backend` and `frontend` services. For Unraid app-style operation, prefer `docker-compose.unraid.yml`.