Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/arrozet/caret/llms.txt

Use this file to discover all available pages before exploring further.

Caret is designed to be self-hosted on a single Linux virtual machine with minimal operational overhead. The production stack runs on a Hetzner Cloud VPS, uses Coolify as a self-hosted open-source PaaS to manage deployments and domains, and relies on Cloudflare for DNS. The database, authentication, and vector search are all delegated to Supabase Cloud — a managed service that runs entirely outside the VPS. This architecture keeps infrastructure costs low while giving you full control over the application layer.
Supabase Cloud is external to the VPS. Do not attempt to run PostgreSQL, the Supabase Auth server, or pgvector on the same machine as the Caret services. Mixing managed and self-hosted Supabase is a significant operational burden and is not part of the supported Caret deployment model. Use the Supabase Cloud project you created during local development as-is.

Production Infrastructure at a Glance

LayerChoiceNotes
HostingHetzner Cloud VPSSingle VM, approximately 9 EUR/month; sufficient for the full Caret stack
PaaSCoolifySelf-hosted open-source PaaS; manages deployments, domains, logs, and Docker Compose resources
ContainersDocker Composedocker-compose.prod.yml is the production deployment unit
CI/CDGitHub Actions + CoolifyAutomatic production deploys triggered on pushes to the prod branch
DNSCloudflareManages caret.page and all subdomains
Database / AuthSupabase CloudManaged PostgreSQL, Auth, and pgvector — runs outside the VPS

Production Domains

The production deployment exposes five public domains, each mapped to a specific service:
DomainServicePurpose
caret.pageFrontendMain user-facing application
www.caret.pageFrontend aliasCNAME to caret.page
api.caret.pageAPI GatewayPublic HTTP REST entrypoint for all /api/v1/... routes
ws.caret.pageCollab ServicePublic WebSocket endpoint for real-time collaboration
ops.caret.pageCoolifyPaaS control plane — deployment dashboard and operations
The frontend must call api.caret.page for all HTTP API traffic and connect directly to ws.caret.page for collaboration WebSocket connections. The collab service is intentionally not routed through the API Gateway: WebSocket connections are long-lived and use a different protocol from HTTP REST calls, so keeping them on a dedicated domain avoids unnecessary proxy complexity.

Step-by-Step Deployment

1

Provision a Hetzner VPS

Create a new VPS in Hetzner Cloud. A shared-CPU instance with 2 vCPUs and 4 GB RAM is sufficient for the full Caret stack at launch scale. Choose a Linux image (Ubuntu LTS recommended) and note the public IPv4 address of your new instance.
2

Configure the Hetzner Firewall

In the Hetzner Cloud console, apply a firewall to your VPS that allows only the required inbound traffic. Restrict all other ingress by default.
ProtocolPort / TypePurpose
TCP22SSH administration
TCP80HTTP (required for ACME TLS certificate validation)
TCP443HTTPS (all public web traffic)
ICMPBasic reachability / ping
Do not expose internal service ports (3000, 3001, 3002, 3003, 8000) directly. All public traffic must enter through Coolify’s built-in reverse proxy.
3

Install Coolify on the VPS

SSH into your VPS and follow the Coolify installation guide to install Coolify. Once running, Coolify is accessible at http://<your-vps-ip>:8000 during initial setup. After configuring your domain, it will be available at https://ops.caret.page.Point the Cloudflare DNS A record for ops.caret.page to your VPS public IPv4 address and let Coolify provision its own TLS certificate via ACME.
4

Configure Cloudflare DNS

In your Cloudflare dashboard for caret.page, create the following DNS records — all pointing to your Hetzner VPS public IPv4 address:
TypeNameTarget
Acaret.page<VPS IPv4>
CNAMEwwwcaret.page
Aapi<VPS IPv4>
Aws<VPS IPv4>
Aops<VPS IPv4>
Use DNS-only mode (grey cloud) for all records unless you have verified that Cloudflare proxying is compatible with your WebSocket configuration on ws.caret.page.
5

Create the Caret Project in Coolify

In the Coolify dashboard:
  1. Add your GitHub repository (arrozet/caret) as a source.
  2. Create a new Resource of type Docker Compose.
  3. Set the Compose file path to /docker-compose.prod.yml.
  4. Set the deployment branch to prod.
  5. Configure the domain for each service in Coolify:
    • Frontend → https://caret.page
    • API Gateway → https://api.caret.page
    • Collab Service → https://ws.caret.page
  6. Enable automatic deployments so that every push to the prod branch triggers a redeploy.
6

Set Production Environment Variables

Add the following environment variables in Coolify’s environment variable management UI (or via GitHub Actions secrets for CI-only values). Never commit secrets to the repository.
# Supabase Cloud connection details
SUPABASE_URL=https://your-project-ref.supabase.co
SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key

# Pooled database connection string (required by all backend services)
DATABASE_URL=postgresql://postgres.your-ref:your-password@aws-0-your-region.pooler.supabase.com:6543/postgres

# JWT secret used by auth-service and document-service to verify Supabase-issued tokens
JWT_SECRET=your-supabase-jwt-secret

# JWT secret used by the collab-service to verify Supabase-issued tokens (same value as JWT_SECRET)
SUPABASE_JWT_SECRET=your-supabase-jwt-secret

# AI service — at least one model key is required
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=          # optional
OPENROUTER_API_KEY=         # optional
OPENROUTER_MODEL=deepseek/deepseek-v4-flash   # optional override

# Production frontend build-time variables (injected at Docker build)
VITE_API_URL=https://api.caret.page/api/v1
VITE_COLLAB_WS_URL=wss://ws.caret.page/document
VITE_SUPABASE_URL=https://your-project-ref.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-key

# CORS: tell the API Gateway which origins are permitted
ALLOWED_ORIGINS=https://caret.page,https://www.caret.page
The production compose file (docker-compose.prod.yml) marks several variables as required using the :? syntax — Docker Compose will refuse to start if they are missing. This acts as a safety net against accidental misconfigurations.
7

Deploy and Verify

Push to the prod branch (or trigger a manual deploy in Coolify) to start the first production deployment. Monitor the build logs in the Coolify dashboard.Once deployed, verify each surface:
  • https://caret.page — loads the Caret frontend
  • https://api.caret.page/health — returns 200 OK from the API Gateway
  • https://ws.caret.page/health — returns 200 OK from the Collab service
  • Sign in, create a workspace and document, and confirm that real-time collaboration and the AI panel are functioning end-to-end

Network Routing Summary

Browser
  | HTTPS  -> api.caret.page  -> Coolify reverse proxy -> api-gateway (internal :3000)
  |                                                         |-> auth-service    (internal :3001)
  |                                                         |-> document-service (internal :3002)
  |                                                         `-> ai-service      (internal :8000)
  |
  | WSS    -> ws.caret.page   -> Coolify reverse proxy -> collab-service (internal :3003)
  |            (bypasses API Gateway entirely)
  |
  All backend services
    -> Supabase Cloud (external, managed PostgreSQL + Auth + pgvector)
Internal service-to-service traffic (e.g. API Gateway calling auth-service or document-service) stays inside the Docker Compose network and never leaves the VPS.

Monitoring

Caret’s production observability relies on two primary tools:
  • Coolify service logs — Each service’s stdout/stderr is captured and streamed in the Coolify dashboard. Use this for operational debugging and deployment verification.
  • Sentry — Error tracking is integrated on both the frontend and backend services. Configure your Sentry DSN as an environment variable to enable automatic error reporting and alerting.
Optional analytics integrations (PostHog or Plausible) can be added as additional environment variables without code changes.

Build docs developers (and LLMs) love