Add a setup guide for the Pi, and a compose file its .env selects
docs/PI.md goes from a Pi with Docker to a working claude.ai connector: configuration, the first token, Caddy, DNS, the VPS forwarding raw TCP, checks from outside, connecting the clients, the monthly token, updates, backups and troubleshooting. docker-compose.override.yml is tracked, so Compose would have merged it on the Pi as well — publishing ports and switching the crawl timer off. The Pi's .env sets COMPOSE_FILE to add deploy/docker-compose.pi.yml instead, which joins the existing Caddy network by name and builds DATABASE_URL, so nothing tracked needs editing there. Postgres moves to a private network shared only with the server. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
# Deployment
|
||||
|
||||
This page explains the moving parts and why each is there. For the steps in
|
||||
order, on the Pi, follow [PI.md](PI.md).
|
||||
|
||||
## The shape of it
|
||||
|
||||
```
|
||||
@@ -35,15 +38,11 @@ this server's bearer check.
|
||||
|
||||
## First deploy
|
||||
|
||||
[PI.md](PI.md) steps 2–5: clone to `/opt/schulcloud-mcp`, write `.env` (the Pi's
|
||||
`COMPOSE_FILE`, `CADDY_NETWORK` and `POSTGRES_PASSWORD`, generated secrets, the
|
||||
first Schulcloud token), then:
|
||||
|
||||
```bash
|
||||
git clone <this repo> /opt/schulcloud-mcp
|
||||
cd /opt/schulcloud-mcp
|
||||
|
||||
cp .env.example .env
|
||||
# Fill in TSC_URL and TSC_JWT_COOKIE (see docs/AUTH.md), then:
|
||||
openssl rand -hex 32 # → MCP_AUTH_TOKEN
|
||||
openssl rand -hex 32 # → MCP_PATH_SECRET, only for claude.ai (see "Connecting Claude")
|
||||
|
||||
docker compose up -d --build
|
||||
docker compose logs -f schulcloud-mcp
|
||||
```
|
||||
@@ -51,7 +50,7 @@ docker compose logs -f schulcloud-mcp
|
||||
Expect:
|
||||
|
||||
```
|
||||
[schulcloud-mcp] listening on 0.0.0.0:8080 — instance https://… , auth enabled, keepalive every 30min
|
||||
[schulcloud-mcp] listening on 0.0.0.0:8080 — instance https://… , auth enabled (plus secret MCP path), token from environment, 29 day(s) left, keepalive every 30min, index every 6h
|
||||
```
|
||||
|
||||
`auth DISABLED` there means `MCP_AUTH_TOKEN` is empty — fix it before exposing
|
||||
@@ -61,39 +60,29 @@ will run but every tool will fail.
|
||||
|
||||
## Joining the existing Caddy
|
||||
|
||||
The Pi already runs Caddy and PostgreSQL in a Compose project. This server needs
|
||||
neither a database nor its own Caddy — only a network it shares with the
|
||||
existing one.
|
||||
The Pi already runs Caddy in a container. This server needs no Caddy of its own
|
||||
— only to sit on the same Docker network, so Caddy reaches it by name and no
|
||||
host port is published.
|
||||
|
||||
Find the network Caddy is on:
|
||||
|
||||
```bash
|
||||
docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{$k}}{{"\n"}}{{end}}' <caddy-container>
|
||||
```
|
||||
|
||||
Then in `docker-compose.yml`, set that name and mark it external:
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
caddy:
|
||||
external: true
|
||||
name: <the network name you just found>
|
||||
```
|
||||
That is what `deploy/docker-compose.pi.yml` does, and the Pi's `.env` selects it
|
||||
with `COMPOSE_FILE=docker-compose.yml:deploy/docker-compose.pi.yml`, so plain
|
||||
`docker compose` commands pick it up and nothing tracked needs editing. It
|
||||
declares the Caddy network external under the name in `CADDY_NETWORK`. Setting
|
||||
`COMPOSE_FILE` also matters for what it leaves out: without it, Compose merges
|
||||
`docker-compose.override.yml`, which is for local development and publishes
|
||||
ports.
|
||||
|
||||
### Postgres
|
||||
|
||||
The index needs a database. On the Pi, use the existing PostgreSQL rather than
|
||||
the container in `docker-compose.yml` — create a database and user for it:
|
||||
The index gets its own Postgres container, on a network shared with this server
|
||||
and nothing else — not with Caddy, and not with whatever else is on Caddy's
|
||||
network. The Pi file builds `DATABASE_URL` from `POSTGRES_PASSWORD`. Migrations
|
||||
run at startup; the first creates `pg_trgm`.
|
||||
|
||||
```sql
|
||||
CREATE USER schulcloud WITH PASSWORD '…';
|
||||
CREATE DATABASE schulcloud OWNER schulcloud;
|
||||
```
|
||||
|
||||
Then set `DATABASE_URL` in `.env` and delete the `postgres` service from the
|
||||
compose file. Migrations run automatically at startup; `pg_trgm` is created by
|
||||
the first migration, which needs the database owner to be able to
|
||||
`CREATE EXTENSION`.
|
||||
An existing Postgres works as well: create a database and a user that owns it
|
||||
(it must be able to `CREATE EXTENSION`), point `DATABASE_URL` at it, and remove
|
||||
the `postgres` service and the `depends_on` that names it. Nothing requires
|
||||
sharing one.
|
||||
|
||||
Without `DATABASE_URL` the server still runs: search crawls live on every call
|
||||
and `/api` returns `503`. The startup log says which mode it is in.
|
||||
|
||||
Reference in New Issue
Block a user