Skip to notes

Public Homelab Notes / 06

Projects

The story of Open Lab Frame, plus the storage and compute projects I plan to build.

2 notes · Current setups, past observations, and future plans stay as recorded.

Projects / Note 01

Open Lab Frame Project

In this note

Chronological project record for the design, infrastructure, deployment, security hardening, and continued development of openlabframe.com.

Homelab Overview | Open Lab Frame | Raspberry Pi 5 | VM101 - OpenLabFrame Dev | Network Topology | Uptime Kuma | Beszel


Project Status

State: Active / In Production
Public Site: https://openlabframe.com
Production Host: Raspberry Pi 5
Development Host: VM101 - OpenLabFrame Dev
Source Repository: <private Open Lab Frame source repository>
Web Server: Nginx
Public Ingress: Cloudflare Tunnel
Production Build: Hardened / hashed / minified dist/

Open Lab Frame is the public portfolio and project-documentation site for the homelab.

It serves as both:

Public portfolio
+
Living record of actual homelab work

Core Project Goal

The goal of Open Lab Frame is to present real technical work being completed in the homelab rather than acting as a generic personal homepage.

The site is intended to demonstrate experience with:

  • Linux
  • Docker
  • Nginx
  • Cloudflare
  • Git
  • GitHub
  • JavaScript
  • CSS
  • HTML
  • Build tooling
  • Infrastructure deployment
  • Monitoring
  • Security hardening
  • Networking
  • Self-hosting
  • Troubleshooting
  • Production change control

The site should continue evolving alongside the real homelab.


Architecture Overview

Current production architecture:

Public Visitor
      ↓
Internet
      ↓
Cloudflare
      ↓
Cloudflare Tunnel
      ↓
Raspberry Pi 5
<private Pi 5 host>
      ↓
Docker
      ↓
Nginx / ehworld
      ↓
Open Lab Frame

Development remains separate:

VM101
   ↓
Readable source
   ↓
npm run build
   ↓
dist/
   ↓
Deployment package
   ↓
Pi 5 staging
   ↓
Production

Major Design Principle

One of the most important decisions in the project is:

Readable development source
        ≠
Public production code

Development source remains readable and maintainable.

Production is generated through the build system and can include:

  • Minification
  • Obfuscation
  • Content hashing
  • Selector hardening
  • JavaScript fragmentation

This avoids making the private source unnecessarily difficult to work on.


Early Infrastructure Phase

Open Lab Frame began as a self-hosted site running from the Raspberry Pi 5.

The Pi 5 became the primary public web infrastructure node.

Current Pi 5 identity:

Hostname: <pi5-hostname>
User:     <admin-user>
Network: Private LAN
RAM:      16 GB
Storage:  1 TB NVMe

The site was deployed through Dockerized Nginx.


Nginx Production Container

Production web server container:

ehworld

Current active website directory:

<PRODUCTION_SITE_DIRECTORY>

This directory contains the built production website served to the public.


Cloudflare Tunnel

The site uses Cloudflare Tunnel rather than exposing the Pi 5 directly to the public Internet.

Architecture:

Nginx
   ↓
cloudflared
   ↓
Cloudflare
   ↓
Visitor

This was especially useful because the home connection uses Starlink behind CGNAT.

No traditional inbound public IPv4 port forwarding is required.


Domain

Primary public domain:

openlabframe.com

Cloudflare handles the public DNS and ingress layer.


Initial Website Direction

Early versions of the website focused on presenting:

  • Personal/homelab identity
  • Current projects
  • Setup information
  • Public links
  • Technical progress
  • Monitoring screenshots
  • Project history

The visual design evolved around a dark interface with gold-accent styling.


Early UI Work

Early website work included:

  • Main title styling
  • Setup panels
  • Responsive positioning
  • About section layout
  • Social/media icons
  • Project controls
  • History/changelog interface
  • Visitor counter
  • Dashboard images
  • Hover behavior

The project gradually moved from a simple personal site toward a structured homelab portfolio.


Visual Identity

The site developed a consistent visual identity around:

Dark background
Gold accents
Glowing edges
Modern panels
Responsive layouts

A modern gold cube was also selected as the favicon/logo direction.


Main Source Files

Readable source has included:

src/
├── index.html
├── projects/
│   └── index.html
├── style.css
├── setup-menu.js
├── visitor-counter.js
├── owner-tools.js
└── history-modal.js

These remain development-oriented files.

Production transformation occurs during the build.


GitHub Repository

Canonical source repository:

<private Open Lab Frame source repository>

GitHub provides:

  • Version control
  • Change history
  • Recovery point
  • Development workflow
  • Source organization

The private repository remains the authoritative source.


Development Environment Evolution

Early development work used GitHub / Codespaces workflows.

The project later gained a dedicated development VM:

VM101 - OpenLabFrame Dev

Current VM101:

VM ID: 101
Network: Private LAN
User:  <admin-user>

VM101 is normally:

OFF

when development is not taking place.


VM101 Purpose

VM101 exists specifically for:

  • Open Lab Frame source editing
  • Git operations
  • Build testing
  • Local previews
  • Production build generation
  • Deployment preparation

Production does not depend on VM101 remaining online.


SSH Access

Windows alias:

ssh <development-alias>

Repository path:

<SOURCE_REPOSITORY>

Development Toolchain

Current known environment:

nvm:     0.40.7
Node.js: 24.21.0
npm:     11.19.0

Normal dependency installation:

npm ci

Build:

npm run build

Output:

dist/

Private Development Preview

VM101 can serve the development version internally.

Backend:

<private development host>:<SERVICE_PORT>

Friendly private URL:

<private development URL>

Path:

Client
   ↓
Pi-hole
   ↓
VM102 / NPM
   ↓
<private development host>:<SERVICE_PORT>
   ↓
VM101

When VM101 is off:

<private development hostname>

being unavailable is expected.


Source / Dist Separation

Development source:

src/

Generated output:

dist/

The correct relationship is:

src/
↓
Build system
↓
dist/

Not:

Edit dist/

The generated production output should never become the primary source of truth.


Build System

The project uses:

build.mjs

as the production build orchestrator.

The build pipeline evolved beyond basic HTML/CSS/JS copying and now includes security/hardening transformations.


Production Goals

The production build aims to:

  • Reduce readable implementation details
  • Minify assets
  • Obfuscate JavaScript
  • Fragment production JavaScript
  • Harden selectors
  • Content-hash filenames
  • Prevent stale caching
  • Avoid source maps
  • Preserve functionality
  • Preserve accessibility
  • Keep source maintainable

JavaScript Hardening - Phase 2

A major production-hardening milestone was JavaScript fragmentation.

The build began producing multiple independently processed JS files.

Production naming follows patterns such as:

j-XXXXXXXX.min.js

The filenames are intentionally meaningless.


JavaScript Fragmentation Goals

The fragmentation phase aimed to avoid exposing:

One large obvious JavaScript bundle

Instead:

Source modules
      ↓
Build
      ↓
Multiple hardened JS outputs

The original execution order is preserved in:

dist/index.html

No Source Maps

Production builds intentionally contain no source maps.

This means files such as:

*.map

should not be generated or deployed publicly.

The readable source remains private instead.


Selector Hardening - Phase 3

The project later added deterministic selector hardening.

Module:

selector-hardening.mjs

Technologies include:

postcss-selector-parser
SHA-256 based deterministic mapping

Class Hardening

Readable classes are transformed to names similar to:

x**********

Example concept:

.project-card

may become:

.x1234567890

The exact value is build-generated.


ID Hardening

Readable IDs are transformed to names similar to:

y**********

This reduces the amount of meaningful naming visible in production HTML.


Shared Selector Map

The build reads:

src/index.html
+
src/style.css

to create a single selector map.

This ensures that selectors remain consistent across:

  • HTML
  • CSS
  • JavaScript

JavaScript Selector Rewrites

The production hardener rewrites references including:

getElementById()
getElementsByClassName()
querySelector()
querySelectorAll()
closest()
matches()

Without this, changing HTML/CSS selectors would break JavaScript behavior.


ARIA Preservation

The hardening process also updates ARIA relationships where applicable.

Examples:

aria-controls
aria-labelledby

This ensures selector hardening does not destroy accessibility relationships.


Font Awesome Preservation

Font Awesome classes are preserved:

fa-*

These are excluded from project selector hardening.


CSS Production Output

CSS production files use hashed/minified names such as:

c-XXXXXXXX.min.css

A changed file gets a changed hash.


Why Content Hashing Matters

Hashed assets allow long-term browser/CDN caching.

Example:

c-ABC12345.min.css

If CSS changes:

New CSS
↓
New hash
↓
New filename

The browser therefore cannot accidentally reuse an old cached asset under the same filename.


Production Cache Strategy

HTML remains refreshable:

Cache-Control: no-cache

Hashed static assets can use:

max-age=31536000
immutable

Images use a shorter cache lifetime.

A previous image cache policy used approximately:

4 hours

Production Cache Validation

Public deployment testing has verified behavior such as:

HTML
→ CF-Cache-Status: DYNAMIC

Hashed assets
→ CF-Cache-Status: HIT
→ Age increasing

This confirms the intended separation between dynamic HTML references and immutable hashed assets.


September 5 Hardening Deployment

A significant Phase 3 production deployment occurred on September 5, 2026.

Before deployment:

  • Selector hardening passed
  • Responsive behavior passed
  • Modal/menu behavior passed
  • CSS/JS references passed
  • Public output was reviewed

September 5 Production ZIP

Deployment archive:

<DEPLOYMENT_ARCHIVE>

Observed size:

877K

Recorded SHA-256:

676b07b29c4fa7d3d2d34433b87dd050755c1e71c7dadc4e2954a56f7e7f5891

ZIP integrity validation:

OK

September 5 Production Backup

A production backup was created before deployment.

Example:

ehlabframe-backup-20260905-072800

Approximate size:

956K

This provided a rollback point.


September 5 New Assets

The production sync included hashed files such as:

c-7350C8F2.min.css
c-E1D2ADA6.min.css
c-E763DD50.min.css

j-31D7E46F.min.js
j-427D344E.min.js
j-8CEBBA48.min.js
j-A3C106A2.min.js

Old obsolete hashed assets were removed through controlled rsync --delete.


Deployment Safety Workflow

The project uses a deliberate production workflow:

Readable source
      ↓
npm run build
      ↓
dist/
      ↓
Local validation
      ↓
ZIP
      ↓
Transfer to Pi 5
      ↓
ZIP integrity check
      ↓
Extract to staging
      ↓
Timestamped production backup
      ↓
rsync dry run
      ↓
Review
      ↓
Live rsync
      ↓
nginx -t
      ↓
Reload
      ↓
Public validation

This workflow should continue to be treated as canonical.


Staging Directory

Production staging:

<STAGING_DIRECTORY>

The staging directory gives the new build a place to exist before touching the live site.


Active Directory

Live production:

<PRODUCTION_SITE_DIRECTORY>

Backup Directories

Production backups:

<PRODUCTION_BACKUP_DIRECTORY>

Each major deployment should preserve a known-good previous state.


rsync Dry Run

A dry run should always occur before live replacement.

Conceptually:

rsync -av --delete --dry-run \
  <STAGING_DIRECTORY>/ \
  <PRODUCTION_SITE_DIRECTORY>/

Review:

  • Additions
  • Changes
  • Deletions

before running the real command.


Live Deployment

Only after reviewing the dry run:

rsync -av --delete \
  <STAGING_DIRECTORY>/ \
  <PRODUCTION_SITE_DIRECTORY>/

Nginx Validation

Before reload:

docker exec ehworld nginx -t

Expected:

syntax is ok
test is successful

Only then:

docker exec ehworld nginx -s reload

Public Validation

After deployment, verify:

Homepage
Projects page
Navigation
Images
Menus
Modals
History
Responsive behavior
HTTPS
Cloudflare Tunnel
Hashed assets
Browser caching

A hard refresh should also be used when validating changes.


Hover Redesign

The visual hover behavior was redesigned during the hardening phase.

Current direction includes:

Gold icon fill
Gold glow
Gold text
Letter-edge glow

The previous card lift / scale behavior was removed.

Panel animations remain.


CSS Reorganization

The main:

src/style.css

was reorganized to improve maintainability while preserving the visual design.

Readable source remains organized even though production CSS is minified and hashed.


Source Baseline - September 9

The later audited:

src(4).zip

became the canonical readable-source baseline.

It superseded:

src(3).zip

for ongoing work.


Audited Source Inventory

The September 9 baseline included approximately:

src/index.html
→ 545 lines

src/projects/index.html
→ 49 lines at that audit point

src/style.css
→ 1,155 lines

JavaScript included:

setup-menu.js
visitor-counter.js
owner-tools.js
history-modal.js

The project later continued evolving beyond the earlier lightweight Projects page.


Projects Page Evolution

The Projects page originally existed as a lightweight placeholder.

Earlier public content included:

Under Development

This was eventually replaced by a real homelab-project page.


Current Projects Page

The current production Projects page contains sections for real devices and projects.

Current device sections include:

Raspberry Pi 5
Raspberry Pi 3 Model B
HP ProDesk 600 G4

Raspberry Pi 5 Project Section

Current Pi 5 section covers:

  • Docker
  • Nginx
  • Open Lab Frame hosting
  • Cloudflare Tunnel
  • Grafana
  • Uptime Kuma
  • Monitoring
  • Traffic/dashboard views

It includes expandable screenshot galleries.

Status:

In use

Raspberry Pi 3 Project Section

The Pi 3 section covers:

  • Pi-hole
  • Tailscale
  • DNS
  • Private networking

It includes Pi-hole dashboard imagery.

Status:

In use

HP ProDesk Project Section

The HP ProDesk 600 G4 section documents the media-server project.

Main highlighted application:

Jellyfin

Current site status has shown:

Configuring

Current Service Icons

The Projects page includes locally hosted icons for:

Jellyfin
Docker
Nginx
Grafana
Cloudflare
Tailscale
Pi-hole

Local hosting reduces dependency on external icon sources.


Project Status Badges

Current visual status convention:

Green
→ In use

Gold
→ Configuring

This gives visitors quick context about project maturity.


Responsive Project Layout

The Projects page includes responsive layouts for different screen sizes.

The design was validated for:

  • Desktop
  • Narrow screens
  • Mobile layouts
  • Expandable content

Accessibility Improvements

Current project-page improvements include:

  • Descriptive alt text
  • Keyboard focus indicators
  • Keyboard-accessible controls
  • Responsive device layouts
  • Expandable image galleries
  • Lightbox behavior

Version 0.2

The current production build identifies:

Version 0.2 - Latest

Title:

Device Projects and Setup Updates

This represents the transition toward the website showing real device-based project content.


Changelog / History

The website includes a history interface.

Supporting source:

history-modal.js

The history feature allows the public site to show its own development milestones.


Setup Menu

Supporting source:

setup-menu.js

This controls interactive setup/project navigation.


Owner Tools

Owner-specific behavior is handled through:

owner-tools.js

An owner-specific protected path has existed under:

a protected owner-only route

Owner-only functionality remains separate from normal public visitor behavior.


Visitor Counter

The website includes a custom visitor counter.

Frontend source:

visitor-counter.js

API:

a visitor-count API


Visitor Cookie

The site uses a long-lived cookie:

a long-lived visitor cookie

This helps avoid repeatedly incrementing the count for the same browser.


D1 Visitor Data

Cloudflare D1 is used for counter persistence.

The visitor counter uses a small Cloudflare D1-backed persistence layer. Exact internal schema details are omitted from the public copy.

A previously validated API example returned a count such as:

{"count":71}

The exact current count naturally changes over time.


YouTube Click Tracking

A separate tracking endpoint was added:

a click-tracking API

It was designed to track:

  • Total clicks
  • Unique clicks

This keeps site analytics lightweight and purpose-built.


Git Mirror

The project also has a Pi 5 local Git mirror process.

Timer:

open-lab-frame-mirror.timer

Schedule:

Daily around 03:00

Configuration includes:

Persistent

so the job can recover from a missed scheduled run.


Monitoring

Open Lab Frame infrastructure is monitored through:

Uptime Kuma

and:

Beszel


Uptime Kuma Role

Uptime Kuma answers:

Is the website / infrastructure reachable?

Alerts can flow through:

Discord
+
ntfy
→ iPhone

Beszel Role

Beszel answers:

How much resource is the Pi 5 using?

The Pi 5 normally has substantial headroom.


Nginx Resource Testing

A direct test of approximately:

500 rapid HTTP requests

showed only approximately:

2–3% CPU

on the Pi 5.

Nginx processes were observed using roughly:

26.7 MiB RSS combined

This confirmed that the static site is extremely lightweight relative to the Pi 5's capacity.


Google Search Indexing

The public Projects page eventually replaced the older placeholder content.

However, Google search results can lag behind the live website.

The correct validation order is:

Check public site
↓
Check live HTML
↓
Check Search Console
↓
Request indexing if appropriate
↓
Wait for Google to refresh

Search Console Workflow

Used workflow:

Google Search Console
      ↓
URL Inspection
      ↓
Test Live URL
      ↓
Request Indexing

A stale Google result does not mean the deployment itself is stale.


Production vs Search Index

Important distinction:

Public website
→ current production truth

Google result
→ cached/indexed representation

Always inspect the real public page before troubleshooting indexing.


Security Philosophy

The project should remain secure without making development painful.

Primary rules:

  • Keep readable source private.
  • Build production output automatically.
  • Do not publish source maps.
  • Do not embed secrets in frontend files.
  • Keep owner/admin paths protected.
  • Use Cloudflare for public ingress.
  • Keep production deployment deliberate.
  • Maintain rollback copies.
  • Do not edit live production directly unless recovering from an emergency.

Production Is Public

Everything inside:

dist/

must be treated as publicly downloadable.

Never place inside production:

Passwords
API secrets
SSH private keys
Cloudflare API tokens
Private webhooks
Recovery codes
Internal credentials
Private environment files

Source Protection Philosophy

Frontend hardening does not make browser code impossible to inspect.

The practical goals are:

Increase casual-copy difficulty
Reduce readable implementation details
Keep production optimized
Preserve private source quality

It is not treated as a replacement for server-side security.


Build Integrity

Production build validation should include searches for unwanted source artifacts.

Examples:

Readable original selector names
Source maps
Old unhashed assets
Unexpected JavaScript function names
Broken ARIA references

The production output should behave correctly while exposing less implementation detail.


Production Deployment Principle

The canonical workflow remains:

Readable private source
        ↓
Build
        ↓
Validate
        ↓
Package
        ↓
Transfer
        ↓
Integrity check
        ↓
Stage
        ↓
Backup production
        ↓
Dry run
        ↓
Deploy
        ↓
Nginx test
        ↓
Reload
        ↓
Public validation

Do not skip steps simply because a change appears small.


Rollback Philosophy

Every meaningful production deployment should have:

Known-good backup
+
Known new build
+
Ability to revert

If a deployment fails:

Stop changing things
↓
Restore last known-good production directory
↓
nginx -t
↓
Reload
↓
Validate

Current Production Baseline

The latest reviewed production direction includes:

  • Full device Projects page
  • Raspberry Pi 5 project section
  • Raspberry Pi 3 project section
  • HP ProDesk Jellyfin project section
  • Local service icons
  • Responsive project layouts
  • Keyboard focus improvements
  • Descriptive alt text
  • Expandable galleries
  • Lightbox behavior
  • Version 0.2 changelog
  • Hashed/minified production assets
  • Production selector hardening
  • JavaScript fragmentation

This supersedes the earlier simple placeholder Projects page.


Project Roadmap Philosophy

Future website sections should reflect actual homelab progress.

Potential future subjects include:

  • NAS Compute Machine
  • Managed Omada networking
  • Additional Docker services
  • Storage architecture
  • Monitoring improvements
  • Backup systems
  • Networking projects
  • New infrastructure milestones

The public site should not claim a project is complete before the actual homelab work supports it.


Current High-Level Project Timeline

Initial Pi 5 website
      ↓
Nginx + Docker
      ↓
Cloudflare Tunnel
      ↓
Custom UI / project panels
      ↓
Visitor counter
      ↓
Monitoring / owner features
      ↓
Private GitHub source workflow
      ↓
Production minification
      ↓
Hashed assets
      ↓
JavaScript fragmentation
      ↓
Selector hardening
      ↓
Dedicated VM101 dev environment
      ↓
Full Projects page
      ↓
Current Version 0.2 production

Project Success Criteria

Open Lab Frame is working correctly when:

Public domain loads
Cloudflare Tunnel works
Pi 5 production host is healthy
Nginx serves correct dist
HTTPS works
Projects page reflects actual homelab state
Hashed assets load
Responsive layout works
JavaScript interactions work
Accessibility remains functional
Monitoring is healthy
Source repository is current
Production can be reproduced from source
Rollback path exists

Related Notes

Homelab Overview
Open Lab Frame
Raspberry Pi 5
VM101 - OpenLabFrame Dev
Network Topology
Uptime Kuma
Beszel
Nginx Proxy Manager
Open Lab Frame Deployment
NAS Compute Machine

Back to Projects

Projects / Note 02

NAS Compute Machine

In this note

Planned high-performance storage and compute system that will become the main heavy-workload node in the Open Lab Frame homelab.

Homelab Overview | NAS Compute Build | HP ProDesk 600 G4 | Proxmox Host | Network Topology | Jellyfin


Project Status

State: Planned / Parts being finalized
Primary Purpose: Storage + virtualization + heavy homelab compute
Expected Operation: Mostly 24/7
Hypervisor: Proxmox
Storage Platform: TrueNAS planned
Bulk Storage: HDD mirror vdevs
Fast Storage: Dual NVMe
GPU: Intel Arc B580
Memory: 64 GB DDR5
CPU: AMD Ryzen 9 9950X

This machine is intended to become the main high-performance compute and storage platform for the homelab.


Core Goal

The project is designed to combine:

High-end compute
+
Large redundant storage
+
Fast NVMe application storage
+
Virtualization
+
Media workloads
+
Self-hosted services

into a single powerful system.

It will complement the existing lightweight always-on infrastructure rather than replacing every Raspberry Pi role.


General Architecture

Planned high-level design:

Starlink
   ↓
TP-Link Archer BE550
   ↓
Omada Managed Switch
   ↓
NAS / Compute Machine
   │
   ├── Proxmox
   │
   ├── TrueNAS
   │
   ├── Application VMs
   │
   ├── Storage services
   │
   ├── Media workloads
   │
   └── Future homelab workloads

Current Planned Hardware

CPU

AMD Ryzen 9 9950X

Status:

Already owned

The 9950X provides:

16 cores
32 threads

and gives the system substantial virtualization and application headroom.


Why the 9950X

The CPU is intended to support multiple simultaneous workloads such as:

  • Proxmox
  • TrueNAS
  • Media applications
  • Immich
  • Databases
  • Docker workloads
  • Game servers
  • Utility VMs
  • Storage services
  • Future experimentation

The intent is not to allocate every core immediately.

Resource headroom should remain available for bursts and future services.


Memory

Current planned memory:

64 GB DDR5 CL40

Status:

Already owned

Current build remains:

Non-ECC

ECC is not part of the current planned configuration.

A future revision could revisit ECC separately, but it should not be documented as part of this build unless the plan actually changes.


Motherboard

Planned motherboard:

ASUS Pro WS B850M-ACE SE

Platform:

AM5
B850
Micro-ATX

The board is intended to provide the workstation-oriented foundation for the storage/compute build.


Case

Planned chassis:

JONSBO N6 NAS Case

Primary reasons:

  • NAS-oriented drive layout
  • Compact storage-focused form factor
  • Multiple 3.5-inch drive support
  • Suitable for a combined compute/storage system

Power Supply

Planned PSU:

ASUS ROG Loki SFX-L 850W Platinum

The PSU must support:

  • Ryzen 9 9950X
  • Intel Arc B580
  • Multiple HDDs
  • Dual NVMe drives
  • Cooling
  • Motherboard
  • Future PCIe devices

The system is designed to run mostly continuously, making PSU quality important.


Cooling

Planned CPU cooling:

240 mm AIO

The build is intended to provide enough thermal headroom for the 9950X while fitting within the NAS-oriented chassis.


Case Fans

Planned fans:

2 × Noctua NF-A12x25 G2 PWM chromax.Black

Goals:

  • Reliable airflow
  • Low noise
  • HDD cooling
  • VRM / motherboard airflow
  • Long-term 24/7 operation

GPU

Current planned GPU:

Intel Arc B580

This supersedes the older RTX 3060 Ti plan.

The GPU can provide hardware acceleration for appropriate future workloads.

Possible roles may include:

  • Media transcoding
  • Compute experimentation
  • Hardware-accelerated applications
  • Future GPU workloads

Exact passthrough/application assignment should be decided during implementation rather than assumed ahead of time.


NVMe Storage

The older storage plan using:

Samsung 970 EVO Plus 1 TB

is being replaced.

Current plan:

2 × Samsung 9100 2 TB NVMe

Total raw NVMe capacity:

4 TB

The two drives are not planned as a mirror.

Each has a different role.


NVMe 1

Planned role:

Proxmox OS
+
Critical services
+
VM storage where appropriate

Conceptually:

Samsung 9100 #1
      ↓
Proxmox
      ↓
Critical VMs / services

NVMe 2

Planned role:

Fast application storage
+
Databases
+
Metadata
+
Cache
+
Active workloads

Possible uses include:

  • Immich database
  • Immich thumbnails
  • Application databases
  • Jellyfin metadata
  • Media metadata
  • Transcoding cache
  • Active game-server worlds
  • Temporary high-speed working data

NVMe Philosophy

The NVMe drives are intended for data that benefits from:

Low latency
+
High IOPS
+
High throughput

They are not intended to replace bulk HDD storage.

The design separates:

Fast operational data

from:

Large persistent bulk data

HDD Storage

Current bulk-storage plan:

4 × Seagate IronWolf Pro 8 TB

Drive characteristics:

3.5-inch
CMR
7200 RPM
NAS-class

Total raw capacity:

32 TB

HDD Layout

Planned topology:

Drive 1 ↔ Drive 2
Drive 3 ↔ Drive 4

Each pair forms a mirror.

Conceptually:

Mirror VDEV 1
├── 8 TB
└── 8 TB

Mirror VDEV 2
├── 8 TB
└── 8 TB

The two mirror vdevs can then participate in the storage pool.


Approximate Usable Capacity

Raw:

32 TB

After mirroring:

~16 TB nominal usable capacity

Actual usable filesystem capacity will be lower because of:

  • TB vs TiB conversion
  • Filesystem overhead
  • ZFS metadata
  • Recommended free-space headroom
  • Snapshots

Therefore:

16 TB

should be treated as the approximate pre-overhead mirrored figure rather than guaranteed user-visible free space.


Why Mirrors

The planned mirror-vdev layout provides:

  • Simple redundancy
  • Good read performance
  • Strong random I/O characteristics
  • Easier future expansion than one large RAIDZ group
  • One-drive fault tolerance within each mirror

Conceptually:

Pool
├── Mirror 1
│   ├── HDD1
│   └── HDD2
│
└── Mirror 2
    ├── HDD3
    └── HDD4

Important Redundancy Principle

RAID / ZFS redundancy is not a backup.

Mirror
→ Protects against certain drive failures

Backup
→ Protects against data loss scenarios

Possible data-loss events that redundancy alone does not solve include:

  • Accidental deletion
  • Filesystem mistakes
  • Malware
  • Application corruption
  • User error
  • Multiple simultaneous failures
  • Physical damage

Local backup planning should remain separate from pool redundancy.


Backup Philosophy

Current long-term preference:

Local backups

The design intentionally does not depend on cloud backup.

Important data should eventually have local copies independent of the primary live storage pool.


TrueNAS Role

TrueNAS is planned to provide the primary bulk-storage layer.

Conceptual architecture:

Proxmox
   ↓
TrueNAS
   ↓
ZFS pool
   ↓
4 × IronWolf Pro

The exact VM/passthrough architecture should be finalized during implementation.


TrueNAS Responsibilities

Potential responsibilities include:

  • ZFS pool management
  • Datasets
  • SMB/NFS shares
  • Snapshot management
  • Storage health monitoring
  • Media storage
  • Photo storage
  • Backup targets
  • Persistent application data

Proxmox Role

Proxmox is planned as the main hypervisor layer.

It can host:

  • TrueNAS
  • Linux VMs
  • Docker application VMs
  • Media workloads
  • Immich
  • Game servers
  • Utility services
  • Future lab workloads

The goal is flexibility without forcing every workload into one giant VM.


Virtualization Principle

Services should be grouped logically.

Avoid:

One giant VM containing everything

but also avoid unnecessary fragmentation into dozens of tiny VMs without a reason.

A balanced structure should consider:

  • Failure domains
  • Backup boundaries
  • Resource usage
  • Hardware passthrough
  • Security
  • Management complexity

Headroom Philosophy

VM allocations should leave reasonable processing and memory headroom.

The goal is not:

Allocate 100% of CPU
Allocate 100% of RAM

Instead:

Expected workload
+
Small safety margin
+
Host headroom
+
Future capacity

This matches the existing approach of allocating slightly more than the minimum workload requirement without exhausting the physical host.


Storage Placement Philosophy

A major project design goal is assigning data to the correct storage tier.


HDD Tier

Best suited for:

Large
Persistent
Sequential
Capacity-oriented

data.

Examples:

  • Jellyfin media
  • Movies
  • TV shows
  • Anime
  • Immich originals
  • Completed video recordings
  • Large archives
  • Persistent game-server backups
  • Backup datasets

NVMe Tier

Best suited for:

Latency-sensitive
IOPS-heavy
Frequently accessed

data.

Examples:

  • Databases
  • Application metadata
  • Thumbnails
  • Cache
  • Transcodes
  • Active game worlds
  • VM disks
  • Application configuration

Media Storage

Long-term Jellyfin media should primarily live on the HDD storage pool.

Conceptually:

Jellyfin application
      ↓
Fast metadata / app storage
      +
HDD media library

This keeps expensive NVMe capacity available for workloads that benefit from it.


Jellyfin Relationship

Current Jellyfin runs on:

VM100 - Jellyfin

on the HP ProDesk.

The future NAS / compute system may eventually take over heavier media-related workloads as the project develops.

Current server:

HP ProDesk
→ Proxmox
→ VM100
→ Jellyfin

Future direction may become:

NAS / Compute
→ Proxmox
→ Media VM/application
→ HDD media pool

The exact migration should be planned and tested before changing the working VM100 environment.


Intel Arc B580 Media Role

The Intel Arc B580 may be used for hardware media acceleration.

Potential benefits include:

  • Hardware decoding
  • Hardware encoding
  • Modern codec support
  • Reduced CPU usage during transcoding

Actual Jellyfin/VM passthrough design should be validated against the final software stack before deployment.


Immich

A major planned workload is:

Immich

The goal is for Immich to become the user's self-hosted photo platform.


Immich Storage Design

Planned layout:

Immich Originals
      ↓
HDD pool

Database
Thumbnails
Cache
Metadata
      ↓
NVMe

This separates large original photo/video storage from latency-sensitive application data.


Immich Capacity

At least approximately:

1 TB

should be available for the user's Immich photo/video library as it grows.

The HDD pool provides significantly more long-term room than the current mobile/cloud-photo workflow.


Immich Architecture Concept

Phone
   ↓
Immich
   ↓
Application / Database
        ↓
      NVMe

Original Photos / Videos
        ↓
     HDD Pool

Game Servers

The machine may also host future game servers.

Recommended storage separation:

Active world / database
→ NVMe

Backups / archives
→ HDD pool

This provides fast live performance while keeping historical copies on higher-capacity storage.


Video Recordings

Completed recordings can be stored on the HDD pool.

Example:

Active recording / processing
      ↓
Fast storage if required
      ↓
Completed recording
      ↓
HDD pool

This avoids consuming NVMe space with long-term bulk files.


Application Databases

Application databases should generally prefer NVMe where practical.

Examples:

  • Immich database
  • Media metadata
  • Service databases
  • Indexes
  • Thumbnail databases
  • Frequently updated application state

This avoids unnecessary random-write workload on the HDD pool.


Cache Does Not Equal Backup

NVMe cache or fast-tier data should not be mistaken for backup.

Fast
≠
Redundant
≠
Backed up

Important application state should still have a backup strategy.


24/7 Operation

The machine is intended to run:

Mostly 24/7

Expected maintenance behavior:

Occasional planned maintenance
~1–2 times per week if needed
~5–10 minutes

The goal is high availability without pretending the system requires enterprise-grade zero downtime.


Power / Thermal Priorities

Because the system will operate continuously, priorities include:

  • Stable PSU
  • Good HDD airflow
  • Controlled CPU temperatures
  • Sensible fan curves
  • Dust management
  • Monitoring
  • Avoiding unnecessary maximum-power operation at idle

Monitoring

The system should eventually participate in the existing monitoring architecture.

Uptime Kuma

Uptime Kuma

Purpose:

Is the system / service reachable?

Beszel

Beszel

Potential purpose:

CPU
RAM
Disk
Network
Temperature
Service/container usage

The exact monitoring deployment can be decided once the node is operational.


Storage Health Monitoring

TrueNAS / ZFS should provide storage-specific health visibility including:

  • SMART data
  • Pool status
  • Scrub results
  • Drive failures
  • ZFS errors
  • Capacity
  • Snapshot state

Storage health should not rely exclusively on a generic host dashboard.


ZFS Scrubs

Regular ZFS scrubs should eventually be scheduled.

Purpose:

Read stored data
↓
Verify checksums
↓
Detect corruption
↓
Repair from redundancy where possible

The exact schedule should be configured once the pool exists.


SMART Testing

The HDDs should eventually use:

  • SMART short tests
  • SMART long tests
  • Temperature monitoring
  • Error monitoring

The exact schedule can be defined during the storage deployment phase.


Snapshot Planning

Important datasets should eventually receive ZFS snapshots.

Potential categories include:

Photos
Application data
Configuration
Game worlds
Important files

Snapshot frequency should match how often the data changes.


Snapshots Are Not Backups

Important distinction:

Snapshot
→ Same storage system

Backup
→ Separate recovery copy

Snapshots are valuable but should not be the only protection for irreplaceable data.


Networking

The machine will eventually connect through the planned:

TP-Link Omada SG2210XMP-M2

Future topology:

Starlink
   ↓
TP-Link Archer BE550
   ↓
Omada SG2210XMP-M2
   ↓
NAS / Compute Machine

Router Design

The future network remains intentionally simple.

The current plan does not include:

This example was not included in the public notes.

The:

TP-Link Archer BE550

remains the primary router and Wi-Fi device.


Opt-In Homelab Philosophy

The new NAS / compute machine does not change the basic network philosophy.

Normal household users should continue using:

BE550
→ Starlink
→ Internet

without depending on:

  • NAS services
  • Pi-hole
  • Tailscale
  • NPM
  • Proxmox
  • Internal homelab DNS

Homelab participation remains opt-in.


Managed Switch Role

The Omada switch will provide the primary high-speed wired distribution layer.

Planned systems may include:

NAS / Compute
HP ProDesk
Raspberry Pi 5
Raspberry Pi 3
Admin PC
Future homelab nodes

10 GbE Future Potential

The planned Omada switch includes:

2 × 10G SFP+

This creates future potential for higher-speed links between major systems.

Examples:

NAS / Compute
↔
Workstation

NAS / Compute
↔
Future high-speed node

The exact NIC/transceiver plan does not need to be finalized until the hardware is ready.


HP ProDesk Relationship

The current HP ProDesk 600 G4 remains the active primary Proxmox host.

Current:

HP ProDesk
↓
Proxmox
↓
VM100
VM101
VM102

The NAS / compute system will eventually provide substantially greater:

  • CPU capacity
  • Storage
  • NVMe capacity
  • GPU capability
  • Expansion room

Workload Migration

Heavy workloads may eventually move from the HP ProDesk to the NAS / compute machine.

Migration should be gradual.

Correct principle:

Build new system
↓
Validate hardware
↓
Validate storage
↓
Validate Proxmox
↓
Validate backups
↓
Migrate one workload
↓
Test
↓
Continue gradually

Do not perform a one-day "move everything" migration.


HP ProDesk Future Role

The future role of the HP ProDesk will be decided only after workload migration is complete and the new system has proven stable.

Current public roadmap:

Heavy workloads
→ NAS / Compute Machine

HP ProDesk
→ Future role not yet finalized

The TP-Link Archer BE550 remains the primary router and Wi-Fi device.


Raspberry Pi Relationship

The new machine does not eliminate the Raspberry Pi infrastructure.


Raspberry Pi 5

Raspberry Pi 5 remains useful for lightweight always-on infrastructure such as:

  • Open Lab Frame
  • Cloudflare Tunnel
  • Uptime Kuma
  • Beszel
  • Monitoring
  • Other lightweight Docker services

Raspberry Pi 3

Raspberry Pi 3 remains useful for:

  • Pi-hole
  • Tailscale DNS
  • Subnet routing

These are lightweight network-infrastructure tasks that do not need the 9950X system.


Why Keep Lightweight Infrastructure Separate

Running every service on the large NAS / compute node would create a larger failure domain.

Keeping some lightweight infrastructure independent means:

NAS maintenance
≠
Everything in the homelab disappears

For example, the Pi 5 can continue serving monitoring or public website infrastructure while the larger system undergoes maintenance.


Failure Domain Philosophy

The project should avoid creating one machine that every single service depends on.

Good separation might become:

Pi 3
→ DNS / Tailscale routing

Pi 5
→ Lightweight infrastructure

NAS / Compute
→ Heavy compute + storage

HP ProDesk
→ Role determined later

This distributes responsibilities across appropriate hardware.


Initial Build Phase

When hardware is assembled, the first goal should be basic stability.

Do not immediately install every production service.

Initial order:

Assemble hardware
↓
Update BIOS
↓
Verify RAM
↓
Verify NVMe
↓
Verify HDDs
↓
Verify GPU
↓
Thermal testing
↓
Stability testing
↓
Install Proxmox

Hardware Validation

Before production use, verify:

CPU recognized correctly
64 GB RAM recognized
Both Samsung 9100 drives recognized
All four IronWolf Pro drives recognized
Intel Arc B580 recognized
Network interfaces recognized
Cooling working
Fans working
No abnormal SMART data

Memory Testing

Because this system will hold important storage workloads, memory should be tested before trusting it with production data.

A sustained memory test during commissioning is worthwhile.

Current memory is:

Non-ECC

so stability testing is especially valuable.


Drive Validation

New HDDs should be tested before building the permanent pool.

Possible validation should include:

  • SMART inspection
  • Extended SMART test
  • Full-drive testing if practical
  • Temperature monitoring
  • Error review

The goal is to catch early-drive failures before loading important data.


NVMe Validation

Both Samsung 9100 drives should be checked for:

  • Correct capacity
  • PCIe link speed
  • Temperature
  • Firmware
  • SMART health
  • Sustained stability

Thermal Validation

The compact NAS case makes airflow especially important.

Test:

CPU load
GPU load
HDD temperatures
NVMe temperatures
Motherboard temperatures

before relying on the machine 24/7.


Proxmox Installation

After hardware validation:

Hardware
↓
Proxmox
↓
Networking
↓
Storage architecture
↓
TrueNAS
↓
Test workloads

Do not begin migration before the base platform is stable.


TrueNAS Deployment

Before creating the permanent data pool:

Confirm disk passthrough / controller design
↓
Confirm TrueNAS sees intended drives
↓
Create pool
↓
Verify mirrors
↓
Configure datasets
↓
Configure snapshots
↓
Configure shares
↓
Test recovery behavior

Dataset Planning

Potential datasets may include:

media
photos
recordings
backups
game-data
archives
shared-files

Application metadata may remain on NVMe rather than the HDD datasets.

Exact dataset names should be chosen during implementation.


Data Placement Example

HDD Pool
├── Media
├── Immich Originals
├── Recordings
├── Backups
└── Archives

NVMe
├── VMs
├── Databases
├── Immich Metadata
├── Jellyfin Metadata
├── Cache
├── Transcodes
└── Active Game Worlds

Migration Safety

Before moving any production workload:

Current service working
+
Current backup exists
+
New destination tested
+
Rollback path known

Then migrate.


Example Jellyfin Migration Philosophy

Do not begin with:

Delete VM100
→ Build replacement

Instead:

Keep VM100 working
↓
Prepare new storage
↓
Copy data
↓
Test new environment
↓
Validate hardware acceleration
↓
Validate local access
↓
Validate Tailscale
↓
Validate VPS
↓
Cut over only when ready

Storage Migration

Large data copies should be verified.

Possible methods include:

  • File counts
  • Checksums where practical
  • Dataset size comparison
  • Application-level library verification

Do not assume a copy succeeded merely because the transfer command exited.


Backups Before Migration

The most valuable datasets should have a known recovery copy before major migrations.

Migration itself is not a backup strategy.


Future Expansion

The mirror-vdev design leaves room conceptually for later storage expansion.

Potential future expansion could involve:

Additional mirror vdevs

if chassis, controller, power, and bay availability allow.

Do not define a future drive expansion until actual capacity needs justify it.


Build Priorities

The project priorities are:

1. Stability
2. Data integrity
3. Recoverability
4. Sensible storage placement
5. Performance
6. Expansion

Raw benchmark speed should not come before storage safety or recoverability.


What This Machine Is Not

The current plan is not:

A cloud-backup appliance
A replacement for every Raspberry Pi

Its primary identity remains:

Storage + Compute

Project Phases

Phase 1 - Hardware

Acquire components
Assemble
Update firmware
Validate cooling
Validate drives
Stress test

Phase 2 - Hypervisor

Install Proxmox
Configure management networking
Configure NVMe storage
Validate host stability

Phase 3 - Storage

Deploy TrueNAS
Pass through storage correctly
Create mirror vdevs
Create pool
Create datasets
Configure SMART
Configure scrubs
Configure snapshots

Phase 4 - Test Workloads

Create non-critical VM
Test storage
Test networking
Test backup/restore
Test GPU if required

Phase 5 - Applications

Potential early workloads:

Immich
Media services
Storage shares
Game servers
Backup targets

Phase 6 - Migration

Gradually migrate workloads from existing systems only after the new environment is proven stable.


Success Criteria

The project can be considered production-ready when:

Hardware stable
CPU temperatures acceptable
HDD temperatures acceptable
NVMe temperatures acceptable
Memory tested
All drives healthy
Proxmox stable
TrueNAS stable
ZFS pool healthy
Mirrors healthy
SMART tests configured
Scrubs configured
Snapshots configured
Backups planned
Network stable
Monitoring active
Test restore successful
Critical workloads tested
Rollback plan documented

Current Planned Hardware Summary

CPU:
AMD Ryzen 9 9950X

Memory:
64 GB DDR5 CL40
Non-ECC

Motherboard:
ASUS Pro WS B850M-ACE SE

Case:
JONSBO N6

PSU:
ASUS ROG Loki SFX-L 850W Platinum

Cooling:
240 mm AIO

Fans:
2 × Noctua NF-A12x25 G2 PWM chromax.Black

GPU:
Intel Arc B580

NVMe:
2 × Samsung 9100 2 TB

HDD:
4 × Seagate IronWolf Pro 8 TB

Current Storage Summary

NVMe #1
→ Proxmox / critical workloads

NVMe #2
→ Fast application data / metadata / cache

4 × 8 TB HDD
→ Two mirrored pairs
→ ~16 TB nominal mirrored capacity

Current Network Summary

Internet
   ↓
Starlink
   ↓
TP-Link Archer BE550
   ↓
TP-Link Omada SG2210XMP-M2
   ↓
NAS / Compute Machine

The homelab remains:

Opt-in

and normal household networking remains independent of homelab services.


Related Notes

Homelab Overview
NAS Compute Build
HP ProDesk 600 G4
Proxmox Host
Network Topology
Jellyfin
Raspberry Pi 5
Raspberry Pi 3
Open Lab Frame Project

Back to Projects