Skip to content

Deploy Pinchy on DigitalOcean

DigitalOcean is a solid choice for running Pinchy — straightforward interface, predictable pricing, and data centers on multiple continents. If your team is distributed or you want to keep your AI agents close to your users, DigitalOcean’s global footprint makes that easy.

Why DigitalOcean for self-hosted AI agents?

Section titled “Why DigitalOcean for self-hosted AI agents?”
  • Global data centers — New York, San Francisco, London, Amsterdam, Frankfurt, Singapore, Bangalore, Sydney, and more. Pick the region closest to your team.
  • Simple pricing — A Droplet with 4 GB RAM starts at around $24/month with predictable costs.
  • Team accounts — Built-in team management for sharing infrastructure access.
  • A DigitalOcean account (free to create, pay-as-you-go)
  • A domain name (optional for testing, required for production HTTPS)
  • An LLM provider API key (Anthropic, OpenAI, or Google) — you’ll enter this in Pinchy’s setup wizard

A “Droplet” is DigitalOcean’s name for a virtual server.

  1. Log in to the DigitalOcean Control Panel

    Click Create → Droplets.

  2. Choose a region

    Pick the datacenter closest to you or your users. Pinchy works in any region.

  3. Choose an image

    Select Ubuntu and keep the default version (24.04 LTS x64).

  4. Choose a size

    Under Droplet Type, keep Basic (Shared CPU). Under CPU options, Regular (SSD) is fine. Pick the $24/mo plan (4 GB RAM, 2 CPUs).

  5. Choose authentication

    Select SSH Key or Password. Either works for the automated setup below — you’ll need SSH access later for production hardening.

  6. Paste the setup script

    Expand Advanced Options and check Add Initialization scripts (free). Paste the following script into the text field. It automatically installs Docker, deploys Pinchy, sets up a firewall, and adds swap.

    cloud-init.yml
    #cloud-config
    # Pinchy v0.5.4 — Automated VPS Setup
    # https://docs.heypinchy.com/guides/vps-deployment/
    #
    # This cloud-init script installs Caddy (reverse proxy), Docker, and Pinchy,
    # configures a firewall, and adds swap. Paste it into the "User Data" field
    # when creating your server.
    #
    # After boot, visit http://<your-server-ip>. Caddy shows a loading page while
    # images are pulling, then seamlessly hands off to Pinchy — no refresh needed.
    # To enable HTTPS later, replace `:80` in /etc/caddy/Caddyfile with your domain
    # and run `systemctl reload caddy` — Let's Encrypt is automatic.
    runcmd:
    # Add Caddy's official Cloudsmith apt repository (GPG-verified)
    - apt-get update -qq
    - apt-get install -y -qq debian-keyring debian-archive-keyring apt-transport-https curl gpg
    - curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
    - curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
    - apt-get update -qq
    # Stage loading page for Caddy's fallback upstream
    - mkdir -p /var/www/pinchy-loading
    - curl -fsSL https://github.com/heypinchy/pinchy/releases/download/v0.5.4/installing.html -o /var/www/pinchy-loading/index.html
    - sed -i "s/INSTALL_START_TIME/$(date +%s)000/" /var/www/pinchy-loading/index.html
    # Write Caddyfile BEFORE installing caddy, so Caddy's first start uses our config
    - mkdir -p /etc/caddy
    - |
    cat > /etc/caddy/Caddyfile <<'EOF'
    # Pinchy reverse proxy
    # Primary upstream: Pinchy on 127.0.0.1:7777
    # Fallback upstream: local loading page on 127.0.0.1:9999
    #
    # lb_policy first → prefer primary; fall back only when primary is unreachable.
    # lb_try_duration 1s → fail fast so users never wait for a dead backend.
    # fail_duration 5s → mark unreachable backend as dead for 5s before retry.
    #
    # To enable HTTPS: replace `:80` with your domain (e.g. pinchy.example.com)
    # and run `systemctl reload caddy`. Caddy provisions Let's Encrypt automatically.
    :80 {
    reverse_proxy 127.0.0.1:7777 127.0.0.1:9999 {
    lb_policy first
    lb_try_duration 1s
    fail_duration 5s
    }
    }
    :9999 {
    bind 127.0.0.1
    handle /api/* {
    respond 503
    }
    handle {
    root * /var/www/pinchy-loading
    try_files /index.html
    file_server
    }
    }
    EOF
    # Install Caddy, Docker, and UFW in one apt call (Caddy starts with our Caddyfile).
    # --force-confold keeps our pre-staged /etc/caddy/Caddyfile without dpkg's
    # interactive conffile prompt, which would otherwise fail cloud-init (no stdin)
    # and leave the caddy package in iU state (postinst skipped, `caddy` user never
    # created, systemd start fails with exit 217/USER).
    - DEBIAN_FRONTEND=noninteractive apt-get install -y -qq -o Dpkg::Options::=--force-confold caddy docker.io docker-compose-v2 ufw
    - systemctl enable --now caddy
    - systemctl reload caddy
    # Firewall
    - ufw allow OpenSSH
    - ufw allow 80/tcp
    - ufw allow 443/tcp
    - ufw --force enable
    # Docker
    - systemctl enable docker
    - systemctl start docker
    # Swap (recommended for 4 GB servers)
    - fallocate -l 2G /swapfile
    - chmod 600 /swapfile
    - mkswap /swapfile
    - swapon /swapfile
    - echo '/swapfile none swap sw 0 0' >> /etc/fstab
    # Generate pinned secrets — Pinchy keeps its secure 127.0.0.1:7777 default,
    # reachable only via Caddy on the same host.
    - mkdir -p /opt/pinchy
    - echo "PINCHY_VERSION=v0.5.4" >> /opt/pinchy/.env
    - echo "DB_PASSWORD=$(openssl rand -hex 32)" >> /opt/pinchy/.env
    - echo "BETTER_AUTH_SECRET=$(openssl rand -hex 32)" >> /opt/pinchy/.env
    - echo "ENCRYPTION_KEY=$(openssl rand -hex 32)" >> /opt/pinchy/.env
    - chmod 600 /opt/pinchy/.env
    # Download compose file and pull images (Caddy serves loading page throughout)
    - curl -fsSL https://raw.githubusercontent.com/heypinchy/pinchy/v0.5.4/docker-compose.yml -o /opt/pinchy/docker-compose.yml
    - cd /opt/pinchy && docker compose pull
    # Start Pinchy — Caddy automatically swaps to the primary upstream within 5s
    - cd /opt/pinchy && docker compose up -d
    # Wait for Pinchy to be healthy (polled directly, not through Caddy)
    - for i in $(seq 1 120); do curl -sf http://127.0.0.1:7777/api/health > /dev/null 2>&1 && break; sleep 2; done
  7. Set the hostname and create the Droplet

    Under Finalize Details, change the hostname to pinchy (or whatever you prefer) and click Create Droplet. It’ll be ready in about 30 seconds, but the setup script needs another 1-2 minutes to pull the Pinchy images.

  8. Note the IP address

    The Droplet’s IPv4 address appears on the dashboard (e.g., 164.90.x.x).

  9. Open Pinchy

    Visit http://<your-droplet-ip> in your browser. You’ll see a loading page that tracks the installation progress. Once the images are pulled (typically 1-2 minutes), it automatically redirects to the Pinchy setup wizard.

    The setup wizard will guide you through creating your admin account and configuring your first LLM provider.

The steps above get Pinchy running over plain HTTP. The cloud-init script already pinned your secrets (DB_PASSWORD, BETTER_AUTH_SECRET, ENCRYPTION_KEY) in /opt/pinchy/.env and installed Caddy as a reverse proxy.

To enable HTTPS, follow the HTTPS setup steps in the Hetzner guide — the cloud-init flow is identical: edit /etc/caddy/Caddyfile, replace :80 with your domain, and reload Caddy. Let’s Encrypt is automatic.

See the VPS Deployment Guide — Production setup for further hardening (domain lock, automatic security updates).

How do I connect to my Droplet to run these commands?

You’ll need to use SSH (Secure Shell) — a way to run commands on a remote server from your terminal.

If you chose password authentication when creating the Droplet:

Terminal window
ssh root@<your-droplet-ip>

Enter the password you set (or check your email for the one DigitalOcean generated).

If you chose SSH key authentication, make sure you have the key on your machine, then:

Terminal window
ssh root@<your-droplet-ip>

Where do I find the terminal?

  • Mac — Open Terminal (search for it in Spotlight with ⌘+Space)
  • Windows — Open PowerShell (search in Start menu) or install Windows Terminal
  • Linux — Open your terminal app (usually Ctrl+Alt+T)

While connected, every command you type runs on your Droplet. Type exit to disconnect.

Section titled “Point your domain (optional but recommended)”

To use HTTPS, you need a domain pointing to your Droplet. Add a DNS record at your domain registrar (the service where you registered your domain):

TypeNameValue
Apinchy (or your preferred subdomain)Your Droplet’s IP address
What’s an A record?

An A record is a DNS entry that maps a domain name (like pinchy.example.com) to an IP address (like 164.90.1.23). When someone visits your domain, their browser looks up the A record to find your server.

Look for “DNS records” or “DNS settings” in your domain registrar’s dashboard.

You can also manage DNS directly in DigitalOcean under Networking → Domains.

DigitalOcean offers automated weekly backups for 20% of the Droplet cost. Enable this under Droplet → Backups — it’s the easiest disaster recovery option.

DigitalOcean offers Cloud Firewalls under Networking → Firewalls. For defense in depth, configure the cloud firewall to only allow ports 22, 80, and 443 — in addition to the host firewall (ufw) that the setup script already configured.

For larger Knowledge Base deployments, attach a DigitalOcean Volume (up to 16 TB) and mount it as a data directory. See Mount Data Directories for details.

If you outgrow the 4 GB Droplet, you can resize it in the control panel. Pinchy’s data lives in Docker volumes, so it survives Droplet resizes. Power off the Droplet first, resize, then power back on — downtime is typically under 2 minutes.