website
Simple greeter — the landing page at 0x29a.ch.
Previously a stock nginx container on the old Docker host, serving a bind-mounted
/mnt/docker/website/html. It now ships as a self-contained image (content baked in)
and runs on the k3s cluster behind the Hetzner Caddy.
Layout
index.html the greeter
_css/styles.css styling
_img/ft.jpg background image
favicon.ico favicon
robots.txt disallow all
Dockerfile nginx:1.29-alpine + the static files
devenv.nix dev shell: podman
Build & push the image
Images live in the Gitea container registry under git.0x29a.ch/aaron/website.
podman reads the Dockerfile natively — a drop-in for docker.
podman build -t git.0x29a.ch/aaron/website:1.0.0 .
podman login git.0x29a.ch # Gitea user + a token with write:package
podman push git.0x29a.ch/aaron/website:1.0.0
Run it locally to smoke-test:
podman run --rm -p 8080:80 git.0x29a.ch/aaron/website:1.0.0
Deploy to k3s
Deployed via the Helm chart in helm-k3s-lab-gitops/apps/website, synced by ArgoCD.
The package is private, so the namespace needs a pull secret referenced by the chart's
image.pullSecret (default gitea-registry):
kubectl create secret docker-registry gitea-registry \
--docker-server=git.0x29a.ch \
--docker-username=<user> \
--docker-password=<gitea-token> \
-n website
Then bump image.tag in the chart's values.yaml and commit; ArgoCD rolls it out from
main. (Make the Gitea package public instead and set image.pullSecret: "" to drop the
secret entirely.)
Traefik holds Ingress rules for both 0x29a.ch and www.0x29a.ch. TLS is terminated at
the edge by Caddy on the Hetzner box, which reverse-proxies to the three k3s nodes over
Tailscale — see ansible-play-infra/inventory/host_vars/0x29a.ch.yml.