k3s · ArgoCD · GitOps · Cloudflare

Self-hosted infra.
GitOps all the way down.

The Afrotomation cluster runs 70+ apps on a bare-metal k3s setup, fully managed via ArgoCD and a single GitLab repository. Every deploy is a git commit. Every secret is SOPS-encrypted. Every cert is auto-renewed.

Architecture

GitLab is the source of truth. ArgoCD pulls changes into k3s. cert-manager, external-dns, and ingress-nginx handle TLS and routing. Cloudflare sits in front of everything.

🗄 GitLab Source of truth
IaC + image registry
ArgoCD Sync loop
image-updater
k3s cluster Bare-metal nodes
VPS 10 + VPS 50
🔒 cert-manager Let's Encrypt TLS
letsencrypt-prod issuer
🌐 ingress-nginx + external-dns Routing + Cloudflare DNS
auto-published hostnames
Cloudflare CDN + DDoS protection
DNS for all subdomains

Control plane

A single-node k3s control plane runs on a Contabo VPS 50 (8 vCPU, 30 GB RAM). An Oracle Ampere ARM64 node (4 OCPU, 24 GB RAM) joins as a worker for lightweight workloads. ArgoCD manages every namespace declaratively; the only manual step is bootstrapping a new namespace secret once per workload.

Runtime

All production images are built via GitLab CI and pushed to the in-house registry at registry.afrotomation.com. The argocd-image-updater watches for new digests and writes back to the GitLab repository, triggering a self-healing sync loop. SOPS + age encrypts every secret committed to the repo; the sops-secrets-operator decrypts at runtime.

Image pipeline

Each workload defines its own GitLab CI job gated on changes to its subdirectory. Semantic-release manages the infra changelog and version tagging. Mirror-to-GitHub ensures a public read-only copy stays in sync on github.com/afrotomation/afrotomation-infra.

Design decisions

k3s over EKS / GKE
Zero managed-plane cost; full control over node placement; runs on commodity VPS without cloud vendor lock-in. Trade-off: manual upgrades and no managed etcd backup.
ArgoCD over Flux
Richer UI for debugging out-of-sync resources; image-updater integration is first-class. Flux would have worked equally well for a small team.
In-house GitLab over GitHub for IaC
IaC secrets and internal service URLs stay off a public SaaS. GitHub is kept as a public read-only mirror. GitLab CI runners run inside the cluster via gitlab-runner workload.
SOPS + age over Sealed Secrets
Git-native encrypted secrets work with any CD tool; decryption key rotation is explicit. Sealed Secrets are controller-scoped and harder to recover from a full cluster rebuild.

Public services

10 live public-facing apps on the cluster, all served over HTTPS via Cloudflare + ingress-nginx + cert-manager.

📅 Cal.com

Self-hosted scheduling and calendar-link platform, replacing Calendly for the Afrotomation team.

Excalidraw

Self-hosted collaborative whiteboard for diagrams, architecture sketches, and brainstorming sessions.

🤖 ADA Dashboard

Internal AI Developer Agent control center — monitors autonomous dev operations and system health.

📊 Codenalytics

Code analytics platform for tracking development velocity, churn, and contribution metrics across repos.

Fasolara

Solar energy monitoring dashboard tracking PV output, battery state, and grid interaction for Sahel Energies.

🍊 Fructosahel

E-commerce storefront for Fructosahel fruit juices and products — part of the Sahel Foods group.

💼 Codeniwork

Freelance and remote work marketplace connecting African tech talent with global opportunities.

💹 Codeninvest

Investment portfolio tracker and African market analytics platform for individual and institutional investors.

🐝 OpenSwarm

Docker Swarm-style orchestration dashboard for managing distributed services across the cluster.

📓 Logseq

Self-hosted knowledge graph and note-taking tool for team documentation and personal wikis.

📡 Hermes

Internal messaging and notification relay service connecting all Afrotomation platform events.

📈 Umami

Privacy-first web analytics platform providing traffic insights across all Afrotomation properties.

Changelog

Last 10 releases — managed by semantic-release from the GitLab repository.

v1.41.42026-05-06

Bug Fixes

  • openswarm: enable PKCE (S256) so codeniserver authorize doesn't reject
v1.41.32026-05-06

Bug Fixes

  • calcom: probe /auth/login + add ALLOWED_HOSTNAMES
v1.41.22026-05-06

Bug Fixes

  • calcom: add DATABASE_DIRECT_URL so prisma migrate deploy can run
v1.41.12026-05-06

Bug Fixes

  • calcom: repoint image refs from ghcr.io to in-house GitLab registry
v1.41.02026-05-06

Features

  • gitops: migrate afrotomation-infra source from GitHub to git.afrotomation.com
  • openswarm: replace basic-auth with codeniserver SSO via oauth2-proxy

Bug Fixes

  • openswarm: point auth-url at internal oauth2-proxy service
  • openswarm: split /oauth2/* onto its own Ingress to break SSO redirect loop
v1.40.12026-05-06

Bug Fixes

  • excalidraw: use nginx ingressClass to match cluster controller
v1.40.02026-05-06

Features

  • logseq: self-host Logseq web app on logseq.afrotomation.com
v1.39.02026-05-06

Features

  • openswarm: self-host OpenSwarm on openswarm.afrotomation.com
v1.38.32026-05-06

Bug Fixes

  • mongodb: switch readiness/liveness to TCP probes
v1.38.02026-05-06

Features

  • excalidraw: self-host Excalidraw on excalidraw.afrotomation.com