In short: a service that publishes the pages branch in your Git repository as a website on your domain; think GitHub Pages if it was open source and community operated.
More specifically, it is a public deployment of git-pages and Caddy configured to work especially with Codeberg but also with other Git forges. It is operated by Catherine 'whitequark' and teammates, and currently deployed using Rage4 anycast infrastructure routing to VPSes in six regions (Europe, North America East, North America West, South America, East Asia, Australia), with site contents stored on Tigris and backed up to Wasabi.
This service is provided as a public utility, especially for those migrating from GitHub to community operated forges, and we plan to operate it indefinitely. It is monitored and has a status page.
The size of a website is currently limited to 768 MiB. We are aiming to eventually raise this to 10 GiB.
Currently, we set COOP/COEP headers on all text/html files by default. This is about to change, so please monitor the linked issue for updates if you make use of SharedArrayBuffer in your code.
git-pages is a self-service static site server for the general public. It is efficient, reliable, scales horizontally to any number of nodes, and deployable in under 5 minutes. It is designed to work with an S3-compatible object store such as MinIO, and integrates with Caddy for TLS termination and on-demand certificate provisioning. It accepts webhook events from Forgejo, Gitea, Gogs, and GitHub. See the git-pages README for more details.
Unlike the pull-based architecture of the similar codeberg.page service, this service is push-based: the forge must notify the pages server whenever there is a content update. This makes it much more efficient, but requires the forge to be configured for publishing (via CI or a webhook).
Publishing a site using git-pages is done using a PUT or POST request to the same URL where the contents will appear. The server is compatible with many popular publishing workflows and has multiple flexible authorization methods.
Select repository > Settings > Webhooks > Add webhook > Forgejo, then configure only the following:
pages or {username}.grebedoc.dev): http://{username}.grebedoc.dev/{repository}): http://{username}.grebedoc.dev/{repository}/pagesLeave 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 special method.
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:
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:
http://{domain}/ or http://{domain}/{subdir}/ (only one level of directories can be used)pagesPages {password}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 special method.
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.
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.
Important! It is necessary to either use the http:// scheme for the initial push (after which it may be upgraded to https://), or perform the initial publishing using a special method.
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}
It is also possible to upload a .tar.gz (Content-Type: application/x-tar+gzip) or a .tar.zst (Content-Type: application/x-tar+zstd) archive. Using Zstandard level 0 to 3 is recommended, especially for large sites: it is a very efficient compression algorithm that will likely reduce the total energy used to publish the site.
Important! It is necessary to either use the http:// scheme for the initial push (after which it may be upgraded to https://), or perform the initial publishing using a special method.
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.
Add a file named _redirects at the root of your repository or archive. See the Codeberg documentation for a reference of the syntax. Note that the _redirects file will not be accessible from your site after publishing; it will only alter how your site works.
It is possible to enter malformed rules in the _redirects file. Such problems will not prevent your site from being published, but the malformed rules are ignored. Any problems are reported in the response to the PUT or POST request used to publish your site (your forge will display them on the webhook configuration page); they are also available at the special https://{host}/.git-pages/manifest.json or https://{host}/{site}/.git-pages/manifest.json URL, which describes how git-pages understands the layout of your site.
There are two ways to unpublish a site.
Publishing a completely empty commit makes all of its contents unreachable and erases the routing information. Once complete, the pages server behaves as if the site was never published.
Git command: git checkout --orphan empty-pages && git commit --allow-empty -m "unpublish" && git push origin empty-pages:pages
If Method B is used for authorization, a DELETE request unpublishes a site.
Curl command: curl https://{domain}/ -X DELETE -H "Authorization: Pages {password}"
Important! The git-pages server deduplicates files globally to reduce operational cost. Consequently, some of your files will linger in the backend store even after you unpublish your site. These files are completely inaccessible from the web, and will be purged by the next garbage collection cycle. (Garbage collection is a work in progress.)
To comply with the terms of service of the TLS certificate authorities (such as Let's Encrypt and ZeroSSL), 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 using its own https:// URL yet. Instead, use the following Curl command (or its equivalent) to publish your site for the first time:
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"
Take a look at the live dashboard (requires you to have working IPv6, which saves me 2 €/month).
It is a great crested grebe! Original photo © Bengt Nyman, CC BY-SA 4.0.
The architecture of grebedoc.dev is the inverse of the architecture of codeberg.page; "Grebedoc" is "Codeberg" backwards.