Skip to content

Using git-pages on Codeberg

A while ago has Codeberg announced their completion of their git-pages rollout.1
This means that you are now able to publish your site on Codeberg using their git-pages2 instance, which brings some benefits, but also drawbacks to consider

I'll use this oportunity to now make an updated version of my original Blog Post for Codeberg Pages, covering how you can publish your site using ProperDocs3 and Forgejo Actions.

Why git-pages?

Codeberg has provided their own service called pages-server4 for a long time now and while it did work and has some cool features, has it entered a maintenance-mode state, with git-pages being the recommended alternative to use.

The primary reason for using git-pages, is that it actually deploys the created site to then serve.
The pages-server did not do such a thing. Instead was it pulling the site content directly from the configured repository to serve.
While this allowed a often time quicker updating if site changes, did it put a lot of stress on the backend, leading to nummerous downtimes.

Through git-pages is the content static and simply needs to be served without any pulling from a repository being required, reducing operations and significantly boosting performance and stability, at the cost of changes requiring a re-deployment to take effect.

Note

While pages-server is in maintenance mode and git-pages is the recommended alternative, does Codeberg have no plans for removing pages-server, nor shut it down. Sites served through pages-server remain functional and the old method remains supported.

Smaller Drawbacks

git-pages, while having great feature-parity with pages-server, has some smaller drawbacks to consider:

  • The raw.codeberg.page sub-domain can not be used on git-pages repos to obtain a Site's raw content. Instead are sites deployed with proper CORS headers, allowing you to now use the content directly from the site domain used.
    This means, that if you used raw.codeberg.org to pull raw files (i.e. JS files) from your site, you now need to replace it with your site's domain and may need to update the path too.

Deploying to git-pages

This section will cover how you can configure a Forgejo Workflow to deploy your page build through ProperDocs.
While this is the recommended aproach, can you also deploy your site by pushing it to a repository or branch and setup a Webhook targeting your site's domain. This aproach may be easier, as it doesn't require you to configure a TXT DNS entry for your custom domain, but comes at the cost of an extra branch/repository needed.

A quick note about custom domains

If you want to deploy your site for a custom domain (i.e. example.com) are some DNS changes required.
Namely, you need to add the following DNS entry to your custom domain:

Type Name Value
TXT _git-pages-forge-allowlist URL to your repository deploying the site.

As an example, the following TXT entry would be needed, if you want to deploy your site from codeberg.org/Knut/ExampleSite to example.com:

_git-pages-forge-allowlist.example.com. TXT "https://codeberg.org/Knut/ExampleSite"

If you want to use a custom subdomain, i.e. docs.example.com do you need to include the subdomain in the full TXT name: _git-pages-forge-allowlist.docs.example.com

For codeberg.page sub-pages is the only requirement, that the {user}.codeberg.page/{repository} matches the User/Organisation and Repository name that it is being deployed from.
Example: If deploying from codeberg.org/Knut/ExampleSite, the site option needs to be https://knut.codeberg.page/ExampleSite.

Only exception is for the {user}.codeberg.page domain itself. If you want to deploy to it directly, is the Repository required to be named pages.

Should you want to deploy to a codeberg.page domain from a Repository without a matching name, will you need to create a Personal Access Token with Read and Write permission for the Repository scope.

The Workflow File

The following Workflow can be used to deploy to git-pages on Codeberg:

deploy_site.yml
name: Deploy Site

on:
  push: # (1)

jobs:
  publish:
    run-on: codeberg-tiny
    steps:
      - name: "Checkout Repository"
        uses: https://code.forgejo.org/actions/checkout@v6
        with:
          fetch-depth: 0 # (2)
      - name: "Setup Python"
        uses: https://code.forgejo.org/actions/setup-python@v6
        with:
          python-version: 3.x
      - name: "Install dependencies"
        run: "pip install -r requirements" # (3)
      - name: "Build Site"
        run: "properdocs build"
      - name: "Deploy Site"
        uses: https://code.forgejo.org/actions/git-pages@v2
        with:
          site: https://example.com # (4)
          token: ${{ secrets.FORGEJO_TOKEN }} # (5)
          source: site/ # (6)

  1. I highly recommend adding branches and paths filters to only trigger this workflow on specific branches and for specific file changes.
    Example:
    on:
      push:
        branches:
          - main
        paths:
          - ".forgejo/workflows/deploy_site.yml"
          - "docs/**"
          - "properdocs.yml"
          - "requirements.txt"
    
    Should you also publish releases on your repository (or push tags) do I recommend to also add tags-ignore: ["**"] to ignore any tags being created, as those counts as pushes too.
  2. Avoids issues with plugins that require proper git history to work right (i.e. git-revision-date-localized-plugin)
  3. Change this to whatever command(s) you need. It's recommended to keep your dependencies in a requirements.txt for easier updating and maintenance.
  4. Set this to either the custom domain you use (i.e. https://example.com) or the {user}.codeberg.page domain you deploy this to, based on the following rules:

    • If the repository is named pages can/should the domain be https://{user}.codeberg.page where {user} is the Account owning the Repository.
    • If the repository is not named pages should the domain be https://{user}.codeberg.page/{repository} where {user} is the Account owning the Repository and {repository} is the Repository name itself.
  5. This doesn't need to be changed, unless you want to deploy from a Repository to a {user}.codeberg.page/{repository} domain, where {repository} is different (i.e. You deploy to knut.codeberg.page/hello from codeberg.org/knut/world).

  6. This should be the name of the site_dir used by ProperDocs which is site by default.
    Note that the action defaults to _site/ so you need to change this unless you configured ProperDocs to build to _site.

Once pushed will this trigger a Workflow that checks out your repository, sets up python, installs the dependencies, builds the site and deploys it.
If everything goes well will your site be deployed and be available at the configured domain.

PR previews

Codeberg recently added support for deploying your site to a preview-subdomain, allowing you to create a Preview for pull requests and similar.

In order to create a PR preview, simply deploy your site to <user>.preview.codeberg.page/<path> using the git-pages action, where <user> would be the username owning the repository and <path> the repository name and PR number in the format <repo>@<pr-id>.
As an example, the following Action Workflow will deploy the preview to knut.preview.codeberg.page/example@<pr-id> with the <pr-id> being the actual PR number:

pr_preview.yml
name: Pull request Preview

on:
  pull_request: # (1)
    types: # (2)
      - opened
      - reopened
      - synchronize

concurrency:
  group: page-preview
  cancel-in-progress: false

jobs:
  createPreview:
    runs-on: codeberg-tiny
    env: # (3)
      SITE_ORIGIN: "https://${{ forge.event.repository.owner.username }}.preview.codeberg.page"
      SITE_BASEPATH: "/${{ forge.event.repository.name }}@${{ forge.event.number }}/"
    steps:
      - name: "Checkout Repository"
        uses: https://code.forgejo.org/actions/checkout@v6
        with:
          fetch-depth: 0 # (4)
      - name: "Setup Python"
        uses: https://code.forgejo.org/actions/setup-python@v6
        with:
          python-version: 3.x
      - name: "Install dependencies"
        run: "pip install -r requirements" # (5)
      - name: "Build Site"
        run: "properdocs build"
      - name: "Deploy Site"
        uses: https://code.forgejo.org/actions/git-pages@v2
        with:
          site: "${{ env.SITE_ORIGIN }}${{ env.SITE_BASEPATH }}" # (6)
          token: "${{ forge.token }}" # (7)
          source: "site/" # (8)
      - name: "Find comment"
        uses: "https://github.com/peter-evans/find-comment@v4" # (9)
        id: comment
        with:
          issue-number: ${{ forge.event.number }} # (10)
          body-includes: "<!-- preview-comment -->" # (11)
      - name: "Create or update comment"
        uses: "https://github.com/peter-evans/create-or-update-comment@v5" # (12)
        with:
          issue-number: ${{ forge.event.number }} # (13)
          comment-id: "${{ steps.comment.outputs.comment-id }}" # (14)
          edit-mode: "replace"
          body: |-
            # Pull request preview ready!

            The Preview of commit ${{ forge.event.pull_request.head.sha }} has been created.
            You can find it here: ${{ env.SITE_ORIGIN }}${{ env.BASEPATH }}

            <!-- preview-comment -->

  1. Make sure to use pull_request and not pull_request_target.
    In addition is it recommended to add a paths option containing the file paths this should trigger on.
    Example:
    on:
      pull_request:
        types:
          - opened
          - reopened
          - synchronize
        paths:
          - ".forgejo/workflows/deploy_site.yml"
          - "docs/**"
          - "properdocs.yml"
          - "requirements.txt"
    
  2. This ensures that the action is only executed when a PR is created, reopened or updated (pushes are made) and not when it gets closed.
  3. This sets the environment variables to later use for the Deploy preview's address:

    • SITE_ORIGIN is the subdomain to use and is resolved to <user>.preview.codeberg.page
    • SITE_BASEPATH is the part after the sub-domain where the site should be served at and needs to be <repository>@<pr-id>

    This setup allows an easy reusable Workflow for multiple repositories, without having to change all the info.

  4. Prevents git history issues with plugins like the git-revisiondate-localized plugin.

  5. Change this to whatever command(s) you need. It's recommended to keep your dependencies in a requirements.txt for easier updating and maintenance.
  6. This needs to be a <user>.preview.codeberg.page/<repo>@<pr-id> domain, which is achieved by using the previously created environment variables.
  7. This doesn't need to be changed.
  8. This should be the name of the site_dir used by ProperDocs which is site by default.
    Note that the action defaults to _site/ so you need to change this unless you configured ProperDocs to build to _site.
  9. Forgejo supports GitHub Actions, as long as they do not rely on the GitHub CLI or Graphs API.
    The find-comment action of peter-evans can be used here, allowing us to find an already existing command and later edit it, instead of always writing a new one.
  10. It's important to set the PR number here for the action to know where to search.
  11. This can be any text you like, for as long as it will be included in the actual comment to be found.
    I use a HTML comment here, as it is the best way of having identifiable text that won't be rendered.
  12. Forgejo supports GitHub Actions, as long as they do not rely on the GitHub CLI or Graphs API.
    The create-or-update-comment action of peter-evans can be used here, allowing us edit an already existing comment, if the previous action finds an ID, or create a new one instead.
  13. It's important to set the PR number here for the action to know where to search.
  14. This uses the comment ID found in the previous action. If none is found will the action automatically create a new comment instead.

With this workflow would you now have a Preview created, deployed and a comment written (or updated) with the link provided to view it.


Footnotes

Comments

Comment system powered by Mastodon.
Leave a comment using Mastodon or another Fediverse-compatible account.


Last update: 16. June 2026 ()