Several sites in one installation (RFC-0034)
One installation is one Studio, one D1 database and one R2 bucket. It can hold any number of sites. Each site is isolated: it has its own content, settings, members’ roles, keys, analytics and comments. One site Worker can serve several of these sites, picking the site from the request’s hostname.
Create a site
The operator creates sites with the deployment token:
cloudhal site create --remote --name "Türkçe" --slug turkce --locale tr --project <projectId>cloudhal site list --remoteThe new site starts with a home page and system pages. Nothing is published. Give it its domains in Studio, under the site’s settings.
Start a language edition
A language edition is a separate site for another language or market. It is a new site in the same project, and it starts from the source site’s structure instead of a blank starter.
cloudhal site create --remote --name "Newsroom English" --slug newsroom-en --locale en --from <sourceSiteId>In Studio, choose New site › Start from › A copy of ….
Copied from the source:
- the theme and its settings, the design, the header and footer, and the time zone;
- the pages in the source’s default language, as drafts in the new language. They are still in the source’s words; a person or an agent translates them. Each copy joins the source page’s translation group, so
hreflangspans both sites and the Translations card shows when the source changes; - the menus, with their page items pointing at the copies.
Not copied: articles, categories and tags (the edition gets empty default taxonomies), media, comments, analytics, members and keys. A page that refers to the source’s media or categories is left out and reported. Nothing is published.
Track translations across the editions
Open Translations and choose All sites in the project. Each site and language gets its own column, and each cell opens that site’s editor. The list shows what is missing, out of date, or waiting for a person’s review in every edition.
Under Settings › Languages, each site compares two options: adding a language to the site, or starting an edition. Create a language edition… opens the New site dialog with this site as the starting point.
Serve it from the same site Worker
-
List the sites in
cloudhal.json. The project’s ownsiteIdalways comes first:{ "siteId": "site_english…", "sites": ["site_turkish…"], "domains": { "site": "en.example.com" } } -
Run
cloudhal deploy. It checks three things:- every site in
sitesexists on the deployment; - every site in
sitesuses this Worker’s theme (Site.theme.name); - every hostname those sites hold gets a Cloudflare Custom Domain route. The zone must be in the same account.
- every site in
-
After you add a domain to a site in Studio, deploy again so the new route exists.
Requests on a hostname that no listed site holds get a 404. They never show another site. The Worker’s *.workers.dev address shows the first site and is marked noindex.
A publish purges only that site’s pages from the edge cache.
Limits
| Workers Free | Workers Paid | |
|---|---|---|
| D1 database size (shared by every site of the installation) | 500 MB | 10 GB |
| Custom domains per zone | 100 | 100 |
A site with another theme
A site Worker renders one theme. A site with another theme gets its own site Worker, which joins the same installation. It shares the same Studio, database and team.
-
Create the theme project with
cloudhal initand point it at the installation. The path is relative to this project:{ "siteId": "site_docs…", "installation": "../newsroom" } -
Run
cloudhal deployin the theme project. It deploys only a site Worker, named<installation>-site-<slug>:- it uses the installation’s database, bucket, analytics dataset and secrets;
- it adds this project’s site to the installation if the site is not there yet;
- it registers the Worker with the installation.
-
Run
cloudhal deployonce more in the installation’s project. The admin Worker then gets a service binding to the new Worker (SITE_1,SITE_2, …), and sends those sites’ cache purges and feed checks to it.
A Worker can’t call another Worker over its public address, so the binding is the only way the admin Worker reaches it. That is why the installation deploys again. Adding a site or a domain later needs only the deploy of the Worker that serves it.