Deploy Trinity on DigitalOcean
About ten minutes, most of it waiting. You run one command on your own computer and end up with Trinity on its own server, behind HTTPS, with your admin password already set. You connect Claude in the browser when you first sign in.
Don't want to use a terminal at all? Trinity is published on the DigitalOcean Marketplace as a 1-Click Droplet image. You create the Droplet from the DigitalOcean control panel, wait about ninety seconds, and claim the admin account in your browser — no doctl, no install command.
Use this page instead when you want the admin password set before the Droplet exists, which closes the 1-Click's browser-claim window. Both produce the same Droplet. See Marketplace 1-Click.
What you need
A DigitalOcean account.
A Claude subscription (Pro or Max) or an Anthropic API key. Trinity's agents sign in to Claude with it. You add it in the browser after the install, not in the installer.
On Windows, WSL. Run everything below inside it.
About $48/month for the server (4 vCPU, 8 GB), billed by DigitalOcean until you delete it.
Optional: SSH keys on your DigitalOcean account. The installer attaches every key already there, so you can
ssh root@<droplet-ip>later. Without one, use the Droplet's browser Console for shell access.
Install
Install DigitalOcean's command-line tool
On macOS:
$ brew install doctlOn Linux or WSL, follow DigitalOcean's install guide.
Give it access to your account
Open API Tokens in DigitalOcean, click Generate New Token, name it, tick Write, and copy the token. It is shown only once. Then run this and paste the token when asked:
$ doctl auth initConfirm it worked:
$ doctl account getExpected: a row with your account's email and status active.
Decide on a password
This is what you will sign in to Trinity with. It needs at least 12 characters and must not start with password, admin, trinity, changeme or letmein; the installer rejects those. Mixing upper- and lowercase letters, a digit and a symbol is what Trinity's own password rules ask for. Your username will be admin.
Run the installer
$ bash <(curl -fsSL https://raw.githubusercontent.com/abilityai/trinity/v0.9.5/scripts/deploy/trinity-do-create.sh)The script installs the release it was fetched from. To install a different one, fetch it from that release's tag; releases are listed on the releases page. The installer from v0.9.5 and earlier also asks for a Claude subscription token; paste one from claude setup-token.
It asks three questions: the password from step 3 (twice), a region (fra1 is the default; nyc3, sfo3, lon1 and sgp1 are also suggested) and a name for the server (trinity by default). The password is not shown as you type it. It shows you the cost and asks before creating anything. Then it creates the server, prints a dot every 15 seconds while it installs Trinity, and waits until the site answers, which takes about six minutes. It finishes with the address, the username admin, and a reminder that the password is the one you chose. After you sign in, Trinity asks you to connect Claude.

Open the address it prints
Sign in as adminwith your password. You are on HTTPS with a real certificate, and the server's internal ports are closed to the internet.
Trinity opens its first-run setup. The Set up this instance screen lists six steps: Secure this instance (marked Recommended), Sign-in email, Connect Claude, Other keys, Your first agent and Usage sharing.
Connect Claude is the one required step: until it is done, no agent can run. Paste either a subscription token or an API key. For a token, run claude setup-token on any computer where Claude Code is signed in to your plan, and copy the sk-ant-oat01-... value it prints. For an API key, create one at console.anthropic.com. Trinity checks the credential with Anthropic before it saves it, then hands it to the starter agents. See Platform Keys → Claude.
Secure this instance is also worth doing now (step 6 below). The rest is optional, and Finish later closes the sequence. See First-Time Setup.

Put a domain in front of itOptional
The Secure this instance step suggests this. An IP address works, but it is awkward to share. Its certificate also lasts only about six days before it is renewed. Renewal happens automatically while the server runs; a Droplet switched off for longer comes back to a browser warning until renewal catches up.
- 1.Point your domain's A record at the server's IP address. If the domain is on Cloudflare, set the record to DNS only (grey cloud). Confirm it resolves with
dig +short your-domain.com. - 2.In the Secure this instance step, enter
https://your-domain.comin Public URL and click Save domain. Later, the same field is under Settings → General → Public URL. Includehttps://. Saving immediately re-points any Telegram and WhatsApp webhooks to the new address, which is why DNS comes first. - 3.Open
https://your-domain.comin a new tab. The first load takes a few seconds while the certificate is obtained. After that it loads normally.
Until that first visit, Trinity cannot tell whether the name works. The step's badge reads Domain saved, and Settings reads saved, waiting for the first visit to confirm it resolves here. After the visit, the badge reads Domain reached, and Settings shows the address with a tick.
The Droplet still answers anyone who finds its address. To take it off the public internet, serve the domain through a Cloudflare Tunnel, reach it over a private network, or both — a tunnel alone keeps the web UI answering anyone with the address. Hardening a Marketplace Install walks through all three choices, and Public Access covers the Cloudflare side.
Verify
The first three checks run in your browser. The rest run on the Droplet: open a shell with ssh root@<droplet-ip>, or use the Droplet's Console in the DigitalOcean control panel.
| Check | How | Expected |
|---|---|---|
| The site serves Trinity | Open https://<droplet-ip> | The sign-in page, valid padlock, no warning |
| You can sign in | admin and your password | The Dashboard with the starter fleet, and first-run setup open over it |
| Claude is connected | Settings → Integrations, after Connect Claude | A subscription named primary under Subscriptions, or the API key field filled in |
| The install finished | tail -20 /var/log/trinity-install.log | The last line is === Trinity is ready at https://<droplet-ip> ===. The first-boot script stops at the first failing command, so this line is written only after the install succeeded |
| The certificate was issued | cat /etc/trinity/tls-status | ok |
| The platform is healthy | curl -s http://localhost:8000/health | {"status":"healthy",...} |
If the installer stops
It checks for doctl before asking anything, and checks each answer as you give it. The messages mean:
doctl from a package instead of snap.y at the cost prompt. Nothing was billed; run the installer again.https://<droplet-ip> after a few minutes.tail -50 /var/log/trinity-install.log.If the install log shows TLS: no valid certificate, Caddy could not obtain the certificate for the IP address. Trinity still starts, but the installer keeps waiting for HTTPS. Read journalctl -u caddy -n 100 on the Droplet, and check that no cloud firewall blocks ports 80 and 443. A Droplet that never came up has nothing to keep: delete it (below) and run the installer again.
Removing it
$ doctl compute droplet delete <name>Use the name you gave the server in step 4 (trinity if you kept the default); doctl asks you to confirm. The server costs about $48/month until you delete it. Deleting it also deletes everything on it, including your agents and Trinity's own backups, which live on the same disk — take a Droplet snapshot first if you want to keep anything. See Backup and Restore.
What the installer does
- •Creates an Ubuntu 24.04 Droplet of size
s-4vcpu-8gbin the region you chose, and attaches every SSH key already on your DigitalOcean account so you canssh root@<ip>later. - •Hands the Droplet a first-boot script that clones Trinity
v0.9.5to/opt/trinityand runsstart.sh --provision --cloud digitalocean --hosted --unattended. That installs Docker, Caddy with a Let's Encrypt certificate for the IP, and the firewall, then Trinity itself. It is the same path the Marketplace 1-Click uses. - •Writes
/opt/trinity/.env: your password asADMIN_PASSWORD, so the admin account exists at first boot, plusFRONTEND_PORT=8081(Caddy owns 80 and 443 and forwards to the web UI),FRONTEND_URL=https://<droplet-ip>,TRINITY_IMAGE_TAG=<release-tag>andTRINITY_INSTALL_SOURCE=do-script— the marker that makes the Secure this instance step appear. - •Runs Trinity on PostgreSQL (releases after v0.9.5; v0.9.5 itself starts on SQLite). The database is a bundled
trinity-postgrescontainer.start.shgenerates its password into.envasPOSTGRES_PASSWORD, next to theDATABASE_URLthat points at it. Keep both with the rest of.env: a lostPOSTGRES_PASSWORDcannot be regenerated for an existing database. - •Leaves Claude to the first sign-in. It asks for no Claude credential. The Connect Claude step checks yours with Anthropic before saving it, which the installer could not do before the server existed.
- •Keeps your password off your screen and out of your shell history. The password travels only in the Droplet's own setup data (user-data), and Trinity's container firewall stops agents from reading that back; the temporary file that carries it is readable only by you and deleted when the installer exits.
- •Waits for
https://<ip>/to answer with a valid certificate, for up to 15 minutes. The Droplet keeps its install log at/var/log/trinity-install.log.
To install a different release, fetch the script from that release's tag, or set TRINITY_IMAGE_TAG when you run it. The value must be a published release tag, because the Droplet uses it both to check out the code and to pull the images. Unlike the 1-Click image, a Droplet created this way has no Trinity login banner.
Managing the Droplet
Status, logs, restarts, password changes, upgrades and backups work as they do on the 1-Click — see Single Server → Managing the Droplet. The everyday commands run from /opt/trinity:
cd /opt/trinity
docker compose -f docker-compose.hosted.yml ps # status
./scripts/deploy/stop.sh # stop (never `down`)
./scripts/deploy/start.sh --hosted # start, and apply .env changesTo upgrade, pin the new release in .env, check out the matching tag, and re-run start.sh --hosted. See Upgrading.
To operate the Droplet from Claude Code, point the Ops Agent at it with these values in the ops agent's .env:
SSH_HOST=<droplet-ip>
SSH_USER=root
TRINITY_PATH=/opt/trinity
COMPOSE_FILE=docker-compose.hosted.yml
FRONTEND_PORT=8081