Building a Personal Cloud on Cloudflare
I want one place for my public site, my writing, and shared platform policy — without re-deciding hosting, DNS, identity, and CI every time an idea appears. That place is pcloud: the megarepo where the personal web platform, Cloudflare foundation, reusable modules, and operational runbooks live together.
One platform repository, one production state
The repository is the ownership boundary. One OpenTofu root composes platform policy, shared services, content infrastructure, and application routing into one production graph and one locked R2 state object. Child modules keep that graph readable without creating independent deployment paths.
pcloud/prod.tfstateA contract instead of shared-state archaeology
Future projects should not know how the foundation was assembled. The platform module publishes a small, non-secret contract: account and zone IDs, primary and Access domains, naming prefix, state bucket, and shared Access group IDs. A project such as an agent control plane consumes a versioned copy, then owns its Workers, queues, databases, storage, credentials, and state in its own repository.
Infrastructure and application code have different owners
OpenTofu attaches stable custom domains, but it does not upload this site's code. Wrangler deploys the prerendered build as Worker Static Assets. Keeping that line explicit means an infrastructure apply cannot roll a newer application deployment back to a placeholder bundle, and the application workflow needs only a narrowly scoped Worker token.
The details that bite later
- State bootstrap. A tiny local-state root creates the R2 bucket that the production root needs.
- Stable names. Resources follow
<prefix>-<project>-<environment>-<resource>, while hostnames remain human. - Thin modules. Shared modules enforce one convention or resource pattern; they do not secretly create an application stack.
- Explicit ownership. A project registry allocates hostnames and a separate state bucket for each future repository before credentials or deployments exist.
What a database costs when you do not have one
Nothing. Durable state arrives only with a real write path, then uses the smallest matching primitive: R2 for objects, D1 for relational data, Durable Objects for coordinated per-entity state, or KV for read-heavy eventually consistent values. This article remains a static file with good build tooling.
The repository is public at github.com/ryansann/pcloud, platform contract and runbooks included.