Tracks deploying the website and docs static apps separately via Cloudflare Pages so that publishing content does not rebuild the main app and shipping a new app version does not rebuild the static sites.
Architecture
shellhub/ (monorepo)
│
├── ui/
│ ├── apps/console/ → Docker Compose (example.shellhub.io)
│ ├── apps/website/ → Cloudflare Pages (shellhub.io)
│ └── apps/docs/ → Cloudflare Pages (docs.shellhub.io)
│
├── api/ ─┐
├── ssh/ │→ Docker Compose (example.shellhub.io)
├── gateway/ ─┘ Separate deploy via release tags
The console is a React/Vite SPA that stays in Docker Compose alongside the backend services. The website (React/Vite landing page) and docs (Astro/MDX) are the two apps moving to Cloudflare Pages.
Cloudflare Pages configuration
Project 1: shellhub-website
| Field |
Value |
| Project name |
shellhub-website |
| Repository |
shellhub-io/shellhub |
| Production branch |
master |
| Root directory |
ui |
| Build command |
npm run build --workspace=apps/website |
| Output directory |
apps/website/dist |
| Custom domain |
shellhub.io |
| Node version (env var) |
NODE_VERSION=22 |
Project 2: shellhub-docs
| Field |
Value |
| Project name |
shellhub-docs |
| Repository |
shellhub-io/shellhub |
| Production branch |
master |
| Root directory |
ui |
| Build command |
npm run build --workspace=apps/docs |
| Output directory |
apps/docs/dist |
| Custom domain |
docs.shellhub.io |
| Node version (env var) |
NODE_VERSION=22 |
Hardcoded URLs
All cross-app URLs are hardcoded today — there are no env vars or centralized constants for them. This needs to be addressed before or as part of the deploy:
docs app (~40 occurrences): cloud.shellhub.io is hardcoded across most MDX pages (quick-start, install guides, agent pages, integrations, embedded Linux). These are mostly in code examples and instructions where Cloud is used as the default server address.
console app (~15 occurrences): links to docs.shellhub.io (add device, welcome screen, self-hosted admin) and www.shellhub.io/pricing (upsell dialogs, feature gates, support paywall).
website app: cloud.shellhub.io and docs.shellhub.io in SSH examples across use-case and feature pages, plus mailto:sales@shellhub.io in CTAs and test assertions.
These should be extracted into env-driven constants or a shared config so that domain changes don't require editing dozens of files, and so that Cloudflare Pages builds can inject the right values.
Deploy flow
A content change (website or docs) triggers a Cloudflare Pages build on merge to master. Each PR gets an automatic preview deploy with a unique URL for review before merging. The main app deploy (API, SSH, Gateway, Console) is independent — stays on Docker Compose / release tags.
Considerations
- Monorepo build: Cloudflare Pages runs
npm install from the configured root directory (ui). npm workspaces resolve dependencies for all apps; the --workspace flag builds only the target app.
- Environment variables: configure
NODE_VERSION=22 in the Cloudflare Pages dashboard.
- Preview deploys: each PR automatically generates a preview deploy — useful for reviewing changes before merging.
- Rollback: Cloudflare keeps deploy history; instant rollback via the dashboard.
- Free tier covers this: unlimited builds and bandwidth, 500 deploys/month, per-PR preview deploys, global CDN, custom domains with automatic SSL, monorepo support.
TODO
Tracks deploying the
websiteanddocsstatic apps separately via Cloudflare Pages so that publishing content does not rebuild the main app and shipping a new app version does not rebuild the static sites.Architecture
The console is a React/Vite SPA that stays in Docker Compose alongside the backend services. The website (React/Vite landing page) and docs (Astro/MDX) are the two apps moving to Cloudflare Pages.
Cloudflare Pages configuration
Project 1:
shellhub-websiteshellhub-websiteshellhub-io/shellhubmasteruinpm run build --workspace=apps/websiteapps/website/distshellhub.ioNODE_VERSION=22Project 2:
shellhub-docsshellhub-docsshellhub-io/shellhubmasteruinpm run build --workspace=apps/docsapps/docs/distdocs.shellhub.ioNODE_VERSION=22Hardcoded URLs
All cross-app URLs are hardcoded today — there are no env vars or centralized constants for them. This needs to be addressed before or as part of the deploy:
docsapp (~40 occurrences):cloud.shellhub.iois hardcoded across most MDX pages (quick-start, install guides, agent pages, integrations, embedded Linux). These are mostly in code examples and instructions where Cloud is used as the default server address.consoleapp (~15 occurrences): links todocs.shellhub.io(add device, welcome screen, self-hosted admin) andwww.shellhub.io/pricing(upsell dialogs, feature gates, support paywall).websiteapp:cloud.shellhub.ioanddocs.shellhub.ioin SSH examples across use-case and feature pages, plusmailto:sales@shellhub.ioin CTAs and test assertions.These should be extracted into env-driven constants or a shared config so that domain changes don't require editing dozens of files, and so that Cloudflare Pages builds can inject the right values.
Deploy flow
A content change (website or docs) triggers a Cloudflare Pages build on merge to
master. Each PR gets an automatic preview deploy with a unique URL for review before merging. The main app deploy (API, SSH, Gateway, Console) is independent — stays on Docker Compose / release tags.Considerations
npm installfrom the configured root directory (ui). npm workspaces resolve dependencies for all apps; the--workspaceflag builds only the target app.NODE_VERSION=22in the Cloudflare Pages dashboard.TODO
console,website, anddocsshellhub-websiteproject on Cloudflare Pagesshellhub-docsproject on Cloudflare Pages_redirects)