New semester, new country, new job, new website?

In which I get a VPS and decide I should self-host all the things.
personal
programming
self-hosting
CI
Author
Published

August 30, 2025

As it often happens with personal projects, I kinda neglected my personal blog for a few months. It’s normal, there’s no shame or guilt associated to it. My life was a bit quiet for a couple of months after my last post, until it very much wasn’t. In February, I applied for a job elsewhere for the first time since I had been working at The Jackson Laboratory (i.e. since 2019). It was a bit of a shot in the dark, one of those “why the heck not” applications; I enjoyed working with the people I worked with, and was more or less satisfied with things as they were. In late February, and increasingly through March, I am sure you are aware things got weird in the US, especially for immigrants like myself.

By April, we were un-making plans: my parents planned on visiting me, and suddenly that was off the cards. I wanted to travel internationally, but decided it was a bad idea now. Another thing happened in April: that place I applied for reached out wanting to have an informal chat about the position. Everything since then is kind of a blur: I had a panel interview in an early morning at the OME 2025 Community Meeting (which I co-organized!). Two weeks later I was in Heidelberg for an day of interviews, in which turned into a 3-week long, triangle-shaped trip that took me back to Brazil before returning to the US (thanks to some visa mishaps).

have you been to Heidelberg? It’s gorgeous.

have you been to Heidelberg? It’s gorgeous.

Anyway: I got the job and for the last two weeks I have been the new Data Management Coordinator in the Data Science Centre at EMBL, which is still something that I struggle to believe at times. I am (back to) living in Germany. I sold a house, uprooted my whole life, and it increasingly looks like it was the right decision, both career-wise and personally. My stress levels are WAY down. Life still feels transitional for the moment, but it will slowly settle down.

EMBL Heidelberg is at the top of a (big) hill, in the middle of the forest. Gorgeous and a nightmare to get to.

EMBL Heidelberg is at the top of a (big) hill, in the middle of the forest. Gorgeous and a nightmare to get to.

Anyway, that’s not why I am writing this post. I’m writing this post because I got myself a VPS.

Why?

The older I get, the more times I go through the cycle of “using product, product gets enshittified, need to find new product”, the more I am starting to believe it is important to (if you can, and if you know how) depend as little as you can on tech companies. In particular, I want to get rid of Microsoft in my life. Which is partly because I was already almost all the way there, and partly because of the role they have played against Palestine. Realistically, the two things I still relied upon were Windows on my gaming PC and Github. Windows is an easy win: Proton is extremely good these days and I don’t play anything that requires Windows. Github is more difficult: I have a (professional) lifetime of little projects there and, importantly, my personal website uses Github Pages.

Worth a try though, right? First step: getting a VPS (i.e. a little server you can play with). I decided to go with Hetzner (this is not an endorsement of them; I’ve had this VPS for a grand total of two days). I already owned https://erickratamero.com. So I decided to get to work. The goal: self-host a Github replacement for personal projects, and find a way to automatically deploy my personal website from a self-hosted repository by building it with Quarto - I wanted to get as close as possible to the seamless Github Pages experience.

Replacing Github: self-hosted Forgejo

The first step is EXTREMELY straightforward: Forgejo is a “software forge” geared towards self-hosting. Feature-wise it is VERY similar to Github. Spinning up a Forgejo instance took me all of 5 minutes. Here is where I thank Rik Huijzer (who I do not know) for this extremely helpful blogpost, which I followed almost verbatim. Install docker, create a minimal Caddyfile and an ini file for Forgejo, a couple of docker compose commands, pointing my domain to the right place, and voilà: https://git.erickratamero.com/ was working!

does this look familiar?

does this look familiar?

For reference purposes, the main deviation from that blogpost I made was using /var/lib/gitea instead of /var/lib/forge everywhere, because I was getting issues with conflicting working directories. I will also emphasize the importance of making sure you are using the correct UIDs and GIDs everywhere. Most of my troubleshooting was issues with Docker volume mounts not working properly because of permissions.

Good start! What about CI? I use Github Actions all the time, so this was a must (especially if I wanted to build my website automatically). Good news! That is also a simple docker compose away, thanks to Forgejo providing a runner image. Again, make sure your user IDs are correct to avoid a permissions nightmare. The one obvious change I made from the blogpost I linked is using a newer image for the runners themselves, by configuring my labels as

ubuntu-24.04:docker://ghcr.io/catthehacker/ubuntu:act-24.04

Sure enough, follow that blogpost and you will have an operational CI runner! This felt like magic to me. One thing left: deploying my pages after they are built. I’ll cut to the chase: the full Github Pages is not feasible in this self-hosted world yet (or maybe it is: I ran out of patience before testing Codeberg Pages but sentences like if you consider using Pages in practice, please consider contacting us first make me think it is not quite ready for an easy setup just yet).

Serving the generated files is relatively easy: I added the following snipper to my Caddyfile

pages.erickratamero.com {
 root * /pages
 file_server
}

and that’s all I needed to do to serve the files inside the /pages folder in my VPS! Now, obviously, given that the Git server is running in that very same VPS, it’s just a matter of copying the files over from the folder where repositories live to the /pages folder, right?

Well, a couple of issues with that: 1) the actions are running in a docker image inside a docker image, essentially. I suppose it is technically possible to set up your volumes just right and do that as a step in your CI action, but I tried everything I could think of and failed; 2) I might have missed something very obvious, but I could not for the life of me find my Git repos stored in a folder structure ANYWHERE. I think they might live inside some database structure? Don’t quote me on that. (if you know where Forgejo stores your repos in a sane folder structure, please do let me know.)

I tried a few really funny things, like using an scp action as a step to copy the generated files to the right folder, but at the end I ran out of patience and decided to settle for good enough. “Good enough” is a cron job that clones the (correct branches of) repositories in a list to the /pages folder structure. So I can push markdown to my Forgejo server, it builds the website using Quarto in an action, and then the cron job eventually puts it in the right place to be server on the web. What you are reading right now was generated using that workflow!

it takes like 30 seconds.

it takes like 30 seconds.

So what did I learn?

This was simultaneously way easier and more annoying than I expected, largely through my own fault. All the things you need are out there as Docker images and spinning them up is almost trivial. Getting everything to work as it should took me longer than I expected (I hate Docker volumes so much), and ultimately I did not get all the way to the result I wanted, but I got 95% of the way there and I have a working(ish) solution. Right now you can go to https://git.erickratamero.com to see my code for this website and for a quarto presentation template I will start using for my talks, and https://pages.erickratamero.com/repo-name-here will deploy pages for individual repos with pretty minimal work on my part other than writing markdown. Maybe this is the kick in the butt I need to write more often…

(the caveats: this is largely a proof-of-concept. I am not a web developer or a security professional: I have no idea if what I’m doing is secure at all! I am operating on the assumption I might need to completely nuke this VPS at any point in time and start from scratch - i.e. keeping backups elsewhere etc etc.)