Deployment Overview
Architecture
Section titled “Architecture”Nothing runs on the host. Every service is a container publishing a host port, and the Cloudflare tunnel targets that host port directly — there is no reverse proxy in the path on either estate.
graph TD GH[GitHub · Deployd-io<br/>push to main] -->|polled every 60s| W[deploy watcher<br/>systemd, dev VM] W -->|POST /api/deploy| C[management console<br/>management.logrite.ai] C --> B[build on the dev host] B --> R[registry<br/>127.0.0.1:5000] R --> P[pin the tag] P --> D[docker compose up -d] D --> DEV[(dev VM<br/>dev-*.logrite.ai)] C -.->|promote · human only| PR[(prod VM<br/>*.logrite.ai)] R -.->|same image, over an ssh tunnel| PR
The dotted edges are the whole difference between the estates: a push reaches dev automatically and never reaches prod. Prod moves when a person clicks Promote, which copies the image already tested on dev rather than rebuilding the commit.
Service Inventory
Section titled “Service Inventory”One instance of each service per VM — prod and dev are separate machines, so
there is no main + dev pair sharing a box. Two host ports differ from the
container port, and the analyzer’s differs between estates.
| Service | prod | dev | Host port |
|---|---|---|---|
| Frontend | app.logrite.ai | dev-app.logrite.ai | 3000 |
| Backend | leapfrogapi.deployd.io | dev-leapfrogapi.logrite.ai | 9800 → 8080 |
| Analyzer | analyzer.logrite.ai | dev-analyzer.logrite.ai | 9000 prod / 9001 dev |
| OpenSearch API | analyticsapi.logrite.ai | dev-analyticsapi.logrite.ai | 9200 (https) |
| OpenSearch Dashboards | analytics.logrite.ai | dev-analytics.logrite.ai | 5601 |
| Semantic Search | search.logrite.ai | dev-search.logrite.ai | 9100 |
| AI Service | aiservice.logrite.ai | dev-aiservice.logrite.ai | 9300 |
| AI Warden relay | warden.logrite.ai | dev-warden.logrite.ai | 9600 |
| Collector ingest shim | ingest.logrite.ai | dev-ingest.logrite.ai | 9700 |
| MCP Server | mcp.logrite.ai | dev-mcp.logrite.ai | 9500 |
| Webhook receiver | webhook.logrite.ai | dev-webhook.logrite.ai | 9999 |
| Uptime tracker | downtime.logrite.ai | one board, both estates | 8765 |
| Dev docs | devdocs.logrite.ai | dev-devdocs.logrite.ai | 3067 → 3000 |
| JobSearch | jobsearch.logrite.ai | dev-jobsearch.logrite.ai | 9081 |
| OTEL traces / logs | traces / logs.logrite.ai | dev- prefixed | 21890 / 21891 |
Prerequisites
Section titled “Prerequisites”There is nothing to install to deploy — builds happen on the target host inside Docker, driven by the console. The list below is for running a service locally.
node --version # 20+java --version # 17+ for the backend; 21 for OpenSearch 3.xmvn --version # 3.8+, backend buildpython3 --version # 3.10+, MCP serverdocker --version # everything on both VMs is a containergh --version && gh auth loginDeployment Strategy
Section titled “Deployment Strategy”main — the only branch
Section titled “main — the only branch”- Every service repo has
mainand nothing else. - A push to
mainis polled by the deploy watcher and deployed to the dev host, served atdev-*.logrite.ai. - It is never deployed to production by a push.
Production
Section titled “Production”- Prod is a separate VM running the same branch.
- It moves only when a human promotes from the management console, which copies the exact image tested on dev into prod’s registry and deploys that — so prod runs the bits that were tested, not a rebuild of the same commit.
- Prod has no deploy key and builds nothing from source.
OpenSearch
Section titled “OpenSearch”- One instance per host; the two hosts do not share one.
- Must be running before most services start.
start-allwaits for OpenSearch health (up to 60 seconds).
See Also
Section titled “See Also”- The in-house deploy platform — how a deploy actually runs today, what it refuses to do, and why
- Management console design — the control surface
- Fresh Deploy — Full step-by-step from scratch
- Startup Sequence — Correct order to start services
- Troubleshooting — Common issues