VPS Deployment
This guide walks you through deploying Pinchy on a fresh Linux VPS. It has been tested on Ubuntu 24.04, but any Linux distribution with Docker support will work.
If you’re coming from a provider-specific guide (Hetzner, DigitalOcean), you should already be connected to your server via SSH. All commands below run on the server, not on your local machine.
Requirements
Section titled “Requirements”| Resource | Minimum | Recommended |
|---|---|---|
| RAM | 4 GB | 8 GB |
| CPU | 2 vCPUs | 4 vCPUs |
| Disk | 20 GB | 40 GB |
| OS | Ubuntu 22.04+ | Ubuntu 24.04 |
You also need:
- A domain name pointing to your server’s IP address (for HTTPS)
- An LLM provider API key (Anthropic, OpenAI, or Google)
What gets deployed
Section titled “What gets deployed”Pinchy runs as three Docker containers:
| Container | Role |
|---|---|
| pinchy | Web UI, REST API, and WebSocket bridge. This is what users interact with. |
| openclaw | The AI agent runtime — manages agents, sessions, plugins, and model calls. Only reachable internally. |
| db | PostgreSQL 17 database. Stores users, agents, settings, and audit logs. Only reachable internally. |
All three start together via Docker Compose. Only the pinchy container publishes a port; the other two communicate over an internal Docker network.
Deploy Pinchy
Section titled “Deploy Pinchy”-
Install Docker
If Docker is not already installed on your server:
Terminal window apt-get updateapt-get install -y docker.io docker-compose-v2Verify the installation:
Terminal window docker --version # Should show: Docker version 24+docker compose version # Should show: Docker Compose version v2+For non-Ubuntu distributions, follow the official Docker installation guide.
What do these commands do?
-apt-get update— refreshes the list of available software packages -apt-get install -y— installs the listed packages (-ymeans “yes, don’t ask for confirmation”): -docker.io— Docker Engine, the tool that runs containers -docker-compose-v2— Docker Compose, which starts multiple containers together -
Download the Docker Compose file
Terminal window mkdir -p /opt/pinchycurl -fsSL https://raw.githubusercontent.com/heypinchy/pinchy/v0.5.4/docker-compose.yml -o /opt/pinchy/docker-compose.yml -
Pin your secrets before first start
Pinchy uses three secrets:
Secret Purpose DB_PASSWORDPostgreSQL database password BETTER_AUTH_SECRETSigns user sessions ENCRYPTION_KEYEncrypts LLM provider API keys at rest (AES-256-GCM) If you don’t set them, Pinchy auto-generates
BETTER_AUTH_SECRETandENCRYPTION_KEYand persists them as files in a Docker volume (pinchy-secrets). This works fine for normal operation — but if that volume is ever deleted (e.g. during a server migration or an accidentaldocker compose down -v), the generated secrets are lost and encrypted data becomes unreadable.DB_PASSWORDdefaults to a weak development value.For production, pin all three explicitly:
Terminal window nano /opt/pinchy/.envAdd these lines (run
openssl rand -hex 32three times to generate each value):Terminal window DB_PASSWORD=<output of openssl rand -hex 32>BETTER_AUTH_SECRET=<output of openssl rand -hex 32>ENCRYPTION_KEY=<output of openssl rand -hex 32>Save and lock down the file:
Terminal window chmod 600 /opt/pinchy/.env -
Pull and start Pinchy
Terminal window cd /opt/pinchydocker compose pulldocker compose up -dPulling the pre-built images takes about 30 seconds.
What do these commands do?
-docker compose pull— downloads the pre-built Pinchy images -docker compose up -d— starts all services in the background -
Verify all services are running
Terminal window docker compose psYou should see three services —
pinchy,openclaw, anddb— all with status Up or healthy.Check the Pinchy logs to make sure everything started correctly:
Terminal window docker compose logs pinchyLook for:
Pinchy ready on http://localhost:7777 -
Open the setup wizard
Pinchy binds to
127.0.0.1:7777by default so it is only reachable from localhost. Open a temporary SSH tunnel from your local machine to reach it:Terminal window ssh -L 7777:localhost:7777 root@<your-server-ip>Then visit
http://localhost:7777in your browser while that SSH session is open.The setup wizard will guide you through creating your admin account and configuring your first LLM provider. You’ll need your API key (from Anthropic, OpenAI, or Google) ready.
That’s it — Pinchy is running! The rest of this guide covers production hardening, which you should do before using Pinchy with real data.
Production setup
Section titled “Production setup”The steps above get Pinchy working, but for production use you should add HTTPS, a firewall, and a domain lock.
Set up HTTPS with Caddy
Section titled “Set up HTTPS with Caddy”Use a reverse proxy that handles HTTPS for you. We recommend Caddy because it automatically gets and renews SSL certificates — zero configuration.
Pinchy already binds to 127.0.0.1:7777 by default — only reachable from localhost. This is exactly what you want when Caddy sits in front of it. No port configuration needed.
Install Caddy:
apt-get install -y caddyEdit the Caddy configuration file:
nano /etc/caddy/CaddyfileReplace the contents with (use your actual domain):
pinchy.example.com { reverse_proxy localhost:7777}Save the file (Ctrl+O, Enter, Ctrl+X in nano) and restart Caddy:
systemctl restart caddyCaddy automatically provisions Let’s Encrypt certificates for your domain. After a few seconds, visit https://pinchy.example.com — you should see Pinchy with a valid HTTPS certificate.
What’s a reverse proxy and why do I need one?
A reverse proxy sits between the internet and Pinchy. When someone visits your domain:
- Their browser connects to Caddy on port 443 (HTTPS)
- Caddy handles the SSL certificate and encryption
- Caddy forwards the request to Pinchy on port 7777 (internal only)
- Pinchy sends the response back through Caddy
This way, Pinchy never needs to deal with SSL certificates directly.
See the Hardening Guide for nginx examples and advanced configuration.
Lock your domain
Section titled “Lock your domain”Once HTTPS is working, lock Pinchy to your domain so it only responds to requests on that exact hostname. This enables secure cookies, HSTS, and origin checks as a package. See the HTTPS & Domain Lock guide for the full walkthrough — in short: open Settings → Security and click Lock to this domain.
Configure a firewall
Section titled “Configure a firewall”A firewall controls which network ports are accessible from the internet. Lock down your server to only the ports you need:
ufw allow OpenSSHufw allow 80/tcpufw allow 443/tcpufw enableType y when asked to confirm. This allows:
- SSH (port 22) — so you can still log in to your server
- HTTP (port 80) — needed for Caddy’s certificate renewal
- HTTPS (port 443) — how users access Pinchy
Everything else is blocked — including port 7777, which is now only reachable by Caddy on the same machine.
Enable automatic security updates
Section titled “Enable automatic security updates”Keep the host OS patched without manual intervention:
apt-get install -y unattended-upgradesdpkg-reconfigure -plow unattended-upgradesSelect Yes when prompted. Ubuntu will now install security updates automatically and reboot overnight when a kernel update requires it.
See the Hardening Guide for further production hardening — Docker security options, network isolation, disk encryption, monitoring, and backup automation.
Add swap (recommended for 4 GB servers)
Section titled “Add swap (recommended for 4 GB servers)”Swap is disk space that your server can use as extra memory when RAM runs low. On servers with only 4 GB RAM, adding swap provides a safety net during heavy agent workloads:
fallocate -l 2G /swapfilechmod 600 /swapfilemkswap /swapfileswapon /swapfileecho '/swapfile none swap sw 0 0' >> /etc/fstabThe last line ensures swap is re-enabled after a server reboot.
Updating Pinchy
Section titled “Updating Pinchy”cd /opt/pinchydocker compose exec db pg_dump -U pinchy pinchy > backup-$(date +%Y%m%d).sqlcurl -fsSL https://raw.githubusercontent.com/heypinchy/pinchy/v0.5.4/docker-compose.yml -o docker-compose.ymldocker compose pulldocker compose up -ddocker image prune -fPinchy runs database migrations automatically on startup — no manual steps needed. docker image prune -f after up -d removes the previous image layer left dangling by pull; without it, a long-running deployment slowly fills its root volume with <none>:<none> layers from prior upgrades. See the Upgrade Guide for version-specific notes, rollback instructions, when to escalate to docker image prune -a -f, and how to set up automated backups.
Troubleshooting
Section titled “Troubleshooting”Checking logs
Section titled “Checking logs”Docker Compose makes logs easy to access:
# All servicesdocker compose logs -f
# Single service (pinchy, openclaw, or db)docker compose logs pinchy --tail 100
# Filter for errorsdocker compose logs pinchy 2>&1 | grep -i errorPinchy container exits immediately
Section titled “Pinchy container exits immediately”Check the logs:
docker compose logs pinchyCommon causes:
- Database not ready — wait a few seconds, the container will auto-restart
- Port already in use — check with
ss -tlnp | grep 7777
WebSocket connection errors in the browser
Section titled “WebSocket connection errors in the browser”If you’re behind a reverse proxy, make sure it supports WebSocket upgrades. For nginx, add:
proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";Caddy handles WebSocket upgrades automatically.
Agent doesn’t respond
Section titled “Agent doesn’t respond”Check if the OpenClaw container is running:
docker compose ps openclawdocker compose logs openclaw --tail 50Common causes:
- No LLM provider configured — open Settings and add an API key
- API key invalid or out of credits — the chat shows a specific error card with details