Track HiveGrid Cloud planning reference
This commit is contained in:
1 parent
b3d5ea6764
commit
e341c5938a
5784 files changed
+1104929
-3
No files matched your search
@@ -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.
|
||||
Reference in new issue
Block a user