Customizing Your Deployment
Pinchy's docker-compose.yml is owned by the Pinchy project and gets replaced whenever you upgrade. If you customize it directly, your changes disappear on the next curl -o docker-compose.yml ....
The supported customization surface is docker-compose.override.yml — a file you create in the same directory as docker-compose.yml. Docker Compose automatically merges it on top of the base file, every time you run docker compose up. Upgrades never touch it.
Recipe 1: Extra environment variables
Section titled “Recipe 1: Extra environment variables”Add debug flags or optional Pinchy variables that aren't in .env.example:
services: pinchy: environment: - DEBUG=pinchy:* - SOME_OPTIONAL_FLAG=trueCompose merges this with the base environment: block — existing variables are kept, new ones are added. For duplicate keys, the override wins. See the Docker Compose merge docs for edge cases.
Recipe 2: Expose the database for an external tool
Section titled “Recipe 2: Expose the database for an external tool”If you want to connect psql or DBeaver from the same host for debugging:
services: db: ports: - "127.0.0.1:5432:5432"Remove the override when you're done debugging.
Recipe 3: Mount additional OpenClaw extensions
Section titled “Recipe 3: Mount additional OpenClaw extensions”If you've written a custom OpenClaw plugin and want it loaded alongside the bundled Pinchy plugins:
services: openclaw: volumes: - /opt/my-extensions:/root/.openclaw/extensions/custom:roMount read-only (:ro) when possible — OpenClaw reads extensions at startup; it doesn't need write access.
What's not supported
Section titled “What's not supported”The override file is for additions, not replacements. The following are outside the supported surface and may break on any release:
- Replacing the
image:on thepinchyoropenclawservice with a different image - Renaming volumes, services, or networks
- Rewiring inter-service dependencies or health checks
- Changing the Postgres image to a non-17 version
- Pre-seeding or hand-editing
openclaw.jsonoutside Pinchy — OpenClaw 2026.5.12+ requiresgateway.auth.tokento be present at startup, and Pinchy's boot-init step seeds it from the database before OpenClaw boots. An out-of-band write collides with that seed and risks restart loops on the OpenClaw container.
If you find yourself needing any of these, open an issue — your use case might belong in core Pinchy rather than in an override.
Testing overrides
Section titled “Testing overrides”Before running docker compose up -d, check the merged config:
docker compose configThis prints the effective configuration (base + override merged) without starting anything. Use it to verify your override does what you expect.
Overrides and upgrades
Section titled “Overrides and upgrades”Your docker-compose.override.yml survives upgrades unchanged. However, if a new Pinchy release changes a base-file field you're overriding (for example, renames a volume), the merge may produce an unexpected result. Re-check docker compose config after every major release.
Resource limits and health checks
Section titled “Resource limits and health checks”Pinchy's docker-compose.yml caps memory and CPU for all three containers, and gives pinchy and db HTTP/TCP health checks so Docker can tell a wedged container from a healthy one. All six limits are overridable via .env — you never need to touch docker-compose.yml itself.
| Variable | Default | Caps |
|---|---|---|
PINCHY_MEM_LIMIT | 1g | Memory for the pinchy container (web UI, API, WebSocket bridge) |
PINCHY_CPUS | 1.5 | CPU cores for pinchy |
OPENCLAW_MEM_LIMIT | 2g | Memory for the openclaw container (agent runtime, model calls) |
OPENCLAW_CPUS | 2 | CPU cores for openclaw |
DB_MEM_LIMIT | 1g | Memory for the db container (PostgreSQL 17) |
DB_CPUS | 1 | CPU cores for db |
Why these exist
Section titled “Why these exist”Without a limit, a single runaway container — a leaking process, a model call that buffers an oversized response, a query that goes wide — can exhaust all memory on the host and take down every other container (and often the host itself) with it. mem_limit/cpus contain that failure to the one container that caused it. Combined with restart: unless-stopped (already set on all three services and not something you should change), an OOM-killed container comes back on its own instead of leaving the deployment wedged until someone notices and runs docker compose up -d by hand.
Sizing your host
Section titled “Sizing your host”The defaults add up to roughly 4 GB of memory ceiling across the three containers (1 + 2 + 1). That's a ceiling, not a reservation — containers use less at idle — but your host needs headroom above that total for the OS, Docker itself, and any reverse proxy you run alongside Pinchy. We recommend a host with meaningfully more than 4 GB, e.g. 6–8 GB or more, so the limits are a backstop rather than a wall you hit during normal operation.
If you're intentionally running on a constrained 4 GB VPS — a real scenario, not just a hypothetical — lower the limits in .env so the three containers leave the OS enough room to breathe:
# .env — tuned for a 4 GB VPSPINCHY_MEM_LIMIT=768mPINCHY_CPUS=1OPENCLAW_MEM_LIMIT=1.5gOPENCLAW_CPUS=1.5DB_MEM_LIMIT=512mDB_CPUS=0.5Health checks
Section titled “Health checks”db and pinchy each have a Docker health check: db polls pg_isready, and pinchy polls its own /api/internal/openclaw-config-ready endpoint. openclaw has a lightweight TCP liveness check — a raw connect to the gateway's WebSocket port (18789) that succeeds as soon as the gateway is accepting connections. It doesn't inspect the gateway's internal state, only that something is listening; OpenClaw's own start script already respawns the gateway process if it dies internally, so this check exists to surface a fully stuck container (process alive, port not listening). Note that Compose does not restart a container just because it is unhealthy — restart: policies act on container exit, not health status. The check is diagnostic: a stuck container shows as unhealthy in docker compose ps so you can spot it and restart it yourself, rather than it silently sitting "up" but unreachable.
You can watch health status with:
docker compose psA container stuck in unhealthy for longer than its configured retries × interval is a signal worth investigating in docker compose logs <service> before assuming a resource limit is to blame.