No description
  • Shell 48.4%
  • Go 31.3%
  • Go Template 17.7%
  • Python 1.6%
  • Dockerfile 1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Parth Lakhani 7da525bac3
All checks were successful
/ go (push) Successful in 4m1s
docs(netbird): use exit node specific groups and routes
2026-10-15 21:44:53 -04:00
.forgejo/workflows feat(schedules): declare and check every scheduled job across all infra managed here 2026-09-18 12:46:34 -04:00
chat-archive feat(backup): openwebui 2-stage backup 2026-09-17 23:51:16 -04:00
dns feat(dns): A record for chat interface 2026-09-17 00:38:59 -04:00
dns-defensive feat: add site-partner for partner's professional site 2026-08-13 22:21:34 -04:00
dns-gram feat(forgejo): forgejo deployment things i forgot to commit 2026-09-11 22:50:44 -04:00
dns-personal feat(email): add rua mailto; update docs with record verifications 2026-08-19 21:59:29 -04:00
docs feat(observability): add alerts when immich processing queues aren't moving 2026-09-23 23:02:50 -04:00
email feat(email): SES domain id for alerts subdomain 2026-08-16 01:15:50 -04:00
forgejo feat: deploy forgejo as vcs on pearllab 2026-08-18 22:51:36 -04:00
foundation docs: refresh root README and split legacy info out to subfolders 2026-09-18 09:59:23 -04:00
internal docs: add readmes for sites, observability, and internal builders 2026-09-18 10:00:42 -04:00
netbird docs: refresh root README and split legacy info out to subfolders 2026-09-18 09:59:23 -04:00
netbird-archive feat(netbird): built offsite archive of netbird dbs to s3 2026-08-20 04:00:15 -04:00
photo-archive docs(backup): restore drills run from operator credentials, permanently 2026-09-19 21:36:54 -04:00
scripts docs(immich): 2023-25 imported; phone upload ordering 2026-10-15 14:15:34 -04:00
services docs(openwebui): model web search comparison; upgrade plan 2026-10-15 21:21:38 -04:00
site-partner feat: add site-partner for partner's professional site 2026-08-13 22:21:34 -04:00
sites docs: refresh root README and split legacy info out to subfolders 2026-09-18 09:59:23 -04:00
tools/schedules feat(observability): add alerts when immich processing queues aren't moving 2026-09-23 23:02:50 -04:00
.gitignore feat(secrets): migrate NetBird service secrets to SOPS + age 2026-08-14 04:15:05 -04:00
.sops.yaml feat(secrets): migrate NetBird service secrets to SOPS + age 2026-08-14 04:15:05 -04:00
CLAUDE.md fix(forgejo): key rotation procrocedure 2026-08-21 21:52:28 -04:00
go.mod feat(schedules): declare and check every scheduled job across all infra managed here 2026-09-18 12:46:34 -04:00
go.sum feat: bring dpd hosted zone under pulumi mgmt 2026-08-13 16:03:37 -04:00
PROJECT_PLAN.md docs: correcting assumptions aboubout minipc and desktop pc 2026-09-12 00:35:24 -04:00
README.md docs: refresh root README and split legacy info out to subfolders 2026-09-18 09:59:23 -04:00
retry-up.sh feat: generalize retry reservation script 2026-08-12 23:36:26 -04:00
TASKS.md docs(netbird): use exit node specific groups and routes 2026-10-15 21:44:53 -04:00

vaderlab-infra

My home network and the things I self-host, managed as code.

Four machines — two in a closet at home, two free VMs in Oracle's cloud — joined into one private network by a self-hosted NetBird overlay. Once they're on that overlay they behave like one system: I can SSH to any of them from anywhere, stream my own media, push work to the GPU box from a laptop, and route traffic out through my house when I'm on someone else's wifi. A few public websites and my email DNS ride along on the same infrastructure.

Nothing here is clicked into existence. Cloud resources are Pulumi programs in Go, services are Docker Compose stacks with rendered config, secrets are sops+age, and CI runs on a self-hosted Forgejo. The repo is as much the point as the network is — it's a deliberate exercise in learning networking and sysadmin by building the real thing rather than a tutorial version of it.

The estate

                        ┌─────────────────────────────────┐
   home closet          │   OCI  (always-free ARM, $0)    │
   ┌──────────────┐     │  ┌───────────────────────────┐  │
   │  pearllab    │     │  │  vaderlab-netbird         │  │
   │  Intel N150  │◄────┼──┤  NetBird control plane    │  │
   │  mini PC     │     │  │  Pocket ID (OIDC), coturn │  │
   │              │     │  └───────────────────────────┘  │
   │  Traefik     │     │  ┌───────────────────────────┐  │
   │  Forgejo     │     │  │  vaderlab-sites           │  │
   │  Immich      │     │  │  public static sites      │  │
   │  Plex        │     │  └───────────────────────────┘  │
   │  backups     │     └─────────────────────────────────┘
   └──────┬───────┘
          │  NetBird overlay (WireGuard)      ┌─────────────────────────┐
   ┌──────┴───────┐                           │  AWS                    │
   │  pearlbox    │                           │  Route 53 — 4 domains   │
   │  RTX 3080    │                           │  SES — outbound mail    │
   │  llama.cpp   │                           │  S3 — offsite backups   │
   │  Open WebUI  │                           │  CloudFront — one site  │
   │  Immich ML   │                           └─────────────────────────┘
   └──────────────┘
Box What it is Detail
pearllab Home mini PC. Always-on anchor: exit node, media server, backup destination, and host for the home service layer behind a shared Traefik. services/pearllab/
pearlbox Home inference box. RTX 3080 running llama.cpp behind llama-swap, Open WebUI, speech-to-text, and Immich's ML workloads. In a closet, overlay-only. services/pearlbox/
vaderlab-netbird OCI VM. The NetBird control plane and Pocket ID — the critical dependency of everything else. netbird/ · services/netbird/
vaderlab-sites OCI VM. Public static sites behind Traefik. No public SSH; reached over the overlay. sites/ · services/sites/

The two cloud boxes sit at exactly Oracle's always-free ceiling and are designed to bill $0. Why they're two boxes and not one, and what happens when that free tier changes, is docs/oci-free-tier.md.

How it's built

  • Cloud resources — Pulumi programs in Go (Go 1.26), one module, thirteen projects. Conventions, stack naming, secret and state handling: docs/pulumi-conventions.md.
  • Services — Docker Compose per box, with .tmpl config rendered by a render.sh that injects decrypted secrets at deploy time. Nothing rendered is committed.
  • Secrets — sops + age for service credentials (secrets.enc.yaml); Pulumi Cloud's own encryption for stack config. Exposure playbook: docs/playbooks/.
  • CI — self-hosted Forgejo Actions on pearllab: go vet and go test on every push (.forgejo/workflows/ci.yml).
  • Provisioning the home boxes is still by hand, deliberately. The READMEs are written as precise manual procedures because a procedure performed once and written down is the specification for the Ansible role that replaces it.

Where things are

Pulumi projects

Each directory is one project with its own state, config and blast radius. Every Pulumi.yaml carries a description: saying what it owns and why it's separate.

foundation/ Spend budget + alert rules. Deploy first; it outlives what it watches.
netbird/ Control-plane VM and its VCN.
sites/ Public-sites VM and its VCN.
dns/ dns-personal/ dns-defensive/ dns-gram/ Route 53, one project per domain so an error in one can't reach another's records.
email/ SES sending identity and a send-only IAM user.
forgejo/ Forgejo's S3 backup bucket and its scoped IAM users.
netbird-archive/ photo-archive/ chat-archive/ Offsite S3 archives, one per service, each with a push-only user that cannot delete.
site-partner/ A partner's site end to end: S3, CloudFront, ACM, Route 53.
internal/ Shared builders the projects are assembled from — ocivm, ocinet, ocibudget, cloudinit, freetier, awsdomain, maildns, mailsender.

Services and operations

services/ Compose stacks per box: netbird, pearllab (incl. Forgejo, Immich), pearlbox (incl. parakeet STT), observability, sites.
scripts/backup/ Encrypted backups of the network definition — peers, policies, passkeys.
scripts/overlay/ Why Docker must not start before the overlay address exists, and the systemd fix.
scripts/takeout/ Google Takeout audit and reconciliation for the Immich migration.
tools/schedules/ Inventory of every scheduled job across the four boxes. Spec, not yet built.
docs/playbooks/ Incident procedures.

Start here

If you want Read
What's open and what's done, across everything TASKS.md — the map, kept current
Why the overlay is built the way it is PROJECT_PLAN.md — goals and accumulated rationale, not status
To work on this with an AI agent CLAUDE.md — standing constraints
To stand the cloud side up from scratch foundation/, then netbird/, then sites/

Two conventions worth knowing before reading anything else. READMEs live next to the thing they describe and record why a value is what it is, not just what it is — the reasoning is the part that isn't recoverable from the code. And TASKS.md is the only file tracking status; anything here describing current state is a bug in this file.