# deploy/portainer/ Portainer stack templates for Mosaic Stack deployments. ## Files | File | Purpose | | -------------------------- | -------------------------------------------------------------------------------------------------------------- | | `federated-test.stack.yml` | Docker Swarm stack for federation end-to-end test instances (`mos-test-1.woltje.com`, `mos-test-2.woltje.com`) | --- ## federated-test.stack.yml A self-contained Swarm stack that boots a federated-tier Mosaic gateway with co-located Postgres 17 (pgvector) and Valkey 8. This is a **test template** — production deployments will use a separate template with stricter resource limits and Docker secrets. ### Deploy via Portainer UI 1. Log into Portainer. 2. Navigate to **Stacks → Add stack**. 3. Set a stack name matching `STACK_NAME` below (e.g. `mos-test-1`). 4. Choose **Web editor** and paste the contents of `federated-test.stack.yml`. 5. Scroll to **Environment variables** and add each variable listed below. 6. Click **Deploy the stack**. ### Required environment variables | Variable | Example | Notes | | -------------------- | --------------------------------------- | -------------------------------------------------------- | | `STACK_NAME` | `mos-test-1` | Unique per stack — used in Traefik router/service names. | | `HOST_FQDN` | `mos-test-1.woltje.com` | Fully-qualified hostname served by this stack. | | `POSTGRES_PASSWORD` | _(generate randomly)_ | Database password. Do **not** reuse between stacks. | | `BETTER_AUTH_SECRET` | _(generate: `openssl rand -base64 32`)_ | BetterAuth session signing key. | | `BETTER_AUTH_URL` | `https://mos-test-1.woltje.com` | Public base URL of the gateway. | Optional variables (uncomment in the YAML or set in Portainer): | Variable | Notes | | ----------------------------- | ---------------------------------------------------------- | | `ANTHROPIC_API_KEY` | Enable Claude models. | | `OPENAI_API_KEY` | Enable OpenAI models. | | `OTEL_EXPORTER_OTLP_ENDPOINT` | Forward traces to a collector (e.g. `http://jaeger:4318`). | ### Required external resources Before deploying, ensure the following exist on the Swarm: 1. **`traefik-public` overlay network** — shared network Traefik uses to route traffic to stacks. ```bash docker network create --driver overlay --attachable traefik-public ``` 2. **`letsencrypt` cert resolver** — configured in the Traefik Swarm stack. The stack template references `tls.certresolver=letsencrypt`; the name must match your Traefik config. 3. **DNS A record** — `${HOST_FQDN}` must resolve to the Swarm ingress IP (or a Cloudflare-proxied address pointing there). ### Deployed instances | Stack name | HOST_FQDN | Purpose | | ------------ | ----------------------- | ---------------------------------- | | `mos-test-1` | `mos-test-1.woltje.com` | DEPLOY-03 — first federation peer | | `mos-test-2` | `mos-test-2.woltje.com` | DEPLOY-04 — second federation peer | ### Image The gateway image is pinned by digest to `fed-v0.1.0-m1` (verified in DEPLOY-01). Update the digest in the YAML when promoting a new build — never use `:latest` or a mutable tag in Swarm. ### Notes - This template boots a **vanilla M1-baseline gateway** in federated tier. Federation grants (Step-CA, mTLS) are M2+ scope and not included here. - Each stack gets its own Postgres volume (`postgres-data`) and Valkey volume (`valkey-data`) scoped to the stack name by Swarm. - `depends_on` is honoured by Compose but ignored by Swarm — healthchecks on Postgres and Valkey ensure the gateway retries until they are ready.