Domains, AWS and Cloudflare
How the hosted opendesk service is laid out across domains, AWS, Cloudflare and Neon.
The hosted service at opendesk.sh runs the same code as a self-hosted install, split into roles and spread across managed infrastructure. The infrastructure is defined in Terraform in deploy/terraform.
Domains
Section titled “Domains”| Domain | Serves | Runs on |
|---|---|---|
opendesk.sh |
Marketing site and install.sh |
Cloudflare Pages |
docs.opendesk.sh |
This documentation | Cloudflare Pages |
app.opendesk.sh |
The web app, help center, widget/v1.js, config.json for the native apps and the iPhone app’s apple-app-site-association |
Cloudflare Pages |
api.opendesk.sh |
The REST API, /docs and /v1/openapi.json |
AWS ECS behind an ALB |
gateway.opendesk.sh |
The realtime gateway (/socket) |
AWS ECS behind the same ALB |
in.opendesk.sh |
Forwarding addresses (<token>@in.opendesk.sh) |
Cloudflare Email Routing and an Email Worker |
Request path
Section titled “Request path”- ECS Fargate runs the opendesk API (
OPENDESK_ROLE=api), workers (OPENDESK_ROLE=worker) and the realtime gateway as separate services, each scaled independently. - NATS runs as a three-node JetStream cluster on ECS. Every API, worker and gateway task connects to it.
- An Application Load Balancer terminates TLS for the API and gateway, with certificates from ACM.
- S3 stores attachments and raw email, in a private bucket. Downloads use short-lived signed URLs.
- SES sends platform email (verification, password reset, invitations) with DKIM, a custom MAIL FROM domain and DMARC.
- Secrets Manager and KMS hold every secret; tasks receive them at start.
- Deployments use short-lived credentials through GitHub OIDC. Images are immutable and tagged by commit.
Cloudflare
Section titled “Cloudflare”- DNS and zone security settings for every domain.
- Pages hosts the site, docs and web app as static builds.
- Email Routing receives all mail for
in.opendesk.shwith a catch-all rule and hands each message to the Email Worker, which posts it toPOST /v1/inbound/emailwith a shared secret. If the API is unavailable, the worker reports a temporary failure so the sending server retries later.
PlanetScale
Section titled “PlanetScale”Postgres runs on PlanetScale in the same AWS region, and the services reach it only over AWS PrivateLink: database traffic never crosses the public internet, and the database accepts no connections from outside private networks. Request handlers go through PgBouncer; background jobs and the event relay use a direct connection, because they need session features such as LISTEN/NOTIFY.
The services connect with a role that reads and writes data but cannot change the schema. Only the migration step, run once per deploy, uses a role that can. opendesk uses no PlanetScale-only features, so the same code runs on stock Postgres.
Data flow for a change
Section titled “Data flow for a change”The events catalog draws this path, including how a private team’s events are kept to that team.
- An agent’s request writes the change and an event in one Postgres transaction.
- A worker’s event relay publishes the event to NATS on
od.events.<workspace_id>. - Every gateway node pushes it to the browsers subscribed to that workspace.
- The relay also queues webhook deliveries.