Codeberg Pages with SSL and Custom Domain

By Artyom Bologov A digitally hand-drawn thumbnail on white background. In the center, a Codeberg logo (triangular iceberg) is drawn in black and dark blue. Around it, handwritten '+aartaka.me', '+SSL', '+Artyom', '+email', and '+SSG' are floating. The handwriting is all wiggly, likely due to author's inexperience or negligence.

Yesterday night, Gitlab sent me an email saying I'm running out of "compute minutes." Whatever that means. Most likely, I was running out of CI/CD resources when building this website on Gitlab Pages. It's been a thing going for some time:

I guess I went overboard with using ed(1) as my new site generator. Nonetheless, that's not nice of Gitlab Pages offering "infinite and free" website builds. And then saying I have no resources anymore.

So I decided to do the most Saturday evening thing programmers do: migrate my website to an absolutely different hosting setup. To Codeberg Pages.

Codeberg doesn't offer some of the features Gitlab provides. In particular, no CI/CD/website builds, and no automatic SSL certificates. Thus this post: to document what I went through to reproduce my current setup on Codeberg:

Domain
aartaka.me and subdomains, managed by Namecheap.
SSL Certificates
With DNS verification, issued by Let's Encrypt (because I'm poor and anti-capitalist.)
Email
Custom Domain Email by Disroot.
Build process
Makefiles and ed(1).

So here's how I went about it.

Getting Started with Codeberg Pages

The documentation by Codeberg is good enough: Create a pages repository, add HTML files to the root, and git push them there.

I diverged from these instructions once: I named the default branch "pages", instead of "main". This way, my website is deployed from "pages", while "main" is reserved for my experiments and drafts.

I also had to move all my files to repository root. On Gitlab, I had them in public/ subdirectory for deployment. But that's too minor to care.

DNS & Email

Again, documentation by Codeberg works: Create a .domains file with your domains:

aartaka.me
aartaka.codeberg.page
pages.aartaka.codeberg.page
pages.pages.aartaka.codeberg.page
My .domains contents

and add DNS records:

CNAME
The simplest case for when you only care about the website. Doesn't work with e.g. my custom domain email setup.
ALIAS
A simple enough case that works with my email. That's the one I picked.
A/AAAA
Didn't try it, sorry.

So here's my final setup:

ALIAS @ codeberg.page.
TXT @ pages.aartaka.codeberg.page
DNS records for Codeberg Pages (as displayed by Namecheap, @ is aartaka.me)

The email is managed by MX and SPF records, and ALIAS/TXT don't interfere with these. Should be fine, given that I'm still receiving spam.

Setting Up SSL with Let's Encrypt

This is likely covered elsewhere, but I want to reproduce this anyway. Especially given that Codeberg docs don't cover this except for one note in Custom Domain page. So I need to explay future myself how in the world all of this works.

So... Let's Encrypt. They are doing miracles, but they require domain ownership check first. And this check is done by putting a file into a .well-known subdirectory on the server.

The problem is: Codeberg blocks requests to .well-known. So one has to use alternative verification strategies. Like DNS verification. Here's the DigitalOcean guide I followed. But the procedure is relatively simple:

sudo certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d \*.aartaka.me -d aartaka.me
Certbot call with a DNS auth extension

It provides all the instructions, and the guide above augments it. Here are the records I had to add:

// Notice the single letsencrypt.org here:
// Namecheap didn't allow me to include any value beyond that.
CAA 0 issue "letsencrypt.org"
CNAME _acme-challenge xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.auth.acme-dns.io.
CAA record to allow certificates from Let's Encrypt and the actual challenge value (redacted)

After DNS records update (I waited for two minutes, but better wait five, just in case,) you can press Enter to continue setup. Certbot will register the domain and generate your certificates.

When the certificates expire, I'll have to run this scary one-liner again. But that's going to happen in 90 days, so who cares?

Website Generation

Now the hardest part: Codeberg doesn't offer any CI/CD beyond static resource publishing. I might've tried to hack them or use some Turing-complete CI quirk. But I don't want trouble.

So I'm generating my pages locally and then pushing them to Codeberg. That's where the "pages" branch comes into play. I'm keeping my "main" clean, and then switch to "pages" and generate all the posts in all the formats:

git checkout pages
git merge master
make all -j 4
git commit --all -m "..."
git push
Every post publication procedure (I usually do that in Magit, though)

I can't imagine the trouble I'd need to go through if I was using some fancy blog engine. Endless npm vulnerabilities and gigabytes of node_modules, likely. But, luckily, I'm using ed(1) as my SSG and I don't have to mess with any of that. And it's taking a really short time to generate all 5 (!) formats for all the ~50 pages I have.

So yes, you might be dissatisfied with Codeberg Pages if you want fancy blog engine builds somewhere in the cloud. But I don't do that, so I'm perfectly fine with Codeberg. Still, do give it a try!

Leave feedback! (via email)