Skip to content
Arbinel

Pages

Pages publishes a branch of a repository as a static website. Forgejo has no equivalent, so everything on this page is specific to Arbinel. This page is for site administrators. For repository owners, see Publish a site with Pages.

Arbinel does not serve the sites itself. It sends the content to a separate Pages backend and notifies the backend when a site changes. Arbinel supports two backends:

  • git-pages runs on your own servers. It uses git-pages, the software behind Codeberg Pages.
  • StaticHost is the hosted service at statichost.eu. It needs a StaticHost team and API key.

Only git-pages supports additional branches.

Pages is configured in the web interface, not in app.ini. The settings are stored in the database, so every node of a high availability cluster sees the same values.

  1. Open Site administration > Integrations > Pages (/admin/pages).
  2. Select Enable Pages.
  3. Select the Pages Backend and fill in its section.
  4. Set the Pages Domain under Common.
  5. Select Save Settings.

When Pages is enabled, repository admins see a Pages tab in the repository settings. The form does not save an enabled configuration if a field that the selected backend needs is empty.

Arbinel encrypts secrets in the database. To keep a stored secret, leave its field empty when you save.

Field Setting key Default Meaning
git-pages Endpoints pages.gitpages_endpoints empty Comma-separated base URLs of the git-pages nodes, for example http://10.0.0.1:3000, http://10.0.0.2:3000.
git-pages Wildcard Domain pages.gitpages_domain empty The domain git-pages serves sites under, the same as the [[wildcard]] domain in its own configuration.
Forge token pages.gitpages_forge_token empty The token sent with every publish. See Forge token.
Field Setting key Default Meaning
StaticHost Team ID pages.statichost_team_id empty The team identifier from StaticHost, such as team_01k6f....
StaticHost API Key pages.statichost_api_key empty The API key of that team.
Forgejo Username pages.forgejo_username empty Required by the form when StaticHost is selected.
Forgejo Access Token pages.forgejo_access_token empty Stored with the StaticHost settings.

The StaticHost API address is https://builder.statichost.eu unless the pages.statichost_api setting contains a different address.

Field Setting key Default Meaning
Enable Pages pages.enabled off Shows the Pages tab in repository settings.
Pages Backend pages.backend statichost gitpages or statichost.
Pages Domain pages.domain codefloe.page The domain sites are served under. Change it for your instance, for example to pages.example.com.
flowchart LR
  F["Arbinel"]
  N1["git-pages node 1"]
  N2["git-pages node 2"]
  E["edge proxy<br/>TLS, site map"]
  V["visitor"]
  F -->|"PUT archive"| N1
  F -->|"PUT archive"| N2
  N1 -.->|"checks the forge token"| F
  V --> E
  E --> N1
  E --> N2
  1. A user pushes to a repository’s Pages branch, or enables Pages, or publishes an additional branch.
  2. Arbinel archives that branch as a gzipped tar and uploads it to every node in git-pages Endpoints, one after the other. The request carries the site’s hostname in the Host header and the forge token in the Forge-Authorization header.
  3. Each node asks Arbinel’s API whether the token has push access to the repository that the hostname and path identify. It accepts the upload only if the answer is yes.
  4. Visitors reach the nodes through an edge proxy that you run.

The nodes never clone the repository, so private repositories are published the same way as public ones, without a deploy key. Every node keeps its own full copy of every site. If a publish fails on some nodes, Arbinel logs the names of those nodes. The nodes then serve different content until the next publish succeeds.

The nodes must not be reachable from the internet. Anyone who can reach a node’s endpoint can try to publish to it.

Arbinel stops an upload to a node after 10 minutes. The size of a site is limited by git-pages, not by Arbinel, so set the limit in the git-pages configuration.

Arbinel archives the branch as it is and runs no build. If the branch contains a statichost.yml, statichost.yaml, .statichost.yml or .statichost.yaml file with a public key, only that directory is published. This way, sites that were set up for StaticHost keep working.

The forge token must grant push access to every repository that can host a site. In practice, this is a site administrator’s token. A token of a regular account can publish only that account’s repositories, and every other site fails with no push permission.

Arbinel accepts the token with or without its scheme, such as token <value> or Bearer <value>. Arbinel sends a token without a scheme as token <value>.

git-pages serves an owner’s sites under one hostname per owner:

Repository Address
alice/blog https://alice.pages.example.com/blog/
alice/pages https://alice.pages.example.com/
alice/blog, branch dev https://alice.pages.example.com/blog@dev/

The owner’s hostname is the owner name in lower case and otherwise unchanged. An owner whose name contains a dot cannot publish, because the dot would split the hostname into two labels that a wildcard certificate does not cover. The nodes must accept underscores in hostnames, which git-pages calls its relaxed-idna feature.

The edge proxy in front of the nodes handles TLS and custom domains, not Arbinel or git-pages. The edge proxy must:

  • terminate TLS for *.<Pages Domain> and for every custom domain users add,
  • rewrite hostnames that git-pages does not know to the location where the site is stored.

Arbinel provides the rewrite table as an HAProxy map file:

curl -H "Authorization: token <admin token>" \
  https://git.example.com/api/v1/admin/pages/site-map

The endpoint needs a site administrator’s token with the read:admin scope. It answers 503 while Pages is off or when the backend is not git-pages. Each line maps a public hostname to <owner>.<Pages Domain> or <owner>.<Pages Domain>/<repo>:

# Generated by Forgejo: GET /api/v1/admin/pages/site-map
# <hostname> <storage-hostname>[/<repo>]
blog.alice.pages.example.com alice.pages.example.com/blog
www.example.org alice.pages.example.com/blog

The map lists every custom domain and the older addresses of each site. Every site has a line for <repo>.<owner>.<Pages Domain>, which was the site address under StaticHost. Sites that also had a flat <owner>-<repo>.<Pages Domain> address have a line for it too. The current address of a site has no line, because it already matches the location where the site is stored. Fetch the map regularly, because it changes whenever a user adds or removes a custom domain.

StaticHost creates one site per repository and clones the repository over SSH. When Pages is enabled, Arbinel adds a deploy key named CodeFloe Pages to the repository. On every push to the Pages branch, Arbinel asks StaticHost to build the site again.

Each site gets its own hostname, <repo>.<owner>.<Pages Domain>. StaticHost issues the TLS certificate on the first HTTPS request after a successful deployment. Custom domains are registered with StaticHost. StaticHost redirects the other domains of a site to the primary domain.

With git-pages, a repository can publish up to five branches besides its main Pages branch. Each one is a separate site, so it uses its own storage on every node. A branch site is republished on every push to the branch and unpublished when the branch is deleted. StaticHost does not support additional branches, so the repository settings do not show this section for StaticHost.

A site is unpublished when the repository admin disables Pages, or when the repository is deleted.

Some deletions, such as purging a user or an organization, do not notify Pages, and a backend can also fail to answer. The pages_teardown_sweep cron task handles both cases. It unpublishes every site whose repository no longer exists, and then removes its records.

It runs every 10 minutes. On a cluster, only the leader runs it. You can change the schedule like any other cron task:

[cron.pages_teardown_sweep]
SCHEDULE = @every 10m

A site created on one backend stays on it when you switch the instance to the other backend. Arbinel still deletes it on the backend that created it, as long as that backend is still configured. If you remove the credentials of the old backend, delete its remaining sites there by hand.

Limit Value
Additional branches per repository 5
Custom domains per site 20
Branch name of an additional branch Letters, digits, ., _ and -, up to 100 characters
Upload timeout per node 10 minutes
Site size Set in git-pages

When quotas are on, the API refuses to enable Pages or publish an additional branch for an owner who is over the repository size quota.

The repository contains contrib/pages-ci/run.ts, which runs a scheduled end-to-end check of Pages. It targets codefloe.com and a fixed test repository, so change both before you use it on another instance.