NextSearch needs two containers of its own on Unraid. Most people already run the rest.
Part one covered what NextSearch does: make the contents of existing Nextcloud folders searchable, strictly read-only, without a cluster alongside. This is the other half — how it lands on an Unraid server without turning into an afternoon.
Unraid is a grateful host for it. Postgres and Redis have been running for other applications on many boxes for a long time. Meilisearch, Tika and Gotenberg are the same services Paperless-ngx uses, so they are well-trodden on Unraid. The plan follows from that: use what is there, and keep the own footprint small.
The full guide in the repository
docs/unraid.md has the complete stack to copy, including the variants for external S3 and for going without Compose Manager.
Why it stays at two containers
The app image ships an all-in-one role: FrankenPHP, the queue worker and the scheduler run under one supervisor in the same container. That leaves NextSearch itself as:
app— the backend withserve,workerandschedulerin oneweb— the Nuxt UI, the only container with a published port
Everything else is a service you point at over the network. All of them exist on Unraid for linux/amd64:
| Service | Image | On Unraid |
|---|---|---|
| Postgres | postgres:18-alpine | Community Applications template, often already running |
| Redis | redis:8-alpine | Community Applications template, often already running |
| Meilisearch | getmeili/meilisearch | Community Applications template |
| Tika | apache/tika:3.3.1.0-full | known from the official Unraid guide for Paperless-ngx |
| Gotenberg | gotenberg/gotenberg:8 | same |
| S3 | minio/minio | Community Applications template — or external S3 |
Tika's -full tag carries Tesseract and its language packs, so OCR needs no container of its own. Gotenberg is used only for previews of Office files; turn those off with PREVIEW_OFFICE_ENABLED=false and you don't need it at all.
Object storage is the one exception to the reuse rule. The stack below runs a small MinIO that writes to Unraid storage — previews and extracted text stay on the array, and external S3 is needed nowhere.
The stack
The least fiddly path is the Compose Manager plugin (Apps → search for "Compose Manager"). It runs a compose stack straight on Unraid, and the whole wiring lives in one file instead of spread across a dozen container templates.
Create a new stack, paste the following in, fill in the hosts:
name: nextsearch
services:
app:
image: mirkohaaser/nextsearch-app:0.2.4
# All-in-one: FrankenPHP + queue worker + scheduler in one container.
command: ["app-entrypoint", "all"]
environment:
APP_KEY: base64:PASTE_A_GENERATED_KEY_HERE
APP_URL: http://YOUR_UNRAID_IP:3000
ADMIN_EMAIL: admin@example.com
ADMIN_PASSWORD: change-me-please
# Reuse the existing Unraid Postgres and Redis.
DB_HOST: 192.168.1.10
DB_PORT: "5432"
DB_DATABASE: nextsearch
DB_USERNAME: nextsearch
DB_PASSWORD: your-postgres-password
REDIS_HOST: 192.168.1.10
REDIS_PORT: "6379"
REDIS_PASSWORD: your-redis-password-or-remove-this-line
# Search and extraction.
MEILISEARCH_HOST: http://192.168.1.10:7700
MEILI_MASTER_KEY: your-meili-master-key
TIKA_URL: http://192.168.1.10:9998
GOTENBERG_URL: http://192.168.1.10:3000
# Object storage: the bundled MinIO on Unraid storage.
FILESYSTEM_DISK: s3
AWS_ENDPOINT: http://minio:9000
AWS_ACCESS_KEY_ID: nextsearch
AWS_SECRET_ACCESS_KEY: nextsearch-secret
AWS_BUCKET: nextsearch
AWS_USE_PATH_STYLE_ENDPOINT: "true"
volumes:
- /mnt/user/appdata/nextsearch/storage:/app/storage
depends_on:
minio:
condition: service_healthy
restart: unless-stopped
minio:
image: minio/minio:RELEASE.2025-09-07T16-13-09Z
command: ["server", "/data", "--console-address", ":9001"]
environment:
MINIO_ROOT_USER: nextsearch
MINIO_ROOT_PASSWORD: nextsearch-secret
volumes:
- /mnt/user/appdata/nextsearch/minio:/data
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 10s
timeout: 5s
retries: 20
restart: unless-stopped
web:
image: mirkohaaser/nextsearch-web:0.2.4
environment:
NUXT_BACKEND_URL: http://app:8080
NITRO_PORT: "3000"
NITRO_HOST: 0.0.0.0
ports:
- "3000:3000"
depends_on:
- app
restart: unless-stopped
Four values are worth a second look:
APP_KEY encrypts the stored Nextcloud credentials and has to be a real key. Generate one on any machine with Docker:
docker run --rm mirkohaaser/nextsearch-app:0.2.4 php artisan key:generate --show
Paste the whole base64:… string — and leave it alone. Swap it later and the saved Nextcloud passwords can no longer be decrypted.
MEILI_MASTER_KEY has to be the same value that is set on the Meilisearch container.
The hosts. Replace 192.168.1.10 with the address the service actually runs on. If a service is a container on the same Unraid Docker network, its container name works too.
The image tag should be pinned to a released version — 0.2.4 here rather than latest. Otherwise a "force update" in Unraid moves the stack to a build nobody asked for.
Only web publishes a port. Behind a reverse proxy (Nginx Proxy Manager, SWAG, Traefik) you point at the web container on 3000 and set APP_URL to the external address.
Search, extraction, object storage
Meilisearch, Tika and Gotenberg are the three services that are new for most people. Two ways from here.
As their own Unraid containers via Community Applications: Meilisearch with MEILI_MASTER_KEY set and MEILI_ENV=production on port 7700, Tika from apache/tika:3.3.1.0-full on 9998, Gotenberg from gotenberg/gotenberg:8 on 3000. Then MEILISEARCH_HOST, TIKA_URL and GOTENBERG_URL point there. Anyone running Paperless-ngx can use its Tika and Gotenberg directly — two URLs, done.
One stumbling block on the side: Gotenberg listens on 3000 itself, and that host port is already taken by the web container. So pick a different host port for a Gotenberg container of your own.
Or into the same stack, if you'd rather not maintain them separately. Then the three services below come along and the URLs above point at the service names (http://meilisearch:7700, http://tika:9998, http://gotenberg:3000):
meilisearch:
image: getmeili/meilisearch:v1.50.0
environment:
MEILI_MASTER_KEY: your-meili-master-key
MEILI_ENV: production
MEILI_NO_ANALYTICS: "true"
volumes:
- /mnt/user/appdata/nextsearch/meili:/meili_data
restart: unless-stopped
tika:
image: apache/tika:3.3.1.0-full
restart: unless-stopped
gotenberg:
image: gotenberg/gotenberg:8.34
command:
- gotenberg
- --api-timeout=120s
- --chromium-disable-javascript=true
- --chromium-allow-list=file:///tmp/.*
restart: unless-stopped
Postgres and Redis stay outside even then — those are the two where reuse pays off most.
For object storage there is nothing to set up: NextSearch creates the bucket itself on first boot. The MinIO volume sits at …/appdata/nextsearch/minio. For a large archive it belongs on a dedicated share rather than in appdata — the blobs grow with the index, and appdata usually lives on the cache pool. Only the path changes.
If you already run a MinIO, drop the minio service along with its depends_on and point AWS_ENDPOINT at the existing instance. For real S3 (AWS, Backblaze B2, Wasabi) AWS_ENDPOINT goes away as well and AWS_USE_PATH_STYLE_ENDPOINT becomes false; the bucket has to exist beforehand there, because a restricted key usually can't create one.
First run, later updates
On first boot app runs the migrations, creates the administrator from ADMIN_EMAIL and ADMIN_PASSWORD, and sets up the Meilisearch index. The container log then reads starting all-in-one. After that, open http://YOUR_UNRAID_IP:3000, sign in, add a Nextcloud instance, run the connection test, pick a folder. Progress shows under Admin → Status.
For an update it is enough to bump the image tags in the stack and redeploy (Compose Manager → Update). The app container re-runs the migrations on start. An image swap touches neither Postgres nor object storage, and the search index rebuilds itself anyway if you ever clear it.
A note on the all-in-one role: it is meant for a single node and bootstraps on start. Exactly one app container may run against a given database. For a distributed setup, use the separate serve, worker and scheduler roles from the regular docker-compose.yml. For an Unraid box at home, all-in-one is the shorter path.
Conclusion
With this setup the effort is not in getting NextSearch up, it's in filling in the hosts that already run. Two containers, one compose stack, one key that has to stay put — after that the scheduler indexes on its own.
Call to action
The stack to copy is in docs/unraid.md, NextSearch itself at https://github.com/McGo/NextSearch.
If you want this set up for a team or a whole organisation — with your own S3, behind a reverse proxy, connected to several instances — feel free to get in touch.
