113 lines
3 KiB
Markdown
113 lines
3 KiB
Markdown
# Coolify — Shared services (Meilisearch + Dragonfly + Imgproxy)
|
||
|
||
These are stateless or namespaceable — one instance can serve all your projects. Saves RAM.
|
||
|
||
## Meilisearch
|
||
|
||
Coolify → + New Service → Database → **Meilisearch**.
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Project name | `meilisearch-shared` |
|
||
| Domain | `search.disclosure.top` |
|
||
| Master key | (generate; copy for `MEILI_MASTER_KEY` env in web app) |
|
||
| Resource limits | 1 CPU, 1 GB RAM |
|
||
|
||
Each project uses different index names: `disclosure_pages`, `disclosure_entities`, `projeto_b_xxx` — no cross-talk.
|
||
|
||
After deploy, in the web app env vars:
|
||
```env
|
||
MEILISEARCH_URL=https://search.disclosure.top
|
||
MEILISEARCH_API_KEY=<master-key>
|
||
```
|
||
|
||
The web app will create + populate indexes on first deploy (see `web/scripts/seed-meili.ts`).
|
||
|
||
## Dragonfly
|
||
|
||
Redis-compatible, drop-in, 25× faster than Redis. Coolify has no template, use a custom Docker Compose service:
|
||
|
||
```yaml
|
||
# In Coolify → + New Resource → Service → Custom Docker Compose
|
||
services:
|
||
dragonfly:
|
||
image: docker.dragonflydb.io/dragonflydb/dragonfly:latest
|
||
restart: unless-stopped
|
||
ulimits:
|
||
memlock: -1
|
||
ports:
|
||
- "6379:6379"
|
||
volumes:
|
||
- dragonfly-data:/data
|
||
command: ["--logtostderr", "--cache_mode=true", "--maxmemory=512mb"]
|
||
mem_limit: 600m
|
||
volumes:
|
||
dragonfly-data:
|
||
```
|
||
|
||
Web app env:
|
||
```env
|
||
REDIS_URL=redis://dragonfly:6379
|
||
```
|
||
|
||
(Coolify networks the services internally; you reach `dragonfly:6379` from inside the network.)
|
||
|
||
## Imgproxy
|
||
|
||
Stateless image resizer:
|
||
|
||
```yaml
|
||
services:
|
||
imgproxy:
|
||
image: ghcr.io/imgproxy/imgproxy:latest
|
||
restart: unless-stopped
|
||
environment:
|
||
IMGPROXY_KEY: ${IMGPROXY_KEY}
|
||
IMGPROXY_SALT: ${IMGPROXY_SALT}
|
||
IMGPROXY_USE_ETAG: "true"
|
||
IMGPROXY_TTL: "31536000"
|
||
IMGPROXY_MAX_SRC_RESOLUTION: "50"
|
||
IMGPROXY_ENABLE_WEBP_DETECTION: "true"
|
||
IMGPROXY_LOCAL_FILESYSTEM_ROOT: "/data"
|
||
volumes:
|
||
- /data/ufo/processing:/data:ro
|
||
ports:
|
||
- "8080:8080"
|
||
mem_limit: 256m
|
||
```
|
||
|
||
Generate `IMGPROXY_KEY` and `IMGPROXY_SALT`:
|
||
```bash
|
||
openssl rand -hex 64 # → key
|
||
openssl rand -hex 64 # → salt
|
||
```
|
||
|
||
Add subdomain `img.disclosure.top` → :8080.
|
||
|
||
Web app uses signed URLs like:
|
||
```
|
||
https://img.disclosure.top/<signature>/rs:fit:800:0/plain/local:///png/doc-x/p-001.png
|
||
```
|
||
|
||
The `web/lib/imgproxy.ts` helper generates these signatures.
|
||
|
||
## Backups (restic + Backblaze B2)
|
||
|
||
Optional but strongly recommended. Coolify has a built-in backup feature per service:
|
||
|
||
1. Each Supabase project's stack → **Backups** → set schedule (e.g., `0 3 * * *` daily 3am).
|
||
2. Destination: configure B2 bucket in Coolify Settings → Backups (one-time setup).
|
||
|
||
Restic runs encrypted, deduplicated. ~$0.005/GB/mo on B2.
|
||
|
||
## Done
|
||
|
||
Stack complete:
|
||
- `disclosure.top` (Next.js)
|
||
- `db.disclosure.top` (Supabase Kong)
|
||
- `studio.disclosure.top` (Supabase Studio)
|
||
- `search.disclosure.top` (Meilisearch)
|
||
- `img.disclosure.top` (Imgproxy)
|
||
- `coolify.disclosure.top` (Coolify panel)
|
||
|
||
Total RAM in production: ~5-6 GB. Plenty of room for 2-3 more projects.
|