Track HiveGrid Cloud planning reference

This commit is contained in:
david committed 2026-06-26 20:48:01 +02:00
1 parent b3d5ea6764
commit e341c5938a
5784 files changed
+1104929 -3

No files matched your search

+141
View File
@@ -0,0 +1,141 @@
# Deploying Meilisearch
This document covers production deployment of the Meilisearch service that
backs `packages/search` and the `search-indexer` worker job. Local
development uses the bundled docker-compose service — see
`docker-compose.yml` and `docs/features/search.md` for the application-side
contract.
## Requirements
- Disk: 1–10 GiB per million indexed documents, SSD strongly recommended.
- Memory: 1 GiB minimum; allocate ~30 % of the dataset size for hot reads.
- Network: reachable only from `apps/web`, `apps/api` and the
`worker-general` service. **Never** expose port 7700 to the public
internet. The master key is the only auth boundary; if the port is open,
the index is open.
- TLS: terminate at the platform's ingress / load balancer; Meilisearch
itself does not speak TLS.
## Environment Variables
| Variable | Required | Purpose |
| --- | --- | --- |
| `MEILI_URL` | yes | URL the search wrapper and worker dial. Internal DNS only (e.g. `http://meilisearch.internal:7700`). |
| `MEILI_MASTER_KEY` | yes | Server-side secret. Min 32 bytes of entropy. Rotate via blue/green; never log. |
| `MEILI_ENV` | yes | `production` in production. Disables the unauthenticated dashboard. |
| `MEILI_NO_ANALYTICS` | recommended | Set to `true` to disable upstream telemetry. |
## Coolify (Hetzner) — recommended for the staging stack
Coolify ships a "custom docker-compose" service type that maps 1:1 onto
the local layout. Paste the snippet below into the project's
docker-compose override (Coolify → Service → Configuration → Compose).
```yaml
services:
meilisearch:
image: getmeili/meilisearch:v1.8
environment:
- MEILI_MASTER_KEY=${MEILI_MASTER_KEY}
- MEILI_ENV=production
- MEILI_NO_ANALYTICS=true
volumes:
- meilisearch-data:/meili_data
healthcheck:
test: ["CMD-SHELL", "wget -q -O - http://127.0.0.1:7700/health | grep -q 'available'"]
interval: 10s
timeout: 5s
retries: 6
start_period: 15s
restart: unless-stopped
networks:
- backend
volumes:
meilisearch-data:
networks:
backend:
external: true
```
Operator steps:
1. Set `MEILI_MASTER_KEY` as a Coolify "secret" (Project → Variables →
"Encrypt"). Length ≥ 32 bytes; generate with `openssl rand -hex 32`.
2. Set `MEILI_URL=http://meilisearch:7700` on `apps/web`, `apps/api` and
the `worker-general` service so they resolve via the internal Docker
network. Do **not** map the port to the host.
3. Add a backup cron that snapshots the `meilisearch-data` volume:
```bash
# /etc/cron.daily/meilisearch-snapshot
docker exec meilisearch \
curl -X POST -H "Authorization: Bearer $MEILI_MASTER_KEY" \
http://127.0.0.1:7700/snapshots
```
4. Verify `/health` is `available` after deploy; the worker logs
`meilisearch.connected` on cold start.
## Dedizierte VM — alternative (Hetzner Cloud)
For traffic spikes that outgrow the central Coolify host, run Meilisearch on
a dedicated Hetzner Cloud VM (e.g. CX22) with a 10 GB volume:
```bash
# Hetzner: attach a 10 GB volume and mount at /meili_data
ssh root@<instance> docker run -d --name meilisearch \
--restart unless-stopped \
-p 7700:7700 \
-v /meili_data:/meili_data \
-e MEILI_MASTER_KEY="$(cat /etc/meilisearch/master-key)" \
-e MEILI_ENV=production \
-e MEILI_NO_ANALYTICS=true \
getmeili/meilisearch:v1.8
```
Front the instance with a private network; never expose
port 7700 to the public internet. Apps reach it via the private DNS name
configured in the `MEILI_URL` env.
## Master-Key Rotation
1. Generate a new key: `openssl rand -hex 32`.
2. Set the new key as `MEILI_MASTER_KEY_NEW` in the secret store.
3. Bring up a parallel Meilisearch container with the new key; replicate
indexes via the snapshot/restore endpoint:
```bash
curl -X POST -H "Authorization: Bearer $OLD_KEY" \
"$OLD_MEILI/snapshots"
# copy the snapshot file, start new container pointing at it
```
4. Flip `MEILI_URL` on the apps to point at the new container.
5. Decommission the old container; rotate the secret-store key (move
`MEILI_MASTER_KEY_NEW` to `MEILI_MASTER_KEY`).
The wrapper's transparent SQL-LIKE fallback (`searchWithFallback`) keeps
search degraded-but-up during the cutover.
## Disaster Recovery
The Postgres database remains the source of truth. To rebuild Meilisearch
from scratch:
```bash
pnpm cli search reindex --tenant=all --index=all
```
This writes `search.index.<entity>.bulkreindex` outbox events only for the
currently supported bulk-reindex set. Today `--index=all` expands to KB
articles, CRM contacts, rows, and users. Entities are rejected until their
tenant-scoped projection has an explicit pager design. The `search-indexer` job
consumes the accepted events and pages over Postgres in 1000-row chunks.
Expected throughput: ~10 k documents per minute per worker replica.
## Backup Retention
Snapshots are full copies of the data directory. Retain at least 7 daily
snapshots offsite (S3 / Backblaze). The volume itself is also covered by
the platform's nightly volume backup if you keep that enabled.