{"id":50506072,"url":"https://github.com/casablanque-code/platform-infra","last_synced_at":"2026-06-02T16:02:13.155Z","repository":{"id":357469225,"uuid":"1236783984","full_name":"casablanque-code/platform-infra","owner":"casablanque-code","description":"Self-hosted infrastructure platform for small engineering teams. Provision VMs, bootstrap services, track nodes, run actions — from a web UI. No tickets, no bottlenecks, no SaaS vendor.","archived":false,"fork":false,"pushed_at":"2026-06-02T13:35:58.000Z","size":218,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-02T15:21:30.364Z","etag":null,"topics":["ansible","devops","infrastructure","open-source","tofu"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/casablanque-code.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-12T15:11:41.000Z","updated_at":"2026-06-02T13:37:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/casablanque-code/platform-infra","commit_stats":null,"previous_names":["casablanque-code/platform-infra"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/casablanque-code/platform-infra","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/casablanque-code%2Fplatform-infra","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/casablanque-code%2Fplatform-infra/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/casablanque-code%2Fplatform-infra/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/casablanque-code%2Fplatform-infra/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/casablanque-code","download_url":"https://codeload.github.com/casablanque-code/platform-infra/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/casablanque-code%2Fplatform-infra/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33829346,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-02T02:00:07.132Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","devops","infrastructure","open-source","tofu"],"created_at":"2026-06-02T16:02:12.247Z","updated_at":"2026-06-02T16:02:13.150Z","avatar_url":"https://github.com/casablanque-code.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# platform-infra\n\nSelf-hosted infrastructure platform for small engineering teams. Provision VMs, bootstrap services, track nodes, run actions — from a web UI. No tickets, no bottlenecks, no SaaS vendor.\n\n→ [Landing](https://platform.casablanque.com) · [Control plane dashboard](https://infra.casablanque.com)\n\n---\n\n## What it does\n\n- **Self-service provisioning** — web UI to create environments (Docker Host, PostgreSQL) on any supported cloud provider\n- **Multi-cloud** — Hetzner, Oracle, AWS, Azure, GCP, Yandex Cloud via provider abstraction\n- **Auto-lifecycle** — configurable TTL (1h–7d), automatic destroy on expiry, no zombie environments\n- **Post-provision bootstrap** — base hardening, Docker CE, service install via SSH scripts after every apply\n- **Node inventory** — nodes check in after bootstrap, control plane tracks health and last seen, flags unreachable\n- **Runtime actions** — reboot, redeploy, run playbooks (Portainer, Node Exporter, Uptime Kuma, pgAdmin, R2 backup) from the dashboard\n- **Deployment history** — full event log with retry count, duration, links to GitHub Actions runs\n\n---\n\n## Architecture\n\n```\nBrowser (React dashboard)\n    │\n    ▼\nCloudflare Workers (control plane)  ←─── cron scheduler (every minute)\n    │           │\n    │           ▼\n    │       Cloudflare D1 (SQLite)\n    │           │\n    ▼           ▼\nGitHub Actions (executor)\n    │\n    ├── provision.yml  →  OpenTofu apply  →  bootstrap scripts  →  /complete\n    ├── destroy.yml    →  OpenTofu destroy  →  /destroy-complete\n    └── action.yml     →  SSH action (reboot / run_script / redeploy)\n\nState storage: Cloudflare R2 (S3-compatible OpenTofu backend)\n```\n\n**Why GitHub Actions as executor?**\nFree distributed runner, no agent infrastructure to maintain, native secrets management, full audit trail via Actions logs.\n\n---\n\n## Stack\n\n| Layer | Tech |\n|---|---|\n| Control plane | Cloudflare Workers + Hono |\n| Database | Cloudflare D1 (SQLite) |\n| State backend | Cloudflare R2 |\n| Frontend | React 19 + Tailwind 4 + Vite |\n| IaC | OpenTofu |\n| Executor | GitHub Actions |\n| Bootstrap | Bash scripts (idempotent) |\n\n---\n\n## Getting started\n\n### Prerequisites\n\n- Cloudflare account (Workers, D1, R2 — all on free tier)\n- GitHub account with Actions enabled\n- `wrangler` CLI installed (`npm i -g wrangler`)\n- `tofu` installed\n\n### 1. Clone\n\n```bash\ngit clone https://github.com/casablanque-code/platform-infra\ncd platform-infra\n```\n\n### 2. Create D1 database\n\n```bash\nwrangler d1 create platform-infra\n# Copy database_id to wrangler.jsonc\nwrangler d1 migrations apply platform-infra --remote\n```\n\n### 3. Create R2 bucket\n\n```bash\nwrangler r2 bucket create platform-infra-state\n```\n\nGet your R2 credentials: Cloudflare Dashboard → R2 → Manage API Tokens.\n\n### 4. Set Cloudflare Workers secrets\n\n```bash\nwrangler secret put GITHUB_TOKEN          # PAT with workflow scope\nwrangler secret put CALLBACK_TOKEN        # random string, e.g. openssl rand -hex 32\nwrangler secret put GITHUB_OWNER          # your GitHub username\nwrangler secret put GITHUB_REPO           # platform-infra\nwrangler secret put GITHUB_WORKFLOW       # provision.yml\nwrangler secret put GITHUB_DESTROY_WORKFLOW # destroy.yml\nwrangler secret put GITHUB_ACTION_WORKFLOW  # action.yml\nwrangler secret put GITHUB_REF            # main\n```\n\n### 5. Set GitHub Actions secrets\n\n```\nCONTROL_PLANE_URL     https://your-worker.workers.dev\nCALLBACK_TOKEN        same as above\nR2_ACCESS_KEY_ID      from Cloudflare R2 API token\nR2_SECRET_ACCESS_KEY  from Cloudflare R2 API token\nR2_BUCKET             platform-infra-state\nR2_ENDPOINT           https://\u003caccount_id\u003e.r2.cloudflarestorage.com\n```\n\nFor real bootstrap (SSH into actual VMs):\n```\nBOOTSTRAP_SSH_KEY     private key matching the public key deployed to VMs\n```\n\n### 6. Deploy\n\n```bash\n# Deploy control plane\ncd workers/control-plane\nwrangler deploy\n\n# Deploy dashboard\ncd apps/dashboard\nnpm run build\nwrangler pages deploy dist\n```\n\n---\n\n## Project structure\n\n```\nplatform-infra/\n├── workers/\n│   └── control-plane/\n│       ├── src/index.ts          # Hono API + scheduler\n│       └── migrations/           # D1 schema (0001–0009)\n├── apps/\n│   └── dashboard/\n│       └── src/App.tsx           # React SPA\n├── templates/\n│   ├── docker-host/\n│   │   ├── template.json         # UI metadata\n│   │   ├── runtime.json          # executor config + post_provision + actions\n│   │   └── tofu/main.tf          # OpenTofu module (mock → replace with real)\n│   └── postgres/\n│       └── ...\n├── providers/\n│   ├── hetzner/provider.json     # tfvars per provider\n│   ├── oracle/provider.json\n│   ├── aws/provider.json\n│   ├── azure/provider.json\n│   ├── gcp/provider.json\n│   └── yandex/provider.json\n├── bootstrap/\n│   ├── base.sh                   # hardening + essentials\n│   ├── docker.sh                 # Docker CE install\n│   ├── checkin.sh                # node registration\n│   ├── install_portainer.sh\n│   ├── install_node_exporter.sh\n│   ├── install_uptime_kuma.sh\n│   ├── install_pgadmin.sh\n│   └── backup_to_r2.sh\n├── .github/workflows/\n│   ├── provision.yml\n│   ├── destroy.yml\n│   └── action.yml\n└── MOCK_REGISTRY.md              # all stubs + migration guide\n```\n\n---\n\n## Connecting a real cloud provider\n\nCurrently all providers use mock outputs (IP `203.0.113.10`). To connect a real provider:\n\n1. Replace `templates/\u003ctemplate\u003e/tofu/main.tf` with real provider resources\n2. Add provider credentials to GitHub Secrets (see `MOCK_REGISTRY.md` for exact secret names per provider)\n3. Add `BOOTSTRAP_SSH_KEY` secret — private key matching the public key deployed to VMs\n4. Create environment from UI — full cycle runs including bootstrap and node check-in\n\nSee [`MOCK_REGISTRY.md`](./MOCK_REGISTRY.md) for the complete migration checklist.\n\n---\n\n## Dashboard\n\n| Tab | What's there |\n|---|---|\n| Dashboard | Env / deployment / node health counters, provider status, recent activity |\n| Environments | List with filters, TTL bar, node health inline, outputs, runtime actions |\n| Deployments | Job history with event timeline, retry count, delete |\n| Nodes | Registered nodes with last seen, delete |\n| Create | Template picker, provider selector, TTL picker, template-specific inputs |\n\n---\n\n## Environment lifecycle\n\n```\nqueued → dispatching → [github_actions_started → runtime_resolved →\n         outputs_captured → bootstrap_skipped/bootstrap_complete] → success\n\nsuccess → destroy_queued → dispatching → destroyed\n```\n\nFailed deployments retry with exponential backoff. Stuck deployments (dispatching \u003e 10 min) are recovered by cron. TTL expiry triggers automatic destroy.\n\n---\n\n## Roadmap\n\n- [ ] Zero Trust access (identity-aware proxy, JWT auth, no open ports)\n- [ ] OPA governance (cost limits, security rules before apply)\n- [ ] Multi-user + RBAC + API keys\n- [ ] Audit log (events already structured, write path pending)\n- [ ] Real provider modules (Hetzner, Oracle free tier first)\n- [ ] Secrets management (encrypted per-environment secrets in D1)\n- [ ] Template catalog expansion (K3s, WireGuard, n8n, Redis)\n\n---\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcasablanque-code%2Fplatform-infra","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcasablanque-code%2Fplatform-infra","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcasablanque-code%2Fplatform-infra/lists"}