Ctrl K
ComunidadGuías…

deploy/self-hosted/README.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Self-hosted deployment assets

This directory is reserved for versioned minddy self-hosting assets. It belongs
to the public main repository; no second deployment repository is part of the
supported distribution.

## Reference Compose profiles

Both profiles use the release-pinned images recorded in `compatibility.json`.
Copy `.env.example` to a protected `.env`, replace every placeholder, and use
the tagged release directory rather than a development checkout. The guided
file deliberately contains only deployment settings; use the root
[`../../.env.example`](../../.env.example) for an exhaustive list of optional
application integrations.

For the normal first installation, prefer `pnpm self-host:install`. It makes
the same configuration explicit, refuses to replace an existing environment
file, and then starts the profile and bootstrap. Run `pnpm self-host:doctor`
afterward for a redacted health and configuration report. The manual commands
below remain the advanced/operator-controlled path.

### Managed Supabase

Use `compose.managed.yml` when the operator already has a compatible managed or
self-hosted Supabase project. It starts minddy and Caddy; it never starts,
copies, or changes Supabase services.

```bash
export MINDDY_DEPLOY_DIR=/srv/minddy/release/deploy/self-hosted
cp "$MINDDY_DEPLOY_DIR/.env.example" "$MINDDY_DEPLOY_DIR/.env"
chmod 600 "$MINDDY_DEPLOY_DIR/.env"
# Edit $MINDDY_DEPLOY_DIR/.env, including the Supabase Cloud URL and keys.
docker compose --env-file "$MINDDY_DEPLOY_DIR/.env" \
  -f "$MINDDY_DEPLOY_DIR/compose.managed.yml" up -d
```

The same command starts the scheduler, which drives Numo turns and routines.
No additional profile, desktop app, or external execution account is required.
Numo does not run code, so neither profile contains a container runner or
mounts the Docker socket.

### Official Supabase stack

Use `compose.full.yml` only with the upstream revision recorded in the matching
compatibility row. `scripts/fetch-official-supabase.mjs` creates an isolated
upstream checkout at the pinned commit. It refuses a non-empty target and
verifies both upstream files before Compose reads them. That checkout is an
operator-owned input, not a copy maintained in this repository.

```bash
export MINDDY_RELEASE_DIR=/srv/minddy/release
export MINDDY_DEPLOY_DIR="$MINDDY_RELEASE_DIR/deploy/self-hosted"
export MINDDY_SUPABASE_DIR=/srv/minddy/supabase
node "$MINDDY_RELEASE_DIR/scripts/fetch-official-supabase.mjs" \
  --destination "$MINDDY_SUPABASE_DIR"
cp "$MINDDY_DEPLOY_DIR/.env.example" "$MINDDY_DEPLOY_DIR/.env"
chmod 600 "$MINDDY_DEPLOY_DIR/.env"
# Configure the upstream Docker environment and minddy variables in this file.
docker compose --env-file "$MINDDY_DEPLOY_DIR/.env" \
  -f "$MINDDY_SUPABASE_DIR/docker/docker-compose.yml" \
  -f "$MINDDY_DEPLOY_DIR/compose.full.yml" up -d
```

The full profile removes every upstream public host port, including the API
gateway and Supavisor. Caddy is the only public service. PostgreSQL binds only to the host
loopback on `MINDDY_POSTGRES_BIND_PORT` for bootstrap and maintenance. Upstream
PostgreSQL and Storage paths remain persistent exactly as defined by the
official distribution; Caddy
uses the named `caddy_data` and `caddy_config` volumes for certificates and
state. Do not change individual upstream service images or make local edits in
`$MINDDY_SUPABASE_DIR`; fetch the next matrix-pinned revision during an upgrade.

## TLS and network boundary

For a public deployment, set `MINDDY_HOST` and `MINDDY_SITE_ADDRESS` to the DNS
hostname and provide `CADDY_EMAIL`. Caddy then obtains and renews certificates
automatically. Ensure ports 80 and 443 reach the host and DNS resolves before
starting the profile. For a pre-existing TLS load balancer, bind Caddy to loopback with
`MINDDY_HTTP_BIND_ADDRESS=127.0.0.1` and configure that balancer to proxy to it.

Both profiles support a server confined to a trusted private network. Set
`MINDDY_HOST` to its private IPv4 address and
`MINDDY_SITE_ADDRESS=http://<private-ip>`. For the complete profile, also set
`SUPABASE_SITE_ADDRESS=http://<private-ip>:8000` and
`MINDDY_SUPABASE_HTTP_BIND_ADDRESS=0.0.0.0`. Restrict ports 80 and 8000 to the
LAN, keep router ports 80, 443, and 8000 closed, and never expose this HTTP mode
to the internet.

For public HTTPS, the complete profile also requires `SUPABASE_HOST`; Caddy
terminates TLS for it and sends API traffic to the upstream `api-gw` service. For a
private full stack, the installer derives the Supabase API address from the
server IP and uses port 8000. PostgreSQL, Supavisor, and all other internal
service ports are never published by the reference profile.

## Scheduled jobs and checks

`scheduler.mjs` mirrors the schedules in [`../../vercel.json`](../../vercel.json)
and sends authenticated requests only to the internal `minddy` service.
`CRON_SECRET` is generated by the installer and the scheduler starts by default.

Releases up to v0.11.0 also shipped an `agent-runner` service. It no longer
exists: when upgrading, start the profile with `--remove-orphans` so Compose
deletes the retired container, and remove `AGENT_EXECUTION_BACKEND`,
`AGENT_RUNNER_URL`, `AGENT_RUNNER_SECRET`, and `AGENT_CONTROL_ORIGIN` from the
protected environment. The application joins the `app_egress` network for
outbound Supabase, AI provider, and forge traffic.

Run the versioned validation before an operator smoke test:

```bash
node "$MINDDY_RELEASE_DIR/scripts/validate-self-hosted-compose.mjs"
```

It renders both Compose profiles with safe disposable values and confirms that
the pinned Caddy and scheduler images include `linux/amd64` and `linux/arm64`.
For a live smoke test, use a disposable Supabase project and a disposable DNS
name. The command starts a fresh profile, waits for health checks, proves Caddy
serves the app and redirects HTTP to HTTPS, restarts the application and proxy,
and starts scheduled jobs:

```bash
node -- "$MINDDY_RELEASE_DIR/scripts/smoke-self-hosted-compose.mjs" \
  --profile managed \
  --env-file "$MINDDY_DEPLOY_DIR/.env" \
  --public-url "https://tickets.example.test"
```

After creating a project and attachment, pass an authenticated, stable read URL
with `--persistence-url` to compare its response before and after the restart.
Inspect `docker compose logs scheduler` after the next schedule boundary for the
expected endpoint calls. Record the TLS certificate issuer and the preserved
project and attachment before declaring a public instance ready.