# 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.
