Skip to content

LinkedIn Content Plan — Oak Techx Homelab Build

Created: 2026-06-07 (post-Session-10 marathon) Goal: Daily LinkedIn posts showcasing the homelab build journey to demonstrate Kay's skills in: infrastructure architecture, DevOps/SRE practices, security engineering, self-hosting, system administration, and home-lab to enterprise patterns. Format: Short LinkedIn posts (~1000-1300 chars, since LinkedIn truncates around 1300 and shorter posts get better engagement). Each post is standalone but the collection tells a coherent narrative. Cadence: Daily, Mon-Fri (skip weekends to avoid feed fatigue). 30+ posts queued. Start: any Monday. Hashtag pattern: #homelab #devops #selfhosted #sysadmin + 1-2 topic-specific. Curriculum note: this content plan also feeds the Path B learning track — writing about a technique forces you to understand it deeply. Each post = one mini-essay = one anchored learning artifact.


Posting principles

  1. One topic per post. Don't cram. LinkedIn audiences scan, not read.
  2. Lead with the problem, not the tech. "We had X breakage; here's how we solved it" beats "We installed Y."
  3. Show a specific decision. "Why I picked Authelia over Keycloak for a 5-user system" is better than "Authelia is great."
  4. Include a concrete artifact when possible: a config snippet, a screenshot, a graph, a 3-line shell command. Posts with code get saved.
  5. End with a question to drive comments. Engagement > impressions.
  6. No corporate jargon. Write like you're explaining to a smart friend at a bar.
  7. Avoid "in this article we will…" preambles. Get to the point.

📅 Post calendar (30 short posts, organized by theme)

Week 1 — Foundation: "Why I built a homelab"

Post 1 — The 15-month-cold server boot

Hook: "I powered on a server that had been cold for 15 months. Here's what I learned about recovery." Body: HP DL380 G7, 148 GB ECC, Proxmox 8.1 install untouched from Feb 2024. Brought it back online May 2026. Recovery checklist: cold-start memory training, BIOS quirks (SPCR firmware bug, PMU resources), iLO password reset via OS-level KCS (in-band IPMI), recovering DNS without iLO web. Everything boots clean → tells you the kit was healthy when last powered off. Takeaway: Cold-storage servers can survive years if PSUs are healthy. Document EVERYTHING before you power down. Hashtags: #homelab #proxmox #ProLiant #DataRecovery

Post 2 — Choosing Proxmox over ESXi (in 2026)

Hook: "Broadcom's ESXi pricing changes in 2024 pushed me back to Proxmox. Two years in, I'd choose Proxmox even at zero cost difference." Body: 3 specific advantages: (1) LXC + KVM in one host = no second toolchain for containers, (2) PBS-native incremental backup vs Veeam licensing, (3) cluster + HA without ESXi+vCenter complexity. Tradeoff: less mature for enterprise compliance scenarios (audit logging, role hierarchy depth). For a homelab + small-team scale, Proxmox is the right call. Hashtags: #proxmox #virtualization #ESXi #homelab

Post 3 — VLAN segmentation in a homelab (when 1 LAN is "enough")

Hook: "Why I run 4 VLANs in my house with 5 users." Body: VLAN 10 (SERVERS), VLAN 40 (MGMT), VLAN 1 (default), VLAN 70 (legacy decommission). Why MGMT is separate: iLO/IPMI exposure. Why SERVERS is separate from family devices: blast-radius containment. pfSense rule: SERVERS → MGMT blocked (verified six ways before trusting). Diagram: pfSense → TL-SG108E switch → 4-port LACP bond → vmbr0 bridge → tagged sub-interfaces. Takeaway: Network segmentation isn't enterprise-only — it's defense-in-depth even at 5 users. Cost: ~30 min of pfSense rule writing. Hashtags: #networking #pfSense #VLAN #networksecurity

Post 4 — The active-backup bond reality check

Hook: "I planned an LACP bond. The switch only supports static LAG. Here's what I learned about troubleshooting silent LACP failures." Body: Built nested LACP bonds (bond0 + bond1 under active-backup bond2). Discovered LACPDUs silently dropped — partner MAC = 00:00:00:00:00:00. TL-SG108E v1 is smart-managed only, not 802.3ad. Migration to single active-backup bond: SIMPLE config + reliable failover. Gotcha: kernel rejects bond mode change while slaves attached → must ifdown bond0 && ifup bond0 to recreate before mode change applies. ifreload swallows the warning. Cost me 30 min. Takeaway: Match topology to switch features. "LACP everywhere" is a cargo-cult choice for non-LACP-capable gear. Hashtags: #networking #linux #troubleshooting #bond

Post 5 — The 333 GB cleanup

Hook: "I deleted 333 GB of stale backups from 2024 in 5 minutes." Body: OMV omv-rpc CLI for shared folder / NFS share lifecycle. Script the destruction; let OMV's salt apply config. Don't manually edit XML. Inventory first (find + du -h --max-depth=3), classify (active / stale / orphan stub), get explicit confirmation per target, then execute. Recovered 333 GB on a half-full 839 GB RAID5 array. Cost: 7 minutes of code, 30 minutes of inventory. Takeaway: Most homelab storage is occupied by ghosts. Audit annually. Hashtags: #openmediavault #linux #storage #homelab

Week 2 — Security & identity

Post 6 — Single-sign-on for a 5-user homelab (Authelia)

Hook: "I added SSO + MFA to 8 services in 2 hours." Body: Authelia + Traefik ForwardAuth middleware. One login → cookie domain hm.iamkay.eu → SSO across every internal service. TOTP enforced for admin-group access. Default policy deny, explicit allowlist per service. Why Authelia over Keycloak: 5-user scale doesn't justify Keycloak's complexity. File-based user DB; argon2id password hashing; SQLite session store. Session: 5 min inactive / 1 h max / 1 month remember. Takeaway: SSO is a 1-day project for a 5-user system. Stop running 8 separate password forms. Hashtags: #sso #authelia #selfhosted #identitymanagement

Post 7 — Self-hosting your password vault (Vaultwarden)

Hook: "My passwords no longer leave my house." Body: Vaultwarden (Rust rewrite of Bitwarden) in Docker-in-LXC. SQLite backend, ~50 MB resident. Bitwarden browser extension + mobile app → point at https://vault.hm.iamkay.eu. PBS-backed daily. Cost: ~$0 (vs Bitwarden Family $40/yr). Tradeoffs: I host my own backup risk (vs Bitwarden's geo-redundant). Off-site backup planned via Cloudflare R2. Takeaway: Self-hosting a password vault is no longer experimental — pair it with strong PBS discipline and you're at parity with hosted offerings. Hashtags: #vaultwarden #bitwarden #passwordmanagement #selfhosted

Post 8 — Cloudflare Tunnel for zero-port-forwarding access

Hook: "My family cloud is on the public internet without opening a single firewall port." Body: Cloudflare Tunnel: cloudflared agent in an LXC → outbound TLS to Cloudflare edge → routes cloud.iamkay.eu requests back through tunnel → Traefik → Nextcloud. Zero ingress firewall changes. Zero port forwards. Free for personal use. Bonus: Cloudflare's DDoS protection + WAF for free. Architecture: Phone (4G) → Cloudflare → cloudflared → Traefik → Nextcloud → NFS → homenas (s-tank RAID5). Takeaway: If you're still doing port forwarding for self-hosted services in 2026, switch to Cloudflare Tunnel today. Hashtags: #cloudflare #zerotrust #networking #selfhosted

Post 9 — Why Nextcloud is NOT behind my SSO

Hook: "Counter-intuitive but correct: I deliberately put Nextcloud outside Authelia." Body: ForwardAuth proxies return HTML login pages. Sync clients (Nextcloud iOS, CalDAV iCal, CardDAV) speak HTTP Basic Auth on every API call. They don't follow HTML redirects → silent failure. Solution: rely on Nextcloud's own brute-force throttle + app passwords + per-user TOTP. Same principle applies to GitLab (git+SSH), Vaultwarden (browser extension), Jellyfin. The rule: never put sync-client-having services behind a forward-auth proxy. Takeaway: Defense-in-depth ≠ defense-everywhere. Match auth pattern to client capabilities. Hashtags: #nextcloud #authelia #identitymanagement #architecture

Post 10 — Pi-hole + DNSSEC for the whole network

Hook: "Every device in my house resolves DNS through a single box. Including the ones I didn't configure." Body: Pi-hole on a 2-vCPU LXC. pfSense Unbound Domain Override pushes hm.iamkay.eu to Pi-hole → local DNS records for every service. Plus 83,600 ad-domains in StevenBlack blocklist → blocked at DNS layer for every device automatically. DNSSEC validation enabled. Admin UI behind Authelia. Takeaway: One DNS box + one switch config = network-wide ad-blocking + internal name service. No per-device setup. Family doesn't notice. Hashtags: #pihole #dns #networking #adblock

Week 3 — Application stack & DevOps

Post 11 — Replacing GitHub for personal use (GitLab CE)

Hook: "I moved my personal repos off GitHub and onto my own server." Body: GitLab CE in Docker-in-LXC. 4 vCPU / 8 GB RAM. Web UI behind Traefik + LE wildcard cert. Git+SSH on port 2222 (LXC sshd owns 22). PAT + 2FA + Runner. First CI/CD pipeline: PASSED in 13 s. Tradeoffs: GitHub's Actions ecosystem is richer; for the kind of work I do solo, GitLab CE is enough. Cost: $0 vs GitHub Pro $4/mo (per user). Backup: PBS daily. Takeaway: Self-hosted GitLab is enterprise-grade out of the box. Set Renovate on the image tag. Hashtags: #gitlab #cicd #selfhosted #devops

Post 12 — Why I'm running Docker INSIDE LXC (not on the host)

Hook: "Everyone says 'don't run Docker inside an LXC.' Here's why I do it anyway." Body: Pattern: each multi-container app gets its OWN unprivileged LXC + docker-compose. Benefits: LXC = unit of backup (PBS), unit of isolation (no shared Docker daemon), unit of resource limit (cgroup), unit of failure (compromised container can't touch others). Tradeoff: extra layer of namespaces (each LXC has its own kernel namespace tree). Features needed: nesting=1,keyctl=1. Production examples: Vaultwarden + Authelia + Pi-hole + GitLab + Nextcloud + cloudflared all on this pattern. Takeaway: "Docker-in-LXC bad" is folklore. With unprivileged LXCs + proper features it's a clean isolation boundary. Hashtags: #docker #lxc #proxmox #containers

Post 13 — Nextcloud as a complete family cloud (350 GB migrated)

Hook: "I dropped my iCloud/Google Drive subscription. Here's the migration." Body: Nextcloud-fpm-alpine + nginx + postgres-16 + redis + cron — 5 containers in one LXC. Local rootfs (200 GB) for app + metadata + thumbnails. NFS-backed s-tank (1.4 TB) for actual user files via Nextcloud's External Storage. CalDAV + CardDAV → native iPhone Calendar + Contacts. Native mobile + desktop sync clients. Auto-upload from camera roll. Family sharing: per-user accounts + 2FA enforced. Takeaway: Modern Nextcloud is at parity with iCloud for files/calendar/contacts for personal use. The trick is matching the storage to your existing usage (200 GB local + 1.4 TB s-tank for me). Hashtags: #nextcloud #familycloud #selfhosted #privacy

Post 14 — Reverse-proxy with Let's Encrypt wildcard (Traefik + DNS-01)

Hook: "All my internal services have browser-trusted HTTPS. Without exposing any of them to the internet." Body: Traefik v3 + Let's Encrypt DNS-01 challenge via Cloudflare API. One wildcard cert *.hm.iamkay.eu covers everything internal. Auto-renews ~30 days before expiry. Internal services NEVER touch the public internet — only the DNS challenge does. Browser shows green padlock everywhere. Pattern works for any DNS provider with API support. Takeaway: HTTP-01 challenges require port 80 exposure. DNS-01 doesn't. Use DNS-01 for internal-only services. Hashtags: #letsencrypt #traefik #tls #cloudflare

Post 15 — The PostgreSQL + Redis sidecar pattern in docker-compose

Hook: "Why I always run PostgreSQL + Redis as sidecars next to each service that needs them, instead of a shared DB cluster." Body: Each docker-compose stack owns its own postgres + redis. Reasoning: simpler backup (LXC backup = whole stack snapshot), simpler restoration (no cross-LXC DB references), easier upgrades (one stack at a time), security isolation (compromised app can't reach another app's DB). Tradeoff: ~200 MB overhead per stack. Worth it for ~5 stacks. Takeaway: Shared databases are an enterprise pattern. For homelab scale, per-app DBs are simpler and safer. Hashtags: #postgresql #redis #docker #architecture

Week 4 — Operations, monitoring, recovery

Post 16 — The observability stack: Prometheus + Grafana + Loki + Uptime Kuma

Hook: "I have full observability for my homelab. Total install time: 90 minutes." Body: One LXC, one docker-compose, 7 containers. Prometheus (30d retention, scrapes node_exporter + cAdvisor). Grafana (provisioned datasources, dashboards). Loki (filesystem storage, structured metadata). Promtail (Docker logs + /var/log). Uptime Kuma (service uptime + status pages). Homepage (4-section launcher with green-dot tiles). Behind Authelia. Resource: 2 vCPU / 4 GB. Takeaway: Stop running prod without observability. The "I'll set up monitoring later" tax compounds. Hashtags: #prometheus #grafana #observability #devops

Post 17 — Backup discipline: Proxmox Backup Server done right

Hook: "First time I tested my backups, the restore worked. Here's what I did differently." Body: PBS in a dedicated VM (not on the same host as backed-up VMs). Removable datastore on USB HDD (UUID-bound so unplug/replug doesn't break). GFS retention: 3 last + 7 daily + 4 weekly + 12 monthly + 2 yearly. Daily 02:00 schedule, mail-on-failure. Restore drill: every quarter, restore one VM to a new VMID, mount, verify hostname + key configs, destroy. If restore drill fails: stop ALL new work, fix backup. Takeaway: Backups you haven't restored from are theater. Schedule restore drills. Hashtags: #backup #pbs #disasterrecovery #sysadmin

Post 18 — The wedding video recovery (ddrescue)

Hook: "I recovered ~60 GB of fragmented .mov files from a 1 TB drive that wouldn't mount." Body: HFS+ partition unreadable. ddrescue to a .img file, ~24 hours, 4 KB unrecoverable at LBA 124.5 GB. Mounted .img read-only via loopback. PhotoRec-recovered files (each named f<offset>_ftyp_.mov showing they're QuickTime fragments). Filed under Recovered/WEDDING-2018-12-22-FINAL/. ClamAV scan clean. Stored on homenas SMB + replicated nightly. Total recovery cost: $0 (drive imaged on USB enclosure), 36 hours wall time. Takeaway: Image first, recover from image. Never operate on the source drive. Hashtags: #datarecovery #ddrescue #digitalpreservation

Post 19 — iLO 3 v1.94: living with end-of-life firmware

Hook: "HP stopped firmware updates for iLO 3 in 2020. Here's how I make a 2010-era BMC work in 2026." Body: TLS 1.0 only → Firefox with security.tls.version.min=1 (other browsers reject). SSH client config: KexAlgorithms +diffie-hellman-group1-sha1, Ciphers +aes128-cbc,3des-cbc, MACs +hmac-sha1. iLO 3 v1.94 ONLY accepts DSA-1024 client keys — RSA paste fails with "Invalid input" in web UI. Method that works: HTTP-fetched .pub file via oemhp_loadSSHKey from interactive SSH session. Isolated on MGMT VLAN 40 + pfSense block from SERVERS VLAN. Takeaway: End-of-life enterprise hardware is usable in homelab if you accept the protocol ceiling and isolate it. Hashtags: #iLO #HPE #legacy #security

Post 20 — Why "thin provisioning" needs monitoring

Hook: "I over-allocated my LVM thin pool by 80%. Here's why I'm fine (and what could go wrong)." Body: 475 GB volume group; 382 GB allocated to thin LVs; 16 GB physically free. Thin provisioning lets you allocate more virtual capacity than physical. As long as actual usage stays below pool size: fine. If multiple LVs grow simultaneously: thin pool exhausts → all LVs see writes fail → filesystem corruption risk. Mitigation: monitor lvs thin pool usage in Prometheus; alert at 75%. Long-term plan: 2× 2 TB NVMe per EliteDesk 800 G5 to migrate heaviest LXCs. Takeaway: Thin provisioning is great until it isn't. Monitor it like a critical alert. Hashtags: #lvm #storage #linux #monitoring

Week 5 — Specific gotchas & engineering insight

Post 21 — The "rsync --chown www-data:root" gotcha with NFS + unprivileged LXC

Hook: "Nextcloud refused to start on NFS. The fix wasn't NFS perms — it was the init script." Body: Mounted NFS into unprivileged LXC at /var/www/html/data. Nextcloud's entrypoint runs rsync --chown www-data:root → fails because NFS server (with all_squash) rejects chowning to GID 0. Tried anonuid=100033,anongid=100033 — still failed because chown changes ownership which all_squash doesn't permit. Solution: don't put NFS at /var/www/html/data. Mount it at /mnt/nfs and register through Nextcloud's External Storage feature. The init's chown doesn't run on /mnt/nfs. Pattern works. Takeaway: When upstream init scripts conflict with your storage choice, change the storage path, not the init script. Most multi-container apps have an "External Storage" abstraction. Hashtags: #nextcloud #nfs #lxc #troubleshooting

Post 22 — Cloudflare Tunnel + Traefik + LE: the SNI mismatch trap

Hook: "cloudflared returned 502 because I gave it the right URL. Here's the fix." Body: Cloudflare's new Routes UI dropped the TLS settings (No TLS Verify, Origin Server Name). When you point cloudflared at https://10.0.10.10:443, it validates the cert against 10.0.10.10. Your LE cert is for cloud.iamkay.eu, not the IP → cert validation fails → 502. Two-part fix: (1) Get LE cert for cloud.iamkay.eu via DNS-01 (added it to Traefik). (2) Change cloudflared service URL to https://cloud.iamkay.eu:443 AND set Docker extra_hosts: ["cloud.iamkay.eu:10.0.10.10"] so resolution is local + cert validation matches the URL hostname. Takeaway: TLS cert SAN must match the URL hostname, regardless of how DNS resolves to the backend. Local /etc/hosts overrides + extra_hosts in docker-compose are powerful here. Hashtags: #cloudflare #tls #docker #networking

Post 23 — The HTTP→HTTPS redirect loop in Traefik

Hook: "Every public request to my cloud was 308'ing to itself. Took 90 minutes to find the entrypoint config." Body: Traefik's web entrypoint had http.redirections.entryPoint.to=websecure — hard-coded HTTP→HTTPS redirect FIRES BEFORE router matching. So an HTTP backend served via Traefik's web entrypoint would always send 308 → https://. cloudflared followed the redirect → hit Cloudflare again → tunnel → same redirect → loop. Fix: serve the route on websecure (HTTPS) with its own LE cert. Don't try to disable the entrypoint-level redirect on a per-router basis (Traefik doesn't support it). Takeaway: Entrypoint-level config in Traefik wins over router-level config. If you want a port-80 backend, give it its own entrypoint (e.g. webexternal:8081) with no redirect. Hashtags: #traefik #reverseproxy #networking #troubleshooting

Post 24 — Pi-hole v6 "custom.list constantly wiped" bug + the fix

Hook: "Every Pi-hole container restart wiped my custom DNS records. Until I found the right config path." Body: Pi-hole v6 auto-populates /etc/pihole/hosts/custom.list from a template at every restart → custom records vanish. Fix: put records in pihole.toml hosts = [...] array (toml-managed, NOT file-managed). Edit via Python on the LXC (pihole container is alpine, no python3 inside). After edit: docker restart pihole (the pihole reloaddns command has its own bug in 6.6.2). Takeaway: Pi-hole v6 moved a lot of config from text files to a single toml. Don't trust v5-era tutorials. Hashtags: #pihole #dns #configmanagement

Post 25 — omv-rpc for scripting OpenMediaVault

Hook: "Stop editing OMV's config.xml by hand. The RPC layer is the right way." Body: OMV regenerates config from /etc/openmediavault/config.xml via salt. Manual edits get clobbered. omv-rpc <service> <method> <params> is the supported interface. Sentinel UUID fa4b1c66-ef79-11e5-87a0-0002b3a176b4 indicates "new object" (the docs don't mention this). omv-salt deploy run <state> applies config after RPC changes. Full deletion workflow: NFS share → SMB share → Shared Folder (recursive). Wrote 333 GB of cleanup in 60 lines. Takeaway: When a config-as-code system has an API, use the API, not the config file. Hashtags: #openmediavault #automation #devops

Week 6 — Architecture decisions & meta

Post 26 — Path A vs Path B vs Path D: organizing a multi-purpose homelab

Hook: "My homelab has three jobs. I document them in three separate trackers." Body: Path A = self-hosted developer tools (GitLab, staging) — replaces paid SaaS. Path B = skills curriculum (k8s, ZFS, networking) — non-load-bearing experiments. Path D = family home cloud (Nextcloud, Jellyfin) — service for 3-5 family members. All three share the same foundation (Proxmox + Authelia + Traefik + PBS). Tracker files: project-tracker.md, learning-tracker.md, home-cloud-tracker.md, homelab-tracker.md for the shared layer. Documentation is the "config" for the homelab. Takeaway: A homelab with three goals risks scope creep. Separate trackers = separate priority lanes. Foundation is shared; goals diverge. Hashtags: #homelab #architecture #productivity

Post 27 — Documentation as code (CLAUDE.md + tracker pattern)

Hook: "My homelab's source of truth is a 90 KB Markdown file. Not a wiki, not Notion." Body: CLAUDE.md lives in the repo at the project root. Hard safety rules (NEVER reboot without asking, NEVER touch homenas without explicit confirmation), architecture decisions locked, current network state, service inventory, pending tasks with severity. Cross-references to topic-specific markdown files. Every session updates the relevant tracker before closing. Session log (SESSION-LOG.md) is append-only forensic detail. Wins: searchable with grep, version-controlled, no auth dependency, survives toolchain changes. Takeaway: For solo or small-team work, Markdown trackers beat any wiki. They're text — they survive everything. Hashtags: #documentation #knowledgemanagement #engineering

Post 28 — Architecture Decision Records in practice (lock the decision, ship the work)

Hook: "I locked my storage architecture decision in writing. It stopped me from re-debating it 4 weeks later." Body: Path B1 (HYBRID): keep P410i as boot controller + add LSI 9305-16i HBA in IT mode for new ZFS data pool. Reasoning documented (reference_p410i_ssd_compatibility.md): P410i works for boot, not for SSDs >2 TB; HBA-IT-mode is the modern path for ZFS; sell P410i later. Locked decision. "Do not propose alternatives without explicit new context." Saved me 3+ hours of back-and-forth. Takeaway: Decisions need a written commit + future-self-blocker phrase. "Locked, do not revisit" is a feature, not rigidity. Hashtags: #engineeringdecisions #architecture #productivity

Post 29 — Why I'm building toward a 4-node Proxmox HA cluster

Hook: "My single-node Proxmox is currently 'good enough.' I'm still building toward 4 nodes. Here's why." Body: G7 carries everything today (LXCs + VM + storage). Going to 4-node cluster: 2× HP EliteDesk 800 G5 SFF in hand; 2 more buying ~September 2026. Plan: G5 #3 = quorum tiebreaker for HA; G5 #4 = OPNsense (replaces pfSense). G7 stays standalone as the storage backend. Migration via PBS (backup on G7, restore on G5 with new IP). Reason: single-node = single failure. With 4 nodes I get HA failover, rolling upgrades, and OPNsense isolation from the hypervisor (current pfSense → OPNsense move = better visibility for the Path B networking curriculum). Takeaway: "Good enough" is an honest framing. Document the path beyond it. Hashtags: #proxmox #ha #homelab #architecture

Post 30 — Lessons from a 12-hour homelab marathon (Session 10)

Hook: "I deployed 4 services in one Saturday: Pi-hole, GitLab, Nextcloud, Cloudflare Tunnel. Here's what I learned about pacing." Body: 14:00 start. Pi-hole DNS at 15:00. GitLab CE end-to-end pipeline by 16:30. Nextcloud through External Storage rewrite by 23:00. Cloudflare Tunnel external access by 00:30 (next day). Wrote 4 build scripts, 5 Traefik routes, 333 GB of cleanup, full audit + LinkedIn plan. Tradeoff: 4 unscheduled gotchas added 90 minutes (Traefik 80→443 redirect loop, NFS+unprivileged-LXC permissions, cloudflared cert validation, Pi-hole CPU starvation under DNS retry storms). Resolution pattern: don't bypass the gotcha — document it, fix it, move on. Takeaway: A marathon is just a sprint with documentation in the middle. Without trackers + session log you can't pause and resume cleanly. Hashtags: #devops #homelab #productivity #engineering


🎯 Optional theme add-ons (if you want to extend)

Path B (learning track) — content as you learn

  • ZFS pool design (when HBA + drives arrive)
  • k3s vs kubeadm hands-on (when you build the test cluster)
  • Tailscale vs Headscale (already evaluated; could turn into a Why-I-picked-X post)
  • iLO IPMI sensor scraping with freeipmi
  • Linux network namespace internals (the LXC bind-mount story)

Path A (developer services)

  • "Why GitLab over Gitea for paid-work code" (decision already made)
  • Self-hosted CI runner with Docker executor
  • GitLab Pages for static site hosting (when you set it up)
  • Container registry self-hosted vs Docker Hub

Path D (family cloud)

  • Jellyfin transcoding on G7 CPUs (when D.2 lands)
  • CalDAV/CardDAV setup deep dive (already done, post 9 covers it lightly)
  • Family-cloud governance: shared albums, quota policy, share-by-link risks

🛠️ Posting workflow recommendation

  1. Draft in Markdown (this file). Each post = one numbered section.
  2. One post per Monday/Wednesday/Friday for first month — Tuesday/Thursday for second month if cadence works. Don't post on weekends (low engagement).
  3. Image for each: screenshot of UI / Grafana panel / architecture diagram (use draw.io or excalidraw, save as PNG). Posts with images get 2× engagement.
  4. Schedule via LinkedIn's native scheduler OR Buffer / Hootsuite if you want to queue all 30 at once.
  5. Engage with replies in first 30 min after publishing — LinkedIn algorithm boosts posts with early engagement.
  6. Track: which posts get saves vs likes (saves > likes for skills-demonstrating content). Adjust topics based on what your audience saves.

🔁 Maintenance

After 30 days of posting, this file becomes a content seed for: - A 5-part blog series (combine related posts) - A conference talk ("Building a family cloud in 12 hours") - A YouTube walkthrough (for higher-visibility audience) - The Path B learning-tracker (each post = a documented skill)

Feed this into your CV/portfolio: "Self-published 30 LinkedIn posts on homelab architecture, security, and DevOps practices, demonstrating skills in [skill list from posts]." Recruiters do search LinkedIn for skill tags — posts function as evergreen indexing.