feat: homelab case study from live infra; Traefik-based deploy

- rewrote homelab (content + topology diagram + stack) from a live inspection of the host:
  Ubuntu 24.04, ~30 Docker services behind Traefik (Cloudflare-fronted, TLS, HTTP/3),
  Authentik SSO forward-auth, CrowdSec, Pi-hole, self-hosted Gitea + CI runner, socket-proxy,
  per-app network isolation; WordPress framed as being decommissioned (not future arch)
- deploy: docker-compose now uses Traefik labels + traefik_proxy network (was assumed nginx
  edge); .env.example adds SITE_HOST/TRAEFIK_ENTRYPOINT; colophon + ARCHITECTURE/DOCKER/
  DEPLOYMENT specs corrected nginx-edge -> Traefik (site container still serves via nginx)
- PROJECT_STATUS: pre-launch checklist updated; infra section added

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
cesnimda
2026-07-04 11:23:09 +02:00
parent a10418ab93
commit bfa8cfd357
8 changed files with 129 additions and 84 deletions
+2 -2
View File
@@ -34,7 +34,7 @@ const copy = {
],
[
'Self-hosted',
'Built and deployed from my own Gitea instance to Docker behind nginx. The contact form is a small stateless .NET service — even that is part of my own stack.',
'Built and deployed from my own Gitea instance to Docker behind Traefik. The contact form is a small stateless .NET service — even that is part of my own stack.',
],
[
'No tracking',
@@ -59,7 +59,7 @@ const copy = {
],
[
'Egendriftet',
'Bygget og rullet ut fra min egen Gitea-instans til Docker bak nginx. Kontaktskjemaet er en liten tilstandsløs .NET-tjeneste — også den er en del av min egen stack.',
'Bygget og rullet ut fra min egen Gitea-instans til Docker bak Traefik. Kontaktskjemaet er en liten tilstandsløs .NET-tjeneste — også den er en del av min egen stack.',
],
[
'Ingen sporing',
+77 -59
View File
@@ -1,6 +1,10 @@
import type { Project } from '@lib/schema';
/* Homelab — capability page (lighter template): no TL;DR/decisions/gallery rendered. */
/*
Homelab — capability page (lighter template): no TL;DR/decisions/gallery rendered.
Content reflects the real setup inspected on the host (Ubuntu 24.04, ~30 Docker
services behind Traefik with Authentik SSO, CrowdSec, Pi-hole, Gitea CI).
*/
export const homelab: Project = {
id: 'homelab',
name: 'Self-hosted infrastructure lab',
@@ -10,88 +14,100 @@ export const homelab: Project = {
stack: [
{ name: 'Ubuntu' },
{ name: 'Docker' },
{ name: 'nginx' },
{ name: 'Gitea' },
{ name: 'Monitoring' },
{ name: 'Backups' },
{ name: 'Traefik' },
{ name: 'Authentik' },
{ name: 'CrowdSec' },
{ name: 'Gitea CI' },
],
links: [],
diagram: {
viewBox: '0 0 1120 300',
viewBox: '0 0 1120 310',
title: { en: 'Homelab topology', no: 'Hjemmelab-topologi' },
desc: {
en: 'Inbound traffic reaches an nginx reverse proxy terminating TLS, which routes to self-hosted services: Gitea, application containers and a monitoring stack.',
no: 'Innkommende trafikk når en nginx reverse proxy som terminerer TLS, og rutes videre til egendriftede tjenester: Gitea, applikasjonscontainere og en overvåkingsstack.',
en: 'Traffic arrives through Cloudflare to a Traefik reverse proxy that terminates TLS and applies Authentik single sign-on, then routes to self-hosted services: Gitea and its CI runner, application containers, and a media stack.',
no: 'Trafikk kommer via Cloudflare til en Traefik reverse proxy som terminerer TLS og bruker Authentik single sign-on, og rutes videre til egendriftede tjenester: Gitea med CI-runner, applikasjonscontainere og en mediastack.',
},
nodes: [
{
id: 'internet',
id: 'cloudflare',
x: 40,
y: 116,
w: 160,
h: 72,
y: 124,
w: 170,
h: 68,
kind: 'external',
label: 'Internet',
sub: { en: 'HTTPS', no: 'HTTPS' },
label: 'Cloudflare',
sub: { en: 'DNS · edge · WAF', no: 'DNS · edge · WAF' },
},
{
id: 'proxy',
x: 280,
y: 116,
w: 190,
h: 72,
id: 'traefik',
x: 290,
y: 124,
w: 180,
h: 68,
kind: 'primary',
label: 'nginx',
label: 'Traefik',
sub: { en: 'reverse proxy · TLS', no: 'reverse proxy · TLS' },
},
{
id: 'authentik',
x: 290,
y: 232,
w: 180,
h: 56,
kind: 'internal',
label: 'Authentik',
sub: { en: 'SSO · forward-auth', no: 'SSO · forward-auth' },
},
{
id: 'gitea',
x: 560,
y: 40,
w: 190,
y: 44,
w: 210,
h: 60,
kind: 'internal',
label: 'Gitea',
sub: { en: 'git.cesnimda.uk', no: 'git.cesnimda.uk' },
label: 'Gitea + runner',
sub: { en: 'git.cesnimda.uk · CI/CD', no: 'git.cesnimda.uk · CI/CD' },
},
{
id: 'apps',
x: 560,
y: 120,
w: 190,
y: 128,
w: 210,
h: 60,
kind: 'internal',
label: 'App services',
sub: { en: 'Docker containers', no: 'Docker-containere' },
label: 'App containers',
sub: { en: 'JobTrack · this site', no: 'JobTrack · denne siden' },
},
{
id: 'monitor',
id: 'media',
x: 560,
y: 200,
w: 190,
y: 212,
w: 210,
h: 60,
kind: 'internal',
label: 'Monitoring',
sub: { en: 'uptime · logs', no: 'oppetid · logger' },
label: 'Media stack',
sub: { en: 'Jellyfin · *arr', no: 'Jellyfin · *arr' },
},
],
edges: [
{ d: 'M200 152 H280', kind: 'flow' },
{ d: 'M470 140 L560 70', kind: 'flow' },
{ d: 'M470 152 H560', kind: 'flow' },
{ d: 'M470 164 L560 230', kind: 'flow' },
{ d: 'M210 158 H290', kind: 'flow' },
{ d: 'M380 192 V232', kind: 'flow', label: 'auth', labelX: 400, labelY: 218 },
{ d: 'M470 150 L560 74', kind: 'flow' },
{ d: 'M470 158 H560', kind: 'flow' },
{ d: 'M470 166 L560 242', kind: 'flow' },
],
},
media: [],
content: {
en: {
valueProp: 'Where I run, break and fix real infrastructure — not just deploy it.',
valueProp:
'Where I run, break and fix real infrastructure — around thirty containerised services behind a single reverse proxy.',
cardTeaser:
'Ubuntu · Docker services · reverse proxy · auth · monitoring · Gitea (this sites own git remote).',
'Ubuntu + Docker · Traefik · Authentik SSO · CrowdSec · Gitea CI — ~30 self-hosted services, and the deploy target for this site.',
tldr: {
what: 'A self-hosted home lab running production-style services.',
why: 'To keep operations skills hands-on.',
stack: 'Ubuntu · Docker · nginx · Gitea · monitoring.',
what: 'A self-hosted home server running ~30 production-style services.',
why: 'To keep operations and security skills hands-on.',
stack: 'Ubuntu · Docker · Traefik · Authentik · CrowdSec · Gitea.',
role: 'Operator.',
},
sections: [
@@ -102,7 +118,7 @@ export const homelab: Project = {
blocks: [
{
type: 'p',
text: 'A home lab running Ubuntu and Docker-based services behind an nginx reverse proxy, with authentication, monitoring and backups. Its where I get ongoing, hands-on practice with deployment, troubleshooting and real-world operations — including the self-hosted Gitea instance that this very site is built and deployed from.',
text: 'An Ubuntu 24.04 server running around thirty Docker services behind a Traefik reverse proxy, with single sign-on, an intrusion-prevention layer, DNS filtering and a full CI/CD setup. Its where I get ongoing, hands-on practice with deployment, security and real-world operations — including the self-hosted Gitea instance and runner that build and deploy this very portfolio.',
},
],
},
@@ -114,10 +130,11 @@ export const homelab: Project = {
{
type: 'ul',
items: [
'nginx reverse proxy terminating TLS in front of every service.',
'Docker Compose stacks for applications, each isolated on its own network.',
'Authentication in front of internal tools; monitoring for uptime and logs.',
'Self-hosted Gitea with CI runners — the deployment target for this portfolio.',
'Traefik terminates TLS and routes every service, fronted by Cloudflare, with separate internal and external entrypoints and HTTP/3.',
'Authentik provides single sign-on as a Traefik forward-auth middleware in front of internal tools; CrowdSec adds intrusion prevention and Pi-hole handles DNS filtering.',
'Gitea and a Gitea Actions runner give me self-hosted git and CI/CD — the build-and-deploy target for this site.',
'The Docker socket is exposed to Traefik only through a hardened socket-proxy, and each application runs on its own isolated Docker network.',
'Portainer and Dozzle handle container management and logs; alongside these run application, media and utility stacks.',
],
},
],
@@ -129,7 +146,7 @@ export const homelab: Project = {
blocks: [
{
type: 'p',
text: 'Tightening backup verification and adding more automated health checks and alerting across the stack.',
text: 'Retiring the legacy WordPress site now that this portfolio replaces it, then tightening backup verification and expanding automated health checks and alerting across the stack.',
},
],
},
@@ -137,13 +154,13 @@ export const homelab: Project = {
},
no: {
valueProp:
'Der jeg drifter, ødelegger og fikser ekte infrastruktur — ikke bare ruller den ut.',
'Der jeg drifter, ødelegger og fikser ekte infrastruktur — rundt tretti containeriserte tjenester bak én reverse proxy.',
cardTeaser:
'Ubuntu · Docker-tjenester · reverse proxy · auth · overvåking · Gitea (git-remoten til denne siden).',
'Ubuntu + Docker · Traefik · Authentik SSO · CrowdSec · Gitea CI — ~30 egendriftede tjenester, og utrullingsmålet for denne siden.',
tldr: {
what: 'En egendriftet hjemmelab som kjører produksjonslignende tjenester.',
why: 'For å holde driftsferdighetene praktiske.',
stack: 'Ubuntu · Docker · nginx · Gitea · overvåking.',
what: 'En egendriftet hjemmeserver med ~30 produksjonslignende tjenester.',
why: 'For å holde drifts- og sikkerhetsferdighetene praktiske.',
stack: 'Ubuntu · Docker · Traefik · Authentik · CrowdSec · Gitea.',
role: 'Operatør.',
},
sections: [
@@ -154,7 +171,7 @@ export const homelab: Project = {
blocks: [
{
type: 'p',
text: 'En hjemmelab som kjører Ubuntu og Docker-baserte tjenester bak en nginx reverse proxy, med autentisering, overvåking og sikkerhetskopier. Det er her jeg får løpende, praktisk øving på utrulling, feilsøking og ekte drift — inkludert den egendriftede Gitea-instansen som denne siden bygges og rulles ut fra.',
text: 'En Ubuntu 24.04-server som kjører rundt tretti Docker-tjenester bak en Traefik reverse proxy, med single sign-on, et lag for inntrengingsvern, DNS-filtrering og full CI/CD. Det er her jeg får løpende, praktisk øving på utrulling, sikkerhet og ekte drift — inkludert den egendriftede Gitea-instansen og runneren som bygger og ruller ut denne porteføljen.',
},
],
},
@@ -166,10 +183,11 @@ export const homelab: Project = {
{
type: 'ul',
items: [
'nginx reverse proxy som terminerer TLS foran hver tjeneste.',
'Docker Compose-stacker for applikasjoner, hver isolert på eget nettverk.',
'Autentisering foran interne verktøy; overvåking av oppetid og logger.',
'Egendriftet Gitea med CI-runnere — utrullingsmålet for denne porteføljen.',
'Traefik terminerer TLS og ruter alle tjenester, med Cloudflare foran, egne interne og eksterne entrypoints og HTTP/3.',
'Authentik gir single sign-on som en Traefik forward-auth-middleware foran interne verktøy; CrowdSec legger til inntrengingsvern og Pi-hole håndterer DNS-filtrering.',
'Gitea og en Gitea Actions-runner gir egendriftet git og CI/CD — bygge- og utrullingsmålet for denne siden.',
'Docker-socketen eksponeres kun til Traefik gjennom en herdet socket-proxy, og hver applikasjon kjører på sitt eget isolerte Docker-nettverk.',
'Portainer og Dozzle håndterer containere og logger; ved siden av kjører applikasjons-, media- og verktøystacker.',
],
},
],
@@ -181,7 +199,7 @@ export const homelab: Project = {
blocks: [
{
type: 'p',
text: 'Strammere verifisering av sikkerhetskopier og flere automatiske helsesjekker og varsling på tvers av stacken.',
text: 'Legge ned den gamle WordPress-siden nå som denne porteføljen erstatter den, og deretter stramme inn verifisering av sikkerhetskopier og utvide automatiske helsesjekker og varsling på tvers av stacken.',
},
],
},