homelab
This commit is contained in:
parent
95b9c4a622
commit
bf2e1a13f0
|
|
@ -0,0 +1,748 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Home Sweet Homelab</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--deep-navy: #0A1128;
|
||||||
|
--rich-gold: #D4AF37;
|
||||||
|
--warm-gold: #F4E5C2;
|
||||||
|
--cream: #FFF8E7;
|
||||||
|
--charcoal: #2C2C2C;
|
||||||
|
--silver: #C0C0C0;
|
||||||
|
--burgundy: #7C2D37;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Didot', 'Bodoni MT', 'Playfair Display', Georgia, serif;
|
||||||
|
line-height: 1.8;
|
||||||
|
color: var(--charcoal);
|
||||||
|
background: linear-gradient(180deg, var(--deep-navy) 0%, #1a2847 100%);
|
||||||
|
position: relative;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Art Deco geometric background pattern */
|
||||||
|
body::before {
|
||||||
|
content: '';
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-image:
|
||||||
|
repeating-linear-gradient(45deg, transparent, transparent 35px, rgba(212, 175, 55, 0.03) 35px, rgba(212, 175, 55, 0.03) 70px),
|
||||||
|
repeating-linear-gradient(-45deg, transparent, transparent 35px, rgba(212, 175, 55, 0.03) 35px, rgba(212, 175, 55, 0.03) 70px);
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Navigation */
|
||||||
|
nav {
|
||||||
|
background: rgba(10, 17, 40, 0.95);
|
||||||
|
border-bottom: 2px solid var(--rich-gold);
|
||||||
|
padding: 1.0rem 0;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-content {
|
||||||
|
max-width: 1000px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 2rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-logo {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 300;
|
||||||
|
color: var(--warm-gold);
|
||||||
|
text-decoration: none;
|
||||||
|
letter-spacing: 0.2em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-back {
|
||||||
|
color: var(--silver);
|
||||||
|
text-decoration: none;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
transition: color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-back:hover {
|
||||||
|
color: var(--rich-gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-back::before {
|
||||||
|
content: '←';
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Article Container */
|
||||||
|
.article-container {
|
||||||
|
max-width: 1000px;
|
||||||
|
margin: 4rem auto;
|
||||||
|
padding: 0 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Article Header */
|
||||||
|
.article-header {
|
||||||
|
background: var(--cream);
|
||||||
|
padding: 4rem 4rem 3rem;
|
||||||
|
border: 2px solid var(--rich-gold);
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Corner decorations */
|
||||||
|
.article-header::before,
|
||||||
|
.article-header::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
border: 2px solid var(--rich-gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-header::before {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
border-right: none;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-header::after {
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
border-left: none;
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-number {
|
||||||
|
font-size: 4rem;
|
||||||
|
font-weight: 300;
|
||||||
|
color: var(--rich-gold);
|
||||||
|
line-height: 1;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 2rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.15em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-category {
|
||||||
|
color: var(--burgundy);
|
||||||
|
font-weight: 700;
|
||||||
|
position: relative;
|
||||||
|
padding-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-category::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%) rotate(45deg);
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
background: var(--rich-gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-title {
|
||||||
|
font-size: 3.5rem;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--deep-navy);
|
||||||
|
line-height: 1.2;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-subtitle {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: var(--charcoal);
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tech Stack */
|
||||||
|
.tech-stack {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
padding-top: 2rem;
|
||||||
|
border-top: 2px solid var(--rich-gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-item {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--deep-navy);
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
background: linear-gradient(135deg, rgba(212, 175, 55, 0.15), rgba(212, 175, 55, 0.05));
|
||||||
|
border-left: 3px solid var(--rich-gold);
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Featured Image */
|
||||||
|
.featured-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 500px;
|
||||||
|
background: linear-gradient(135deg, var(--deep-navy) 0%, var(--burgundy) 100%);
|
||||||
|
border: 2px solid var(--rich-gold);
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sunburst pattern on image */
|
||||||
|
.featured-image::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 200%;
|
||||||
|
height: 200%;
|
||||||
|
background: repeating-conic-gradient(
|
||||||
|
from 0deg,
|
||||||
|
rgba(212, 175, 55, 0.1) 0deg 10deg,
|
||||||
|
transparent 10deg 20deg
|
||||||
|
);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-placeholder {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
text-align: center;
|
||||||
|
color: var(--warm-gold);
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Article Content */
|
||||||
|
.article-content {
|
||||||
|
background: var(--cream);
|
||||||
|
padding: 4rem;
|
||||||
|
border: 2px solid var(--rich-gold);
|
||||||
|
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content h2 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--deep-navy);
|
||||||
|
margin: 3rem 0 1.5rem;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content h2::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: -0.5rem;
|
||||||
|
left: 0;
|
||||||
|
width: 80px;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(90deg, var(--rich-gold), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content h3 {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--burgundy);
|
||||||
|
margin: 2rem 0 1rem;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content p {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: 1.8;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
color: var(--charcoal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content ul,
|
||||||
|
.article-content ol {
|
||||||
|
margin: 1.5rem 0 1.5rem 2rem;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content li {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
padding-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content ul li::marker {
|
||||||
|
color: var(--rich-gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content ol li::marker {
|
||||||
|
color: var(--rich-gold);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content strong {
|
||||||
|
color: var(--deep-navy);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content blockquote {
|
||||||
|
border-left: 4px solid var(--rich-gold);
|
||||||
|
padding: 1.5rem 2rem;
|
||||||
|
margin: 2rem 0;
|
||||||
|
background: rgba(212, 175, 55, 0.05);
|
||||||
|
font-style: italic;
|
||||||
|
color: var(--burgundy);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content code {
|
||||||
|
background: rgba(10, 17, 40, 0.05);
|
||||||
|
padding: 0.2rem 0.5rem;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-family: 'Monaco', 'Courier New', monospace;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: var(--burgundy);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content pre {
|
||||||
|
background: var(--deep-navy);
|
||||||
|
color: var(--warm-gold);
|
||||||
|
padding: 2rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin: 2rem 0;
|
||||||
|
border: 2px solid var(--rich-gold);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content pre code {
|
||||||
|
background: none;
|
||||||
|
padding: 0;
|
||||||
|
color: var(--warm-gold);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decorative Divider */
|
||||||
|
.deco-divider {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 3rem 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deco-divider::before,
|
||||||
|
.deco-divider::after {
|
||||||
|
content: '';
|
||||||
|
flex: 1;
|
||||||
|
height: 2px;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
transparent,
|
||||||
|
var(--rich-gold),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.diamond {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
background: var(--rich-gold);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
margin: 0 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
footer {
|
||||||
|
background: rgba(10, 17, 40, 0.95);
|
||||||
|
color: var(--silver);
|
||||||
|
text-align: center;
|
||||||
|
padding: 3rem 2rem;
|
||||||
|
margin-top: 4rem;
|
||||||
|
border-top: 2px solid var(--rich-gold);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-ornament {
|
||||||
|
width: 100px;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(90deg, transparent, var(--rich-gold), transparent);
|
||||||
|
margin: 0 auto 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer p {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive Design */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.article-header {
|
||||||
|
padding: 2rem 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-number {
|
||||||
|
font-size: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-title {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-subtitle {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content {
|
||||||
|
padding: 2rem 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content h2 {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content h3 {
|
||||||
|
font-size: 1.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-content p,
|
||||||
|
.article-content ul,
|
||||||
|
.article-content ol {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-stack {
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-item {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Navigation -->
|
||||||
|
<nav>
|
||||||
|
<div class="nav-content">
|
||||||
|
<a href="#" class="nav-logo">Tech Chronicles</a>
|
||||||
|
<a href="#" class="nav-back">Back to Articles</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Article Container -->
|
||||||
|
<div class="article-container">
|
||||||
|
<!-- Article Header -->
|
||||||
|
<header class="article-header">
|
||||||
|
<div class="article-number">01</div>
|
||||||
|
<div class="article-meta">
|
||||||
|
<span class="article-category">Infrastructure</span>
|
||||||
|
<span class="article-date">November 2025</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="article-title">Welcome to my homelab</h1>
|
||||||
|
<p class="article-subtitle">
|
||||||
|
A tour through an idealized infrastructure setup that probably violates several fire codes
|
||||||
|
</p>
|
||||||
|
<div class="tech-stack">
|
||||||
|
<span class="tech-item">Kubernetes</span>
|
||||||
|
<span class="tech-item">LGTM Stack</span>
|
||||||
|
<span class="tech-item">Pi-hole</span>
|
||||||
|
<span class="tech-item">TrueNAS</span>
|
||||||
|
<span class="tech-item">Home Assistant</span>
|
||||||
|
<span class="tech-item">ZFS</span>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Featured Image -->
|
||||||
|
<div class="featured-image">
|
||||||
|
<div class="image-placeholder">Homelab Infrastructure</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Article Content -->
|
||||||
|
<article class="article-content">
|
||||||
|
<p>
|
||||||
|
You know how when someone's coming over, you do that frantic cleaning spree where you start
|
||||||
|
shoving everything into closets and you try and convince everyone that you're always this neat? This article is like
|
||||||
|
that, but for my homelab. The actual setup is a stratographic column of different ideas and experiments from different time periods that are forced to work together to form a cohesive unit.
|
||||||
|
What I'm about to talk about are the Wins that have solved problems for me and made my life easier.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Let me give you the tour.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="deco-divider">
|
||||||
|
<div class="diamond"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>The Kubernetes Cluster</h2>
|
||||||
|
<p>
|
||||||
|
I got into Kubernetes the hard way. I had a handful of services running on various VMs, each with their
|
||||||
|
own quirks and manual deployment steps. Updating anything meant SSH-ing into the right machine, remembering
|
||||||
|
which directory the config lived in, and hoping I didn't fat-finger something in production. After the third
|
||||||
|
time I had to delete a VM because I couldn't remember a password, I decided there had to be a better way.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Right now, I'm running a single-node cluster. Both the control plane and worker live on the same machine,
|
||||||
|
which is like saying you ride a motorcycle, and it's actually a moped. The plan is to expand this into a proper multi-node setup
|
||||||
|
eventually. For now, it's handling everything I need: automated deployments, rolling updates, and the kind
|
||||||
|
of infrastructure-as-code setup that lets me sleep at night knowing I can rebuild everything from YAML if I
|
||||||
|
need to.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The nice thing about Kubernetes is that once you get past the initial learning cliff,
|
||||||
|
deploying new services becomes almost trivial. Write a manifest, apply it, and
|
||||||
|
watch it spin up. No more manual configuration files scattered across different machines.
|
||||||
|
Services get their own networks. Routing is included. You would need a vastly more complex
|
||||||
|
solution to do what Kubernetes does even at a basic level.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="deco-divider">
|
||||||
|
<div class="diamond"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Monitoring with LGTM</h2>
|
||||||
|
<p>
|
||||||
|
If Kubernetes is the engine, then monitoring is the dashboard. I'm running the full LGTM stack: Loki for
|
||||||
|
logs, Grafana for visualization, Tempo for traces, and Mimir for metrics. It sounds like overkill for a
|
||||||
|
homelab, and maybe it is, but I got tired of playing detective every time something went sideways.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Every time a container would fail, it would restart, taking its logs to the grave with it. I would be
|
||||||
|
none-the-wiser about what actually happened. Kubernetes is excellent for keeping uptime- well, up. But
|
||||||
|
it masks the problem. This would be a reason why some tech-centric people prefer hard failures over soft
|
||||||
|
failures. Hard failures can address the problem. Soft failures let the problems pile up under the rug.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Now I can pull up Grafana, see exactly when CPU spiked, cross-reference it with logs in Loki, and actually
|
||||||
|
understand what my problem is. Also, there's something satisfying about having charts and graphs that
|
||||||
|
show your systems are healthy. Or unhealthy. At least you know. Imagine if your own body had such charts.
|
||||||
|
People would be checking them every day.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="deco-divider">
|
||||||
|
<div class="diamond"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>DNS Redundancy with Pi-hole</h2>
|
||||||
|
<p>
|
||||||
|
Here's a fun scenario: you're rebooting your homelab for updates or it shuts down after a power outage.
|
||||||
|
You wake up and your phone doesn't work. You try to connect to your Pi-hole instance to see the problem,
|
||||||
|
but your computer doesn't have an IP. So now you can't change your DNS/DHCP configuration, because your
|
||||||
|
computer can't talk to the device that should be managing that. To solve the problem you would have had
|
||||||
|
to have solved the problem already. A Catch-22.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This happened to me several times before I set up a Raspberry Pi running Pi-hole as a fallback. It sits
|
||||||
|
outside the main homelab infrastructure, always on, always ready. When the primary DNS is up, it's just a
|
||||||
|
redundant backup. When I need to restart things, it seamlessly takes over. I rsync the config to the backup
|
||||||
|
Pi once a day to keep them consistent, or provide a good backup should I really screw something up.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
As a bonus, Pi-hole blocks ads at the network level, which is it's main benefit, but I almost forget about
|
||||||
|
it until I get off my network. It's such a robust product that I only remember it when I want to mess with
|
||||||
|
DNS/DHCP (break things).
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="deco-divider">
|
||||||
|
<div class="diamond"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>TrueNAS for Storage</h2>
|
||||||
|
<p>
|
||||||
|
Storage is one of those problems that sneaks up on you. First it's just a few documents. Then some photos.
|
||||||
|
Then you're ripping your DVD collection and suddenly you need 10TB and redundancy because losing years of
|
||||||
|
data to a single drive failure sounds like a nightmare.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
TrueNAS handles all of this with ZFS under the hood. I've got it set up with mirrored drives, which means
|
||||||
|
I can lose a disk without losing data. It serves media to devices around the house, backs up important files,
|
||||||
|
and generally acts as the single source of truth for anything I don't want to lose.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The web interface makes it approachable too. I'm not particularly interested in becoming a storage expert,
|
||||||
|
but TrueNAS lets me configure RAID levels, set up snapshots, and monitor drive health without needing a PhD
|
||||||
|
in filesystems. It just works, which is exactly what storage should do.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="deco-divider">
|
||||||
|
<div class="diamond"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Network Gear and Routing</h2>
|
||||||
|
<p>
|
||||||
|
A good homelab needs a solid network foundation. I'm running a managed switch that handles VLANs, which lets
|
||||||
|
me segment traffic appropriately. IoT devices get their own VLAN, which means even if some random smart bulb
|
||||||
|
gets compromised, it can't reach the rest of the network. It also brings me some sense of organization. My
|
||||||
|
Rasperry Pi cluster can stay organized on one VLAN without mucking up my devices list.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The router is running custom firmware that gives me way more control than any consumer router ever would. I
|
||||||
|
can shape traffic, set up VPNs, and actually see what's happening on my network. It's the kind of thing where
|
||||||
|
once you start looking at the data, you realize how much garbage is constantly flying around your home network.
|
||||||
|
Smart TVs phoning home. IoT devices pinging random servers. It's enlightening in a slightly creepy way.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="deco-divider">
|
||||||
|
<div class="diamond"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Backup Strategy</h2>
|
||||||
|
<p>
|
||||||
|
Here's something nobody thinks about until it's too late: backups. The homelab itself is somewhat ephemeral.
|
||||||
|
I can rebuild it from configs. But the data? That needs to be protected.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
I'm following the 3-2-1 rule: three copies of data, on two different types of media, with one copy offsite (well sorta).
|
||||||
|
TrueNAS handles the local copies with snapshots and redundancy. It's in a ZRAID configuration for drive parity. I've
|
||||||
|
got an external drive I have plugged into the homelab using a docking station that I will periodically turn on. I have
|
||||||
|
most of my configs backed up to my desktop or in the cloud, so in the event of a failure, I can get back online quick.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
It's not exciting. It's not fun to set up. I've actually found I've misconfigured it several times and
|
||||||
|
through sheer luck that hasn't been a problem yet. But it's the difference between a minor inconvenience and a
|
||||||
|
catastrophic loss. I learned this lesson on my desktop when I was dual booting Windows and Linux. Windows
|
||||||
|
introduced a bug that deleted non-Windows boot drives. Now everything is backed up, automated, and I can actually sleep at night.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="deco-divider">
|
||||||
|
<div class="diamond"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Automation and Services</h2>
|
||||||
|
<p>
|
||||||
|
The real power of a homelab comes from what you do with it. I've got Home Assistant running for home automation,
|
||||||
|
which ties together all the random smart devices I've accumulated over the years. Lights, sensors, you name it, all
|
||||||
|
talking to each other in ways they were never designed to. At some point in the future, I'd like to replace my
|
||||||
|
light switches with dimmers that can be run by Home Assistant, so they will dim or brighten depending on the
|
||||||
|
time of day.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Kubernetes ingress reverse proxying handles all the web service routing, complete with automatic SSL certificates. I don't have to
|
||||||
|
think about certificate renewal or manually configuring HTTPS anymore. Cert-manager does that all for me.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
I've got a Gitea server for personal projects, a password manager to sync across devices, an Obsidian-livesync instance for my note taking,
|
||||||
|
and a handful of other services that make daily life a little easier. Each one solves a specific problem, and
|
||||||
|
together they form an ecosystem that's genuinely useful.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
My last ditch effort for automation is n8n. It is what I would call "code glue." Any services that need to talk to each other
|
||||||
|
in some way, but don't have preconfigured methods to do so, I can stitch together with n8n. It allows me to create workflows,
|
||||||
|
use logic, create webhooks, and modify data before sending it somewhere else. If I need something done and there's no right way
|
||||||
|
to do it, you bet I'm gonna make an n8n workflow.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="deco-divider">
|
||||||
|
<div class="diamond"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Power Management</h2>
|
||||||
|
<p>
|
||||||
|
Something people don't talk about enough: power. Not just whether things are plugged in, but power management
|
||||||
|
during outages. I've got a UPS (Unattended Power Supply) handling the critical infrastructure. It's not designed
|
||||||
|
to keep things running for hours, but it gives me enough time to gracefully shut everything down if the power
|
||||||
|
goes out.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
More importantly, it protects against surges and brown-outs. Electronics are expensive, and replacing a failed
|
||||||
|
server because of dirty power is both costly and annoying. The UPS communicates with the servers too, so if I'm
|
||||||
|
not home and the power goes out, everything shuts down safely on its own.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="deco-divider">
|
||||||
|
<div class="diamond"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Constant Evolution</h2>
|
||||||
|
<p>
|
||||||
|
One morning I woke up to find my phone disconnected from the network. To my surprise, it wasn't Pi-holes fault,
|
||||||
|
it was a drive failure. Not a ZRAIDed TrueNAS drive, but the main one. I had misconfigured backups at this point.
|
||||||
|
Upon restart, my homelab wouldn't boot. I was in a pickle, but I didn't dispair. I thought it would be a chance to
|
||||||
|
start anew. I thought about many of the changes I would make.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
First of all, I would get rid of Proxmox. I had it installed as a Type II hypervisor on the OS level. I was <del>conned</del>
|
||||||
|
meme-d into installing it, only to find it overly complex to do simple things. Worst of all, I had absolutely no use for a VM.
|
||||||
|
I was already comfortable with containers. If I needed a GPU I could theoretically do a passthrough to a VM, but the convoluted
|
||||||
|
abstractions always made it impossible to actually configure applications with it. I would rather run an OS and run containers/VMs
|
||||||
|
as need be than just abstract the functionality away.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Argo CD. A deified tool among some. A waste of resources to me. For example: any Argo CD instance needs another host of Argo CD service
|
||||||
|
instances that can be quite beefy on any system. And for what? To do what Kubernetes does automatically? You would be better off
|
||||||
|
creating a pipeline orchestrator from scratch using cron, webhook scripts, and Terraform.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
There's a happy ending to the story. Eventually, after rebooting the homelab a couple dozen times trying and failing to hit the boot
|
||||||
|
menu key fast enough, I discovered that my drive hadn't failed at all. It works even now, and for no reason at all. Amazing.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
I still have future plans for my homelab. If I ever come into some more hardware, I could finally set up that second node for
|
||||||
|
my Kubernetes cluster. I might even leave it bare-metal so I can keep the GPU available for any future projects where I might want
|
||||||
|
some ubiquitous computing power anywhere in the world. It would also be nice to move TrueNAS to it's own dedicated hardware.
|
||||||
|
There's always more to learn and experiment with. I wonder what sort of homelab I could have a year from now.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer>
|
||||||
|
<div class="footer-ornament"></div>
|
||||||
|
<p>Tech Chronicals 2025</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
|
|
@ -476,15 +476,17 @@
|
||||||
<span class="post-category">Infrastructure</span>
|
<span class="post-category">Infrastructure</span>
|
||||||
<span>September 2025</span>
|
<span>September 2025</span>
|
||||||
</div>
|
</div>
|
||||||
|
<a href="https://steen.run/blog/Homelab/index.html">
|
||||||
<h2 class="post-title">Home Sweet Homelab</h2>
|
<h2 class="post-title">Home Sweet Homelab</h2>
|
||||||
|
</a>
|
||||||
<p class="post-description">
|
<p class="post-description">
|
||||||
Welcome to my homelab! Let me show you around.
|
Welcome to my homelab! Let me show you around.
|
||||||
</p>
|
</p>
|
||||||
<div class="tech-stack">
|
<div class="tech-stack">
|
||||||
<div class="tech-item">Kubernetes</div>
|
<div class="tech-item">Kubernetes</div>
|
||||||
<div class="tech-item">Proxmox</div>
|
<div class="tech-item">Pi-hole</div>
|
||||||
<div class="tech-item">ArgoCD</div>
|
<div class="tech-item">ZFS</div>
|
||||||
<div class="tech-item">OTEL-LGTM Stack</div>
|
<div class="tech-item">LGTM Stack</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue