diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 720fa3f..156af2d 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -44,5 +44,10 @@ jobs: - name: Install API dependencies into .venv run: ./.venv/bin/python -m pip install --upgrade pip && ./.venv/bin/pip install -r api/requirements.txt + - name: Validate shared-edge compose overlay + run: | + cp .env.example .env + docker compose -f docker-compose.yml -f docker-compose.public-edge.yml config --quiet + - name: Run repo checks run: ./scripts/check.sh diff --git a/README.md b/README.md index a9259a2..4c0a76e 100644 --- a/README.md +++ b/README.md @@ -175,6 +175,21 @@ APP_HTTPS_PUBLISH=127.0.0.1:18443 Then point the existing host reverse proxy at `http://127.0.0.1:18080`. +If the existing ingress is another Compose-managed container on the same host, +use the optional shared-edge overlay instead of routing through a published host +port. Create the external network once, then start Memory Engine with both files: + +```bash +docker network create public_edge +docker compose -f docker-compose.yml -f docker-compose.public-edge.yml up --build -d +``` + +The overlay attaches only the Memory Engine Caddy proxy to `public_edge` with +the stable alias `memory_engine_proxy`. The API, database, Redis, and MinIO stay +on the private default network. Configure the outer ingress to proxy the public +Memory Engine hostname to `memory_engine_proxy:80`; the outer ingress remains +the sole public TLS terminator. + The fastest path on a fresh server is the deploy script: ```bash @@ -497,6 +512,7 @@ If you want faster/stronger change, raise epsilon to `0.005–0.01`. ## Directory map - `docker-compose.yml` — full local node stack +- `docker-compose.public-edge.yml` — optional shared-network attachment for a co-hosted container ingress - `docs/maintenance.md` — deployment, status, backup, restore, and troubleshooting runbook - `docs/UBUNTU_APPLIANCE.md` — reference `Ubuntu Server 24.04.4 LTS` host recipe - `docs/how-the-stack-works.md` — architecture, request flows, playback model, storage, and testing notes diff --git a/docker-compose.public-edge.yml b/docker-compose.public-edge.yml new file mode 100644 index 0000000..ee24253 --- /dev/null +++ b/docker-compose.public-edge.yml @@ -0,0 +1,12 @@ +services: + proxy: + networks: + default: + public_edge: + aliases: + - memory_engine_proxy + +networks: + public_edge: + name: public_edge + external: true diff --git a/docs/maintenance.md b/docs/maintenance.md index 2fe1de9..b575a87 100644 --- a/docs/maintenance.md +++ b/docs/maintenance.md @@ -468,6 +468,49 @@ Then route the public hostname or path from the server's existing reverse proxy to `http://127.0.0.1:18080`. Keep the default MinIO compose service private unless you need the console briefly for inspection. +### Containerized ingress on a shared Docker network + +When the server's public ingress also runs in Docker, prefer the tracked +`docker-compose.public-edge.yml` overlay over a host-loopback hop. Create the +external bridge once: + +```bash +docker network inspect public_edge >/dev/null 2>&1 || docker network create public_edge +``` + +Start or recreate the Memory Engine proxy with the overlay: + +```bash +docker compose \ + -f docker-compose.yml \ + -f docker-compose.public-edge.yml \ + up -d --build proxy +``` + +The overlay keeps `proxy` on the private default network so it can reach +`api:8000`, and also attaches it to `public_edge` as +`memory_engine_proxy`. No application or storage service joins the shared +network. The outer ingress should terminate public TLS and reverse proxy over +plain HTTP to `memory_engine_proxy:80`; do not expose the API directly or run a +second public TLS hop between the two proxies. + +Verify the network boundary and upstream response before enabling the public +hostname: + +```bash +docker network inspect public_edge \ + --format '{{range $id, $container := .Containers}}{{println $container.Name}}{{end}}' + +docker exec getent hosts memory_engine_proxy +docker exec \ + wget -qO- --header='Host: memory.example.com' \ + http://memory_engine_proxy/healthz +``` + +The network membership should include the Memory Engine proxy and the outer +ingress only. The health request should return the normal Memory Engine JSON +payload through its own Caddy proxy. + If a failed start already left containers or networks in a partial state, clean up just this compose project and start it again: