Static site hosting for Git forges

What is grebedoc.dev?

A public instance of git-pages run by Catherine 'whitequark' that serves static pages from Codeberg or other Git forges. It is deployed on Fly.io.

Unlike the pull-based codeberg.page, this service is push-based: the forge must notify the pages service whenever there is a content update. This makes it extremely efficient, but also means that configuration is needed before use.

Unlike GitHub Pages and Codeberg Pages, this service sets Access-Control-Allow-Origin: *, Cross-Origin-Embedder-Policy: credentialless, Cross-Origin-Opener-Policy: same-origin headers, making service worker based hacks obsolete.

See the git-pages README for details.

What is the purpose of operating grebedoc.dev?

This service is provided as a public utility, especially for those migrating from GitHub to community-operated forges, and I plan to operate it indefinitely. It is monitored and has a status page.

I don't have a domain. How do I serve static pages from Codeberg?

Select repository > Settings > Webhooks > Add webhook > Forgejo, then configure only the following:

Leave everything else at the default values and select Add webhook. Next update to the pages branch will cause its contents to become available at the target URL.

Important! It is necessary to either use the http:// scheme for the webhook for the initial push (after which it may be upgraded to https://), or perform the initial publishing using a method described below.

I own a domain. How do I serve static pages from Codeberg or another Forgejo/Gitea/Gogs/GitHub-based forge?

Method A: To prove that you control the domain, update the configuration of your domain to add a TXT record at the _git-pages-repository subdomain with the full git clone URL (something like https://forge.tld/user/repo.git) as its value.

Method B: To prove that you control the domain, generate a strong password (32 or more random alphanumeric characters) and compute a challenge as: SHA256("{domain} {password}"). This can be done by running echo -n "{domain} {password}" | sha256sum in the terminal, or with the following JavaScript-based form:

Enable JavaScript to use this form.

Update the configuration of your domain to add a TXT record at the _git-pages-challenge subdomain with the challenge as its value.

Important! Keep the password secret. Anyone who knows it can replace the contents of your static site with anything they want.

After using Method A or Method B, configure your domain to have A/AAAA records pointing to the same server as grebedoc.dev. In most cases this can be done using an ALIAS record, but if this functionality isn't available it will need to be done by hand.

Select repository > Settings > Webhooks > Add webhook > Forgejo, then configure only the following:

Leave everything else at the default values and select Add webhook. The next time the pages branch is pushed, its contents will be published at the target URL.

Important! It is necessary to either use the http:// scheme for the webhook for the initial push (after which it may be upgraded to https://), or perform the initial publishing using a method described below.

This configuration method is not limited to Codeberg; it works with any Forgejo, Gitea, Gogs, or GitHub based forge. If the forge does not make it possible to supply an Authorization: header, use http://Pages:{password}@{domain}/ as the target URL instead.

I own a domain. How do I serve static pages from a type of forge not mentioned above?

Follow the DNS configuration steps for Method A or Method B as described above. Next, configure your forge or Git repository to issue a PUT HTTP request after a branch has been updated with this Curl command (or its equivalent):

For Method A: curl http://{domain}/ -X PUT --data "https://{forge}/{repo}.git"

For Method B: curl http://{domain}/ -X PUT -H "Authorization: Pages {password}" --data "https://{forge}/{repo}.git"

The optional -H "X-Pages-Branch: {branch}" argument may be used to publish from a branch other than pages. This functionality requires the PUT method to be used, and is not available with webhooks.

I own a domain. How do I serve static pages if I don't want to use Git or don't want my repository to be exposed?

Follow the DNS configuration steps for Method B (only) as described above. Next, make a ZIP or tar archive of your site and upload it with this Curl command (or its equivalent):

For a ZIP archive: curl http://{domain}/ -X PUT -H "Authorization: Pages {password}" -H "Content-Type: application/zip" --data-binary @{archive}

For a tar archive: curl http://{domain}/ -X PUT -H "Authorization: Pages {password}" -H "Content-Type: application/x-tar" --data-binary @{archive}

I own a domain. How do I migrate from another pages server without downtime?

Follow the DNS configuration steps for Method A or Method B as described above. Before altering the ALIAS or A/AAAA records, use the following Curl command (or its equivalent) to publish your site at the new server:

For Method A: curl https://grebedoc.dev/ -X PUT -H "Host: {domain}" --data "https://{forge}/{repo}.git"

For Method B: curl https://grebedoc.dev/ -X PUT -H "Host: {domain}" -H "Authorization: Pages {password}" --data "https://{forge}/{repo}.git"

Verify the deployment by requesting the index page: curl https://grebedoc.dev/ -H "Host: {domain}"

Now, alter the ALIAS or A/AAAA records for your domain.

I really don't want to use unencrypted connections.

To comply with terms of service of the certificate authorities, this service only acquires certificates for domains it has a published site for, regardless of the DNS settings or HTTP headers. This means that the site cannot be published for the first time using its own https:// URL. However, the steps described above also work around this issue.

Is that a bird looking at me?

It is a great crested grebe! Original photo © Bengt Nyman, CC BY-SA 4.0.

What's up with the name?

The architecture of grebedoc.dev is the inverse of the architecture of codeberg.page; "Grebedoc" is "Codeberg" backwards.

a great crested grebe looking at the reader intensely