After The Unicorns Forced Me Into GitOps, my first priority was version control. But I didn’t want to use Github alone. As a home-labber I’m apparently allergic to trusting cloud services. Thus I landed on self-hosted Gitea.
Gitea Setup
I used docker compose to get it running using their docs. And after a docker compose up I could see the Gitea web UI at http://server-ip:3000 and finalized the installation there. Yet this didn’t magically start to track my files.
I needed a repo. After creating one via the web UI, I initialized a local one:
git init
git branch -M main
# to cache your credentials for future pushes
git config --global credential.helper store
# add private files like .env or .ssh_keys; also include postgres/
nano .gitignore
git add .
git commit -m "Initial commit"
# fill in your details!!
git remote add origin http://your-username:GITEA_TOKEN@your-server-ip:3000/your-username/repo-name.git
git push -u origin mainCreating a Gitea token
Go to User Settings ⇒ Applications. Enter a “Token Name,” select Read/Write for repositories, and click Generate Token.
And that’s it! Almost… because now I could track my changes, yet I didn’t have a clear idea of what I was tracking. Creating documentation & runbooks have been in my mind for a while. And with version control in place, I had everything I needed to start.
Documentation Site
Lucky for me, Gitea was the last service I’ll have to rediscover the wheel. I created an On New Services runbook that used Gitea as the blueprint for what a typical service looked like — written in Markdown via Obsidian, of course. But I wanted a place to link them together and explore them visually (I have a thing for that). A Quartz 4 docs site is perfect for the job:
docs:
build: ./docs
container_name: docs
environment:
GIT_REPO: "http://your-username:DOCS_GITEA_TOKEN@your-server-ip:3000/your-username/repo-name.git"
networks:
- gitea # the same internal docker network that gitea & postgres/SQLite are on
ports:
- "80:80" # you may need a different host port if 80 is already taken
volumes:
- ./docs/quartz/content:/vault:ro
- ./docs/quartz:/usr/src/app/quartz
restart: unless-stoppedIn your docs directory, you’ll need this Dockerfile to build from1:
FROM shommey/dockerized-quartz:latest
# Update to Node.js 22
RUN apt-get update && \
apt-get install -y curl && \
curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \
apt-get install -y nodejs && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
node --version && \
npm --version
RUN git clone https://github.com/jackyzha0/quartz.git . && \
npm installAfter creating another Git repo for the docs site, initialize the Quartz boilerplate:
# remove docs/ from the main repo tracking
nano .gitignore
# in /docs/quartz
git clone https://github.com/jackyzha0/quartz.git .
git branch -M main
# node must be >= v22; npm >= v10.9.2
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc
# initialize Quartz repo
npm i
npx quartz create
git remote set-url origin http://your-username:GITEA_TOKEN@your-server-ip:3000/your-username/docs-repo-name.git
git push -u origin main And after a build, you should see a template Quartz site at http://server-ip:80. But it doesn’t help if theres no documentation there… You can write markdown files at docs/vault/content — and if you’re patient, a manual restart will serve the files.
What if you’re not patient?
Then you’re in the same boat as me. We need CI/CD — lets create a gitea-runner that automatically rebuilds the docs site on repo push:
gitea-runner:
container_name: gitea-runner
image: gitea/act_runner
environment:
- GITEA_INSTANCE_URL=http://gitea:3000
- GITEA_RUNNER_REGISTRATION_TOKEN=PASTE_TOKEN_HERE
networks:
- gitea
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./gitea-runner/config.yaml:/config.yaml
depends_on:
- giteaRegistering a Gitea Runner
Go to Repository Settings ⇒ Actions ⇒ Runners. Copy and paste the Registration Token under Create new Runner.
In the gitea-runner directory, we need to generate a default config for job containers that the runner spawns:
docker run --rm --entrypoint="" gitea/act_runner act_runner generate-config > config.yamlThen add this to the config so they can reach the gitea network:
container:
network: "gitea"With that set, we can create the workflow file at .gitea/workflows/deploy.yaml:
on:
push:
branches: [main] # when pushed to main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- run: docker exec docs sh -c "cd /usr/src/app/quartz && git pull && npx quartz build --directory /vault --output /usr/share/nginx/html"
# cd into the quartz dir --> pull changes --> build new siteEt voilà! After running docker compose up for the runner, any .md files pushed to docs/vault/content will appear on your docs site almost instantly.
Yet what do I do When It All Falls Down?
Footnotes
-
Made possible by shommey’s dockerized-quartz ↩