|
Source for the yarilomail.org website (the open-source mail server), built with VitePress and self-hosted on Kubernetes. Licensed under AGPLv3, see LICENSE. |
npm workspace monorepo (one site for now, room for more subdomains later):
main/→ yarilomail.org
npm install
npm run -w main docs:dev # local dev server with hot reload
npm run -w main docs:build # production build -> main/.vitepress/dist
npm run -w main docs:preview # preview the production build
npm run -w main test # unit tests (node:test)main/index.md+main/.vitepress/theme/Home.vue- landing pagemain/news/*.md- news entries (frontmatter:date,title,link)main/security.md,main/support.md- static pagesmain/.vitepress/data/advisories.json- security advisories listed on/security, one object per advisory:id(CVE),date(YYYY-MM-DD),severity(critical|high|moderate|low),summary,linkmain/public/- static assets (favicon, OG image, robots.txt, IndexNow key)
GitOps via ArgoCD on the microk8s cluster. The site is built into a small
nginx:alpine image, pushed to GHCR, and rolled out by ArgoCD.
mainbranch →yarilomail.org(production,helm_values/values-prod.yaml)developbranch →wwwdev.yarilomail.org(staging,helm_values/values-staging.yaml)
The image is built on every push (<sha> + latest tags), but a new
versioned image tag is only produced when you bump version/appVersion in
helm/Chart.yaml. The deployed tag defaults to
Chart.AppVersion, so bumping the chart is what rolls out a new image via
ArgoCD. On main, a new version also creates a git tag v<appVersion> and a
GitHub release (notes generated by git-cliff).
To ship a change: merge it, then bump helm/Chart.yaml: CI builds the
v<appVersion> image and ArgoCD (argocd-app.yaml) syncs it into namespace
yarilomail.
TLS is issued by cert-manager (letsencrypt-prod ClusterIssuer, Cloudflare
DNS-01). The origin sits behind Cloudflare; the ingress is restricted to
Cloudflare IP ranges. Staging serves X-Robots-Tag: noindex.
The Ingress carries the label cloudflare-whitelist: "true":
the cluster's one cf-whitelist CronJob rewrites its
whitelist-source-range from api.cloudflare.com every 6 hours, and both
ArgoCD applications ignore that annotation, so cloudflareWhitelist.ipRanges
is only the starting list.
nginx logs the client's address: CF-Connecting-IP is taken from requests
that come from the pod network (set_real_ip_from 10.0.0.0/8, where the
ingress controller is), so the log shows the visitor rather than the
controller; kubelet probes carry no header and log their own address.
On a production release the workflow also pings IndexNow (Bing, Yandex,
Seznam) with the URLs read from the live sitemap. The verification key lives
at main/public/<key>.txt and must stay reachable: deleting it breaks the
ping.
Dockerfile,deploy/nginx.conf- image build + static servinghelm/- chart (Deployment, Service, Ingress)helm_values/- per-environment values (prod, staging)argocd-app.yaml- ArgoCD Applications (prod + staging)