5520 lines
170 KiB
HTML
5520 lines
170 KiB
HTML
|
||
<!doctype html>
|
||
<html lang="en" class="no-js">
|
||
<head>
|
||
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
|
||
<meta name="description" content="Single source of truth for the homelab">
|
||
|
||
|
||
|
||
<link rel="canonical" href="http://192.168.1.8:13080/infra/proxmox-state/">
|
||
|
||
|
||
<link rel="prev" href="../../ct-inventory/">
|
||
|
||
|
||
<link rel="next" href="../portmap/">
|
||
|
||
|
||
|
||
|
||
|
||
<link rel="icon" href="../../assets/images/favicon.png">
|
||
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.6">
|
||
|
||
|
||
|
||
<title>Proxmox state - nuclide.systems docs</title>
|
||
|
||
|
||
|
||
<link rel="stylesheet" href="../../assets/stylesheets/main.484c7ddc.min.css">
|
||
|
||
|
||
<link rel="stylesheet" href="../../assets/stylesheets/palette.ab4e12ef.min.css">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
|
||
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
|
||
|
||
|
||
|
||
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
|
||
|
||
|
||
|
||
|
||
|
||
</head>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<body dir="ltr" data-md-color-scheme="slate" data-md-color-primary="black" data-md-color-accent="blue">
|
||
|
||
|
||
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
|
||
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
|
||
<label class="md-overlay" for="__drawer"></label>
|
||
<div data-md-component="skip">
|
||
|
||
|
||
<a href="#proxmox-host-optimization-inventory-nuc" class="md-skip">
|
||
Skip to content
|
||
</a>
|
||
|
||
</div>
|
||
<div data-md-component="announce">
|
||
|
||
</div>
|
||
|
||
|
||
|
||
|
||
<header class="md-header" data-md-component="header">
|
||
<nav class="md-header__inner md-grid" aria-label="Header">
|
||
<a href="../.." title="nuclide.systems docs" class="md-header__button md-logo" aria-label="nuclide.systems docs" data-md-component="logo">
|
||
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
|
||
|
||
</a>
|
||
<label class="md-header__button md-icon" for="__drawer">
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
|
||
</label>
|
||
<div class="md-header__title" data-md-component="header-title">
|
||
<div class="md-header__ellipsis">
|
||
<div class="md-header__topic">
|
||
<span class="md-ellipsis">
|
||
nuclide.systems docs
|
||
</span>
|
||
</div>
|
||
<div class="md-header__topic" data-md-component="header-topic">
|
||
<span class="md-ellipsis">
|
||
|
||
Proxmox state
|
||
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<form class="md-header__option" data-md-component="palette">
|
||
|
||
|
||
|
||
|
||
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="black" data-md-color-accent="blue" aria-hidden="true" type="radio" name="__palette" id="__palette_0">
|
||
|
||
|
||
|
||
|
||
|
||
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="blue" aria-hidden="true" type="radio" name="__palette" id="__palette_1">
|
||
|
||
|
||
</form>
|
||
|
||
|
||
|
||
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
|
||
|
||
|
||
|
||
|
||
|
||
<label class="md-header__button md-icon" for="__search">
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
|
||
</label>
|
||
<div class="md-search" data-md-component="search" role="dialog">
|
||
<label class="md-search__overlay" for="__search"></label>
|
||
<div class="md-search__inner" role="search">
|
||
<form class="md-search__form" name="search">
|
||
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
|
||
<label class="md-search__icon md-icon" for="__search">
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
|
||
</label>
|
||
<nav class="md-search__options" aria-label="Search">
|
||
|
||
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
|
||
</button>
|
||
</nav>
|
||
|
||
<div class="md-search__suggest" data-md-component="search-suggest"></div>
|
||
|
||
</form>
|
||
<div class="md-search__output">
|
||
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
|
||
<div class="md-search-result" data-md-component="search-result">
|
||
<div class="md-search-result__meta">
|
||
Initializing search
|
||
</div>
|
||
<ol class="md-search-result__list" role="presentation"></ol>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
</nav>
|
||
|
||
</header>
|
||
|
||
<div class="md-container" data-md-component="container">
|
||
|
||
|
||
|
||
|
||
|
||
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
|
||
<div class="md-grid">
|
||
<ul class="md-tabs__list">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../.." class="md-tabs__link">
|
||
|
||
|
||
|
||
|
||
|
||
Home
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../../CHANGELOG/" class="md-tabs__link">
|
||
|
||
|
||
|
||
|
||
|
||
Changelog
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../../RESUME/" class="md-tabs__link">
|
||
|
||
|
||
|
||
|
||
|
||
Resume
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../../ct-inventory/" class="md-tabs__link">
|
||
|
||
|
||
|
||
|
||
|
||
CT inventory
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item md-tabs__item--active">
|
||
<a href="./" class="md-tabs__link">
|
||
|
||
|
||
|
||
Infra
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../../services/homelab-architecture/" class="md-tabs__link">
|
||
|
||
|
||
|
||
Services
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../../security/data-leak-audit-comparison/" class="md-tabs__link">
|
||
|
||
|
||
|
||
Security & audits
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../../ideas/stack-ideas/" class="md-tabs__link">
|
||
|
||
|
||
|
||
Ideas
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-tabs__item">
|
||
<a href="../../history/traefik-migration/" class="md-tabs__link">
|
||
|
||
|
||
|
||
History
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</div>
|
||
</nav>
|
||
|
||
|
||
|
||
<main class="md-main" data-md-component="main">
|
||
<div class="md-main__inner md-grid">
|
||
|
||
|
||
|
||
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
|
||
<div class="md-sidebar__scrollwrap">
|
||
<div class="md-sidebar__inner">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
|
||
<label class="md-nav__title" for="__drawer">
|
||
<a href="../.." title="nuclide.systems docs" class="md-nav__button md-logo" aria-label="nuclide.systems docs" data-md-component="logo">
|
||
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
|
||
|
||
</a>
|
||
nuclide.systems docs
|
||
</label>
|
||
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../.." class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Home
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../CHANGELOG/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Changelog
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../RESUME/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Resume
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../ct-inventory/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
CT inventory
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
|
||
|
||
|
||
|
||
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" checked>
|
||
|
||
|
||
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Infra
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="true">
|
||
<label class="md-nav__title" for="__nav_5">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
|
||
|
||
Infra
|
||
|
||
|
||
</label>
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--active">
|
||
|
||
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
|
||
|
||
|
||
|
||
|
||
|
||
<label class="md-nav__link md-nav__link--active" for="__toc">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Proxmox state
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<a href="./" class="md-nav__link md-nav__link--active">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Proxmox state
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
|
||
|
||
|
||
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<label class="md-nav__title" for="__toc">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
Table of contents
|
||
</label>
|
||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#tldr-top-5-actionable-wins" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
TL;DR — top 5 actionable wins
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#1-system-snapshot" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
1. System snapshot
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#2-memory-vmct-sizing-measured-numbers" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
2. Memory & VM/CT sizing (measured numbers)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="2. Memory & VM/CT sizing (measured numbers)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#concrete-ct-101-picture" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Concrete CT 101 picture
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#concrete-ct-104-picture" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Concrete CT 104 picture
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#other-guests" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Other guests
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#3-zfs-tuning" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
3. ZFS tuning
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="3. ZFS tuning">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#pool" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Pool
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#arc" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
ARC
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#per-dataset" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Per-dataset
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#pool-features" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Pool features
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#commands" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Commands
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#4-storage-vm-disk-options" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
4. Storage & VM disk options
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="4. Storage & VM disk options">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#vm-100-haos" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
VM 100 (haos)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#lxc-local-zfs-storage" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
LXC local-zfs storage
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#unas-share-current-state-measured" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
UNAS share — current state (measured)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#5-cpu-boot-kernel" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
5. CPU / boot / kernel
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="5. CPU / boot / kernel">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#hybrid-core-scheduling" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Hybrid-core scheduling
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#6-reliability-spof" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
6. Reliability / SPOF
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="6. Reliability / SPOF">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#single-disk-is-the-biggest-risk" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Single disk is the biggest risk
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#boot-redundancy" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Boot redundancy
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#7-backups-high-priority-silent-risk" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
7. Backups (HIGH PRIORITY — silent risk)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#8-apt-repositories-cleanup" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
8. APT / repositories cleanup
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="8. APT / repositories cleanup">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#unattended-upgrades-configured-2026-05-20" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Unattended-upgrades (configured 2026-05-20)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#9-networking" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
9. Networking
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#10-container-specific-issues" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
10. Container-specific issues
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="10. Container-specific issues">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ct-104-docker-ai-image-gen-48-gib-cap-16-cores-gpu-passthrough" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
CT 104 (docker / AI / image-gen) — 48 GiB cap, 16 cores, GPU passthrough
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ct-101-shepard-docker-currently-160-gib-cap-peak-156-gib" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
CT 101 (shepard / docker) — currently 160 GiB cap, peak 15.6 GiB
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ct-102-adguard-dns-undersized" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
CT 102 (adguard / DNS) — undersized
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ct-103-backrest-fine" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
CT 103 (backrest) — fine
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ct-105-nextcloud-privileged-cifs" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
CT 105 (nextcloud) — privileged + CIFS
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ct-108-zoraxy-slight-oversize" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
CT 108 (zoraxy) — slight oversize
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ct-104-docker-stacks-inventory-optstacks" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
CT 104 — Docker stacks inventory (/opt/stacks)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#general-lxc-hygiene" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
General LXC hygiene
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#anti-fat-finger-protection-protection-1-boot-order" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Anti-fat-finger protection (protection: 1) + boot order
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#11a-dns-adguard-rewrites-site-wide-consistency" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
11a. DNS — AdGuard rewrites & site-wide consistency
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="11a. DNS — AdGuard rewrites & site-wide consistency">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#why-this-matters" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Why this matters
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#recommended-rewrite-set" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Recommended rewrite set
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#verify-clients-are-actually-using-adguard" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Verify clients are actually using AdGuard
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#optional-hardening-once-the-rewrites-are-stable" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Optional hardening once the rewrites are stable
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#action-checklist" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Action checklist
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#11b-tls-certificates-for-the-proxmox-web-ui" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
11b. TLS certificates for the Proxmox web UI
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="11b. TLS certificates for the Proxmox web UI">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#option-a-reverse-proxy-pve-through-zoraxy-recommended" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Option A — Reverse-proxy PVE through Zoraxy (recommended)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#option-b-pves-built-in-acme-with-dns-01" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Option B — PVE's built-in ACME with DNS-01
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#option-c-push-zoraxys-cert-into-pve" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Option C — Push Zoraxy's cert into PVE
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#recommended-path" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Recommended path
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#other-cts-with-web-uis-worth-fronting-via-zoraxy" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Other CTs with web UIs worth fronting via Zoraxy
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#11-maintenance-observability" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
11. Maintenance / observability
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#13-update-management-current-model" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
13. Update management — current model
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="13. Update management — current model">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#layer-1-host-packages-debian-proxmox" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Layer 1 — Host packages (Debian + Proxmox)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#layer-2-ct-os-packages-debian" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Layer 2 — CT OS packages (Debian)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#layer-3-helper-script-app-binaries-adguard-zoraxy" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Layer 3 — Helper-script app binaries (AdGuard, Zoraxy)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#layer-4-docker-engine-inside-cts" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Layer 4 — Docker engine inside CTs
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#layer-5-docker-images-the-75-containers" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Layer 5 — Docker images (the ~75 containers)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#14-vm-100-haos-auto-restart-watchdog" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
14. VM 100 (HAOS) auto-restart watchdog
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#15-identity-pocket-id-on-its-own-ct" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
15. Identity — Pocket-ID on its own CT
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="15. Identity — Pocket-ID on its own CT">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#state-as-of-2026-05-20" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
State as of 2026-05-20
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#duplication-procedure-used" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Duplication procedure used
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#zoraxy-cutover" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Zoraxy cutover
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#secrets-rotation-list-deferred-to-cutover-day" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Secrets-rotation list (deferred to cutover day)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#16-ct-109-ops-planned-observability-ops-lxc" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
16. CT 109 "ops" — planned observability + ops LXC
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="16. CT 109 "ops" — planned observability + ops LXC">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#stack-to-deploy-on-ct-109" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Stack to deploy on CT 109
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#sidecars-deployed-on-each-host" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Sidecars deployed on each host
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#services-that-stay-where-they-are-not-on-ct-109" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Services that stay where they are (NOT on CT 109)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#migration-of-gotify-tier-b-schedule-when-ct-109-is-otherwise-stable" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Migration of Gotify (Tier B — schedule when CT 109 is otherwise stable)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#migration-of-mcp-gateway-tier-b-split-control-workload" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Migration of MCP Gateway (Tier B — split control / workload)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#arcane-specifics" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Arcane specifics
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#build-order" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Build order
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#17-lldp-unifi-topology-visibility" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
17. LLDP / UniFi topology visibility
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#18a-unas-access-uid-consistency-model-post-nfsv4-investigation" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
18a. UNAS access — UID consistency model (post-NFSv4 investigation)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="18a. UNAS access — UID consistency model (post-NFSv4 investigation)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#universal-uid-landscape-on-unas" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Universal UID landscape on UNAS
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#per-ct-access-pattern-canonical" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Per-CT access pattern (canonical)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#convention-for-new-containers" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Convention for new containers
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#why-bindfs-for-ct-105-specifically" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Why bindfs for CT 105 specifically
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#trigger-event-to-revisit" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Trigger event to revisit
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#18-homarr-inventory-services-to-include-on-the-dashboard" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
18. Homarr inventory — services to include on the dashboard
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="18. Homarr inventory — services to include on the dashboard">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#group-infrastructure" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Group: infrastructure
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#group-network" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Group: network
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#group-ops-to-populate-when-ct-109-lands" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Group: ops (to populate when CT 109 lands)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#group-apps-subset-long-list-fill-from-existing-homepage-labels-in-optstacks" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Group: apps (subset — long list, fill from existing homepage.* labels in /opt/stacks/*/)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#12-suggested-action-order" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
12. Suggested action order
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#19-changes-applied-2026-05-20-session-2" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
19. Changes applied 2026-05-20 (session 2)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="19. Changes applied 2026-05-20 (session 2)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#optimizations-executed" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Optimizations executed
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#pocket-id-migration-completed" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Pocket-ID migration completed
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#proxmox-oidc-via-pocket-id" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Proxmox OIDC via Pocket-ID
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#audit-footnote-side-effects-of-this-run" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Audit footnote — side effects of this run
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../portmap/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Port map
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../storage/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Storage
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../volumes/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Volumes
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../docker-networks/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Docker networks
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../connection-hosts/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Connection hosts
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../proxmox-memory-audit/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Memory audit
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--nested">
|
||
|
||
|
||
|
||
|
||
|
||
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_6" >
|
||
|
||
|
||
<label class="md-nav__link" for="__nav_6" id="__nav_6_label" tabindex="0">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Services
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_6_label" aria-expanded="false">
|
||
<label class="md-nav__title" for="__nav_6">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
|
||
|
||
Services
|
||
|
||
|
||
</label>
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/homelab-architecture/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Homelab architecture
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/dev-environment/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Dev environment (Coder + Gitea)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/mcp-gateway/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
MCP gateway
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/mcp-servers/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
MCP servers
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/pocket-id/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Pocket-ID (OIDC)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/backrest/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Backrest (backups)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/databases/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Databases
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/secrets-manager/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Secrets manager
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/comfyui/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
ComfyUI
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/zoraxy/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Zoraxy
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/adguard-dns/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
AdGuard DNS
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/cloud-gpu/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Cloud GPU
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/arcane/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Arcane
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/doc-ingestion/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Doc ingestion pipeline
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../services/llm-benchmark/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
LLM benchmark
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--nested">
|
||
|
||
|
||
|
||
|
||
|
||
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_7" >
|
||
|
||
|
||
<label class="md-nav__link" for="__nav_7" id="__nav_7_label" tabindex="0">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Security & audits
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_7_label" aria-expanded="false">
|
||
<label class="md-nav__title" for="__nav_7">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
|
||
|
||
Security & audits
|
||
|
||
|
||
</label>
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../security/data-leak-audit-comparison/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Comparison
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../security/data-leak-audit-2026-05-20-tr004-cloud-sandbox/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
2026-05-20 · cloud-sandbox breach
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../security/data-leak-audit-2026-05-21-tr004-artifacts/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
2026-05-21 · artifacts (clean)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../security/audit-claude-code-meta/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Self-audit (Claude Code)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../security/transcripts/audit-chat-2026-05-21/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Transcript (audit session)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--nested">
|
||
|
||
|
||
|
||
|
||
|
||
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_8" >
|
||
|
||
|
||
<label class="md-nav__link" for="__nav_8" id="__nav_8_label" tabindex="0">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Ideas
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_8_label" aria-expanded="false">
|
||
<label class="md-nav__title" for="__nav_8">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
|
||
|
||
Ideas
|
||
|
||
|
||
</label>
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../ideas/stack-ideas/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Stack ideas
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item md-nav__item--nested">
|
||
|
||
|
||
|
||
|
||
|
||
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_9" >
|
||
|
||
|
||
<label class="md-nav__link" for="__nav_9" id="__nav_9_label" tabindex="0">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
History
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
<span class="md-nav__icon md-icon"></span>
|
||
</label>
|
||
|
||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_9_label" aria-expanded="false">
|
||
<label class="md-nav__title" for="__nav_9">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
|
||
|
||
History
|
||
|
||
|
||
</label>
|
||
<ul class="md-nav__list" data-md-scrollfix>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../history/traefik-migration/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Traefik (abandoned 2026-05-16)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../history/traefik-migration-docker-labels/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Traefik labels (abandoned)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../history/mcp-gateway-requirements/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
MCP gateway requirements (superseded)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../history/scrubbing-list-2026-05-17/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Scrubbing list (2026-05-17)
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<li class="md-nav__item">
|
||
<a href="../../history/case-study/" class="md-nav__link">
|
||
|
||
|
||
|
||
<span class="md-ellipsis">
|
||
|
||
|
||
Case study
|
||
|
||
|
||
|
||
</span>
|
||
|
||
|
||
|
||
</a>
|
||
</li>
|
||
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
|
||
|
||
</ul>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
|
||
<div class="md-sidebar__scrollwrap">
|
||
<div class="md-sidebar__inner">
|
||
|
||
|
||
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<label class="md-nav__title" for="__toc">
|
||
<span class="md-nav__icon md-icon"></span>
|
||
Table of contents
|
||
</label>
|
||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#tldr-top-5-actionable-wins" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
TL;DR — top 5 actionable wins
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#1-system-snapshot" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
1. System snapshot
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#2-memory-vmct-sizing-measured-numbers" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
2. Memory & VM/CT sizing (measured numbers)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="2. Memory & VM/CT sizing (measured numbers)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#concrete-ct-101-picture" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Concrete CT 101 picture
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#concrete-ct-104-picture" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Concrete CT 104 picture
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#other-guests" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Other guests
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#3-zfs-tuning" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
3. ZFS tuning
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="3. ZFS tuning">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#pool" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Pool
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#arc" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
ARC
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#per-dataset" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Per-dataset
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#pool-features" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Pool features
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#commands" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Commands
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#4-storage-vm-disk-options" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
4. Storage & VM disk options
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="4. Storage & VM disk options">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#vm-100-haos" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
VM 100 (haos)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#lxc-local-zfs-storage" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
LXC local-zfs storage
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#unas-share-current-state-measured" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
UNAS share — current state (measured)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#5-cpu-boot-kernel" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
5. CPU / boot / kernel
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="5. CPU / boot / kernel">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#hybrid-core-scheduling" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Hybrid-core scheduling
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#6-reliability-spof" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
6. Reliability / SPOF
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="6. Reliability / SPOF">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#single-disk-is-the-biggest-risk" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Single disk is the biggest risk
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#boot-redundancy" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Boot redundancy
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#7-backups-high-priority-silent-risk" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
7. Backups (HIGH PRIORITY — silent risk)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#8-apt-repositories-cleanup" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
8. APT / repositories cleanup
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="8. APT / repositories cleanup">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#unattended-upgrades-configured-2026-05-20" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Unattended-upgrades (configured 2026-05-20)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#9-networking" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
9. Networking
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#10-container-specific-issues" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
10. Container-specific issues
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="10. Container-specific issues">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ct-104-docker-ai-image-gen-48-gib-cap-16-cores-gpu-passthrough" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
CT 104 (docker / AI / image-gen) — 48 GiB cap, 16 cores, GPU passthrough
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ct-101-shepard-docker-currently-160-gib-cap-peak-156-gib" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
CT 101 (shepard / docker) — currently 160 GiB cap, peak 15.6 GiB
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ct-102-adguard-dns-undersized" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
CT 102 (adguard / DNS) — undersized
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ct-103-backrest-fine" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
CT 103 (backrest) — fine
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ct-105-nextcloud-privileged-cifs" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
CT 105 (nextcloud) — privileged + CIFS
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ct-108-zoraxy-slight-oversize" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
CT 108 (zoraxy) — slight oversize
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#ct-104-docker-stacks-inventory-optstacks" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
CT 104 — Docker stacks inventory (/opt/stacks)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#general-lxc-hygiene" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
General LXC hygiene
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#anti-fat-finger-protection-protection-1-boot-order" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Anti-fat-finger protection (protection: 1) + boot order
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#11a-dns-adguard-rewrites-site-wide-consistency" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
11a. DNS — AdGuard rewrites & site-wide consistency
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="11a. DNS — AdGuard rewrites & site-wide consistency">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#why-this-matters" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Why this matters
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#recommended-rewrite-set" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Recommended rewrite set
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#verify-clients-are-actually-using-adguard" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Verify clients are actually using AdGuard
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#optional-hardening-once-the-rewrites-are-stable" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Optional hardening once the rewrites are stable
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#action-checklist" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Action checklist
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#11b-tls-certificates-for-the-proxmox-web-ui" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
11b. TLS certificates for the Proxmox web UI
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="11b. TLS certificates for the Proxmox web UI">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#option-a-reverse-proxy-pve-through-zoraxy-recommended" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Option A — Reverse-proxy PVE through Zoraxy (recommended)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#option-b-pves-built-in-acme-with-dns-01" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Option B — PVE's built-in ACME with DNS-01
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#option-c-push-zoraxys-cert-into-pve" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Option C — Push Zoraxy's cert into PVE
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#recommended-path" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Recommended path
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#other-cts-with-web-uis-worth-fronting-via-zoraxy" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Other CTs with web UIs worth fronting via Zoraxy
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#11-maintenance-observability" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
11. Maintenance / observability
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#13-update-management-current-model" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
13. Update management — current model
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="13. Update management — current model">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#layer-1-host-packages-debian-proxmox" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Layer 1 — Host packages (Debian + Proxmox)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#layer-2-ct-os-packages-debian" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Layer 2 — CT OS packages (Debian)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#layer-3-helper-script-app-binaries-adguard-zoraxy" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Layer 3 — Helper-script app binaries (AdGuard, Zoraxy)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#layer-4-docker-engine-inside-cts" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Layer 4 — Docker engine inside CTs
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#layer-5-docker-images-the-75-containers" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Layer 5 — Docker images (the ~75 containers)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#14-vm-100-haos-auto-restart-watchdog" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
14. VM 100 (HAOS) auto-restart watchdog
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#15-identity-pocket-id-on-its-own-ct" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
15. Identity — Pocket-ID on its own CT
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="15. Identity — Pocket-ID on its own CT">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#state-as-of-2026-05-20" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
State as of 2026-05-20
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#duplication-procedure-used" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Duplication procedure used
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#zoraxy-cutover" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Zoraxy cutover
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#secrets-rotation-list-deferred-to-cutover-day" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Secrets-rotation list (deferred to cutover day)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#16-ct-109-ops-planned-observability-ops-lxc" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
16. CT 109 "ops" — planned observability + ops LXC
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="16. CT 109 "ops" — planned observability + ops LXC">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#stack-to-deploy-on-ct-109" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Stack to deploy on CT 109
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#sidecars-deployed-on-each-host" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Sidecars deployed on each host
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#services-that-stay-where-they-are-not-on-ct-109" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Services that stay where they are (NOT on CT 109)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#migration-of-gotify-tier-b-schedule-when-ct-109-is-otherwise-stable" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Migration of Gotify (Tier B — schedule when CT 109 is otherwise stable)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#migration-of-mcp-gateway-tier-b-split-control-workload" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Migration of MCP Gateway (Tier B — split control / workload)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#arcane-specifics" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Arcane specifics
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#build-order" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Build order
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#17-lldp-unifi-topology-visibility" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
17. LLDP / UniFi topology visibility
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#18a-unas-access-uid-consistency-model-post-nfsv4-investigation" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
18a. UNAS access — UID consistency model (post-NFSv4 investigation)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="18a. UNAS access — UID consistency model (post-NFSv4 investigation)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#universal-uid-landscape-on-unas" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Universal UID landscape on UNAS
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#per-ct-access-pattern-canonical" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Per-CT access pattern (canonical)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#convention-for-new-containers" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Convention for new containers
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#why-bindfs-for-ct-105-specifically" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Why bindfs for CT 105 specifically
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#trigger-event-to-revisit" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Trigger event to revisit
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#18-homarr-inventory-services-to-include-on-the-dashboard" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
18. Homarr inventory — services to include on the dashboard
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="18. Homarr inventory — services to include on the dashboard">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#group-infrastructure" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Group: infrastructure
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#group-network" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Group: network
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#group-ops-to-populate-when-ct-109-lands" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Group: ops (to populate when CT 109 lands)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#group-apps-subset-long-list-fill-from-existing-homepage-labels-in-optstacks" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Group: apps (subset — long list, fill from existing homepage.* labels in /opt/stacks/*/)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#12-suggested-action-order" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
12. Suggested action order
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#19-changes-applied-2026-05-20-session-2" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
19. Changes applied 2026-05-20 (session 2)
|
||
|
||
</span>
|
||
</a>
|
||
|
||
<nav class="md-nav" aria-label="19. Changes applied 2026-05-20 (session 2)">
|
||
<ul class="md-nav__list">
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#optimizations-executed" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Optimizations executed
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#pocket-id-migration-completed" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Pocket-ID migration completed
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#proxmox-oidc-via-pocket-id" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Proxmox OIDC via Pocket-ID
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
</li>
|
||
|
||
<li class="md-nav__item">
|
||
<a href="#audit-footnote-side-effects-of-this-run" class="md-nav__link">
|
||
<span class="md-ellipsis">
|
||
|
||
Audit footnote — side effects of this run
|
||
|
||
</span>
|
||
</a>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
<div class="md-content" data-md-component="content">
|
||
|
||
<article class="md-content__inner md-typeset">
|
||
|
||
|
||
|
||
|
||
|
||
<h1 id="proxmox-host-optimization-inventory-nuc">Proxmox Host Optimization Inventory — <code>nuc</code><a class="headerlink" href="#proxmox-host-optimization-inventory-nuc" title="Permanent link">¶</a></h1>
|
||
<p>Generated: 2026-05-20
|
||
Host: <code>nuc</code> · PVE <code>9.1.11</code> · Kernel <code>6.17.13-4-pve</code> · Debian 13 (trixie)
|
||
CPU: Intel Core Ultra 7 155H (16C / 22T, hybrid P+E+LP-E) · 1 socket · 1 NUMA
|
||
RAM: 62 GiB physical · 31 GiB zram swap (50 % of RAM, zstd, prio 100)
|
||
Storage: single Crucial P3 2 TB NVMe (QLC, DRAM-less) → <code>rpool</code> (ZFS, ashift=12, no redundancy)
|
||
Workload: 1 VM (HAOS) + 9 LXCs (Docker, AdGuard, Backrest, Nextcloud, Zoraxy, Pocket-ID, Dev, Secrets, DB) + 1 planned (Ops/CT109)</p>
|
||
<hr />
|
||
<h2 id="tldr-top-5-actionable-wins">TL;DR — top 5 actionable wins<a class="headerlink" href="#tldr-top-5-actionable-wins" title="Permanent link">¶</a></h2>
|
||
<ol>
|
||
<li><strong>Memory overcommit is dangerous.</strong> Allocated guest RAM (≈ 290 GiB) is ~4.7× physical (62 GiB). Right-size CT 101 (was 160 → done, now 32) and CT 104 (still 128) — see §2. ✅ <em>applied 2026-05-20</em></li>
|
||
<li><strong>ZFS ARC is artificially capped at 6.2 GiB.</strong> Default would be ~31 GiB. After §1 settles, raise to 16 GiB. See §3.</li>
|
||
<li><strong>No redundancy on a QLC SSD with 19 % wear and 59 TB written.</strong> Single-disk <code>rpool</code> on a DRAM-less consumer QLC drive is a SPOF. Add a second NVMe and convert to mirror — biggest reliability win available. See §6.</li>
|
||
<li><strong>Backups never prune.</strong> Was configured <code>keep-all=1</code> — fixed to <code>keep-last=3,keep-daily=7,keep-weekly=4,keep-monthly=6</code>. See §7. ✅ <em>applied 2026-05-20</em></li>
|
||
<li><strong><code>atime</code> and <code>autotrim</code></strong> on ZFS. ✅ <em>applied 2026-05-20</em></li>
|
||
<li><strong>No DNS rewrites</strong> in AdGuard — every internal target is IP-only; add a split-horizon for <code>nuclide.systems</code> and a <code>.lan</code> shorthand set. See §11a.</li>
|
||
<li><strong>Self-signed Proxmox web UI cert</strong> — front via Zoraxy for free LE. See §11b.</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="1-system-snapshot">1. System snapshot<a class="headerlink" href="#1-system-snapshot" title="Permanent link">¶</a></h2>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Resource</th>
|
||
<th>State</th>
|
||
<th>Notes</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Load avg</td>
|
||
<td>normal</td>
|
||
<td>PSI: CPU some=2.4 % / IO some=1 % over 60 s</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Memory</td>
|
||
<td>52 / 62 GiB used, 4.5 GiB free</td>
|
||
<td>tight; zram swap 15 GiB in use</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Swap</td>
|
||
<td>zram0 (zstd, 31 GiB) prio 100</td>
|
||
<td>working as designed; just a symptom of §1</td>
|
||
</tr>
|
||
<tr>
|
||
<td>ARC</td>
|
||
<td>6.0 / 6.2 GiB (capped)</td>
|
||
<td>hit ratio ~99 % but cap is far below default</td>
|
||
</tr>
|
||
<tr>
|
||
<td>NVMe wear</td>
|
||
<td><strong>Percentage Used 19 %</strong>, 59.2 TB written</td>
|
||
<td>~5 % wear/year at current rate; healthy for now</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Temperature</td>
|
||
<td>56–58 °C</td>
|
||
<td>well under the 95 °C critical threshold</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Uptime</td>
|
||
<td>(see <code>uptime</code>)</td>
|
||
<td>scrub clean, no checksum errors</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Cluster</td>
|
||
<td>standalone</td>
|
||
<td>quorum OK, no HA configured</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<hr />
|
||
<h2 id="2-memory-vmct-sizing-measured-numbers">2. Memory & VM/CT sizing (measured numbers)<a class="headerlink" href="#2-memory-vmct-sizing-measured-numbers" title="Permanent link">¶</a></h2>
|
||
<p>Read from <code>/sys/fs/cgroup/lxc/<id>/memory.{current,peak,max}</code> and <code>free -h</code> inside each guest:</p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Guest</th>
|
||
<th>Cap</th>
|
||
<th>Current</th>
|
||
<th>Peak</th>
|
||
<th>Swap-in-use</th>
|
||
<th>Verdict</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>VM 100 (haos)</td>
|
||
<td>16 384 MiB</td>
|
||
<td>13 056 MiB</td>
|
||
<td>n/a</td>
|
||
<td>n/a</td>
|
||
<td>balloon disabled; HAOS actually uses what it has</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 101 (shepard)</td>
|
||
<td>160 000 MiB</td>
|
||
<td><strong>7.2 GiB</strong></td>
|
||
<td><strong>15.6 GiB</strong></td>
|
||
<td>706 MiB</td>
|
||
<td><strong>wildly over-sized</strong> — peak is 10 % of cap</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 102 (adguard)</td>
|
||
<td>512 MiB</td>
|
||
<td>343 MiB</td>
|
||
<td><strong>509 MiB (99 %)</strong></td>
|
||
<td>19 MiB</td>
|
||
<td><strong>under-sized</strong> — at the cap, AdGuardHome alone is 350 MiB</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 103 (backrest)</td>
|
||
<td>512 MiB</td>
|
||
<td>89 MiB</td>
|
||
<td>305 MiB</td>
|
||
<td>16 MiB</td>
|
||
<td>fine</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 104 (docker/AI)</td>
|
||
<td>128 000 MiB</td>
|
||
<td>18.8 GiB</td>
|
||
<td><strong>29.3 GiB</strong></td>
|
||
<td><strong>9.3 GiB</strong></td>
|
||
<td>real workload, but currently swapping — likely starved by CT 101</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 105 (nextcloud)</td>
|
||
<td>8 192 MiB</td>
|
||
<td>2.1 GiB</td>
|
||
<td>3.5 GiB</td>
|
||
<td>53 MiB</td>
|
||
<td>fine</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 108 (zoraxy)</td>
|
||
<td>2 048 MiB</td>
|
||
<td>271 MiB</td>
|
||
<td>463 MiB</td>
|
||
<td>25 MiB</td>
|
||
<td>fine; could halve</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Sum of declared caps ≈ 290 GiB on a 62 GiB host.</strong> Sum of actual peaks ≈ 49 GiB — totally fits. CT 101's 160 GB cap is the entire problem: it's a phantom that scares the scheduler without using anything close to that.</p>
|
||
<h3 id="concrete-ct-101-picture">Concrete CT 101 picture<a class="headerlink" href="#concrete-ct-101-picture" title="Permanent link">¶</a></h3>
|
||
<p>12 cores, load avg 8.5, ~9 Docker containers (Shepard frontend/backend, Keycloak, Neo4j, MongoDB, MongoExpress, TimescaleDB, Caddy, home-showcase-collector). Peak RSS 15.6 GiB.</p>
|
||
<p>→ Drop memory cap to <strong>32 GiB</strong> (2× peak headroom). No reboot required for LXC memory changes.</p>
|
||
<h3 id="concrete-ct-104-picture">Concrete CT 104 picture<a class="headerlink" href="#concrete-ct-104-picture" title="Permanent link">¶</a></h3>
|
||
<p>16 cores, load avg 8.0, ~65 Docker containers including Immich (with ML/vectorchord), ComfyUI (image-gen), LobeChat, n8n, Daytona, LiteLLM, Vaultwarden, Paperless-ngx+AI, Karakeep, Memos, Gotify, Garage S3, plus a forest of MCP servers, Speaches (OpenVINO using the Arc iGPU). 128 GiB of 200 GiB rootfs used.</p>
|
||
<p>Peak RSS 29.3 GiB, but <strong>9.3 GiB sitting in swap</strong> — under memory pressure. Two paths:
|
||
1. <strong>Recommended</strong>: cut CT 101 first, then CT 104's pressure mostly disappears on its own. Re-measure peak after CT 101 is fixed. Likely safe to cap at <strong>48 GiB</strong> then.
|
||
2. Leave the 128 GiB cap as a generous ceiling — harmless once CT 101 is sane.</p>
|
||
<h3 id="other-guests">Other guests<a class="headerlink" href="#other-guests" title="Permanent link">¶</a></h3>
|
||
<ul>
|
||
<li><strong>CT 102 (AdGuard)</strong>: hitting its cap. Bump to <strong>1 GiB</strong> to give DNS room to breathe. (DNS is the single point of failure for the LAN — don't squeeze it.) <code>pct set 102 -memory 1024</code>.</li>
|
||
<li><strong>CT 108 (Zoraxy)</strong>: cap <strong>1 GiB</strong> is plenty.</li>
|
||
<li><strong>VM 100 (HAOS)</strong>: 13 GiB actually used. Enable ballooning so the host can reclaim idle RAM:
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a>qm<span class="w"> </span><span class="nb">set</span><span class="w"> </span><span class="m">100</span><span class="w"> </span>-balloon<span class="w"> </span><span class="m">4096</span>
|
||
</code></pre></div>
|
||
This leaves memory=16384 as a ceiling but lets the host shrink it under pressure.</li>
|
||
<li>KSM is already active (10 255 shared pages) — fine.</li>
|
||
<li>zram swap: keep size at <code>ram / 2</code> until CT 101 is fixed; reduce to <code>ram / 4</code> afterwards.</li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="3-zfs-tuning">3. ZFS tuning<a class="headerlink" href="#3-zfs-tuning" title="Permanent link">¶</a></h2>
|
||
<h3 id="pool">Pool<a class="headerlink" href="#pool" title="Permanent link">¶</a></h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Setting</th>
|
||
<th>Current</th>
|
||
<th>Recommend</th>
|
||
<th>Why</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>autotrim</code></td>
|
||
<td><strong>off</strong></td>
|
||
<td><code>on</code></td>
|
||
<td>QLC needs trim; weekly fstrim alone is OK but autotrim is "free"</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>ashift</code></td>
|
||
<td>12</td>
|
||
<td>keep</td>
|
||
<td>correct for NVMe</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>atime</code></td>
|
||
<td><strong>on</strong> (relatime)</td>
|
||
<td><strong>off</strong></td>
|
||
<td>unused on a hypervisor; reduces write amp on QLC</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>xattr</code></td>
|
||
<td>sa</td>
|
||
<td>keep</td>
|
||
<td>already optimal</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>compression</code></td>
|
||
<td>on (lz4)</td>
|
||
<td>keep</td>
|
||
<td>helping (1.61× on HAOS disk)</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>dnodesize</code></td>
|
||
<td>legacy</td>
|
||
<td><code>auto</code></td>
|
||
<td>minor; only matters with millions of small files</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>recordsize</code> (rpool)</td>
|
||
<td>128 K</td>
|
||
<td>keep for general</td>
|
||
<td>tune per-dataset (see below)</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="arc">ARC<a class="headerlink" href="#arc" title="Permanent link">¶</a></h3>
|
||
<p><code>/etc/modprobe.d/zfs.conf</code> currently caps <code>zfs_arc_max=6669991936</code> (≈ 6.2 GiB).
|
||
- After §2 sizing is done, raise this to 16 GiB: <code>options zfs zfs_arc_max=17179869184</code> and <code>zfs_arc_min=4294967296</code>.
|
||
- Apply live without reboot: <code>echo 17179869184 > /sys/module/zfs/parameters/zfs_arc_max</code>.</p>
|
||
<h3 id="per-dataset">Per-dataset<a class="headerlink" href="#per-dataset" title="Permanent link">¶</a></h3>
|
||
<ul>
|
||
<li><strong>VM zvols</strong> (<code>rpool/data/vm-*</code>): default <code>volblocksize</code> is 16 K — fine. HAOS disk uses <code>cache=writethrough</code>; on ZFS, <strong>switch to <code>cache=none</code></strong> (or unset) — writethrough doubles the sync cost on top of ZFS's own integrity guarantees.</li>
|
||
<li><strong>CT 104 (<code>subvol-104-disk-0</code>, Docker + image-gen)</strong>: keep <code>recordsize=128K</code>. The workload is dominated by large model files and image outputs, not small-file DB traffic — shrinking the record size would hurt, not help.</li>
|
||
<li><strong>Nextcloud (<code>subvol-105-disk-1</code>)</strong>: leave at 128 K (mixed sizes, mostly larger files).</li>
|
||
</ul>
|
||
<h3 id="pool-features">Pool features<a class="headerlink" href="#pool-features" title="Permanent link">¶</a></h3>
|
||
<p><code>zpool upgrade rpool</code> was run during this audit and enabled <code>redaction_list_spill</code> + <code>raidz_expansion</code>. Other disabled features (<code>fast_dedup</code>, <code>longname</code>, <code>large_microzap</code>, <code>dynamic_gang_header</code>, <code>block_cloning_endian</code>, <code>physical_rewrite</code>) can be enabled with another <code>zpool upgrade rpool</code> — only do this if you do not need to roll back to an older ZFS.</p>
|
||
<h3 id="commands">Commands<a class="headerlink" href="#commands" title="Permanent link">¶</a></h3>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a>zpool<span class="w"> </span><span class="nb">set</span><span class="w"> </span><span class="nv">autotrim</span><span class="o">=</span>on<span class="w"> </span>rpool
|
||
<a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a>zfs<span class="w"> </span><span class="nb">set</span><span class="w"> </span><span class="nv">atime</span><span class="o">=</span>off<span class="w"> </span>rpool
|
||
<a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="c1"># (optional, once memory is sane):</span>
|
||
<a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="nb">echo</span><span class="w"> </span><span class="s1">'options zfs zfs_arc_max=17179869184'</span><span class="w"> </span>><span class="w"> </span>/etc/modprobe.d/zfs.conf
|
||
<a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a>update-initramfs<span class="w"> </span>-u<span class="w"> </span>-k<span class="w"> </span>all
|
||
</code></pre></div>
|
||
<hr />
|
||
<h2 id="4-storage-vm-disk-options">4. Storage & VM disk options<a class="headerlink" href="#4-storage-vm-disk-options" title="Permanent link">¶</a></h2>
|
||
<h3 id="vm-100-haos">VM 100 (<code>haos</code>)<a class="headerlink" href="#vm-100-haos" title="Permanent link">¶</a></h3>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="gd">- scsi0: local-zfs:vm-100-disk-1,cache=writethrough,discard=on,size=32G,ssd=1</span>
|
||
<a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a><span class="gi">+ scsi0: local-zfs:vm-100-disk-1,cache=none,discard=on,iothread=1,size=32G,ssd=1</span>
|
||
</code></pre></div>
|
||
<ul>
|
||
<li><code>cache=none</code> (or remove cache entirely) — let ZFS manage caching.</li>
|
||
<li><code>iothread=1</code> with <code>virtio-scsi-pci</code> controller — already using <code>virtio-scsi-pci</code>, just add iothread.</li>
|
||
<li>Already has <code>discard=on</code> and <code>ssd=1</code> ✔</li>
|
||
</ul>
|
||
<h3 id="lxc-local-zfs-storage">LXC <code>local-zfs</code> storage<a class="headerlink" href="#lxc-local-zfs-storage" title="Permanent link">¶</a></h3>
|
||
<ul>
|
||
<li><code>sparse 1</code> is set ✔ — thin-provisioned.</li>
|
||
<li>All CTs are on <code>local-zfs</code> rootfs; OK.</li>
|
||
</ul>
|
||
<h3 id="unas-share-current-state-measured">UNAS share — current state (measured)<a class="headerlink" href="#unas-share-current-state-measured" title="Permanent link">¶</a></h3>
|
||
<p>Backend: <code>192.168.1.31</code> (looks like a UniFi NAS — exports <code>/volume/.../.unifi-drive/storage/.data</code>, the only NFS export listed is restricted to four allowed clients: the host <code>.20</code>, CT 104 <code>.40</code>, plus <code>.60</code> and <code>172.30.33.1</code>).</p>
|
||
<p>Two parallel mounts on the host pointed at the <strong>same backing data</strong>:</p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Mount</th>
|
||
<th>Type</th>
|
||
<th>Options (key bits)</th>
|
||
<th>Consumers</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>/mnt/pve/unas</code></td>
|
||
<td>NFS <strong>v3</strong></td>
|
||
<td><code>proto=tcp, mountproto=udp, rsize/wsize=1M, hard, relatime, timeo=600</code></td>
|
||
<td>CT 103 (backrest), CT 104 (docker) — bind-mounted to <code>/mnt/pve/unas</code> inside</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>/mnt/pve/unas_smb</code></td>
|
||
<td>CIFS <strong>v3.1.1</strong></td>
|
||
<td><code>cache=strict, actimeo=1, soft, rsize/wsize=4M, uid/gid=33</code></td>
|
||
<td>CT 105 (nextcloud) — bind-mounted to <code>/mnt/pve/unas</code> inside</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Issues:</strong></p>
|
||
<ol>
|
||
<li><strong>CT 105 is on CIFS to the same data CT 104 uses via NFS.</strong> Pure duplication. Nextcloud does massive amounts of <code>stat()</code> traffic; <code>actimeo=1</code> on the CIFS mount forces <em>every</em> metadata lookup to hit the wire, which is slow.</li>
|
||
<li><strong>NFS is v3, not v4.x.</strong> v4 is preferred unless the UDM doesn't export it. v4 fixes locking, removes the separate mountd dance, and supports session trunking.</li>
|
||
<li><strong><code>mountproto=udp</code></strong> under packet loss can intermittently fail to (re)mount. Set <code>mountproto=tcp</code>.</li>
|
||
<li><strong><code>hard</code> mount with no <code>intr</code> equivalent.</strong> If UNAS goes away, anything blocked on it hangs the calling process indefinitely. For non-critical use cases (Nextcloud, but <strong>not</strong> backrest), <code>soft,timeo=100,retrans=3</code> is friendlier — Backrest backups should stay <code>hard</code>.</li>
|
||
<li><strong>CT 105 cannot mount NFS directly</strong> because the UNAS export only allows IPs <code>.20/.40/.60/.172.30.33.1</code> — <code>.41</code> (CT 105) is missing. So either keep the host-side bind-mount approach (correct) or have UNAS export to <code>.41</code> too.</li>
|
||
<li><strong>The bind-mount approach is correct</strong> for unprivileged CTs that can't run NFS/CIFS clients themselves. Don't change that pattern.</li>
|
||
</ol>
|
||
<p><strong>Recommended consolidation:</strong></p>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="c1"># 1. Probe whether the NAS speaks NFSv4</span>
|
||
<a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a>mount<span class="w"> </span>-t<span class="w"> </span>nfs<span class="w"> </span>-o<span class="w"> </span><span class="nv">vers</span><span class="o">=</span><span class="m">4</span>.2,proto<span class="o">=</span>tcp<span class="w"> </span><span class="m">192</span>.168.1.31:/var/nfs/shared/storage<span class="w"> </span>/mnt/test
|
||
<a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="c1"># if it works:</span>
|
||
<a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a>pvesm<span class="w"> </span><span class="nb">set</span><span class="w"> </span>unas<span class="w"> </span>--options<span class="w"> </span><span class="nv">vers</span><span class="o">=</span><span class="m">4</span>.2,proto<span class="o">=</span>tcp,hard,noatime
|
||
<a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a><span class="c1"># (this re-mounts on next access; or unmount/remount /mnt/pve/unas)</span>
|
||
<a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a>
|
||
<a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a><span class="c1"># 2. Switch CT 105 to the NFS bind-mount</span>
|
||
<a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a>pct<span class="w"> </span><span class="nb">set</span><span class="w"> </span><span class="m">105</span><span class="w"> </span>--mp0<span class="w"> </span>/mnt/pve/unas,mp<span class="o">=</span>/mnt/pve/unas
|
||
<a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a><span class="c1"># (CT 105 currently uses unas_smb → unas. New line bind-mounts the NFS mount.)</span>
|
||
<a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a><span class="c1"># Then verify nextcloud-aio still sees uid/gid 33 properly — NFS uses host UIDs,</span>
|
||
<a id="__codelineno-3-11" name="__codelineno-3-11" href="#__codelineno-3-11"></a><span class="c1"># whereas CIFS was forcing uid=33. May need to chown on the NAS or add an idmap.</span>
|
||
<a id="__codelineno-3-12" name="__codelineno-3-12" href="#__codelineno-3-12"></a>
|
||
<a id="__codelineno-3-13" name="__codelineno-3-13" href="#__codelineno-3-13"></a><span class="c1"># 3. Drop the CIFS storage once CT 105 is migrated</span>
|
||
<a id="__codelineno-3-14" name="__codelineno-3-14" href="#__codelineno-3-14"></a>pvesm<span class="w"> </span>remove<span class="w"> </span>unas_smb<span class="w"> </span><span class="c1"># if it exists as PVE storage</span>
|
||
<a id="__codelineno-3-15" name="__codelineno-3-15" href="#__codelineno-3-15"></a><span class="c1"># or remove the entry from /etc/pve/storage.cfg</span>
|
||
</code></pre></div>
|
||
<p><strong>Notes on perf:</strong></p>
|
||
<ul>
|
||
<li>1 GbE NIC ceiling is ~118 MB/s. NFS rsize/wsize=1M already saturates that.</li>
|
||
<li>If you have or add a 2.5 GbE / 10 GbE link on either side, also enable jumbo frames (MTU 9000) on <code>vmbr0</code>, the host NIC, and UNAS. That alone can ~double bulk-read throughput.</li>
|
||
<li>For Nextcloud's small-file stats: <code>actimeo=60</code> (NFS) or <code>cache=loose,actimeo=60</code> (CIFS, if you stay on it) — dramatically cuts roundtrips at the cost of slightly stale directory listings.</li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="5-cpu-boot-kernel">5. CPU / boot / kernel<a class="headerlink" href="#5-cpu-boot-kernel" title="Permanent link">¶</a></h2>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Item</th>
|
||
<th>State</th>
|
||
<th>Recommend</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Governor</td>
|
||
<td><code>performance</code></td>
|
||
<td>keep</td>
|
||
</tr>
|
||
<tr>
|
||
<td>HWP EPP</td>
|
||
<td><code>default</code></td>
|
||
<td>set to <code>balance_performance</code> if you want some idle savings without latency cost: <code>echo balance_performance > /sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>intel_iommu=on iommu=pt</code></td>
|
||
<td>set ✔</td>
|
||
<td>keep</td>
|
||
</tr>
|
||
<tr>
|
||
<td>GPU passthrough (<code>i915.force_probe=!7dd5 xe.force_probe=7dd5</code>)</td>
|
||
<td>set for Arc Xe (Meteor Lake)</td>
|
||
<td>keep</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>nvme_core.default_ps_max_latency_us=0</code></td>
|
||
<td>set ✔</td>
|
||
<td>disables NVMe power-save — good for stability, costs ~1 W idle</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>kernel.numa_balancing</code></td>
|
||
<td>0</td>
|
||
<td>correct for single socket</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Old kernels installed</td>
|
||
<td>6.17.13-4 (current) + 7.0.0-3</td>
|
||
<td>keep both for now; remove 7.0.0-3 once you've booted 7.0.2-5 successfully after the pending upgrade</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="hybrid-core-scheduling">Hybrid-core scheduling<a class="headerlink" href="#hybrid-core-scheduling" title="Permanent link">¶</a></h3>
|
||
<p>The 155H has P-cores (cores 0–11), E-cores (12–17), LP-E cores (18–21). Linux 6.x with <code>intel_pstate=active</code> handles ITD/HWP well; no manual pinning is needed for current workloads. If a CT becomes latency-sensitive, you can pin it with <code>cpuset</code> via <code>lxc.cgroup2.cpuset.cpus</code> (P-cores only).</p>
|
||
<hr />
|
||
<h2 id="6-reliability-spof">6. Reliability / SPOF<a class="headerlink" href="#6-reliability-spof" title="Permanent link">¶</a></h2>
|
||
<h3 id="single-disk-is-the-biggest-risk">Single disk is the biggest risk<a class="headerlink" href="#single-disk-is-the-biggest-risk" title="Permanent link">¶</a></h3>
|
||
<ul>
|
||
<li>Current: 1× CT2000P3PSSD8 (QLC, DRAM-less). 19 % wear in (check <code>power_on_hours</code>).</li>
|
||
<li><strong>Recommendation:</strong> add a second 2 TB NVMe (ideally a TLC drive with DRAM — Crucial T500, WD SN770, Samsung 990 Pro, Solidigm P44 Pro). Then:
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a>zpool<span class="w"> </span>attach<span class="w"> </span>rpool<span class="w"> </span>nvme-CT2000P3PSSD8_2429E8BBCFB4-part3<span class="w"> </span>/dev/disk/by-id/<new-disk>-part3
|
||
</code></pre></div>
|
||
(requires partitioning the new disk to match — <code>sgdisk -R</code> from the existing). Pool becomes a mirror with full self-heal.</li>
|
||
<li>If a second internal slot isn't available, at minimum increase backup frequency for CT 101/104 (the irreplaceable data).</li>
|
||
</ul>
|
||
<h3 id="boot-redundancy">Boot redundancy<a class="headerlink" href="#boot-redundancy" title="Permanent link">¶</a></h3>
|
||
<p><code>proxmox-boot-tool kernel list</code> shows one bootloader entry. After §6 mirror is set up, run <code>proxmox-boot-tool init /dev/<new-disk>-partN</code> so either disk can boot.</p>
|
||
<hr />
|
||
<h2 id="7-backups-high-priority-silent-risk">7. Backups (HIGH PRIORITY — silent risk)<a class="headerlink" href="#7-backups-high-priority-silent-risk" title="Permanent link">¶</a></h2>
|
||
<p><code>/etc/pve/storage.cfg</code>:
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a>nfs: unas
|
||
<a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a> prune-backups keep-all=1
|
||
</code></pre></div></p>
|
||
<p><strong><code>keep-all=1</code> means backups are never deleted automatically.</strong> UNAS already holds 2 TB. Set a real policy, e.g.:</p>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a>pvesm<span class="w"> </span><span class="nb">set</span><span class="w"> </span>unas<span class="w"> </span>--prune-backups<span class="w"> </span>keep-last<span class="o">=</span><span class="m">3</span>,keep-daily<span class="o">=</span><span class="m">7</span>,keep-weekly<span class="o">=</span><span class="m">4</span>,keep-monthly<span class="o">=</span><span class="m">6</span>
|
||
</code></pre></div>
|
||
<p>Also: there is <strong>no <code>vzdump</code> job configured</strong> in <code>/etc/pve/jobs.cfg</code>. Backups are either manual or driven from CT 103 (Backrest). Recommend a scheduled <code>vzdump</code> job for at least VM 100 and CT 101/104 <em>in addition to</em> Backrest, so PVE-native restores remain trivial.</p>
|
||
<hr />
|
||
<h2 id="8-apt-repositories-cleanup">8. APT / repositories cleanup<a class="headerlink" href="#8-apt-repositories-cleanup" title="Permanent link">¶</a></h2>
|
||
<p>State today:</p>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a>/etc/apt/sources.list.d/
|
||
<a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a>├── ceph.list # all lines commented — fine but consider deleting the file
|
||
<a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a>├── proxmox.sources # pve-no-subscription (modern deb822) ← keep
|
||
<a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a>├── pve-enterprise.list.bak # backup, safe to remove
|
||
<a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a>├── pve-enterprise.sources # Enabled: false ← keep as-is or remove
|
||
<a id="__codelineno-7-6" name="__codelineno-7-6" href="#__codelineno-7-6"></a>├── pve-install-repo.list # pve-no-subscription duplicate
|
||
<a id="__codelineno-7-7" name="__codelineno-7-7" href="#__codelineno-7-7"></a>└── pve-no-subscription.list # pve-no-subscription duplicate
|
||
</code></pre></div>
|
||
<p><code>pve-install-repo.list</code> and <code>pve-no-subscription.list</code> duplicate what <code>proxmox.sources</code> already declares. APT deduplicates fetches but the duplication is a foot-gun (one of them will go stale on the next PVE major version transition). Recommended cleanup:</p>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a>rm<span class="w"> </span>/etc/apt/sources.list.d/pve-install-repo.list
|
||
<a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a>rm<span class="w"> </span>/etc/apt/sources.list.d/pve-no-subscription.list
|
||
<a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a>rm<span class="w"> </span>/etc/apt/sources.list.d/pve-enterprise.list.bak
|
||
<a id="__codelineno-8-4" name="__codelineno-8-4" href="#__codelineno-8-4"></a><span class="c1"># keep proxmox.sources and pve-enterprise.sources (already disabled)</span>
|
||
<a id="__codelineno-8-5" name="__codelineno-8-5" href="#__codelineno-8-5"></a>apt<span class="w"> </span>update
|
||
</code></pre></div>
|
||
<p>Also: there are <strong>9 pending upgrades</strong> including <code>pve-manager 9.1.18</code> (you're on 9.1.11) and a kernel update. Run <code>apt update && apt full-upgrade</code> at a convenient window.</p>
|
||
<h3 id="unattended-upgrades-configured-2026-05-20">Unattended-upgrades (configured 2026-05-20)<a class="headerlink" href="#unattended-upgrades-configured-2026-05-20" title="Permanent link">¶</a></h3>
|
||
<p>The host previously had a cron line <code>0 2 * * * apt-get update && apt-get upgrade -y</code> that was silently no-op'ing on every kernel / PVE point release — <code>apt-get upgrade</code> refuses to install new dependencies, which PVE updates always introduce.</p>
|
||
<p>Replaced with <code>unattended-upgrades</code> in a conservative profile:</p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>File</th>
|
||
<th>Purpose</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>/etc/apt/apt.conf.d/52unattended-upgrades-pve</code></td>
|
||
<td>local policy — origins allowlist + email + reboot policy</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>/etc/apt/apt.conf.d/20auto-upgrades</code></td>
|
||
<td>enables the daily update-list + unattended-upgrade run</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Auto-applied:</strong>
|
||
- <code>origin=Debian,codename=trixie,label=Debian</code> (stable main)
|
||
- <code>origin=Debian,codename=trixie-security,label=Debian-Security</code>
|
||
- <code>origin=Debian,codename=trixie-updates</code> (stable point updates)</p>
|
||
<p><strong>Held for manual <code>apt full-upgrade</code></strong> (intentionally — review release notes first):
|
||
- <code>origin=Proxmox,...</code> — pve-manager, kernels, qemu-server, all PVE components</p>
|
||
<p><strong>Settings:</strong>
|
||
- <code>Automatic-Reboot "false"</code> — kernel updates require a manual reboot
|
||
- <code>Remove-Unused-Dependencies "true"</code> — autoremove orphans after upgrades
|
||
- <code>AutoFixInterruptedDpkg "true"</code> — resume after crash mid-upgrade
|
||
- <code>Mail "notify@home.box"</code>, <code>MailReport "on-change"</code> — alerts on actual changes</p>
|
||
<p><strong>Triggered by:</strong>
|
||
- <code>apt-daily.timer</code> (daily ~07:00) — refresh package lists
|
||
- <code>apt-daily-upgrade.timer</code> (daily ~06:00) — apply unattended upgrades</p>
|
||
<p><strong>Caveat: mail delivery isn't reaching you yet.</strong> Postfix is up but has <code>relayhost = (none)</code> — change notifications get delivered locally to <code>/var/mail/notify</code> on the host, not to your inbox. Set up a smart-host relay (Gmail/Postmark/etc.) if you want the mails to actually land. Until then, check <code>/var/log/unattended-upgrades/unattended-upgrades.log</code> for history.</p>
|
||
<p><strong>Verify any time:</strong>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a>unattended-upgrade<span class="w"> </span>--dry-run<span class="w"> </span>--debug<span class="w"> </span><span class="m">2</span>><span class="p">&</span><span class="m">1</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>-E<span class="w"> </span><span class="s2">"Allowed origins|would be upgraded|pkgs that look"</span>
|
||
<a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a>systemctl<span class="w"> </span>list-timers<span class="w"> </span>apt-daily-upgrade.timer
|
||
<a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a>tail<span class="w"> </span>/var/log/unattended-upgrades/unattended-upgrades.log
|
||
</code></pre></div></p>
|
||
<hr />
|
||
<h2 id="9-networking">9. Networking<a class="headerlink" href="#9-networking" title="Permanent link">¶</a></h2>
|
||
<ul>
|
||
<li>Single bridge <code>vmbr0</code> on <code>enp86s0</code> — no VLAN aware (<code>bridge-vlan-aware yes</code>). If you ever want to segment guests by VLAN, add it now (no impact on existing guests as long as you don't tag them):
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a>bridge-vlan-aware yes
|
||
<a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a>bridge-vids 2-4094
|
||
</code></pre></div></li>
|
||
<li><code>net.core.rmem_max</code> / <code>wmem_max</code> are at distro defaults (208 KiB). With a 1 GbE NIC the impact is small (link is already saturated at NFS rsize=1M), but with future 2.5/10 GbE bump to 16 MiB:
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a>cat<span class="w"> </span>>/etc/sysctl.d/99-net.conf<span class="w"> </span><span class="s"><<'EOF'</span>
|
||
<a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a><span class="s">net.core.rmem_max=16777216</span>
|
||
<a id="__codelineno-11-3" name="__codelineno-11-3" href="#__codelineno-11-3"></a><span class="s">net.core.wmem_max=16777216</span>
|
||
<a id="__codelineno-11-4" name="__codelineno-11-4" href="#__codelineno-11-4"></a><span class="s">net.ipv4.tcp_rmem=4096 87380 16777216</span>
|
||
<a id="__codelineno-11-5" name="__codelineno-11-5" href="#__codelineno-11-5"></a><span class="s">net.ipv4.tcp_wmem=4096 65536 16777216</span>
|
||
<a id="__codelineno-11-6" name="__codelineno-11-6" href="#__codelineno-11-6"></a><span class="s">EOF</span>
|
||
<a id="__codelineno-11-7" name="__codelineno-11-7" href="#__codelineno-11-7"></a>sysctl<span class="w"> </span>--system
|
||
</code></pre></div></li>
|
||
<li>TCP congestion control is <code>cubic</code>. <code>bbr</code> is generally better for mixed workloads — change only if you measure a problem.</li>
|
||
<li><code>wlo1</code> is present but unused — confirm and disable in BIOS or <code>iface wlo1 inet manual</code> (already done). No action.</li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="10-container-specific-issues">10. Container-specific issues<a class="headerlink" href="#10-container-specific-issues" title="Permanent link">¶</a></h2>
|
||
<h3 id="ct-104-docker-ai-image-gen-48-gib-cap-16-cores-gpu-passthrough">CT 104 (docker / AI / image-gen) — 48 GiB cap, 16 cores, GPU passthrough<a class="headerlink" href="#ct-104-docker-ai-image-gen-48-gib-cap-16-cores-gpu-passthrough" title="Permanent link">¶</a></h3>
|
||
<p>Measured: 18.8 GiB current, peak 29.3 GiB, <strong>9.3 GiB in swap</strong>, load 8.0, ~65 Docker containers (Immich + ML, ComfyUI, LobeChat, n8n, Daytona, LiteLLM, Vaultwarden, Paperless+AI, many MCP servers, Speaches-OpenVINO).</p>
|
||
<ul>
|
||
<li><code>cores: 16</code> is justified by the workload (load avg 8 across 16 = ~50 % avg). Don't drop.</li>
|
||
<li>128 GiB cap is generous but currently 9 GiB is in swap — this is <strong>memory pressure from CT 101's phantom cap</strong>, not from CT 104's own needs. Fix CT 101 first, re-measure, then either lower CT 104 to 48 GiB or leave it.</li>
|
||
<li>GPU pass-through (<code>/dev/dri/card1</code>, <code>renderD128</code>) confirmed visible inside CT and being used by Speaches via OpenVINO ✔</li>
|
||
<li>Keep <code>recordsize=128K</code> (large files dominate).</li>
|
||
<li><code>swap: 32000</code> is high — consider <code>swap: 8192</code>. Heavy CT swap-out on a QLC root SSD adds write amplification.</li>
|
||
<li>Bind-mounted <code>/mnt/pve/unas</code> (NFS) is the right choice ✔</li>
|
||
<li>Bonus: raise scheduler weight if image-gen latency matters: <code>pct set 104 -cpuunits 200</code>.</li>
|
||
</ul>
|
||
<h3 id="ct-101-shepard-docker-currently-160-gib-cap-peak-156-gib">CT 101 (shepard / docker) — currently 160 GiB cap, peak 15.6 GiB<a class="headerlink" href="#ct-101-shepard-docker-currently-160-gib-cap-peak-156-gib" title="Permanent link">¶</a></h3>
|
||
<p>Workload: ~9 containers — Shepard frontend/backend, Keycloak, Neo4j, MongoDB, MongoExpress, TimescaleDB, Caddy, home-showcase-collector.</p>
|
||
<ul>
|
||
<li><strong>Drop memory cap to 32 GiB</strong>: <code>pct set 101 -memory 32768</code>. No restart needed.</li>
|
||
<li><code>cores: 12</code> is fine (load 8.5 — close to fully loaded, real work).</li>
|
||
<li><code>swap: 8192</code> ✔</li>
|
||
<li>This single change unblocks everything else.</li>
|
||
</ul>
|
||
<h3 id="ct-102-adguard-dns-undersized">CT 102 (adguard / DNS) — undersized<a class="headerlink" href="#ct-102-adguard-dns-undersized" title="Permanent link">¶</a></h3>
|
||
<p>Measured: 343 MiB used at the <strong>512 MiB cap</strong>, AdGuardHome alone is 350 MiB RSS, the CT is one OOM event from killing the LAN's DNS.</p>
|
||
<ul>
|
||
<li><code>pct set 102 -memory 1024</code> (bump to 1 GiB).</li>
|
||
<li>Add <code>onboot: 1</code> (already set) + <code>startup: order=1</code> (boots first) + <code>protection: 1</code> (anti-fatfinger). This is the only DNS — treat it like infrastructure.</li>
|
||
</ul>
|
||
<h3 id="ct-103-backrest-fine">CT 103 (backrest) — fine<a class="headerlink" href="#ct-103-backrest-fine" title="Permanent link">¶</a></h3>
|
||
<p>89 MiB used, peak 305 MiB. No changes needed.</p>
|
||
<h3 id="ct-105-nextcloud-privileged-cifs">CT 105 (nextcloud) — privileged + CIFS<a class="headerlink" href="#ct-105-nextcloud-privileged-cifs" title="Permanent link">¶</a></h3>
|
||
<ul>
|
||
<li><strong>Privileged container</strong> (no <code>unprivileged: 1</code>). For a public-facing app this is the wrong tradeoff. Migration: stop CT, <code>vzdump</code> backup, restore as unprivileged. Be ready to fix file ownership on the bind-mount afterwards (privileged UID 33 → unprivileged needs <code>lxc.idmap</code>).</li>
|
||
<li><strong>Uses CIFS bind-mount to UNAS</strong> with <code>actimeo=1</code> — see §4. Switch to NFS bind-mount, after confirming UID mapping (CIFS forces uid=33; NFS uses host UIDs as-is).</li>
|
||
<li>Memory cap 8 GiB, peak 3.5 GiB — fine as-is.</li>
|
||
<li>Runs Nextcloud AIO stack (mastercontainer-managed: apache, postgres, redis, imaginary, collabora, notify-push).</li>
|
||
</ul>
|
||
<h3 id="ct-108-zoraxy-slight-oversize">CT 108 (zoraxy) — slight oversize<a class="headerlink" href="#ct-108-zoraxy-slight-oversize" title="Permanent link">¶</a></h3>
|
||
<p>Peak 463 MiB on a 2 GiB cap. Lower to 1 GiB if desired (cosmetic).</p>
|
||
<h3 id="ct-104-docker-stacks-inventory-optstacks">CT 104 — Docker stacks inventory (<code>/opt/stacks</code>)<a class="headerlink" href="#ct-104-docker-stacks-inventory-optstacks" title="Permanent link">¶</a></h3>
|
||
<p>CT 104 keeps its Docker workloads in a <strong>git-tracked monorepo at <code>/opt/stacks/</code></strong> with one directory per stack, plus meta-docs (<code>PORTMAP.md</code>, <code>storage.md</code>, <code>volumes.md</code>, <code>docker-networks.md</code>, <code>todo.md</code>). Good practice — this is how to keep ~65 containers manageable. The other CTs (101, 105) don't have <code>/opt/stacks</code> — their compose files live elsewhere.</p>
|
||
<p><strong>Stack list (29 dirs):</strong></p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Stack</th>
|
||
<th>Status</th>
|
||
<th>Notes</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>ai/</code></td>
|
||
<td><strong>active</strong> — large subtree</td>
|
||
<td>comfyui, lobehub, litellm, speaches, mcp-gateway, mcp-servers (many MCP yml files), searxng. Custom <code>syncstack.py</code> to manage cross-file project names.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>arr-stack/</code></td>
|
||
<td>dormant (defined, not running)</td>
|
||
<td>rdtclient, prowlarr, audiobookshelf, shelfarr, flaresolverr</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>arcane/</code></td>
|
||
<td>dormant</td>
|
||
<td>Docker dashboard</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>daytona/</code></td>
|
||
<td>active (as <code>daytona-minimal</code>)</td>
|
||
<td>dev environments + runner + registry</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>dozzle/</code></td>
|
||
<td>dormant</td>
|
||
<td>container log viewer</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>gotify/</code></td>
|
||
<td>active</td>
|
||
<td>push notifications</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>homepage/</code></td>
|
||
<td>dormant</td>
|
||
<td>dashboard</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>immich/</code></td>
|
||
<td>active (5 containers)</td>
|
||
<td>photo platform + ML</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>karakeep/</code></td>
|
||
<td>active (3 containers)</td>
|
||
<td>bookmark mgr + chrome + meilisearch</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>memos/</code></td>
|
||
<td>active</td>
|
||
<td>notes</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>n8n/</code></td>
|
||
<td>active</td>
|
||
<td>pinned <code>2.20.11</code> (good — there's an explicit version-drift comment in the compose)</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>nexa/</code></td>
|
||
<td>dormant</td>
|
||
<td>(?)</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>paperless_ai/</code>, <code>paperless-ngx/</code></td>
|
||
<td>active (5 containers between them)</td>
|
||
<td>OCR pipeline</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>pocketid/</code></td>
|
||
<td>active</td>
|
||
<td>OIDC provider</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>proxy/</code></td>
|
||
<td>dormant</td>
|
||
<td>(?)</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>qdrant/</code></td>
|
||
<td>dormant</td>
|
||
<td>vector DB</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>shared-db/</code></td>
|
||
<td>active</td>
|
||
<td>shared-postgres + garage (S3-compatible) + pgadmin (defined)</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>streamio/</code></td>
|
||
<td>dormant</td>
|
||
<td>media</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>traccar/</code></td>
|
||
<td>active</td>
|
||
<td>GPS tracker</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>vaultwarden/</code></td>
|
||
<td>active</td>
|
||
<td>password mgr</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>vpn/</code></td>
|
||
<td>dormant</td>
|
||
<td>gluetun (intended VPN egress wrapper?)</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>backups/</code>, <code>docs/</code>, <code>scripts/</code></td>
|
||
<td>meta dirs (no compose)</td>
|
||
<td></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Observations:</strong></p>
|
||
<ol>
|
||
<li><strong>~10 stacks are defined but dormant.</strong> No RAM/CPU cost while down, but their images sit on disk and the git repo accrues dead code. Either run them, document why they're parked, or <code>git rm</code> them — repo drift is the silent killer of "I know what's running" confidence.</li>
|
||
<li><strong>Stack name ≠ compose project name</strong> for the <code>ai/</code> and <code>daytona/</code> trees (multiple compose files per dir, different project names). The <code>syncstack.py</code> helper exists for this; just be aware that <code>docker compose -f</code> lookups by directory name don't match.</li>
|
||
<li><strong>Disk-reclaim potential (measured <code>docker system df</code>):</strong></li>
|
||
</ol>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Asset</th>
|
||
<th>Total</th>
|
||
<th>Reclaimable</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Images</td>
|
||
<td>83 / 61.6 GB</td>
|
||
<td><strong>8.3 GB</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Build cache</td>
|
||
<td>105 entries / 9.0 GB</td>
|
||
<td><strong>4.6 GB</strong></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Volumes</td>
|
||
<td>31 / 3.0 GB</td>
|
||
<td>940 MB (21 dangling)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Containers</td>
|
||
<td>60 active</td>
|
||
<td>0</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><div class="highlight"><pre><span></span><code><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a>pct<span class="w"> </span><span class="nb">exec</span><span class="w"> </span><span class="m">104</span><span class="w"> </span>--<span class="w"> </span>docker<span class="w"> </span>system<span class="w"> </span>prune<span class="w"> </span>-a<span class="w"> </span>--volumes
|
||
<a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a><span class="c1"># or non-destructively just the build cache:</span>
|
||
<a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a>pct<span class="w"> </span><span class="nb">exec</span><span class="w"> </span><span class="m">104</span><span class="w"> </span>--<span class="w"> </span>docker<span class="w"> </span>builder<span class="w"> </span>prune<span class="w"> </span>-a
|
||
</code></pre></div>
|
||
~13 GB to recover. On a 200 GB rootfs that's 64 % full, this is meaningful.</p>
|
||
<ol>
|
||
<li><strong>Stack→Zoraxy mapping (§11b):</strong> when fronting via Zoraxy, the canonical service endpoints (per <code>PORTMAP.md</code>) are CT 104's IP <code>192.168.1.40</code> + port. Worth cross-referencing that file when setting up reverse-proxy entries.</li>
|
||
</ol>
|
||
<h3 id="general-lxc-hygiene">General LXC hygiene<a class="headerlink" href="#general-lxc-hygiene" title="Permanent link">¶</a></h3>
|
||
<ul>
|
||
<li>Strip the giant HTML banners from the top of every <code>/etc/pve/lxc/*.conf</code> — pure noise in <code>pct config</code>.</li>
|
||
<li>All CTs except 105 are unprivileged ✔ with <code>nesting=1,keyctl=1</code> (appropriate for Docker).</li>
|
||
</ul>
|
||
<h3 id="anti-fat-finger-protection-protection-1-boot-order">Anti-fat-finger protection (<code>protection: 1</code>) + boot order<a class="headerlink" href="#anti-fat-finger-protection-protection-1-boot-order" title="Permanent link">¶</a></h3>
|
||
<p>Applied across all critical guests (2026-05-20). <code>protection: 1</code> blocks <code>pct destroy</code> / "Remove" from the UI until manually unset — cheap insurance against the wrong-CT-deleted incident.</p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Guest</th>
|
||
<th>protection</th>
|
||
<th>startup order</th>
|
||
<th>Rationale</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>CT 102 (AdGuard / DNS)</td>
|
||
<td>✅</td>
|
||
<td><strong>order=1</strong> (boots first)</td>
|
||
<td>LAN-wide DNS — nothing resolves until this is up</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 108 (Zoraxy / LE proxy)</td>
|
||
<td>✅</td>
|
||
<td><strong>order=2</strong></td>
|
||
<td>Public-facing reverse proxy + LE; depends on DNS</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 103 (Backrest)</td>
|
||
<td>✅</td>
|
||
<td>default</td>
|
||
<td>Holds backup config and snapshot metadata</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 104 (Docker / AI / image-gen)</td>
|
||
<td>✅</td>
|
||
<td>default</td>
|
||
<td>Largest data footprint (200 G rootfs); 65 containers</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 105 (Nextcloud)</td>
|
||
<td>✅</td>
|
||
<td>default</td>
|
||
<td>User data</td>
|
||
</tr>
|
||
<tr>
|
||
<td>VM 100 (HAOS)</td>
|
||
<td>✅</td>
|
||
<td>default</td>
|
||
<td>Home automation state</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 101 (shepard)</td>
|
||
<td>❌ (left optional)</td>
|
||
<td>default</td>
|
||
<td>Currently a dev/iteration target; protect once stabilized: <code>pct set 101 -protection 1</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>The <code>onboot: 1</code> flag was already set on all guests ✔ — they all auto-start on host reboot. The two <code>startup</code> ordered ones now also boot in the right sequence: DNS → Zoraxy → everything else in parallel.</p>
|
||
<p>To remove protection on a guest later: <code>pct set <id> -protection 0</code> (or <code>qm set 100 -protection 0</code>).</p>
|
||
<hr />
|
||
<h2 id="11a-dns-adguard-rewrites-site-wide-consistency">11a. DNS — AdGuard rewrites & site-wide consistency<a class="headerlink" href="#11a-dns-adguard-rewrites-site-wide-consistency" title="Permanent link">¶</a></h2>
|
||
<p><strong>Current state (measured):</strong></p>
|
||
<ul>
|
||
<li>AdGuard Home runs on CT 102 (<code>192.168.1.2</code>, hostname <code>dns</code>) — DNS on <code>0.0.0.0:53/tcp+udp</code>, admin UI on <code>:80</code>.</li>
|
||
<li>Upstream stack is well-configured: load-balanced mix of Telekom-DoT, NextDNS, DNS4EU, Quad9, Cloudflare, Google (DoH/DoQ where supported), bootstrap+fallback on Cloudflare.</li>
|
||
<li>All 6 LXCs resolve via <code>nameserver 192.168.1.2</code> ✔</li>
|
||
<li>Proxmox host (<code>192.168.1.20</code>) resolves via <code>192.168.1.2</code> ✔ — but its <code>search</code> domain is <code>box</code> (probably an install-time leftover; AdGuard's <code>local_domain_name</code> is <code>lan</code>).</li>
|
||
<li>HAOS VM is on <code>192.168.1.60</code> — DNS setting unknown without Home Assistant access; <strong>verify</strong>.</li>
|
||
<li><code>rewrites: []</code> and <strong><code>rewrites_enabled: false</code></strong> — no internal name resolution is happening today.</li>
|
||
</ul>
|
||
<h3 id="why-this-matters">Why this matters<a class="headerlink" href="#why-this-matters" title="Permanent link">¶</a></h3>
|
||
<p>Without rewrites, you address everything by IP. That's brittle (IP changes break links), invisible in logs, and prevents nice tricks like split-horizon DNS for <code>nuclide.systems</code> (so the same name resolves to Zoraxy LAN-internally without going through your public IP / WAN hairpin).</p>
|
||
<h3 id="recommended-rewrite-set">Recommended rewrite set<a class="headerlink" href="#recommended-rewrite-set" title="Permanent link">¶</a></h3>
|
||
<p>In AdGuard UI → Filters → DNS rewrites, <strong>enable rewrites</strong> and add:</p>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a># Split-horizon: public domain → Zoraxy on LAN
|
||
<a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a>nuclide.systems → 192.168.1.4
|
||
<a id="__codelineno-13-3" name="__codelineno-13-3" href="#__codelineno-13-3"></a>*.nuclide.systems → 192.168.1.4
|
||
<a id="__codelineno-13-4" name="__codelineno-13-4" href="#__codelineno-13-4"></a>
|
||
<a id="__codelineno-13-5" name="__codelineno-13-5" href="#__codelineno-13-5"></a># Service-name shortcuts under the local_domain_name (`.lan`)
|
||
<a id="__codelineno-13-6" name="__codelineno-13-6" href="#__codelineno-13-6"></a>pve.lan → 192.168.1.20 # Proxmox UI
|
||
<a id="__codelineno-13-7" name="__codelineno-13-7" href="#__codelineno-13-7"></a>nuc.lan → 192.168.1.20 # host shorthand
|
||
<a id="__codelineno-13-8" name="__codelineno-13-8" href="#__codelineno-13-8"></a>dns.lan → 192.168.1.2 # AdGuard itself
|
||
<a id="__codelineno-13-9" name="__codelineno-13-9" href="#__codelineno-13-9"></a>zoraxy.lan → 192.168.1.4 # reverse proxy
|
||
<a id="__codelineno-13-10" name="__codelineno-13-10" href="#__codelineno-13-10"></a>shepard.lan → 192.168.1.49 # CT 101
|
||
<a id="__codelineno-13-11" name="__codelineno-13-11" href="#__codelineno-13-11"></a>docker.lan → 192.168.1.40 # CT 104
|
||
<a id="__codelineno-13-12" name="__codelineno-13-12" href="#__codelineno-13-12"></a>nextcloud.lan → 192.168.1.41 # CT 105
|
||
<a id="__codelineno-13-13" name="__codelineno-13-13" href="#__codelineno-13-13"></a>haos.lan → 192.168.1.60 # VM 100
|
||
<a id="__codelineno-13-14" name="__codelineno-13-14" href="#__codelineno-13-14"></a>unas.lan → 192.168.1.31 # NAS
|
||
<a id="__codelineno-13-15" name="__codelineno-13-15" href="#__codelineno-13-15"></a>router.lan → 192.168.1.1 # UniFi gateway
|
||
</code></pre></div>
|
||
<p>The split-horizon entries are the highest-value: once Zoraxy proxies <code>pve.nuclide.systems</code> (see §11b), the same URL works both from the public internet and from inside the LAN — with no NAT-loopback weirdness and with the LAN traffic never leaving the building.</p>
|
||
<p><strong>Edit the YAML directly if preferred</strong> (<code>/opt/AdGuardHome/AdGuardHome.yaml</code> inside CT 102), then restart AdGuard. The line <code>rewrites_enabled: false</code> must flip to <code>true</code>.</p>
|
||
<h3 id="verify-clients-are-actually-using-adguard">Verify clients are actually using AdGuard<a class="headerlink" href="#verify-clients-are-actually-using-adguard" title="Permanent link">¶</a></h3>
|
||
<p>After rewrites are in, walk the inventory:</p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Client</th>
|
||
<th>Should use DNS</th>
|
||
<th>Check</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>All 6 LXCs</td>
|
||
<td>✔ already at .2</td>
|
||
<td><code>pct exec <id> -- cat /etc/resolv.conf</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Proxmox host</td>
|
||
<td>✔ already at .2</td>
|
||
<td><code>cat /etc/resolv.conf</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>HAOS VM (192.168.1.60)</td>
|
||
<td>unknown</td>
|
||
<td>HAOS UI → Settings → System → Network → check DNS servers; should be <code>192.168.1.2</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Router (192.168.1.1, UniFi)</td>
|
||
<td><strong>DHCP-hands-out DNS to clients</strong> — must serve .2 as primary</td>
|
||
<td>UniFi: Settings → Networks → LAN → DHCP DNS: <code>192.168.1.2</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>IoT devices (Roborock at .64, others)</td>
|
||
<td>inherit via DHCP from router</td>
|
||
<td>once UniFi DHCP serves .2, every device that DHCP-renews picks it up. Force-renew or reboot stragglers.</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Anything with hard-coded <code>1.1.1.1</code> / <code>8.8.8.8</code></td>
|
||
<td>bypassing the filter</td>
|
||
<td>grep service configs for upstream DNS — apps like Pi-hole-aware clients, some Smart TVs, Chromecasts</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="optional-hardening-once-the-rewrites-are-stable">Optional hardening once the rewrites are stable<a class="headerlink" href="#optional-hardening-once-the-rewrites-are-stable" title="Permanent link">¶</a></h3>
|
||
<ul>
|
||
<li><strong>DNSSEC</strong>: <code>enable_dnssec: true</code> (currently false). Most upstreams already validate, but flipping this on adds end-to-end checking.</li>
|
||
<li><strong>Block DoH bypass</strong>: AdGuard has a "Blocked services" preset for Cloudflare/Google DoH endpoints — useful so clients can't sidestep the filter.</li>
|
||
<li><strong>Resolve <code>box</code> search-domain confusion</strong>: edit <code>/etc/resolv.conf</code> (or set it via <code>/etc/network/interfaces</code>) on the host to <code>search lan</code> so it matches AdGuard's <code>local_domain_name</code>.</li>
|
||
<li><strong>Secondary DNS for resilience</strong>: CT 102 is currently the sole DNS — if it crashes, the LAN goes blind. Either add <code>protection: 1</code> (done above) and rely on it, or stand up a tiny secondary AdGuard on a different CT and configure UniFi DHCP to hand out both. (Out of scope for low-hanging fruit, but worth knowing.)</li>
|
||
<li><strong>Conditional forwarding for UNAS</strong>: if UNAS announces hostnames (mDNS or its own DNS), point AdGuard at it for the relevant zone via "Upstream DNS servers" using the <code>[/zone/]upstream</code> syntax.</li>
|
||
</ul>
|
||
<h3 id="action-checklist">Action checklist<a class="headerlink" href="#action-checklist" title="Permanent link">¶</a></h3>
|
||
<ol>
|
||
<li>AdGuard UI → Filters → DNS rewrites: paste the table above.</li>
|
||
<li>AdGuard UI → Settings → DNS settings → <strong>enable</strong> "DNS rewrites".</li>
|
||
<li>UniFi: confirm DHCP option 6 = <code>192.168.1.2</code> (LAN clients get AdGuard).</li>
|
||
<li>HAOS: confirm Home Assistant has <code>192.168.1.2</code> set as DNS.</li>
|
||
<li>Force-renew DHCP leases on key clients (or just wait — most renew within 24 h).</li>
|
||
<li>After §11b is done, the public <code>pve.nuclide.systems</code> resolves to <code>.4</code> from inside the LAN automatically.</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="11b-tls-certificates-for-the-proxmox-web-ui">11b. TLS certificates for the Proxmox web UI<a class="headerlink" href="#11b-tls-certificates-for-the-proxmox-web-ui" title="Permanent link">¶</a></h2>
|
||
<p><strong>Current state:</strong> the PVE web UI on <code>https://192.168.1.20:8006</code> uses the self-signed certificate generated at install (<code>/etc/pve/local/pveproxy-ssl.pem</code> is absent → falls back to <code>pve-ssl.pem</code>). Every login throws a browser warning.</p>
|
||
<p><strong>The wider setup:</strong> Zoraxy (CT 108, <code>192.168.1.4</code>) already handles Let's Encrypt for <code>nuclide.systems</code> (the public domain for this host). So there are three sane options; pick <strong>A</strong> unless you have a reason not to.</p>
|
||
<h3 id="option-a-reverse-proxy-pve-through-zoraxy-recommended">Option A — Reverse-proxy PVE through Zoraxy (recommended)<a class="headerlink" href="#option-a-reverse-proxy-pve-through-zoraxy-recommended" title="Permanent link">¶</a></h3>
|
||
<p>Pros: single source of LE truth (Zoraxy already renews); no DNS-plugin setup; no exposing the API; nice domain like <code>pve.nuclide.systems</code>. Cons: depends on Zoraxy being up (keep IP:8006 as fallback); needs WebSocket pass-through for the noVNC console and <code>xterm.js</code> shell.</p>
|
||
<ol>
|
||
<li><strong>Zoraxy host entry</strong></li>
|
||
<li>Domain: <code>pve.nuclide.systems</code> (or whatever subdomain)</li>
|
||
<li>Target: <code>https://192.168.1.20:8006</code></li>
|
||
<li><strong>Enable WebSocket support</strong> (mandatory — noVNC, xterm.js, task log streaming all use it)</li>
|
||
<li><strong>Skip backend TLS verification</strong> (PVE's cert is self-signed)</li>
|
||
<li>Enable HSTS once you've confirmed the setup works</li>
|
||
<li>Optionally restrict by source: only LAN + Cloudflare/Tailscale IPs</li>
|
||
<li><strong>DNS</strong>: add an A record <code>pve.nuclide.systems</code> → public IP (or split-horizon to <code>192.168.1.20</code> for LAN). Zoraxy will ACME-challenge via whichever method it's configured for (HTTP-01 or DNS-01).</li>
|
||
<li><strong>Keep <code>https://192.168.1.20:8006</code> reachable on LAN</strong> as an emergency fallback. Don't disable it.</li>
|
||
<li>Set the PVE redirect-to-HTTPS rules in Zoraxy on for both <code>:80</code> and <code>:443</code>.</li>
|
||
</ol>
|
||
<p><strong>Important caveat:</strong> the PVE Mobile app and the <code>pvesh</code> / API clients may not love going through a reverse proxy (they're picky about TLS SNI and cookie domains). Keep direct IP access available for API tooling, or test thoroughly.</p>
|
||
<h3 id="option-b-pves-built-in-acme-with-dns-01">Option B — PVE's built-in ACME with DNS-01<a class="headerlink" href="#option-b-pves-built-in-acme-with-dns-01" title="Permanent link">¶</a></h3>
|
||
<p>Pros: no reverse proxy in the path; PVE renews itself; works for the API too. Cons: requires a DNS provider plugin (your registrar's API token), and an LE-acceptable FQDN that resolves publicly.</p>
|
||
<ol>
|
||
<li>Register an ACME account:
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a>pvenode<span class="w"> </span>acme<span class="w"> </span>account<span class="w"> </span>register<span class="w"> </span>default<span class="w"> </span>you@nuclide.systems
|
||
</code></pre></div></li>
|
||
<li>Configure a DNS plugin. PVE supports <code>acme-dns</code>, <code>cloudflare</code>, <code>route53</code>, <code>desec</code>, etc. via the <code>acme.sh</code> plugin set. Example for Cloudflare:
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a>pvenode<span class="w"> </span>acme<span class="w"> </span>plugin<span class="w"> </span>add<span class="w"> </span>dns<span class="w"> </span>cf<span class="w"> </span>--api<span class="w"> </span>cf<span class="w"> </span>--data<span class="w"> </span><span class="nv">CF_Token</span><span class="o">=</span>XXXXXXXX
|
||
</code></pre></div>
|
||
Replace <code>cf</code> plugin name to match whichever registrar you use for <code>nuclide.systems</code>.</li>
|
||
<li>Tell the node which domain(s) and how:
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-16-1" name="__codelineno-16-1" href="#__codelineno-16-1"></a>pvenode<span class="w"> </span>config<span class="w"> </span><span class="nb">set</span><span class="w"> </span>--acme<span class="w"> </span><span class="nv">domains</span><span class="o">=</span>nuc.nuclide.systems
|
||
<a id="__codelineno-16-2" name="__codelineno-16-2" href="#__codelineno-16-2"></a>pvenode<span class="w"> </span>config<span class="w"> </span><span class="nb">set</span><span class="w"> </span>--acmedomain0<span class="w"> </span><span class="nv">domain</span><span class="o">=</span>nuc.nuclide.systems,plugin<span class="o">=</span>cf
|
||
</code></pre></div></li>
|
||
<li>Order:
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a>pvenode<span class="w"> </span>acme<span class="w"> </span>cert<span class="w"> </span>order
|
||
</code></pre></div>
|
||
PVE drops the cert at <code>/etc/pve/nodes/nuc/pveproxy-ssl.pem</code> and renews ~30 days before expiry via the <code>pve-daily-update</code> timer.</li>
|
||
</ol>
|
||
<h3 id="option-c-push-zoraxys-cert-into-pve">Option C — Push Zoraxy's cert into PVE<a class="headerlink" href="#option-c-push-zoraxys-cert-into-pve" title="Permanent link">¶</a></h3>
|
||
<p>Only useful if A and B are off the table. Zoraxy stores its issued certs (location varies by Zoraxy version — typically under its data dir, e.g. <code>/opt/zoraxy/conf/certs/</code>). Cron a script that copies the active cert/key and concatenates them as <code>/etc/pve/local/pveproxy-ssl.pem</code> (cert + chain) and <code>/etc/pve/local/pveproxy-ssl.key</code>, then <code>systemctl reload pveproxy</code>. Brittle — only worth it if you must.</p>
|
||
<h3 id="recommended-path">Recommended path<a class="headerlink" href="#recommended-path" title="Permanent link">¶</a></h3>
|
||
<p>Do <strong>A</strong> (reverse proxy through Zoraxy) for the web UI. It piggybacks on existing renewal. The mobile-app/API edge cases are usually fine if Zoraxy passes the WebSocket and preserves the <code>Host</code> header. If you later need full ACME on the node itself (e.g. you want valid TLS for <code>pvesh</code> and the API at the node FQDN too), layer <strong>B</strong> on top — they don't conflict.</p>
|
||
<h3 id="other-cts-with-web-uis-worth-fronting-via-zoraxy">Other CTs with web UIs worth fronting via Zoraxy<a class="headerlink" href="#other-cts-with-web-uis-worth-fronting-via-zoraxy" title="Permanent link">¶</a></h3>
|
||
<p>While you're at it, route through Zoraxy for free LE:
|
||
- Backrest (CT 103) — currently IP-only
|
||
- AdGuard (CT 102) admin UI — <code>192.168.1.2:3000</code>
|
||
- Nextcloud (CT 105) — almost certainly already exposed; verify it terminates LE in Zoraxy and not internally
|
||
- Zoraxy itself (CT 108) — self-hosted, already TLS</p>
|
||
<p>For each, add a Zoraxy host entry, set a subdomain, and disable any local TLS / port-exposed listener that bypasses Zoraxy.</p>
|
||
<hr />
|
||
<h2 id="11-maintenance-observability">11. Maintenance / observability<a class="headerlink" href="#11-maintenance-observability" title="Permanent link">¶</a></h2>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Item</th>
|
||
<th>State</th>
|
||
<th>Recommend</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>lm-sensors</code></td>
|
||
<td>not installed</td>
|
||
<td><code>apt install lm-sensors && sensors-detect --auto</code> for CPU/NVMe temps in the UI</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Journal size</td>
|
||
<td>1.5 GiB</td>
|
||
<td>OK; cap at 1 GiB if you want predictability: <code>journalctl --vacuum-size=1G</code> and <code>SystemMaxUse=1G</code> in <code>journald.conf</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>fstrim.timer</code></td>
|
||
<td>active (weekly)</td>
|
||
<td>OK; <code>zfs trim</code> runs separately when autotrim=on</td>
|
||
</tr>
|
||
<tr>
|
||
<td>ZFS scrub</td>
|
||
<td>last run 2026-05-10, clean</td>
|
||
<td>default monthly timer is good</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Subscription nag</td>
|
||
<td>not removed</td>
|
||
<td>If desired, <code>pve-no-nag</code> patch or the <code>proxmox-helper-scripts</code> line — purely cosmetic</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Email alerts</td>
|
||
<td>(check <code>/etc/pve/user.cfg</code>)</td>
|
||
<td>configure <code>root@pam</code> email for failed scrub / failed backup notifications</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<hr />
|
||
<h2 id="13-update-management-current-model">13. Update management — current model<a class="headerlink" href="#13-update-management-current-model" title="Permanent link">¶</a></h2>
|
||
<p>The host previously had <code>0 2 * * * apt-get update && apt-get upgrade -y</code> (silently no-op'd on every PVE/kernel update) and a weekly <code>bash <(wget tteck/.../update-lxcs-cron.sh)</code> cron that ran <code>dist-upgrade</code> across every LXC. Both removed 2026-05-20 and replaced with the structure below.</p>
|
||
<h3 id="layer-1-host-packages-debian-proxmox">Layer 1 — Host packages (Debian + Proxmox)<a class="headerlink" href="#layer-1-host-packages-debian-proxmox" title="Permanent link">¶</a></h3>
|
||
<ul>
|
||
<li><code>unattended-upgrades 2.12</code> installed on the host.</li>
|
||
<li><code>/etc/apt/apt.conf.d/52unattended-upgrades-pve</code> allows only <code>Debian</code>, <code>Debian-Security</code>, <code>trixie-updates</code> — <strong>Proxmox origin held</strong> for manual review.</li>
|
||
<li>Triggered by <code>apt-daily.timer</code> and <code>apt-daily-upgrade.timer</code> (ship with <code>apt</code>, both <code>active enabled</code>).</li>
|
||
<li><code>Automatic-Reboot "false"</code> — kernel updates wait for a manual reboot.</li>
|
||
<li><code>Mail "notify@home.box"</code>, <code>MailReport "on-change"</code> — Postfix is up but <strong><code>relayhost = (none)</code></strong>, so mail is delivered locally to <code>/var/mail/notify</code> (not your inbox until you wire a smart-host).</li>
|
||
</ul>
|
||
<h3 id="layer-2-ct-os-packages-debian">Layer 2 — CT OS packages (Debian)<a class="headerlink" href="#layer-2-ct-os-packages-debian" title="Permanent link">¶</a></h3>
|
||
<p><code>unattended-upgrades</code> deployed inside every CT (CT 104 already had it; 101/102/103/105/108/110 added 2026-05-20):</p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>CT</th>
|
||
<th>u-u version</th>
|
||
<th>Distro</th>
|
||
<th>Status</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>101</td>
|
||
<td>2.12</td>
|
||
<td>trixie</td>
|
||
<td>active</td>
|
||
</tr>
|
||
<tr>
|
||
<td>102</td>
|
||
<td>2.9.1</td>
|
||
<td>bookworm</td>
|
||
<td>active</td>
|
||
</tr>
|
||
<tr>
|
||
<td>103</td>
|
||
<td>2.9.1</td>
|
||
<td>bookworm</td>
|
||
<td>active</td>
|
||
</tr>
|
||
<tr>
|
||
<td>104</td>
|
||
<td>2.12</td>
|
||
<td>trixie</td>
|
||
<td>active</td>
|
||
</tr>
|
||
<tr>
|
||
<td>105</td>
|
||
<td>2.9.1</td>
|
||
<td>bookworm</td>
|
||
<td>active</td>
|
||
</tr>
|
||
<tr>
|
||
<td>108</td>
|
||
<td>2.12</td>
|
||
<td>trixie</td>
|
||
<td>active</td>
|
||
</tr>
|
||
<tr>
|
||
<td>110</td>
|
||
<td>2.12</td>
|
||
<td>trixie</td>
|
||
<td>active</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Per-CT allowlist is Debian-only — third-party repos (<code>docker.com</code>, <code>jotta.cloud</code>, <code>claude.ai</code>, <code>cli.github.com</code>, <code>dl.k6.io</code>) are <strong>excluded</strong> because they ship breaking changes outside Debian's freeze. Upgrade those with explicit <code>apt upgrade <pkg></code>.</p>
|
||
<h3 id="layer-3-helper-script-app-binaries-adguard-zoraxy">Layer 3 — Helper-script app binaries (AdGuard, Zoraxy)<a class="headerlink" href="#layer-3-helper-script-app-binaries-adguard-zoraxy" title="Permanent link">¶</a></h3>
|
||
<p>Each helper-scripts CT ships <code>/usr/bin/update</code> that re-<code>curl|bash</code>'s the community-scripts installer. Replaced with proper systemd timers using the apps' own update mechanisms:</p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>CT</th>
|
||
<th>Timer</th>
|
||
<th>Schedule</th>
|
||
<th>Mechanism</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>102 AdGuard</td>
|
||
<td><code>adguard-update.timer</code></td>
|
||
<td>Wed 03:30 (+15 m jitter)</td>
|
||
<td>native <code>AdGuardHome --update</code> flag</td>
|
||
</tr>
|
||
<tr>
|
||
<td>108 Zoraxy</td>
|
||
<td><code>zoraxy-update.timer</code></td>
|
||
<td>Wed 03:40 (+15 m jitter)</td>
|
||
<td>GitHub releases API, <strong>stable semver only (skips RCs)</strong>, binary swap + 30 s health check + auto-rollback</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Both log to <code>/var/log/{adguard,zoraxy}-update.log</code> and journal. Manual invoke: <code>systemctl start <name>-update.service</code>.</p>
|
||
<h3 id="layer-4-docker-engine-inside-cts">Layer 4 — Docker engine inside CTs<a class="headerlink" href="#layer-4-docker-engine-inside-cts" title="Permanent link">¶</a></h3>
|
||
<p><code>docker-ce</code> updates in CT 101, 104, 105, 110 — held by the Debian-only allowlist. Apply with <code>apt upgrade docker-ce docker-ce-cli containerd.io</code> when you want them. Add <code>origin=Docker</code> to the allowlist if you want to auto-apply (not recommended; engine updates occasionally break running containers).</p>
|
||
<h3 id="layer-5-docker-images-the-75-containers">Layer 5 — Docker images (the ~75 containers)<a class="headerlink" href="#layer-5-docker-images-the-75-containers" title="Permanent link">¶</a></h3>
|
||
<p><strong>Plan: deploy Diun on CT 109</strong> (ops LXC, see §16). Diun watches image tags on registries, posts to Gotify when a new image is available. Pulls remain manual (<code>docker compose pull && up -d</code>) — protects against latest-tag drift like the n8n incident pinned in <code>/opt/stacks/n8n/docker-compose.yaml</code>.</p>
|
||
<p><strong>Layer 6 — Nextcloud-AIO</strong>: self-updates via the mastercontainer (CT 105). No external mechanism needed.</p>
|
||
<hr />
|
||
<h2 id="14-vm-100-haos-auto-restart-watchdog">14. VM 100 (HAOS) auto-restart watchdog<a class="headerlink" href="#14-vm-100-haos-auto-restart-watchdog" title="Permanent link">¶</a></h2>
|
||
<p>Old approach: <code>*/5 * * * * /root/vm100.sh > /dev/null</code> in cron. Script archived to <code>/root/vm100.sh.bak</code> on 2026-05-20.</p>
|
||
<p>Replaced with a systemd timer + oneshot:</p>
|
||
<ul>
|
||
<li><code>/usr/local/sbin/vm100-watchdog.sh</code> — only restarts on <code>status: stopped</code>; skips paused/prelaunch/transitional states; respects <code>/var/lock/qemu-server/lock-100.conf</code> so it doesn't race vzdump or migration</li>
|
||
<li><code>vm100-watchdog.service</code> (Type=oneshot)</li>
|
||
<li><code>vm100-watchdog.timer</code> (<code>OnUnitActiveSec=1min</code>, RandomizedDelaySec=15s)</li>
|
||
</ul>
|
||
<p>Recovery latency improved from 5 min → 1 min; logging structured in <code>journalctl -u vm100-watchdog</code>.</p>
|
||
<hr />
|
||
<h2 id="15-identity-pocket-id-on-its-own-ct">15. Identity — Pocket-ID on its own CT<a class="headerlink" href="#15-identity-pocket-id-on-its-own-ct" title="Permanent link">¶</a></h2>
|
||
<h3 id="state-as-of-2026-05-20">State as of 2026-05-20<a class="headerlink" href="#state-as-of-2026-05-20" title="Permanent link">¶</a></h3>
|
||
<p><strong>CT 110 "id"</strong> created at <code>192.168.1.5</code> as the dedicated IdP host. Pocket-ID was previously on CT 104 as one of ~65 docker containers; moved off because:</p>
|
||
<ul>
|
||
<li>Pocket-ID gates auth for everything else; sharing a host with image-gen workloads (9 GiB swap pressure on CT 104) means a single OOM/restart there knocks out SSO across the whole estate</li>
|
||
<li>Pattern match with CT 102 (DNS) and CT 108 (reverse proxy) — each infra-critical concern gets its own CT</li>
|
||
</ul>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>CT 110 setting</th>
|
||
<th>Value</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Hostname / IP</td>
|
||
<td><code>id</code> / <code>192.168.1.5</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Cores / RAM / rootfs</td>
|
||
<td>1 / 1 GB / 4 GB</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Privilege</td>
|
||
<td>unprivileged, nesting=1, keyctl=1</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Boot order</td>
|
||
<td><code>onboot=1</code>, <code>startup=order=3</code> (after DNS=1, Zoraxy=2)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Protection</td>
|
||
<td><code>protection: 1</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Auto-updates</td>
|
||
<td>unattended-upgrades, Debian-only allowlist</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Docker</td>
|
||
<td>29.5.1 + compose v5.1.3</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="duplication-procedure-used">Duplication procedure used<a class="headerlink" href="#duplication-procedure-used" title="Permanent link">¶</a></h3>
|
||
<ol>
|
||
<li><code>sqlite3 pocket-id.db ".backup /tmp/pi-snap/pocket-id.db"</code> on CT 104 (online, no downtime to id.nuclide.systems)</li>
|
||
<li>tar everything except <code>*.db*</code>; restore the live snapshot as <code>pocket-id.db</code></li>
|
||
<li><code>pct pull</code> → <code>pct push</code> to CT 110</li>
|
||
<li>Adapted compose to drop the <code>shared_backend</code> external network reference (CT 110 uses default bridge)</li>
|
||
<li><code>docker compose up -d</code></li>
|
||
<li>Verified <code>http://192.168.1.5:11000/healthz</code> returns 200</li>
|
||
</ol>
|
||
<h3 id="zoraxy-cutover">Zoraxy cutover<a class="headerlink" href="#zoraxy-cutover" title="Permanent link">¶</a></h3>
|
||
<p><code>id.nuclide.systems</code> upstream needs to change from <code>192.168.1.40:11000</code> → <code>192.168.1.5:11000</code>. Single-line config edit in Zoraxy + reload. Verified live in §11b once executed.</p>
|
||
<h3 id="secrets-rotation-list-deferred-to-cutover-day">Secrets-rotation list (deferred to cutover day)<a class="headerlink" href="#secrets-rotation-list-deferred-to-cutover-day" title="Permanent link">¶</a></h3>
|
||
<ul>
|
||
<li><code>OIDC_CLIENT_SECRET</code> for the Arcane registration (exposed in chat transcript): rotate in Pocket-ID UI, update Arcane env, restart Arcane</li>
|
||
<li><code>ENCRYPTION_KEY</code> and <code>JWT_SECRET</code> in <code>/opt/stacks/arcane/docker-compose.yml</code>: move to <code>.env</code> (currently empty), regenerate, restart Arcane. Existing user sessions get invalidated — fine, ask everyone to log in again</li>
|
||
</ul>
|
||
<hr />
|
||
<h2 id="16-ct-109-ops-planned-observability-ops-lxc">16. CT 109 "ops" — planned observability + ops LXC<a class="headerlink" href="#16-ct-109-ops-planned-observability-ops-lxc" title="Permanent link">¶</a></h2>
|
||
<p>Single LXC holding everything monitoring/ops-shaped. Sizing target: <strong>4 cores / 8 GiB RAM / 50 GiB rootfs</strong>, unprivileged, nesting=1. RAM bumped from 6 → 8 GiB to accommodate Loki. Disk bumped from 30 → 50 GiB for Loki log retention (30d) alongside Prometheus TSDB.</p>
|
||
<p>⚠️ <strong>IP conflict:</strong> inventory originally assigned <code>192.168.1.6</code> but CT 113 (db) took <code>.6</code> and CT 112 (secrets) took <code>.7</code>. CT 109 needs the next free infra IP — likely <code>.8</code> (verify against UniFi DHCP table before provisioning).</p>
|
||
<p><strong>Access model (initial):</strong> LAN-only. No Zoraxy routes until Tinyauth is deployed. Services reachable directly by IP.</p>
|
||
<h3 id="stack-to-deploy-on-ct-109">Stack to deploy on CT 109<a class="headerlink" href="#stack-to-deploy-on-ct-109" title="Permanent link">¶</a></h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Service</th>
|
||
<th>Purpose</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Prometheus</td>
|
||
<td>metrics TSDB, 30d retention</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Loki</td>
|
||
<td>log aggregation backend — receives from Alloy agents on all hosts</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Grafana</td>
|
||
<td>dashboards over Prometheus + Loki (unified metrics + log search)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Alertmanager + alertmanager-gotify-bridge</td>
|
||
<td>alert routing → Gotify</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Arcane Manager</td>
|
||
<td>central docker management UI; edge agents on CT 101 + CT 104 + CT 110 (mTLS, agent-dialed-out)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Dozzle UI</td>
|
||
<td>live log tail (quick debugging); agents on CT 101 + CT 104 + CT 110. Complements Loki — Dozzle for live, Loki for historical/search</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>Homarr</strong></td>
|
||
<td>unified dashboard, native Pocket-ID OIDC, Prometheus widget + Grafana iframe support</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Diun</td>
|
||
<td>docker image update notifier → Gotify</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Tinyauth</td>
|
||
<td>forward-auth gate for non-OIDC apps (Backrest, raw Dozzle, raw Prometheus, raw Grafana/Loki). OIDC client to Pocket-ID</td>
|
||
</tr>
|
||
<tr>
|
||
<td>docker-socket-proxy</td>
|
||
<td>local + remote (CT 101/104/110) — hardened read-only docker.sock for Homarr/Arcane discovery</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>sshwifty</strong></td>
|
||
<td>web SSH client, multi-tab — multiple concurrent shells to different hosts (PVE, CT 104, CT 103, CT 111, etc.). LAN-only, port 8182. SSH key auth per host, no password prompt. Zoraxy + Tinyauth gate deferred.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>docs-server</strong></td>
|
||
<td>mkdocs Material site (<code>/docs</code> git repo → static HTML); migrating here from CT 111 where it currently runs at port 13080. LAN-only, no Zoraxy route.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="sidecars-deployed-on-each-host">Sidecars deployed on each host<a class="headerlink" href="#sidecars-deployed-on-each-host" title="Permanent link">¶</a></h3>
|
||
<p>Two agents per host — <strong>node-exporter</strong> (metrics) and <strong>Alloy</strong> (logs). Kept separate: node-exporter metric names are assumed by every Prometheus dashboard/alert; Alloy emitting compatible metrics adds validation risk for no gain.</p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Host</th>
|
||
<th>Sidecars</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>PVE host</td>
|
||
<td>node-exporter, smartctl-exporter, pve-exporter, <strong>Alloy</strong> (journald → Loki: pve-manager, pveproxy, pvedaemon, LXC/VM lifecycle)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 101</td>
|
||
<td>node-exporter, cAdvisor, Dozzle agent, Arcane edge agent, docker-socket-proxy, <strong>Alloy</strong> (Docker logs + journald → Loki)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 103</td>
|
||
<td>node-exporter, <strong>Alloy</strong> (backrest.service journal + <code>/var/log/rclone-*.log</code> → Loki)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 104</td>
|
||
<td>node-exporter, cAdvisor, Dozzle agent, Arcane edge agent, docker-socket-proxy, intel_gpu_exporter, <strong>Alloy</strong> (Docker logs + journald → Loki)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 110</td>
|
||
<td>node-exporter, Dozzle agent, Arcane edge agent, <strong>Alloy</strong> (journald → Loki)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 111</td>
|
||
<td>node-exporter, intel_gpu_exporter, <strong>Alloy</strong> (journald + Coder/Gitea logs → Loki)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>CT 113</td>
|
||
<td>node-exporter, postgres_exporter, <strong>Alloy</strong> (journald + postgres logs → Loki)</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="services-that-stay-where-they-are-not-on-ct-109">Services that stay where they are (NOT on CT 109)<a class="headerlink" href="#services-that-stay-where-they-are-not-on-ct-109" title="Permanent link">¶</a></h3>
|
||
<ul>
|
||
<li>AdGuard (CT 102), Zoraxy (CT 108), Backrest (CT 103), Pocket-ID (CT 110) — each has its own CT for blast-radius reasons</li>
|
||
<li>All app stacks (Immich, Nextcloud, Shepard, n8n, ComfyUI, etc.)</li>
|
||
</ul>
|
||
<h3 id="migration-of-gotify-tier-b-schedule-when-ct-109-is-otherwise-stable">Migration of Gotify (Tier B — schedule when CT 109 is otherwise stable)<a class="headerlink" href="#migration-of-gotify-tier-b-schedule-when-ct-109-is-otherwise-stable" title="Permanent link">¶</a></h3>
|
||
<p>Gotify currently runs in CT 104 docker stack at <code>gotify.nuclide.systems</code>. Moving to CT 109 isolates alerting from CT 104 outages but means updating env vars / webhook targets in ~10 places (MCP servers, Backrest webhooks). Plan: copy DB and app tokens via volume tar, deploy on CT 109, update Zoraxy upstream, then sweep dependents.</p>
|
||
<h3 id="migration-of-mcp-gateway-tier-b-split-control-workload">Migration of MCP Gateway (Tier B — split control / workload)<a class="headerlink" href="#migration-of-mcp-gateway-tier-b-split-control-workload" title="Permanent link">¶</a></h3>
|
||
<p><code>/opt/stacks/ai/mcp-gateway/</code> on CT 104 is the OIDC-gated control plane for the ~20 MCP child containers. Decision (2026-05-20): move <strong>only the gateway</strong> to CT 109; <strong>the child MCP containers stay on CT 104</strong> (they're workload, not control plane).</p>
|
||
<p>Mechanics:
|
||
- Gateway on CT 109 uses <code>DOCKER_HOST=tcp://<CT 104 socket-proxy>:2375</code> (the docker-socket-proxy already planned for CT 104) instead of the bind-mounted <code>/var/run/docker.sock</code>. socket-proxy ACL must allow <code>containers, exec, images</code> (read+write).
|
||
- Migrate state files via volume tar: <code>config.json</code>, <code>agents.json</code>, <code>prompts/</code>, <code>usage.db</code>, <code>gateway_tokens.json</code>, <code>nc_user_creds.json</code>. Keep them on CT 109 local zfs, not UNAS (per-request latency matters).
|
||
- Pocket-ID redirect URI stays <code>https://mcp.nuclide.systems/sso/callback</code> — only Zoraxy's upstream flips from <code>192.168.1.40:8080</code> to the CT 109 IP.
|
||
- Don't touch the children; gateway still spawns them by name against CT 104's daemon.</p>
|
||
<p>Build-order slot: after Arcane + socket-proxy land in §16's checklist, before Tinyauth.</p>
|
||
<h3 id="arcane-specifics">Arcane specifics<a class="headerlink" href="#arcane-specifics" title="Permanent link">¶</a></h3>
|
||
<ul>
|
||
<li>Existing <code>/opt/stacks/arcane/</code> on CT 104 has the Manager 80 % built: 41 MB SQLite DB carrying Pocket-ID OIDC client + admin user <code>fkrebs@nucli.de</code></li>
|
||
<li>Container currently stopped (~since May 19)</li>
|
||
<li><strong>Edge mode</strong> chosen for agents — agent dials out to Manager over HTTPS/gRPC with mTLS. Manager auto-generates the edge CA on first start; each agent enrolls with a token and gets a 1 yr client cert with auto-renewal</li>
|
||
<li>Same <code>ghcr.io/getarcaneapp/arcane:latest</code> image for Manager and agents; mode is env-driven (<code>ARCANE_EDGE_AGENT=true</code> on agents)</li>
|
||
<li>Intel iGPU is not in Arcane's GPU monitoring catalog (NVIDIA + AMD only). LXC-level passthrough to CT 104 stays untouched; only Arcane's GPU widgets will be blank for the Arc</li>
|
||
</ul>
|
||
<h3 id="build-order">Build order<a class="headerlink" href="#build-order" title="Permanent link">¶</a></h3>
|
||
<ol>
|
||
<li>Create CT 109 (specs above)</li>
|
||
<li>Deploy node-exporter on host + Prometheus + Grafana first (start collecting baselines)</li>
|
||
<li>Deploy Arcane Manager with the existing DB restored from CT 104</li>
|
||
<li>Issue agent tokens, deploy Edge agents on CT 101/104/110</li>
|
||
<li>Deploy Dozzle Manager + agents</li>
|
||
<li>Deploy Diun</li>
|
||
<li>Deploy sshwifty (configure host list + SSH keys for PVE, CT 103, CT 104, CT 111; LAN-only port 8182)</li>
|
||
<li>Deploy Tinyauth (configure Pocket-ID client first)</li>
|
||
<li>Deploy Homarr</li>
|
||
<li>Front the lot via Zoraxy: <code>arcane.</code>, <code>dozzle.</code>, <code>grafana.</code>, <code>prom.</code>, <code>home.</code>, <code>shell.</code> <code>.nuclide.systems</code></li>
|
||
<li>Verify each through the Tinyauth gate where applicable</li>
|
||
<li>Add Diun watchlist + Alertmanager routing → Gotify</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="17-lldp-unifi-topology-visibility">17. LLDP / UniFi topology visibility<a class="headerlink" href="#17-lldp-unifi-topology-visibility" title="Permanent link">¶</a></h2>
|
||
<p>Investigated 2026-05-20:</p>
|
||
<ul>
|
||
<li><code>lldpd</code> is <strong>installed and active</strong> on the host (defaults: advertises + listens)</li>
|
||
<li>Existing <code>/usr/local/bin/update_interface_desc.sh</code> hourly cron consumes LLDP from neighbors and writes <code># PortDescr:</code> comments into <code>/etc/network/interfaces</code></li>
|
||
<li>Host is on switch <strong>port 10</strong> of the D-Link DGS-1210-28P (<code>SysName: dgs1210</code>, FW <code>6.32.008</code>).</li>
|
||
<li><code>/usr/local/bin/update_interface_desc.sh</code> was silently failing — <code>lldpcli</code> not in cron's PATH <strong>and</strong> the original logic only appended new lines, never replaced stale ones. Rewritten 2026-05-20:</li>
|
||
<li>PATH set inside the script (<code>/usr/sbin</code> included)</li>
|
||
<li>Uses <code>lldpcli show neighbors -f keyvalue</code> for machine-readable parsing</li>
|
||
<li>Single <code># LLDP: <chassis> :: <port-descr></code> line per interface; legacy <code># PortDescr:</code> lines stripped</li>
|
||
<li>Idempotent (second run = no-op, no backup churn)</li>
|
||
<li>Daily-keyed backup <code>/etc/network/interfaces.bak.YYYYMMDD</code></li>
|
||
<li>Only logs on actual change</li>
|
||
<li>Old script preserved at <code>/usr/local/bin/update_interface_desc.sh.bak-2026-05-20</code></li>
|
||
</ul>
|
||
<p><strong>The UDM Pro won't see "nuc" in its topology view</strong> because LLDP frames use the Nearest-Bridge multicast (<code>01:80:c2:00:00:0e</code>) which any 802.1D-compliant switch terminates by spec — and the D-Link DGS-1210-28P sits between the host and the UDM. LLDP-MED is <strong>not</strong> a fix for this; it's for endpoint (VoIP/MFP) discovery, not transparent LLDP forwarding.</p>
|
||
<p>Remediation paths in order of effort:</p>
|
||
<ol>
|
||
<li><strong>Enable SNMP v2c/v3 on the DGS-1210</strong> + add as a Generic SNMP device in UniFi → UDM sees the switch and can map port↔MAC. Most practical for this stack.</li>
|
||
<li><strong>Add <code>snmpd</code> to the host</strong> + generic SNMP device in UniFi → CPU/mem/iface stats from Proxmox visible in UniFi (not in topology, but in monitoring).</li>
|
||
<li><strong>UniFi-managed switch between host and UDM</strong> — clean answer; requires hardware.</li>
|
||
</ol>
|
||
<p>D-Link DGS-1210 admin UI lives at <code>http://192.168.1.10/</code>. Verify the admin password is non-default — DGS-1210 ships with <code>admin</code>/blank or <code>admin</code>/<code>admin</code> on most firmware revisions. A flat-LAN switch with default creds is one of the easier vectors. <em>(Credentials redacted from this doc — check your password manager.)</em></p>
|
||
<p>Useful inspection from the host any time: <code>lldpcli show neighbors</code>.</p>
|
||
<hr />
|
||
<h2 id="18a-unas-access-uid-consistency-model-post-nfsv4-investigation">18a. UNAS access — UID consistency model (post-NFSv4 investigation)<a class="headerlink" href="#18a-unas-access-uid-consistency-model-post-nfsv4-investigation" title="Permanent link">¶</a></h2>
|
||
<p><strong>Investigation result (2026-05-20):</strong> UNAS Pro advertises NFSv4 in <code>rpcinfo</code> but has no v4 export tree configured. Every v4 mount attempt returns <code>No such file or directory</code>. Ubiquiti has <strong>not</strong> announced NFSv4 support and the <a href="https://community.ui.com/questions/When-will-NFSv4-be-available-for-UNAS-Pro/b8f8b00b-c5ac-4e19-adc4-9e5cae06d35f">community thread asking for it</a> has no ETA. The official help center also confirms: <em>"UniFi Drive does not support certain NFS export options, such as <code>no_root_squash</code>"</em>. So root_squash + v3-only is the long-term reality.</p>
|
||
<h3 id="universal-uid-landscape-on-unas">Universal UID landscape on UNAS<a class="headerlink" href="#universal-uid-landscape-on-unas" title="Permanent link">¶</a></h3>
|
||
<p>Every NFS client write lands as <strong>uid 977 / gid 988</strong> (UNAS's <code>all_squash</code> + <code>anon_uid=977</code>/<code>anon_gid=988</code>). The chown probe confirmed no client can change this from the host side. Files written via the legacy CIFS mount appear as <strong>uid 33</strong> to the CIFS client <em>but</em> are stored differently on UNAS — the CIFS <code>forceuid=33</code> mount option lies about ownership client-side.</p>
|
||
<h3 id="per-ct-access-pattern-canonical">Per-CT access pattern (canonical)<a class="headerlink" href="#per-ct-access-pattern-canonical" title="Permanent link">¶</a></h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>CT</th>
|
||
<th>Mount</th>
|
||
<th>Container uid</th>
|
||
<th>Effective on disk</th>
|
||
<th>Status</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>103 backrest</td>
|
||
<td>NFS bind from host</td>
|
||
<td>root</td>
|
||
<td>squashes to 977</td>
|
||
<td>✓ consistent</td>
|
||
</tr>
|
||
<tr>
|
||
<td>104 docker</td>
|
||
<td>NFS bind from host</td>
|
||
<td>mostly root, n8n=1000 (latent)</td>
|
||
<td>squashes to 977</td>
|
||
<td>✓ for root containers; n8n latent if it ever writes to UNAS</td>
|
||
</tr>
|
||
<tr>
|
||
<td>105 nextcloud</td>
|
||
<td>CIFS today (forceuid=33) → <strong>NFS + bindfs</strong> target</td>
|
||
<td>uid 33 (www-data) inside Nextcloud, bindfs translates to 977 on disk</td>
|
||
<td>needs migration</td>
|
||
<td>🚨 still CIFS</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="convention-for-new-containers">Convention for new containers<a class="headerlink" href="#convention-for-new-containers" title="Permanent link">¶</a></h3>
|
||
<p>Set <code>PUID=977 PGID=988</code> on any container that writes to UNAS. This pre-aligns with UNAS's enforced mapping and avoids latent permission issues (the n8n class). For images that don't support PUID/PGID, run them as root inside the container — root squashes to 977 cleanly.</p>
|
||
<h3 id="why-bindfs-for-ct-105-specifically">Why bindfs for CT 105 specifically<a class="headerlink" href="#why-bindfs-for-ct-105-specifically" title="Permanent link">¶</a></h3>
|
||
<p>Nextcloud's PHP code hard-checks file ownership against <code>www-data</code> (uid 33). Without remap, NFS reads return uid 977 and Nextcloud refuses to operate normally. CIFS hides this with <code>forceuid=33</code>. NFS+bindfs achieves the same lie with the much faster NFS rail underneath — verified ~5× speed-up on metadata-heavy ops in the non-destructive test on 2026-05-20.</p>
|
||
<h3 id="trigger-event-to-revisit">Trigger event to revisit<a class="headerlink" href="#trigger-event-to-revisit" title="Permanent link">¶</a></h3>
|
||
<p>Watch <a href="https://community.ui.com/RELEASES">community.ui.com/RELEASES</a> for a UniFi Drive release that adds:
|
||
- NFSv4 export option (would enable idmap)
|
||
- <code>no_root_squash</code> support (would enable server-side chown to specific uids)
|
||
- Configurable <code>anonuid</code>/<code>anongid</code> (would let us match a real uid)</p>
|
||
<p>Any of these would let us simplify the CT 105 stack.</p>
|
||
<hr />
|
||
<h2 id="18-homarr-inventory-services-to-include-on-the-dashboard">18. Homarr inventory — services to include on the dashboard<a class="headerlink" href="#18-homarr-inventory-services-to-include-on-the-dashboard" title="Permanent link">¶</a></h2>
|
||
<p>Captured here so the eventual Homarr config can be assembled in one pass. Groups follow the existing <code>homepage.*</code> label convention used in compose files.</p>
|
||
<h3 id="group-infrastructure">Group: <code>infrastructure</code><a class="headerlink" href="#group-infrastructure" title="Permanent link">¶</a></h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Service</th>
|
||
<th>URL</th>
|
||
<th>Notes</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Proxmox UI</td>
|
||
<td><code>https://192.168.1.20:8006</code></td>
|
||
<td>until LE via Zoraxy lands, see §11b</td>
|
||
</tr>
|
||
<tr>
|
||
<td>AdGuard Home (CT 102)</td>
|
||
<td><code>http://192.168.1.2/</code> (UI on <code>:80</code>)</td>
|
||
<td>DNS + admin</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Zoraxy (CT 108)</td>
|
||
<td><code>http://192.168.1.4:8000/</code></td>
|
||
<td>reverse proxy admin</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Backrest (CT 103)</td>
|
||
<td><code>http://192.168.1.3:9898/</code></td>
|
||
<td>backup orchestration, will be fronted via Tinyauth + Zoraxy</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>Pocket-ID (CT 110)</strong></td>
|
||
<td><code>https://id.nuclide.systems/</code></td>
|
||
<td>new home, 2026-05-20</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="group-network">Group: <code>network</code><a class="headerlink" href="#group-network" title="Permanent link">¶</a></h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Service</th>
|
||
<th>URL</th>
|
||
<th>Notes</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>UDM Pro</td>
|
||
<td><code>https://192.168.1.1/</code></td>
|
||
<td>UniFi controller</td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>D-Link DGS-1210-28P</strong></td>
|
||
<td><code>http://192.168.1.10/</code></td>
|
||
<td>core L2 switch; host on port 10</td>
|
||
</tr>
|
||
<tr>
|
||
<td>UNAS Pro</td>
|
||
<td><code>https://192.168.1.31/</code></td>
|
||
<td>UniFi NAS</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="group-ops-to-populate-when-ct-109-lands">Group: <code>ops</code> (to populate when CT 109 lands)<a class="headerlink" href="#group-ops-to-populate-when-ct-109-lands" title="Permanent link">¶</a></h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Service</th>
|
||
<th>URL</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Grafana</td>
|
||
<td><code>https://grafana.nuclide.systems</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Arcane</td>
|
||
<td><code>https://arcane.nuclide.systems</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Dozzle</td>
|
||
<td><code>https://dozzle.nuclide.systems</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Prometheus</td>
|
||
<td><code>https://prom.nuclide.systems</code> (gated by Tinyauth)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Alertmanager</td>
|
||
<td><code>https://alerts.nuclide.systems</code> (gated by Tinyauth)</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="group-apps-subset-long-list-fill-from-existing-homepage-labels-in-optstacks">Group: <code>apps</code> (subset — long list, fill from existing <code>homepage.*</code> labels in <code>/opt/stacks/*/</code>)<a class="headerlink" href="#group-apps-subset-long-list-fill-from-existing-homepage-labels-in-optstacks" title="Permanent link">¶</a></h3>
|
||
<p>Immich, Nextcloud, Vaultwarden, Karakeep, Memos, Paperless-ngx, n8n, ComfyUI, LobeChat, LiteLLM, Traccar, Gotify, Speaches, Daytona, Searxng, Kroki, etc. Pull display labels and icons from the existing <code>homepage.name=</code> / <code>homepage.icon=</code> values per compose.</p>
|
||
<hr />
|
||
<h2 id="12-suggested-action-order">12. Suggested action order<a class="headerlink" href="#12-suggested-action-order" title="Permanent link">¶</a></h2>
|
||
<ol>
|
||
<li><strong>Done 2026-05-20</strong> ✅:</li>
|
||
<li><strong>Memory / sizing</strong>: CT 101 160 → 32 GiB; CT 102 512 MiB → 1 GiB; HAOS balloon = 4 GiB</li>
|
||
<li><strong>Protection</strong>: CT 102 startup=1+protection; CT 108 startup=2+protection; CT 103/104/105/110/VM100 protection</li>
|
||
<li><strong>CT 110 (id)</strong> built at 192.168.1.5, Pocket-ID duplicated (online SQLite snapshot)</li>
|
||
<li><strong>ZFS</strong>: <code>autotrim=on</code>, <code>atime=off rpool</code></li>
|
||
<li><strong>Backups</strong>: retention set on <code>unas</code></li>
|
||
<li><strong>APT</strong>: duplicate sources removed; host <code>unattended-upgrades</code> deployed (Debian-only)</li>
|
||
<li><strong>Per-CT u-u</strong>: deployed to all 7 CTs with Debian-only allowlist</li>
|
||
<li><strong>Cron cleanup</strong>: removed weekly tteck-LXC-update curl-pipe-bash; removed daily broken <code>apt-get upgrade -y</code>; replaced <code>/root/vm100.sh</code> cron with <code>vm100-watchdog.timer</code> (1 min, lock-aware)</li>
|
||
<li><strong>Self-updaters</strong>: AdGuard (<code>--update</code> flag) Wed 03:30; Zoraxy (GitHub stable releases + rollback) Wed 03:40</li>
|
||
<li><strong><code>zpool upgrade rpool</code></strong> ran during the audit (enabled <code>redaction_list_spill</code>, <code>raidz_expansion</code>)</li>
|
||
<li><strong>Today with a maintenance window</strong>:</li>
|
||
<li><strong>Cut Zoraxy over to CT 110</strong> for <code>id.nuclide.systems</code> (single upstream edit; rollback path = revert one line)</li>
|
||
<li><code>apt full-upgrade</code> (kernel 7.0.0-3 → 7.0.2-5, pve-manager 9.1.11 → 9.1.18) + reboot</li>
|
||
<li>VM 100 disk options (<code>cache=none</code>, <code>iothread=1</code>) — §4. Requires VM stop/start.</li>
|
||
<li>Switch CT 105 from CIFS → NFS bind-mount (§4). Test UID mapping.</li>
|
||
<li>Drop the <code>unas_smb</code> storage once CT 105 is migrated.</li>
|
||
<li><strong>This week</strong>:</li>
|
||
<li>Re-measure CT 104 peak RSS after fixing CT 101 — likely safe to drop to 48 GiB.</li>
|
||
<li>Convert CT 105 to unprivileged (backup → restore as unprivileged).</li>
|
||
<li>Raise ARC cap to 16 GiB.</li>
|
||
<li>Probe NFSv4 against UNAS; switch if supported.</li>
|
||
<li><strong>Wire Postfix relayhost</strong> (Gmail/Postmark/your SMTP) so unattended-upgrades + zfs-zed + cron failures actually mail you.</li>
|
||
<li><strong>Rotate Backrest plan</strong> to back up real data (currently still pointed at <code>/media/data-dir</code> — a 50 KB test file from August 2025); see §7.</li>
|
||
<li><strong>Medium term</strong>:</li>
|
||
<li><strong>Build CT 109</strong> ops LXC (§16) — Prometheus + Grafana + Arcane Manager + Dozzle + Homarr + Diun + Tinyauth</li>
|
||
<li>Migrate Gotify from CT 104 to CT 109 (~30 min of env-var updates)</li>
|
||
<li><strong>Rotate exposed secrets</strong> that appeared in this transcript: Arcane <code>OIDC_CLIENT_SECRET</code>, <code>ENCRYPTION_KEY</code>, <code>JWT_SECRET</code>; Immich <code>IMMICH_API_KEY</code></li>
|
||
<li>Backrest: enable auth, redesign plans to cover all data tiers (§7), front via Tinyauth for OIDC</li>
|
||
<li><strong>Next purchase window</strong>:</li>
|
||
<li>Second NVMe → mirror <code>rpool</code> (§6)</li>
|
||
<li><code>proxmox-boot-tool init</code> on the new disk</li>
|
||
<li>2.5 GbE NIC + matching switch port to UNAS for image-gen / backup speed</li>
|
||
<li>UniFi-managed switch between host and UDM (or accept SNMP-only visibility from UniFi)</li>
|
||
</ol>
|
||
<hr />
|
||
<hr />
|
||
<h2 id="19-changes-applied-2026-05-20-session-2">19. Changes applied 2026-05-20 (session 2)<a class="headerlink" href="#19-changes-applied-2026-05-20-session-2" title="Permanent link">¶</a></h2>
|
||
<h3 id="optimizations-executed">Optimizations executed<a class="headerlink" href="#optimizations-executed" title="Permanent link">¶</a></h3>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>#</th>
|
||
<th>Item</th>
|
||
<th>Command / action</th>
|
||
<th>Result</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>1</td>
|
||
<td>CT 101 protection + boot order</td>
|
||
<td><code>pct set 101 -protection 1 -startup order=10</code></td>
|
||
<td>✅</td>
|
||
</tr>
|
||
<tr>
|
||
<td>4</td>
|
||
<td>CT 104 memory cap 128→48 GiB</td>
|
||
<td><code>pct set 104 -memory 49152</code></td>
|
||
<td>✅ (swap 32→8 deferred: still 10.4 GB in use)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>5</td>
|
||
<td>CT 102 rootfs 2→4 GiB</td>
|
||
<td><code>pct resize 102 rootfs 4G</code></td>
|
||
<td>✅ now 28% used</td>
|
||
</tr>
|
||
<tr>
|
||
<td>A</td>
|
||
<td>VM 100 disk: cache=none + iothread=1</td>
|
||
<td><code>qm set 100 -scsi0 ...,cache=none,iothread=1</code> + <code>scsihw virtio-scsi-single</code></td>
|
||
<td>✅ HAOS healthy</td>
|
||
</tr>
|
||
<tr>
|
||
<td>C</td>
|
||
<td>Host apt full-upgrade</td>
|
||
<td>kernel 7.0.0→7.0.2-5, pve-manager 9.1.11→9.1.18</td>
|
||
<td>✅ installed; <strong>reboot pending</strong></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 id="pocket-id-migration-completed">Pocket-ID migration completed<a class="headerlink" href="#pocket-id-migration-completed" title="Permanent link">¶</a></h3>
|
||
<ul>
|
||
<li><code>id.nuclide.systems</code> Zoraxy proxy cutover confirmed: <code>192.168.1.40:11000</code> → <code>192.168.1.5:11000</code></li>
|
||
<li>CT 104 <code>/opt/stacks/pocketid/</code> directory fully removed (data migrated to CT 110 2026-05-20)</li>
|
||
<li>Backup: <code>/opt/zoraxy/conf/proxy/id.nuclide.systems.config.bak-pre-ct110</code> (keep as rollback)</li>
|
||
</ul>
|
||
<h3 id="proxmox-oidc-via-pocket-id">Proxmox OIDC via Pocket-ID<a class="headerlink" href="#proxmox-oidc-via-pocket-id" title="Permanent link">¶</a></h3>
|
||
<p>Realm <code>pocket-id</code> added; user <code>fkrebs@nucli.de@pocket-id</code> mapped to Administrator role.</p>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a>pveum<span class="w"> </span>realm<span class="w"> </span>add<span class="w"> </span>pocket-id<span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-18-2" name="__codelineno-18-2" href="#__codelineno-18-2"></a><span class="w"> </span>--type<span class="w"> </span>openid<span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-18-3" name="__codelineno-18-3" href="#__codelineno-18-3"></a><span class="w"> </span>--issuer-url<span class="w"> </span>https://id.nuclide.systems<span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-18-4" name="__codelineno-18-4" href="#__codelineno-18-4"></a><span class="w"> </span>--client-id<span class="w"> </span>38469e7e-1fff-4841-83a9-74bf38d847eb<span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-18-5" name="__codelineno-18-5" href="#__codelineno-18-5"></a><span class="w"> </span>--client-key<span class="w"> </span><secret><span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-18-6" name="__codelineno-18-6" href="#__codelineno-18-6"></a><span class="w"> </span>--username-claim<span class="w"> </span>email<span class="w"> </span><span class="se">\</span>
|
||
<a id="__codelineno-18-7" name="__codelineno-18-7" href="#__codelineno-18-7"></a><span class="w"> </span>--comment<span class="w"> </span><span class="s2">"Pocket-ID OIDC"</span>
|
||
<a id="__codelineno-18-8" name="__codelineno-18-8" href="#__codelineno-18-8"></a>
|
||
<a id="__codelineno-18-9" name="__codelineno-18-9" href="#__codelineno-18-9"></a>pveum<span class="w"> </span>user<span class="w"> </span>add<span class="w"> </span>fkrebs@nucli.de@pocket-id
|
||
<a id="__codelineno-18-10" name="__codelineno-18-10" href="#__codelineno-18-10"></a>pveum<span class="w"> </span>aclmod<span class="w"> </span>/<span class="w"> </span>--users<span class="w"> </span>fkrebs@nucli.de@pocket-id<span class="w"> </span>--roles<span class="w"> </span>Administrator
|
||
</code></pre></div>
|
||
<p>OIDC client inserted directly into Pocket-ID SQLite (API key stored as SHA-256 hash — not reversible):</p>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a>DB: /opt/stacks/pocketid/data/pocket-id.db on CT 110
|
||
<a id="__codelineno-19-2" name="__codelineno-19-2" href="#__codelineno-19-2"></a>Table: oidc_clients
|
||
<a id="__codelineno-19-3" name="__codelineno-19-3" href="#__codelineno-19-3"></a>client_id: 38469e7e-1fff-4841-83a9-74bf38d847eb
|
||
<a id="__codelineno-19-4" name="__codelineno-19-4" href="#__codelineno-19-4"></a>name: Proxmox VE
|
||
<a id="__codelineno-19-5" name="__codelineno-19-5" href="#__codelineno-19-5"></a>callback_urls: ["https://192.168.1.20:8006"]
|
||
</code></pre></div>
|
||
<p><strong>To add future OIDC clients without UI access:</strong>
|
||
<div class="highlight"><pre><span></span><code><a id="__codelineno-20-1" name="__codelineno-20-1" href="#__codelineno-20-1"></a>python3<span class="w"> </span>-c<span class="w"> </span><span class="s2">"</span>
|
||
<a id="__codelineno-20-2" name="__codelineno-20-2" href="#__codelineno-20-2"></a><span class="s2">import uuid, secrets, bcrypt, json, datetime</span>
|
||
<a id="__codelineno-20-3" name="__codelineno-20-3" href="#__codelineno-20-3"></a><span class="s2">client_id = str(uuid.uuid4())</span>
|
||
<a id="__codelineno-20-4" name="__codelineno-20-4" href="#__codelineno-20-4"></a><span class="s2">secret_plain = secrets.token_urlsafe(32)</span>
|
||
<a id="__codelineno-20-5" name="__codelineno-20-5" href="#__codelineno-20-5"></a><span class="s2">secret_hash = bcrypt.hashpw(secret_plain.encode(), bcrypt.gensalt(rounds=10)).decode()</span>
|
||
<a id="__codelineno-20-6" name="__codelineno-20-6" href="#__codelineno-20-6"></a><span class="s2">print(f'id={client_id}')</span>
|
||
<a id="__codelineno-20-7" name="__codelineno-20-7" href="#__codelineno-20-7"></a><span class="s2">print(f'secret={secret_plain}')</span>
|
||
<a id="__codelineno-20-8" name="__codelineno-20-8" href="#__codelineno-20-8"></a><span class="s2">print(f'hash={secret_hash}')</span>
|
||
<a id="__codelineno-20-9" name="__codelineno-20-9" href="#__codelineno-20-9"></a><span class="s2">"</span>
|
||
<a id="__codelineno-20-10" name="__codelineno-20-10" href="#__codelineno-20-10"></a><span class="c1"># Then INSERT into oidc_clients with the hash, use secret_plain in the app config</span>
|
||
<a id="__codelineno-20-11" name="__codelineno-20-11" href="#__codelineno-20-11"></a><span class="c1"># callback_urls and logout_callback_urls are JSON arrays stored as BLOB</span>
|
||
<a id="__codelineno-20-12" name="__codelineno-20-12" href="#__codelineno-20-12"></a><span class="c1"># credentials field is '{}' for standard clients</span>
|
||
</code></pre></div></p>
|
||
<p><strong>Note on Pocket-ID API keys:</strong> The <code>key</code> column in <code>api_keys</code> stores a SHA-256 hash of the real key (64-char hex). The plaintext key is only shown once at creation time in the UI. If lost, create a new one — there is no recovery path.</p>
|
||
<p><strong>Login flow:</strong> In PVE web UI, select realm <code>pocket-id</code> at login. You will be redirected to <code>https://id.nuclide.systems</code> for authentication and returned to PVE. The <code>email</code> claim is used as the PVE username.</p>
|
||
<hr />
|
||
<h2 id="audit-footnote-side-effects-of-this-run">Audit footnote — side effects of this run<a class="headerlink" href="#audit-footnote-side-effects-of-this-run" title="Permanent link">¶</a></h2>
|
||
<ul>
|
||
<li><code>zpool upgrade rpool</code> was executed (not <code>-n</code>). Enabled features: <code>redaction_list_spill</code>, <code>raidz_expansion</code>. Safe on current ZFS version; the pool can no longer be imported by ZFS releases that pre-date these features. No data risk.</li>
|
||
<li>No other state changes were made by this audit.</li>
|
||
</ul>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</article>
|
||
</div>
|
||
|
||
|
||
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
|
||
</div>
|
||
|
||
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
|
||
Back to top
|
||
</button>
|
||
|
||
</main>
|
||
|
||
<footer class="md-footer">
|
||
|
||
<div class="md-footer-meta md-typeset">
|
||
<div class="md-footer-meta__inner md-grid">
|
||
<div class="md-copyright">
|
||
|
||
|
||
Made with
|
||
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
|
||
Material for MkDocs
|
||
</a>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
|
||
</div>
|
||
<div class="md-dialog" data-md-component="dialog">
|
||
<div class="md-dialog__inner md-typeset"></div>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
<script id="__config" type="application/json">{"annotate": null, "base": "../..", "features": ["navigation.tabs", "navigation.sections", "navigation.expand", "navigation.top", "search.highlight", "search.suggest", "content.code.copy"], "search": "../../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
|
||
|
||
|
||
<script src="../../assets/javascripts/bundle.79ae519e.min.js"></script>
|
||
|
||
|
||
</body>
|
||
</html> |