Skip to content

How to use Codeberg Pages for MkDocs

Codeberg1 is a Website providing Git Hosting and services for free and open source software, content and projects.
It's managed by a non-profit (Codeberg e.V.) and offers a lot of things, including their own static page hosting Codeberg Pages.

Since I moved my blog to Codeberg Pages a while ago and since I find its set of features quite good did I now decide to make this little tutorial on how you can automate the publishing and updating of your MkDocs Site for Codeberg Pages.

Important notes

There are a few important notes I have to make here, before we can get started. Namely, there are a few minor issues you have to keep in mind when wanting to use Codeberg and Codeberg pages.
As of writing this (5th of november, 2023) there are the following issues/limitations with Codeberg Pages:

  • You cannot define a specific folder (i.e. docs/) and/or a specific branch for your repository to use with Codeberg Pages. Only the root folder of the pages branch (or default branch if repo is named pages) will work.
  • Project pages (sub-pages) are supported, but only on the user.codeberg.page domain. Using a custom Apex or sub-domain for a user/org-level domain (Meaning it is used for a pages repository) will cause this functionality to no longer work. This means that a repository named project will not appear on https://example.com/project if example.com is set as a user/org-level domain. Additionally will user.codeberg.page/project be redirected to your custom domain.
  • Custom 404 pages from MkDocs are not supported nor used. Codeberg Pages will always display their own error page instead.
  • Custom domains are defined in a .domains file in the root of the repo's pages branch (Or default branch if the repo is named pages). This can have minor conflicts with MkDocs' default ignore behaviour for files. A workaround is explained in this post.

If you're okay with these limitations and issues, read on.

Preparations

Before your site can actually be published will you need to make sure, that you've prepared some stuff first, to ensure it will work.

First of all, you need to make sure you have a CI/CD system ready to use on your repository. I use Woodpecker-CI2, an open source CI software, in this guide, but any CI that can work with Forgejo3, Soft-fork of Gitea4 used to manage the Git Hosting of Codeberg, should be fine to use here.
It's worth noting that Codeberg offers their own Woodpecker-CI Instance5 to use for free. Only requirement is that you have to apply for access.6

Next should you create an API token for Codeberg. This is required as otherwise, your CI won't be able to commit and push the docs to the repository.

Finally should you have prepared your repository. This means that you either set up a pages branch (Preferably orphaned) to push towards, or have created a repository named pages.
I will use the second option in this guide, but this also means that I'll need a second repository hosting the source (config files, markdown files, etc), as everything on the default branch of the pages repository would be served on your user.codeberg.page domain.

I suggest to have the following file structure prepared for your source repository:

.woodpecker/
└── publish_docs.yml
docs/
└── index.md
domains # Used for custom domains
mkdocs.yml
requirements.txt

The usage of a .woodpecker folder instead of a .woodpecker.yml file is recommended, as it would allow you to later add additional CI workflows for different things.

Preparing the woodpecker file

Info

The below example file will show some placeholder/example values which you should change to your own stuff. Namely...

  • knut will be used as user, which is Codeberg's example account and should be replaced with your username on Codeberg.
  • docs-source will be used as the source repository containing the raw MkDocs content and should be replaced with your source repo name.

The first thing you should do is add the source repository as a new repo in the Woodpecker-CI instance. Next should you add the necessary secrets to it, to ensure that they will be present when using the file.
In my example below do I include two secrets:

  • cbemail which contains the e-mail to use for the Git user. This can be replaced with your e-mail in the file if you're not afraid of others knowing it.
  • cbtoken which contains a valid PAT (Personal Access Token) for your Codeberg account. This ensures that we can push the final docs to the target repository without requiring login data to be included in whatever way.

In my example do I have .woodpecker/publish_docs.yml which does the publishing for us. Let's see how the file looks like and then go over all the necessary stuff:

publish_docs.yml
when:
  - event: push
    branch: master
    path:
      include: ["docs/**", "mkdocs.yml", "requirements.txt"]

variables:
  setup_git: &setup_git
    - apk add git
    - git config --global user.email "$CBEMAIL"
    - git config --global user.name "CI Docs Builder"

steps:
  cloneTargetRepo:
    image: alpine:3.18.4
    secrets: [cbemail]
    commands:
      - chmod -R a+w
      - <<: *setup_git
      - git config --global --add safe.directory /woodpecker/src/codeberg.org/knut/docs-source
      - git config --global init.defaultBranch pages
      - git clone -b pages https://codeberg.org/knut/pages.git
      - chmod -R a+w pages
  buildDocs:
    image: woodpeckerci/plugin-mkdocs:1.2.0 
    settings:
      site_dir: pages
  commitAndPush:
    image: alpine:3.18.4
    secrets: [cbtoken, cbemail]
    commands:
      - <<: *setup_git
      - cd pages
      - git remote set-url origin https://$CBTOKEN@codeberg.org/knut/pages.git
      - git add --all
      - git commit -m "Update Docs ($( env TZ=Europe/Berlin date +"%d.%m.%Y %Z" )) [SKIP CI]"
      - git push

Lets get over the different parts to look at...

when:
  - event: push
    branch: master
    path:
      include: ["docs/**", "mkdocs.yml", "requirements.txt"]
This configures Woodpecker-CI to only run when a push is made towards the master branch and only files defined in include are modified.
Make sure to update master to whatever branch you use for your doc source and also update include to have the file paths necessary. The option supports glob patterns.

variables:
  setup_git: &setup_git
    - apk add git
    - git config --global user.email "$CBEMAIL"
    - git config --global user.name "CI Docs Builder"
This sets up a reusable list of commands using YAML's anchor feature to later use in the commands of Woodpecker-CI.
$CBEMAIL would be an enviroment variable that would be defined in a step using the secrets option.

steps:
  cloneTargetRepo:
    image: alpine:3.18.4
    secrets: [cbemail]
    commands:
      - chmod -R a+w
      - <<: *setup_git
      - git config --global --add safe.directory /woodpecker/src/codeberg.org/knut/docs-source
      - git config --global init.defaultBranch pages
      - git clone -b pages https://codeberg.org/knut/pages.git
      - chmod -R a+w pages
This is the first step of the workflow which does multiple things:

  • It applies proper permissions using chmod to avoid access issues
  • It adds and setups git using the previously mentioned YAML anchor that has been created. The <<: tells woodpecker to inject the anchor at this position.
  • It configures a safe directory in git to avoid security issues
  • It sets a default branch
  • It clones the target repository to where the built docs would be pushed. Make sure to update the URL here to whatever target repo yours would be.
  • It applies proper permission to the cloned repo folder.

Also, note that I use alpine here as image. It's a lightweight, bare-bone solution that offers necessary commands (chmod, mv, etc) without being too big in size.
Feel free to use any other image here, as long as they are available for Docker and offer necessary commands.

steps:
  # ...
  buildDocs:
    image: woodpeckerci/plugin-mkdocs:1.2.0 
    settings:
      site_dir: pages
This step uses the official MkDocs plugin7 for Woodpecker-CI to build the documentation. The plugin itself uses Material for MkDocs as base alongside some other dependencies. Please see their documentation page for all settings.
We use the site_dir: setting to change the target directory for the built docs to our target repository (pages).

steps:
  # ...
  commitAndPush:
    image: alpine:3.18.4
    secrets: [cbtoken, cbemail]
    commands:
      - <<: *setup_git
      - cd pages
      - git remote set-url origin https://$CBTOKEN@codeberg.org/knut/pages.git
      - git add --all
      - git commit -m "Update Docs ($( env TZ=Europe/Berlin date +"%d.%m.%Y %Z" )) [SKIP CI]"
      - git push
This final step sets up git again like before, but also moves into the pages folder and sets the target URL to the target repository, while including the $CBTOKEN. This should be a valid Codeberg PAT to allow pushing the changes.
It then adds all the changed files, commits them (Note the [SKIP CI] which tells Woodpecker-CI to ignore this commit) and finally pushes it to the target repository to publish.

And that's all. Your site should now be available under your codeberg.page subdomain.

Adding custom domains

Similar to GitHub Pages does Codeberg pages allow you to define custom domains to use. The difference here is, that not only can you define multiple custom domains for one repository, but they also use a different file.

The file in question is called .domains which is already a smaller issue. With GitHub Pages you can have a CNAME file in the docs folder and MkDocs would carry it over into the build site. With the file from Codeberg Pages however can this not be done.
The main reason is MkDocs ignoring files starting with a dot by default.

You could now alter the configuration of MkDocs to change what files to ignore, or you can do the solution I'll show you below.

To make things work, all you have to do is make a domains file, fill it with the custom domain(s) you want to use and then add the following line to your workflow file:

publish_docs.yml
when:
  - event: push
    branch: master
    path:
      include: ["docs/**", "mkdocs.yml", "requirements.txt"]

variables:
  setup_git: &setup_git
    - apk add git
    - git config --global user.email "$CBEMAIL"
    - git config --global user.name "CI Docs Builder"

steps:
  cloneTargetRepo:
    image: alpine:3.18.4
    secrets: [cbemail]
    commands:
      - chmod -R a+w
      - <<: *setup_git
      - git config --global --add safe.directory /woodpecker/src/codeberg.org/knut/docs-source
      - git config --global init.defaultBranch pages
      - git clone -b pages https://codeberg.org/knut/pages.git
      - chmod -R a+w pages
  buildDocs:
    image: woodpeckerci/plugin-mkdocs:1.2.0 
    settings:
      site_dir: pages
  commitAndPush:
    image: alpine:3.18.4
    secrets: [cbtoken, cbemail]
    commands:
      - <<: *setup_git
      - mv domains pages/.domains
      - cd pages
      - git remote set-url origin https://$CBTOKEN@codeberg.org/knut/pages.git
      - git add --all
      - git commit -m "Update Docs ($( env TZ=Europe/Berlin date +"%d.%m.%Y %Z" )) [SKIP CI]"
      - git push
This single line would now move the domains file into the pages folder and also rename it to .domains in order for Codeberg Pages to recognize it.

And that's already it. Your domain should now be available under your custom domain.

DNS settings

Remember to also configure your domain's DNS properly to have the domains work.
You can visit the Codeberg Pages documentation for how to setup and configure custom domains.


Footnotes


Last update: 26. November 2023 ()

Comments

Comment through the Fediverse! (Click to open)

You can use a Fediverse-compatible client such as Mastodon or Pleroma to leave a comment on this blog post!