How To: Host a static site in Codeberg Pages
Blogs in 2026
Sometimes we want to passively communicate.
Sometimes we want to document so we don't forget.
Sometimes we don't want to catch up on 8 years of tech to do something simple.
Sometimes we don't want to deal with hosting.
Sometimes we just want to share.
Sometimes we just want static site generators and Codeberg Pages.
Prepare Codeberg
Codeberg.org is an web-based Git Forge built on Forgejo, which is a soft-fork of Gitea, which was forked from Gogs... I think.
They're big on FOSS and encourage public repos with permissible licensing.
I use Creative Commons Attribution-ShareAlike 4.0 International in my own projects hosted on Codeberg.
Create an account, and once logged in create a new repository.
During repository creation, expand Advanced settings and select:
- Default Label Set
- SHA256 Object format
-
mainDefault branch
Skip the setup instructions that the repo gives you for now.
Prepare webhook
Codeberg offers codeberg.page as a free way to host static websites.
There is a CI section available at the bottom of the page if you self-host your own Forgejo instance.
We are going to (mostly) follow the "Set up your website (new method without CI)" method.
Be sure to read through the process, but for now, only follow Step 2: set up a webhook as they describe.
The Target URL I used for mine was https://spont.codeberg.page/yahr-matey, the same URL you visit
to view the blog.
Reorganize Git
We're going to pull some funky branch logic so that:
-
mainbranch contains only source files -
pages, an orphaned branch, contains only generated files
This basically keeps two separate, unrelated versions of your repo; one containing the source used to generate content, the other containing only generated content.
This approach requires two separate add/commit/push flows
Since it's basically two different repos pointed to the same origin, we need to perform our add/commit/push workflows in both our project root and the generated content directory.
Skip this next set of steps if your project has an existing remote repository
git init --object-format=sha256 # omit --object-format if you don't use SHA256 hash git remote add origin git@codeberg.org:user/my_new_blog.git git checkout -b main tee .gitignore <<EOF __pycache__ cache output EOF git add .gitignore git add . git commit -m 'init' git push -u origin main
It is important to add your generated output directory to .gitignore.
I use Nikola so the directory containing my generated content is output.
That dir contains the generated files that we do not want included in our repo's main branch.
It contains files that we do want in that pages branch that we created earlier, so we're essentially going to make it a separate
project that points only at the pages branch, and contains only the generated blog contents.
cd output # Or the generated content directory git init --object-format=sha256 git remote add origin git@codeberg.org:user/my_new_blog.git git checkout --orphan pages # Clear _all_ repo contents on the `pages` branch from git tracking so it only contains `output` contents git rm -r --cached ../. # Go back to project and `main` branch so we can generate output to commit cd .. # Project dir should still be on `main` but just in case git checkout main # Generate blog files nikola build # Go back to content repo cd output git add . git commit -m 'first post' git push -u origin pages
Repo Settings
Since main contains the source to generate our content, and pages contains the content that gets published, we want to make sure to enable Branch Protection Rules.
The linked docs are for GitHub but they're near identical in Codeberg.
We want to make sure to create a rule for main that disallows pushing to it and only allows merge request approval from you.
We need to do the same thing for the pages branch.
Workflow
Now that we've got our git repos configured, the workflow for posting becomes:
- Make changes to project files
- Format
.mdfiles (I use mdformat) -
git add/commit/pushthem to Codeberg - Create PR to
main - Merge PR
-
pullfrommain - Generate your new content
-
cdto your generated content directory -
git add/commit/pushnewly generated content to feature branch - Create PR to
pages - Merge PR
Summary
You should see your empty, but rendered, blog if you visit your URL: https://user.codeberg.page/my_new_blog pretty quickly, less than a minute in my experience.
You did it, yay!
