{
    "version": "https://jsonfeed.org/version/1",
    "title": "AMUD Dashboard Blog",
    "home_page_url": "https://boubli.github.io/AMUD-Dashboard/blog",
    "description": "AMUD Dashboard Blog",
    "items": [
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/encrypted-secrets-at-rest",
            "content_html": "<p>Storing <code>X-Plex-Token=abc123</code> in plain text in a yaml file on disk always felt wrong. Storing it in plain text in SQLite felt equally wrong.</p>\n<p>AMUD Dashboard encrypts integration secrets <strong>at rest</strong> with AES-GCM. Plex, Jellyfin, Proxmox API tokens, Home Assistant tokens — encrypted blob in the database, not readable if someone copies <code>amud.db</code> without the key.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-keyfile\">The keyfile<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/encrypted-secrets-at-rest#the-keyfile\" class=\"hash-link\" aria-label=\"Direct link to The keyfile\" title=\"Direct link to The keyfile\" translate=\"no\">​</a></h2>\n<p><code>.amud-secrets-key</code> on the host. Derived key material for encryption/decryption at runtime.</p>\n<p><strong>Back it up with your database.</strong> Restore DB without key = your tokens are toast. You'll re-enter them in settings. Annoying but not catastrophic.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"whats-not-encrypted\">What's not encrypted<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/encrypted-secrets-at-rest#whats-not-encrypted\" class=\"hash-link\" aria-label=\"Direct link to What's not encrypted\" title=\"Direct link to What's not encrypted\" translate=\"no\">​</a></h2>\n<p>App URLs, card names, layout stuff — none of that's secret. Your Jellyfin URL being <code>http://10.0.0.5:8096</code> isn't the sensitive part. The API key is.</p>\n<p>Password <strong>hashes</strong> use Argon2id separately. Different layer. Same philosophy: don't store usable secrets in recoverable form.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"threat-model-realistic\">Threat model (realistic)<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/encrypted-secrets-at-rest#threat-model-realistic\" class=\"hash-link\" aria-label=\"Direct link to Threat model (realistic)\" title=\"Direct link to Threat model (realistic)\" translate=\"no\">​</a></h2>\n<p>This stops \"someone copied my backup drive\" from leaking your Proxmox token. It doesn't stop someone with root on your running server — they own the box anyway.</p>\n<p>Homelab threat model. Not banking.</p>\n<p>Full security writeup: <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/security\">/docs/security</a></p>\n<p>Rotate tokens in integrations settings if you think the DB leaked. Same as any other dashboard.</p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/encrypted-secrets-at-rest",
            "title": "Where Your Plex Token Actually Lives in AMUD Dashboard",
            "summary": "AES-GCM encrypted integration creds in SQLite, .amud-secrets-key on disk. What gets encrypted and what doesn't.",
            "date_modified": "2026-02-25T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Security",
                "Rust"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/sqlite-wal-not-postgres",
            "content_html": "<p>\"Why not Postgres?\"</p>\n<p>Because then I'd need to run Postgres.</p>\n<p>AMUD Dashboard is a dashboard. Config storage is a few hundred KB of apps, settings, and encrypted tokens. Running a whole separate database server for that is like buying a warehouse to store a shoebox.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"sqlite-with-wal\">SQLite with WAL<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/sqlite-wal-not-postgres#sqlite-with-wal\" class=\"hash-link\" aria-label=\"Direct link to SQLite with WAL\" title=\"Direct link to SQLite with WAL\" translate=\"no\">​</a></h2>\n<p>Write-Ahead Logging lets readers (the web UI loading settings) coexist with writers (you saving a new app card) without the lock contention that makes people hate SQLite in web apps from 2010.</p>\n<p>For a single-tenant homelab dashboard with one admin clicking settings occasionally? Perfect fit.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"operational-wins\">Operational wins<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/sqlite-wal-not-postgres#operational-wins\" class=\"hash-link\" aria-label=\"Direct link to Operational wins\" title=\"Direct link to Operational wins\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\"><strong>Zero extra container</strong> — <code>amud.db</code> sits next to the binary</li>\n<li class=\"\"><strong>Backup</strong> — <code>cp amud.db backup.db</code></li>\n<li class=\"\"><strong>Restore</strong> — swap file, restart</li>\n<li class=\"\"><strong>Inspect</strong> — <code>sqlite3 amud.db</code> when debugging</li>\n</ul>\n<p>I've done all of these at 1am. Postgres would add connection strings, another service to monitor, another thing to backup separately.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"when-id-reach-for-postgres\">When I'd reach for Postgres<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/sqlite-wal-not-postgres#when-id-reach-for-postgres\" class=\"hash-link\" aria-label=\"Direct link to When I'd reach for Postgres\" title=\"Direct link to When I'd reach for Postgres\" translate=\"no\">​</a></h2>\n<p>Multi-tenant SaaS. Hundreds of concurrent writers. Horizontal scaling. AMUD Dashboard is explicitly none of those — see roadmap \"won't do SaaS.\"</p>\n<p>Homelab tool. Homelab database. Match the complexity to the problem.</p>\n<p><a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/intro\">/docs/intro</a></p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/sqlite-wal-not-postgres",
            "title": "Why AMUD Dashboard Uses SQLite Instead of Postgres (Yes, Really)",
            "summary": "Embedded DB for embedded dashboard. WAL mode, single-file backup, no extra container for config storage.",
            "date_modified": "2026-02-23T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Rust",
                "Homelab"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/migrated-from-homepage",
            "content_html": "<p>I ran Homepage for a year. Liked it. Still recommend it for the right person.</p>\n<p>Switching to AMUD Dashboard wasn't \"Homepage bad, AMUD Dashboard good.\" It was \"I'm tired of this specific workflow.\"</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-i-lost\">What I lost<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/migrated-from-homepage#what-i-lost\" class=\"hash-link\" aria-label=\"Direct link to What I lost\" title=\"Direct link to What I lost\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\"><strong>Git-tracked config</strong> — every service change was a commit. That's gone. AMUD Dashboard lives in SQLite, not <code>services.yaml</code> in a repo.</li>\n<li class=\"\"><strong>Community widget YAML</strong> — Homepage's widget library is huge. AMUD Dashboard has built-in Plex/Jellyfin/HA/Proxmox stuff but not the long tail of community widgets.</li>\n<li class=\"\"><strong>Docker-only mental model</strong> — Homepage fits the \"everything in compose\" crowd perfectly.</li>\n</ul>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-i-gained\">What I gained<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/migrated-from-homepage#what-i-gained\" class=\"hash-link\" aria-label=\"Direct link to What I gained\" title=\"Direct link to What I gained\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\"><strong>UI edits at midnight</strong> — add a card from my phone browser. No SSH, no git pull on the host.</li>\n<li class=\"\"><strong>Native Proxmox LXC control</strong> — not a widget bolted on. First-class CTID binding and power actions.</li>\n<li class=\"\"><strong>RAM</strong> — meaningful on a crowded Proxmox node.</li>\n<li class=\"\"><strong>One-file backup</strong> — <code>amud.db</code> instead of yaml + env + secrets scattered around.</li>\n</ul>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"who-should-stay-on-homepage\">Who should stay on Homepage<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/migrated-from-homepage#who-should-stay-on-homepage\" class=\"hash-link\" aria-label=\"Direct link to Who should stay on Homepage\" title=\"Direct link to Who should stay on Homepage\" translate=\"no\">​</a></h2>\n<p>You like GitOps. You generate configs from Ansible. You want fifty community widgets. YAML doesn't make you twitch.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"who-should-try-amud-dashboard\">Who should try AMUD Dashboard<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/migrated-from-homepage#who-should-try-amud-dashboard\" class=\"hash-link\" aria-label=\"Direct link to Who should try AMUD Dashboard\" title=\"Direct link to Who should try AMUD Dashboard\" translate=\"no\">​</a></h2>\n<p>Proxmox primary. YAML fatigue. Want live LXC status without shell scripts. Okay with \"config in a database\" as the trade.</p>\n<p>Migration tip: screenshot your Homepage layout, recreate cards in AMUD Dashboard while watching TV. Took me about forty minutes for ~25 services. Your mileage varies.</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">curl -sSL https://raw.githubusercontent.com/boubli/AMUD-Dashboard/main/setup-amud.sh | bash</span><br></div></code></pre></div></div>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/migrated-from-homepage",
            "title": "I Migrated From Homepage to AMUD Dashboard — What I Lost and Gained",
            "summary": "Honest post-Homepage review. GitOps YAML vs browser config. No sugarcoating.",
            "date_modified": "2026-02-21T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Homelab",
                "Self-Hosted"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/why-two-binaries",
            "content_html": "<p>\"Why not one binary?\"</p>\n<p>Because on Proxmox the dashboard server lives in an <strong>unprivileged LXC</strong> and the thing that talks to <code>/proc</code>, the Docker socket, and the PVE API on port 8006 needs to live on the <strong>host</strong>.</p>\n<p>Different trust boundaries. Different privilege levels.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"amud-server\">amud-server<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/why-two-binaries#amud-server\" class=\"hash-link\" aria-label=\"Direct link to amud-server\" title=\"Direct link to amud-server\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\">Serves HTTP/WebSockets</li>\n<li class=\"\">Owns SQLite</li>\n<li class=\"\">Runs as unprivileged <code>amud</code> user in the LXC</li>\n<li class=\"\">Never needs root</li>\n</ul>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"amud-agent\">amud-agent<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/why-two-binaries#amud-agent\" class=\"hash-link\" aria-label=\"Direct link to amud-agent\" title=\"Direct link to amud-agent\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\">Reads host hardware</li>\n<li class=\"\">Queries Proxmox API</li>\n<li class=\"\">Optionally reads Docker socket</li>\n<li class=\"\">Runs on hypervisor host with the permissions that requires</li>\n</ul>\n<p>They talk over <code>/opt/amud/run/amud.sock</code>. Bind-mounted into the LXC on Proxmox installs. Shared Docker volume in container deployments.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"challenge-response-auth\">Challenge-response auth<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/why-two-binaries#challenge-response-auth\" class=\"hash-link\" aria-label=\"Direct link to Challenge-response auth\" title=\"Direct link to Challenge-response auth\" translate=\"no\">​</a></h2>\n<p>The socket isn't world-writable chaos. Agent proves it knows <code>AMUD_AGENT_SECRET</code> before the server accepts telemetry. Stops random local processes from feeding fake metrics.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"could-i-merge-them\">Could I merge them?<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/why-two-binaries#could-i-merge-them\" class=\"hash-link\" aria-label=\"Direct link to Could I merge them?\" title=\"Direct link to Could I merge them?\" translate=\"no\">​</a></h2>\n<p>On single-box Docker or bare-metal where server and agent share a host, they're still separate processes for isolation. Server crash doesn't take down polling. Agent restart doesn't drop active web sessions.</p>\n<p>Might be over-engineered for a homelab. I'd rather over-engineer the security boundary than under-engineer it.</p>\n<p><a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/ARCHITECTURE\">/docs/ARCHITECTURE</a></p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/why-two-binaries",
            "title": "Why AMUD Dashboard Is Two Binaries Instead of One Blob",
            "summary": "Server in LXC, agent on the hypervisor host. Separation of privileges and why the Unix socket exists.",
            "date_modified": "2026-02-19T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Rust",
                "Proxmox",
                "Homelab"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/contribute-to-amud",
            "content_html": "<p>AMUD Dashboard isn't a startup. It's a homelab tool I built because I wanted it. But it gets better when other people break it in ways I didn't imagine.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"fastest-help-star-the-repo\">Fastest help: star the repo<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/contribute-to-amud#fastest-help-star-the-repo\" class=\"hash-link\" aria-label=\"Direct link to Fastest help: star the repo\" title=\"Direct link to Fastest help: star the repo\" translate=\"no\">​</a></h2>\n<p><a href=\"https://github.com/boubli/AMUD-Dashboard\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">github.com/boubli/AMUD-Dashboard</a></p>\n<p>Stars help GitHub discovery and lists like awesome-selfhosted. Sounds shallow. Matters anyway.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"try-it-and-tell-me-your-stack\">Try it and tell me your stack<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/contribute-to-amud#try-it-and-tell-me-your-stack\" class=\"hash-link\" aria-label=\"Direct link to Try it and tell me your stack\" title=\"Direct link to Try it and tell me your stack\" translate=\"no\">​</a></h2>\n<p>Proxmox version, RAM numbers, screenshot of your dashboard. <a href=\"https://github.com/boubli/AMUD-Dashboard/discussions\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">GitHub Discussions</a> is the place. \"Works on my weird ARM NAS\" posts are gold.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"bug-reports-that-get-fixed-fast\">Bug reports that get fixed fast<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/contribute-to-amud#bug-reports-that-get-fixed-fast\" class=\"hash-link\" aria-label=\"Direct link to Bug reports that get fixed fast\" title=\"Direct link to Bug reports that get fixed fast\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\">Steps to reproduce</li>\n<li class=\"\"><code>journalctl -u amud-agent -n 50</code> output</li>\n<li class=\"\">Whether you're Docker or native LXC</li>\n</ul>\n<p>Vague \"doesn't work\" issues sit longer. Fair warning.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"pr-areas\">PR areas<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/contribute-to-amud#pr-areas\" class=\"hash-link\" aria-label=\"Direct link to PR areas\" title=\"Direct link to PR areas\" translate=\"no\">​</a></h2>\n<table><thead><tr><th>Area</th><th>Stack</th></tr></thead><tbody><tr><td>amud-server</td><td>Rust, Axum</td></tr><tr><td>amud-agent</td><td>Rust, Tokio</td></tr><tr><td>UI</td><td>HTML, Alpine.js, CSS</td></tr><tr><td>Docs</td><td>Docusaurus, Markdown</td></tr><tr><td>Themes</td><td>CSS variables</td></tr></tbody></table>\n<p>Roadmap: <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/roadmap\">/docs/roadmap</a> — ARM64 CI, webhooks, multi-node agents on the list.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"submit-a-theme\">Submit a theme<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/contribute-to-amud#submit-a-theme\" class=\"hash-link\" aria-label=\"Direct link to Submit a theme\" title=\"Direct link to Submit a theme\" translate=\"no\">​</a></h2>\n<p>CSS file + preview screenshot → PR to <code>docs/static/themes/</code> → shows up in <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/themes\">/themes</a>.</p>\n<p>That's a contribution normies can do without touching Rust. Please do.</p>\n<p>Thanks for reading this series. Go break something and file an issue.</p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/contribute-to-amud",
            "title": "AMUD Dashboard Is Open Source — Here's How to Actually Help",
            "summary": "Stars, issues, PRs, themes, docs. Homelab projects grow from real users reporting real weird setups.",
            "date_modified": "2026-02-17T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Homelab",
                "Self-Hosted"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/why-rust-for-homelab-daemon",
            "content_html": "<p>A homelab dashboard is a weird workload. It idles 99% of the time but still needs to poll metrics every few seconds, hold WebSocket connections, encrypt secrets, and never leak memory over months of uptime.</p>\n<p>That's systems programming territory. Not \"spin up Express and call it a day\" territory.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"why-not-node\">Why not Node<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/why-rust-for-homelab-daemon#why-not-node\" class=\"hash-link\" aria-label=\"Direct link to Why not Node\" title=\"Direct link to Why not Node\" translate=\"no\">​</a></h2>\n<p>I've run plenty of Node homelab tools. V8 heap sitting at 80–150MB for a bookmark page hurts when that box also runs Jellyfin and Sonarr. GC pauses during telemetry polling are rare but annoying when you're staring at a graph that stutters.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"why-not-go\">Why not Go<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/why-rust-for-homelab-daemon#why-not-go\" class=\"hash-link\" aria-label=\"Direct link to Why not Go\" title=\"Direct link to Why not Go\" translate=\"no\">​</a></h2>\n<p>Go would've been fine honestly. I picked Rust because I wanted memory safety without a GC, static binaries with embedded assets (<code>include_str!</code> for UI templates), and Tokio's async model for concurrent integration polls.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-stack-that-stuck\">The stack that stuck<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/why-rust-for-homelab-daemon#the-stack-that-stuck\" class=\"hash-link\" aria-label=\"Direct link to The stack that stuck\" title=\"Direct link to The stack that stuck\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\"><strong>Axum</strong> — HTTP + WebSockets</li>\n<li class=\"\"><strong>rusqlite</strong> — embedded config, WAL mode</li>\n<li class=\"\"><strong>hyper + rustls</strong> — Proxmox HTTPS</li>\n<li class=\"\"><strong>hyperlocal</strong> — Docker socket</li>\n<li class=\"\"><strong>Argon2id</strong> — passwords</li>\n</ul>\n<p>Compile once, drop binary on host, run. No runtime install step.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"trade-offs-ill-admit\">Trade-offs I'll admit<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/why-rust-for-homelab-daemon#trade-offs-ill-admit\" class=\"hash-link\" aria-label=\"Direct link to Trade-offs I'll admit\" title=\"Direct link to Trade-offs I'll admit\" translate=\"no\">​</a></h2>\n<p>Rust compile times are slow. Contributor pool is smaller than JS. I occasionally fight the borrow checker at 2am.</p>\n<p>For a long-running daemon on a 256MB LXC though? I'd make the same call again.</p>\n<p>Architecture: <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/ARCHITECTURE\">/docs/ARCHITECTURE</a></p>\n<p>Want to hack on it: <a href=\"https://github.com/boubli/AMUD-Dashboard\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">github.com/boubli/AMUD-Dashboard</a></p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/why-rust-for-homelab-daemon",
            "title": "Why I Picked Rust for a Dashboard That Sits Idle All Day",
            "summary": "GC pauses, static binaries, Tokio concurrency. Developer brain dump on language choice for AMUD.",
            "date_modified": "2026-02-15T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Rust",
                "Homelab"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/portainer-deploy",
            "content_html": "<p>I live in SSH. Some of you live in Portainer. Both are valid.</p>\n<p>AMUD Dashboard deploys as a stack: <code>amud_app</code> + <code>amud_agent</code> + <code>amud_run</code> volume.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"portainer-steps\">Portainer steps<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/portainer-deploy#portainer-steps\" class=\"hash-link\" aria-label=\"Direct link to Portainer steps\" title=\"Direct link to Portainer steps\" translate=\"no\">​</a></h2>\n<ol>\n<li class=\"\"><strong>Stacks → Add stack</strong> → name it <code>amud</code></li>\n<li class=\"\">Paste the compose from <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/installation/docker\">/docs/installation/docker</a></li>\n<li class=\"\">Set <code>AMUD_AGENT_SECRET</code> to something long and random</li>\n<li class=\"\"><strong>Same secret in both services</strong> — write it down</li>\n<li class=\"\">Deploy</li>\n</ol>\n<p>Agent needs <code>/var/run/docker.sock:ro</code> and <code>AMUD_DOCKER=1</code>.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"after-deploy\">After deploy<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/portainer-deploy#after-deploy\" class=\"hash-link\" aria-label=\"Direct link to After deploy\" title=\"Direct link to After deploy\" translate=\"no\">​</a></h2>\n<p><code>http://your-host:8000</code> → login → change password → add cards in UI.</p>\n<p>Bind <code>./data</code> to a host path you snapshot. That's your backup.</p>\n<p>Portainer-specific notes: <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/installation/portainer\">/docs/installation/portainer</a></p>\n<p>Docker path uses a bit more RAM than native Proxmox LXC. Trade-off for convenience.</p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/portainer-deploy",
            "title": "Deploying AMUD Dashboard Through Portainer (For Clickers Not SSHers)",
            "summary": "Stack template, matching AMUD_AGENT_SECRET, Docker socket mount. GUI homelab crowd deserves dashboards too.",
            "date_modified": "2026-02-13T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Docker",
                "Homelab"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/wall-mounted-dashboard",
            "content_html": "<p>I've got an old iPad on a desk mount running AMUD Dashboard in guest mode. Shows CPU, which lights are on, if Plex is streaming, whether the *arr stack is actually running. Wife approves because it doesn't look like a terminal.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"appearance-settings-that-matter\">Appearance settings that matter<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/wall-mounted-dashboard#appearance-settings-that-matter\" class=\"hash-link\" aria-label=\"Direct link to Appearance settings that matter\" title=\"Direct link to Appearance settings that matter\" translate=\"no\">​</a></h2>\n<p><strong>Settings → Appearance</strong></p>\n<ul>\n<li class=\"\"><strong>Grid columns:</strong> 4–5 on a landscape tablet</li>\n<li class=\"\"><strong>Glass opacity:</strong> lower = cleaner in bright rooms</li>\n<li class=\"\"><strong>Background:</strong> grab a 2K wallpaper from <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/themes\">/themes</a></li>\n<li class=\"\"><strong>Custom CSS:</strong> Nord or Everforest for low glare</li>\n</ul>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-to-put-on-the-board\">What to put on the board<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/wall-mounted-dashboard#what-to-put-on-the-board\" class=\"hash-link\" aria-label=\"Direct link to What to put on the board\" title=\"Direct link to What to put on the board\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\">Home Assistant card (lights + temp)</li>\n<li class=\"\">Plex/Jellyfin with live stream badge</li>\n<li class=\"\">Host CPU/RAM bars</li>\n<li class=\"\">Key services with RUNNING status</li>\n</ul>\n<p>Skip the admin controls on a shared display. Guest account.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"kiosk-browsers\">Kiosk browsers<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/wall-mounted-dashboard#kiosk-browsers\" class=\"hash-link\" aria-label=\"Direct link to Kiosk browsers\" title=\"Direct link to Kiosk browsers\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\"><strong>Android:</strong> Fully Kiosk Browser</li>\n<li class=\"\"><strong>iPad:</strong> Guided Access</li>\n<li class=\"\"><strong>Linux SBC:</strong> Chromium <code>--kiosk</code></li>\n</ul>\n<p>Point at your HTTPS URL (see the reverse proxy post). WebSockets need to work or the graphs lie.</p>\n<p>That's it. Old hardware, new purpose, zero YAML.</p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/wall-mounted-dashboard",
            "title": "Turning an Old Tablet Into a Homelab Status Board",
            "summary": "Grid density, guest mode, theme gallery wallpapers, kiosk browser tips. AMUD Dashboard was basically made for wall mounts.",
            "date_modified": "2026-02-11T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Homelab",
                "Themes"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/admin-vs-guest",
            "content_html": "<p>Put a dashboard on a kitchen wall tablet. Someone will eventually tap the wrong button.</p>\n<p>AMUD Dashboard has <strong>Admin</strong> and <strong>Guest</strong> roles. Guests get links. Admins get the keys to the kingdom.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-guests-can-do\">What guests can do<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/admin-vs-guest#what-guests-can-do\" class=\"hash-link\" aria-label=\"Direct link to What guests can do\" title=\"Direct link to What guests can do\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\">Open app URLs</li>\n<li class=\"\">See the layout you configured</li>\n<li class=\"\">Optionally see host CPU/RAM if you enable <strong>Guest system telemetry visibility</strong> under <strong>Settings → Privacy &amp; Access</strong></li>\n</ul>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-guests-cant-do\">What guests can't do<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/admin-vs-guest#what-guests-cant-do\" class=\"hash-link\" aria-label=\"Direct link to What guests can't do\" title=\"Direct link to What guests can't do\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\">Edit cards or settings</li>\n<li class=\"\">Start/stop containers</li>\n<li class=\"\">See container names/VMIDs on sensitive telemetry</li>\n<li class=\"\">Mess with integrations</li>\n</ul>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"wall-tablet-setup\">Wall tablet setup<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/admin-vs-guest#wall-tablet-setup\" class=\"hash-link\" aria-label=\"Direct link to Wall tablet setup\" title=\"Direct link to Wall tablet setup\" translate=\"no\">​</a></h2>\n<ol>\n<li class=\"\">Create a Guest user</li>\n<li class=\"\">Enable public telemetry if you want the pretty graphs</li>\n<li class=\"\">Log the tablet into Guest</li>\n<li class=\"\">Stop worrying</li>\n</ol>\n<p>Admins keep full power controls on linked LXCs. Guests just see whether stuff is running without the big red stop button.</p>\n<p><a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/configuration\">/docs/configuration</a></p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/admin-vs-guest",
            "title": "Guest Mode So Your Family Doesn't Stop the Plex Container",
            "summary": "Admin sees power controls. Guest sees links and optional telemetry. Kitchen tablet stays safe.",
            "date_modified": "2026-02-09T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Homelab",
                "Security"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/fix-checking-badge",
            "content_html": "<p>Top bar shows live CPU. App cards say <strong>CHECKING...</strong> forever.</p>\n<p>Welcome to the most common AMUD Dashboard support question. Good news: it's usually one of like four things.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"read-the-agent-logs-first\">Read the agent logs first<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/fix-checking-badge#read-the-agent-logs-first\" class=\"hash-link\" aria-label=\"Direct link to Read the agent logs first\" title=\"Direct link to Read the agent logs first\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">journalctl -u amud-agent --no-pager -n 20</span><br></div></code></pre></div></div>\n<p>Look for <code>[LXC]</code> lines:</p>\n<table><thead><tr><th>Log</th><th>Meaning</th></tr></thead><tbody><tr><td><code>PVE_API_TOKEN not set</code></td><td>Token missing from systemd env</td></tr><tr><td><code>Successfully fetched 0 containers</code></td><td>Privilege Separation still on</td></tr><tr><td><code>HTTP 401</code></td><td>Wrong token secret</td></tr><tr><td><code>HTTP 500/595</code></td><td>Bad node hostname in config</td></tr></tbody></table>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"fix-the-token-in-systemd\">Fix the token in systemd<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/fix-checking-badge#fix-the-token-in-systemd\" class=\"hash-link\" aria-label=\"Direct link to Fix the token in systemd\" title=\"Direct link to Fix the token in systemd\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">nano /etc/systemd/system/amud-agent.service</span><br></div></code></pre></div></div>\n<p>Under <code>[Service]</code>:</p>\n<div class=\"language-ini codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-ini codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">Environment=\"PVE_API_TOKEN=PVEAPIToken=amud@pve!amud-token=YOUR-SECRET\"</span><br></div></code></pre></div></div>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">systemctl daemon-reload &amp;&amp; systemctl restart amud-agent</span><br></div></code></pre></div></div>\n<p>Also paste the same token in the UI under <strong>Settings → Proxmox VE</strong>. Both places. Yes, redundant. Yes, necessary.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"privilege-separation\">Privilege Separation<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/fix-checking-badge#privilege-separation\" class=\"hash-link\" aria-label=\"Direct link to Privilege Separation\" title=\"Direct link to Privilege Separation\" translate=\"no\">​</a></h2>\n<p>When creating the API token in Proxmox, <strong>uncheck Privilege Separation</strong>. I cannot stress this enough. Spent two hours on this once. Not proud.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"ctid-wrong\">CTID wrong<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/fix-checking-badge#ctid-wrong\" class=\"hash-link\" aria-label=\"Direct link to CTID wrong\" title=\"Direct link to CTID wrong\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">pct list</span><br></div></code></pre></div></div>\n<p>Make sure the app card ID matches reality.</p>\n<p>Full troubleshooting bible: <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/troubleshooting\">/docs/troubleshooting</a></p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/fix-checking-badge",
            "title": "Why Your App Cards Are Stuck on CHECKING...",
            "summary": "CPU bars work but LXC badges don't? It's almost always the Proxmox API token. Here's how to read agent logs and fix it.",
            "date_modified": "2026-02-07T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Proxmox",
                "Homelab"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/backup-amud-db",
            "content_html": "<p>I've seen people maintain elaborate backup scripts for YAML dashboards — git repos, env files, secret sidecars, three different paths.</p>\n<p>AMUD Dashboard backup:</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">cp /opt/amud/data/amud.db ~/backups/amud-$(date +%F).db</span><br></div></code></pre></div></div>\n<p>Done. Apps, tabs, settings, users, encrypted creds (encrypted blob in DB).</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"restore\">Restore<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/backup-amud-db#restore\" class=\"hash-link\" aria-label=\"Direct link to Restore\" title=\"Direct link to Restore\" translate=\"no\">​</a></h2>\n<ol>\n<li class=\"\">Stop <code>amud-server</code></li>\n<li class=\"\">Replace <code>amud.db</code></li>\n<li class=\"\">Start <code>amud-server</code></li>\n</ol>\n<p>Your dashboard is exactly as it was. I've used this to clone a test setup to prod. Worked first try.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"dont-forget-the-keyfile\">Don't forget the keyfile<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/backup-amud-db#dont-forget-the-keyfile\" class=\"hash-link\" aria-label=\"Direct link to Don't forget the keyfile\" title=\"Direct link to Don't forget the keyfile\" translate=\"no\">​</a></h2>\n<p>Integrations use <code>.amud-secrets-key</code> for AES-GCM. Backup it <strong>with</strong> the database. Restore DB without key = encrypted tokens become useless noise.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"cron-it-and-forget-it\">Cron it and forget it<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/backup-amud-db#cron-it-and-forget-it\" class=\"hash-link\" aria-label=\"Direct link to Cron it and forget it\" title=\"Direct link to Cron it and forget it\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">0 3 * * * cp /opt/amud/data/amud.db /mnt/nas/backups/amud-$(date +\\%F).db</span><br></div></code></pre></div></div>\n<p>Keep a week of dailies. Homelab disasters always happen on the day you skipped backups.</p>\n<p>More: <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/troubleshooting\">/docs/troubleshooting</a></p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/backup-amud-db",
            "title": "Back Up Your Entire Dashboard in One File",
            "summary": "amud.db is your whole config. Copy it. Don't forget .amud-secrets-key if you use encrypted integrations.",
            "date_modified": "2026-02-05T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Homelab",
                "Self-Hosted"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/bare-metal-linux-install",
            "content_html": "<p>Sometimes you have a spare NUC or mini PC that does one job: show the dashboard on a wall and nothing else.</p>\n<p>Docker on that box is overhead you don't need.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"directory-layout\">Directory layout<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/bare-metal-linux-install#directory-layout\" class=\"hash-link\" aria-label=\"Direct link to Directory layout\" title=\"Direct link to Directory layout\" translate=\"no\">​</a></h2>\n<div class=\"language-text codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-text codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">/opt/amud/run   → Unix socket</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">/opt/amud/data  → amud.db</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">/opt/amud/ui    → templates</span><br></div></code></pre></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"dont-run-as-root\">Don't run as root<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/bare-metal-linux-install#dont-run-as-root\" class=\"hash-link\" aria-label=\"Direct link to Don't run as root\" title=\"Direct link to Don't run as root\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">sudo groupadd --system amud</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">sudo useradd --system -g amud -s /sbin/nologin amud</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">sudo mkdir -p /opt/amud/run /opt/amud/data /opt/amud/ui</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">sudo chown -R amud:amud /opt/amud</span><br></div></code></pre></div></div>\n<p>Server runs as <code>amud</code>. Agent typically needs more privileges for host metrics — see the full guide for the permission model.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"binaries\">Binaries<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/bare-metal-linux-install#binaries\" class=\"hash-link\" aria-label=\"Direct link to Binaries\" title=\"Direct link to Binaries\" translate=\"no\">​</a></h2>\n<p>Grab latest from <a href=\"https://github.com/boubli/AMUD-Dashboard/releases\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">GitHub Releases</a>. Drop <code>amud-server</code> and <code>amud-agent</code> in <code>/usr/local/bin/</code>, set up systemd units, go.</p>\n<p>Works on Debian, Ubuntu, Fedora, Arch — anything with systemd.</p>\n<p>Full walkthrough: <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/installation/linux\">/docs/installation/linux</a></p>\n<p>When I'd pick this over Proxmox LXC: dedicated dashboard hardware, no hypervisor, absolute minimum RAM.</p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/bare-metal-linux-install",
            "title": "Running AMUD Dashboard on Bare Metal (No Docker, No LXC)",
            "summary": "Dedicated amud system user, /opt/amud layout, systemd units. Lowest overhead if you have a spare NUC.",
            "date_modified": "2026-02-03T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Homelab",
                "Self-Hosted"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/amud-vs-heimdall-homepage-homarr",
            "content_html": "<p>I built AMUD. I'm biased. Here's the honest comparison anyway.</p>\n<table><thead><tr><th></th><th style=\"text-align:center\">AMUD</th><th style=\"text-align:center\">Heimdall</th><th style=\"text-align:center\">Homepage</th><th style=\"text-align:center\">Homarr</th></tr></thead><tbody><tr><td>Runtime</td><td style=\"text-align:center\">Rust binary</td><td style=\"text-align:center\">PHP/Laravel</td><td style=\"text-align:center\">Node/React</td><td style=\"text-align:center\">Next.js</td></tr><tr><td>Config</td><td style=\"text-align:center\">SQLite + UI</td><td style=\"text-align:center\">DB + UI</td><td style=\"text-align:center\">YAML</td><td style=\"text-align:center\">UI + files</td></tr><tr><td>Idle RAM</td><td style=\"text-align:center\">~26–35MB (PVE native)</td><td style=\"text-align:center\">~150MB</td><td style=\"text-align:center\">varies</td><td style=\"text-align:center\">200MB+</td></tr><tr><td>Proxmox LXC control</td><td style=\"text-align:center\">native</td><td style=\"text-align:center\">no</td><td style=\"text-align:center\">widgets</td><td style=\"text-align:center\">limited</td></tr><tr><td>YAML required</td><td style=\"text-align:center\">never</td><td style=\"text-align:center\">no</td><td style=\"text-align:center\">yes</td><td style=\"text-align:center\">partial</td></tr></tbody></table>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"pick-heimdall-if\">Pick Heimdall if<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/amud-vs-heimdall-homepage-homarr#pick-heimdall-if\" class=\"hash-link\" aria-label=\"Direct link to Pick Heimdall if\" title=\"Direct link to Pick Heimdall if\" translate=\"no\">​</a></h2>\n<p>You want simple bookmarks and PHP on your server doesn't bother you. No live telemetry needed.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"pick-homepage-if\">Pick Homepage if<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/amud-vs-heimdall-homepage-homarr#pick-homepage-if\" class=\"hash-link\" aria-label=\"Direct link to Pick Homepage if\" title=\"Direct link to Pick Homepage if\" translate=\"no\">​</a></h2>\n<p>You live in Git, love YAML, want the widget ecosystem. You're good at debugging indent errors. Respect.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"pick-homarr-if\">Pick Homarr if<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/amud-vs-heimdall-homepage-homarr#pick-homarr-if\" class=\"hash-link\" aria-label=\"Direct link to Pick Homarr if\" title=\"Direct link to Pick Homarr if\" translate=\"no\">​</a></h2>\n<p>You want the polished drag-drop UI and don't care about RAM. *arr integration out of the box matters to you.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"pick-amud-dashboard-if\">Pick AMUD Dashboard if<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/amud-vs-heimdall-homepage-homarr#pick-amud-dashboard-if\" class=\"hash-link\" aria-label=\"Direct link to Pick AMUD Dashboard if\" title=\"Direct link to Pick AMUD Dashboard if\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\">Proxmox is your hypervisor and you want native LXC status + power controls</li>\n<li class=\"\">You refuse to maintain YAML for a link portal</li>\n<li class=\"\">You want Plex/Jellyfin/HA/host metrics without gluing shell scripts</li>\n<li class=\"\">~26MB idle on Proxmox sounds nice</li>\n</ul>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-amud-dashboard-wont-become\">What AMUD Dashboard won't become<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/amud-vs-heimdall-homepage-homarr#what-amud-dashboard-wont-become\" class=\"hash-link\" aria-label=\"Direct link to What AMUD Dashboard won't become\" title=\"Direct link to What AMUD Dashboard won't become\" translate=\"no\">​</a></h2>\n<p>SaaS. YAML-first config. Node/PHP dependency. It's a homelab tool. Stays that way.</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">curl -sSL https://raw.githubusercontent.com/boubli/AMUD-Dashboard/main/setup-amud.sh | bash</span><br></div></code></pre></div></div>\n<p><a href=\"https://github.com/boubli/AMUD-Dashboard\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">GitHub</a> · <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/themes\">Themes</a></p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/amud-vs-heimdall-homepage-homarr",
            "title": "AMUD Dashboard vs Heimdall vs Homepage vs Homarr (I'll Be Honest)",
            "summary": "I built AMUD Dashboard so I'm biased. Here's when you'd still pick something else.",
            "date_modified": "2026-02-01T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Homelab",
                "Self-Hosted"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/reverse-proxy-websockets",
            "content_html": "<p>Deployed AMUD Dashboard behind Nginx, opened the page, everything looked fine except the CPU bar was stuck at 0% like the server was dead. Server wasn't dead. Nginx just ate the WebSocket upgrade.</p>\n<p>AMUD Dashboard streams telemetry over WebSockets. Your reverse proxy <strong>must</strong> forward upgrade headers or you get a pretty but useless dashboard.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"nginx-snippet-that-actually-works\">Nginx snippet that actually works<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/reverse-proxy-websockets#nginx-snippet-that-actually-works\" class=\"hash-link\" aria-label=\"Direct link to Nginx snippet that actually works\" title=\"Direct link to Nginx snippet that actually works\" translate=\"no\">​</a></h2>\n<div class=\"language-nginx codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-nginx codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">location / {</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    proxy_pass http://127.0.0.1:8000;</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    proxy_set_header Host $host;</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    proxy_set_header X-Real-IP $remote_addr;</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    proxy_set_header X-Forwarded-Proto $scheme;</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    proxy_http_version 1.1;</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    proxy_set_header Upgrade $http_upgrade;</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    proxy_set_header Connection \"upgrade\";</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">}</span><br></div></code></pre></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"https-cookies\">HTTPS cookies<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/reverse-proxy-websockets#https-cookies\" class=\"hash-link\" aria-label=\"Direct link to HTTPS cookies\" title=\"Direct link to HTTPS cookies\" translate=\"no\">​</a></h2>\n<p>Once you're on HTTPS:</p>\n<div class=\"language-bash codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-bash codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">AMUD_SECURE_COOKIES=1</span><br></div></code></pre></div></div>\n<p>Restart the server. Forget this and you'll chase phantom login bugs.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"caddy\">Caddy<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/reverse-proxy-websockets#caddy\" class=\"hash-link\" aria-label=\"Direct link to Caddy\" title=\"Direct link to Caddy\" translate=\"no\">​</a></h2>\n<div class=\"language-caddy codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-caddy codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">amud.homelab.local {</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    reverse_proxy localhost:8000</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">}</span><br></div></code></pre></div></div>\n<p>Usually just works. Caddy's the easy mode.</p>\n<p>Full configs: <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/installation/reverse-proxy\">/docs/installation/reverse-proxy</a></p>\n<p>After setup: login works, graphs move, LXC badges update. If not, browser console first. Always browser console first.</p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/reverse-proxy-websockets",
            "title": "Putting AMUD Dashboard Behind Nginx Without Breaking Live Metrics",
            "summary": "If your CPU graphs freeze at 0%, your reverse proxy probably isn't forwarding WebSocket upgrades. Fix inside.",
            "date_modified": "2026-01-30T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Homelab",
                "Security"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/securing-homelab-dashboard",
            "content_html": "<p>Your dashboard is a map to your entire homelab. Treat it like one.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"passwords\">Passwords<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/securing-homelab-dashboard#passwords\" class=\"hash-link\" aria-label=\"Direct link to Passwords\" title=\"Direct link to Passwords\" translate=\"no\">​</a></h2>\n<p><strong>Argon2id</strong> hashes in SQLite. Not SHA-256 alone, not md5 (please). Older installs with legacy SHA-256 get transparently re-hashed on next login.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"sessions\">Sessions<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/securing-homelab-dashboard#sessions\" class=\"hash-link\" aria-label=\"Direct link to Sessions\" title=\"Direct link to Sessions\" translate=\"no\">​</a></h2>\n<p>32-byte random tokens, 24h lifetime, <code>HttpOnly</code>, <code>SameSite=Strict</code>. Behind HTTPS set <code>AMUD_SECURE_COOKIES=1</code> or you're leaving cookies exposed on misconfigured proxies.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"brute-force\">Brute force<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/securing-homelab-dashboard#brute-force\" class=\"hash-link\" aria-label=\"Direct link to Brute force\" title=\"Direct link to Brute force\" translate=\"no\">​</a></h2>\n<p>5 failed logins per username in 5 minutes. Enough to stop dumb scripts, not enough to lock you out forever if you typo once.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"integration-secrets\">Integration secrets<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/securing-homelab-dashboard#integration-secrets\" class=\"hash-link\" aria-label=\"Direct link to Integration secrets\" title=\"Direct link to Integration secrets\" translate=\"no\">​</a></h2>\n<p>Plex tokens, Jellyfin keys, Proxmox API tokens, HA tokens — <strong>AES-GCM encrypted at rest</strong> with a host keyfile (<code>.amud-secrets-key</code>). Backup that file with your database or restores get awkward.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"csrf--csp\">CSRF + CSP<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/securing-homelab-dashboard#csrf--csp\" class=\"hash-link\" aria-label=\"Direct link to CSRF + CSP\" title=\"Direct link to CSRF + CSP\" translate=\"no\">​</a></h2>\n<p>State-changing requests need CSRF tokens. CSP with per-request nonces on scripts. Boring security stuff that matters when your dashboard is internet-facing behind a reverse proxy.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"production-checklist\">Production checklist<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/securing-homelab-dashboard#production-checklist\" class=\"hash-link\" aria-label=\"Direct link to Production checklist\" title=\"Direct link to Production checklist\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\">Change <code>admin</code> / <code>password</code> (seriously)</li>\n<li class=\"\">HTTPS + <code>AMUD_SECURE_COOKIES=1</code></li>\n<li class=\"\">Restricted Proxmox API user, not root</li>\n<li class=\"\">Backup <code>amud.db</code> and <code>.amud-secrets-key</code></li>\n</ul>\n<p>Full doc: <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/security\">/docs/security</a></p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/securing-homelab-dashboard",
            "title": "Securing a Dashboard That Knows Where Everything Lives",
            "summary": "Argon2id passwords, encrypted integration secrets, CSRF, rate limiting — what AMUD Dashboard actually ships with.",
            "date_modified": "2026-01-28T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Security",
                "Self-Hosted"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/twelve-free-themes",
            "content_html": "<p>The default AMUD Dashboard look is orange glass. I like it. My partner said it looked like a Cheetos-themed spaceship cockpit. Fair.</p>\n<p>So I built a <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/themes\">theme gallery</a> with twelve ready-made CSS themes and actual dashboard preview screenshots so you can pick before you paste.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"included-themes\">Included themes<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/twelve-free-themes#included-themes\" class=\"hash-link\" aria-label=\"Direct link to Included themes\" title=\"Direct link to Included themes\" translate=\"no\">​</a></h2>\n<p>Dracula, Nord, Catppuccin Mocha, Tokyo Night, Gruvbox Dark, Cyberpunk Neon, Solarized Dark, Rose Pine, Everforest, Monokai, One Dark, Sunset Warm.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"apply-one-in-three-clicks\">Apply one in three clicks<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/twelve-free-themes#apply-one-in-three-clicks\" class=\"hash-link\" aria-label=\"Direct link to Apply one in three clicks\" title=\"Direct link to Apply one in three clicks\" translate=\"no\">​</a></h2>\n<ol>\n<li class=\"\">Open <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/themes\">/themes</a></li>\n<li class=\"\">Hit <strong>Copy CSS</strong></li>\n<li class=\"\"><strong>Settings → Appearance → Custom CSS</strong> → paste → save</li>\n</ol>\n<p>Instant. No restart. No import-from-URL (that feature got cut on purpose — copy-paste is safer and works offline).</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"wallpapers-too\">Wallpapers too<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/twelve-free-themes#wallpapers-too\" class=\"hash-link\" aria-label=\"Direct link to Wallpapers too\" title=\"Direct link to Wallpapers too\" translate=\"no\">​</a></h2>\n<p>Each theme has a bundled 2K wallpaper. <strong>Copy wallpaper URL</strong> → paste into background image setting. Makes wall tablets look intentional instead of \"sysadmin panel accidentally left on.\"</p>\n<p>Broke the layout with bad CSS? Been there. Recovery guide: <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/troubleshooting\">/docs/troubleshooting</a></p>\n<p>Want to roll your own? CSS variable reference: <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/themes\">/docs/themes</a></p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/twelve-free-themes",
            "title": "12 Free Themes Because Orange Glass Isn't for Everyone",
            "summary": "Copy-paste CSS from the theme gallery. Dracula, Nord, Catppuccin, Cyberpunk Neon, and eight more with preview screenshots.",
            "date_modified": "2026-01-26T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Themes",
                "Homelab"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/home-assistant-dashboard-card",
            "content_html": "<p>I had a Home Assistant card that was literally just a URL. Useful, but my wall tablet deserved better.</p>\n<p>AMUD Dashboard can show on that card:</p>\n<ul>\n<li class=\"\">How many <strong>lights</strong> are on</li>\n<li class=\"\">How many <strong>switches</strong> are on</li>\n<li class=\"\">Average home <strong>temperature</strong></li>\n</ul>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-one-naming-rule-that-trips-people-up\">The one naming rule that trips people up<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/home-assistant-dashboard-card#the-one-naming-rule-that-trips-people-up\" class=\"hash-link\" aria-label=\"Direct link to The one naming rule that trips people up\" title=\"Direct link to The one naming rule that trips people up\" translate=\"no\">​</a></h2>\n<p>Your app card has to be named exactly <strong><code>Home Assistant</code></strong>. Not \"HA\" or \"homeassistant\" or \"the smart house thing.\" Exactly that string. Yes, I should make that more flexible someday. For now, that's the deal.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"setup\">Setup<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/home-assistant-dashboard-card#setup\" class=\"hash-link\" aria-label=\"Direct link to Setup\" title=\"Direct link to Setup\" translate=\"no\">​</a></h2>\n<ol>\n<li class=\"\">HA → Profile → Long-Lived Access Tokens → create one</li>\n<li class=\"\">AMUD → <strong>Settings → Smart Home</strong> → URL + token → save</li>\n</ol>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"how-it-polls-without-being-rude-to-ha\">How it polls without being rude to HA<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/home-assistant-dashboard-card#how-it-polls-without-being-rude-to-ha\" class=\"hash-link\" aria-label=\"Direct link to How it polls without being rude to HA\" title=\"Direct link to How it polls without being rude to HA\" translate=\"no\">​</a></h2>\n<p>Prefers the <strong>Template API</strong> (<code>POST /api/template</code>) so HA computes counts server-side. Falls back to <code>/api/states</code> if templates aren't available. Heavier, but works.</p>\n<p>Runs on the same Tokio runtime as everything else — won't block your CPU graphs.</p>\n<p>Pair with LXC status: see the HA container is up <em>and</em> you've got four lights on at 2am. Investigate that later.</p>\n<p><a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/configuration\">/docs/configuration</a></p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/home-assistant-dashboard-card",
            "title": "Home Assistant Stats on Your Dashboard (Not Just a Link to :8123)",
            "summary": "Name your app card Home Assistant, drop in a long-lived token, get lights/switches/temp on the card.",
            "date_modified": "2026-01-24T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Integrations",
                "Homelab"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/plex-jellyfin-live-badges",
            "content_html": "<p>\"Is anyone watching something right now or can I restart the container?\"</p>\n<p>That's the question I wanted answered from the dashboard, not from opening Plex on my phone.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"setup-boring-but-fast\">Setup (boring but fast)<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/plex-jellyfin-live-badges#setup-boring-but-fast\" class=\"hash-link\" aria-label=\"Direct link to Setup (boring but fast)\" title=\"Direct link to Setup (boring but fast)\" translate=\"no\">​</a></h2>\n<p><strong>Settings → Integrations</strong></p>\n<p><strong>Jellyfin:</strong> base URL + API key from Dashboard → Advanced → API Keys.</p>\n<p><strong>Plex:</strong> base URL + <code>X-Plex-Token</code>. If you've never extracted a Plex token before, welcome to the club — there's a few documented ways and they're all mildly annoying.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-the-badge-does\">What the badge does<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/plex-jellyfin-live-badges#what-the-badge-does\" class=\"hash-link\" aria-label=\"Direct link to What the badge does\" title=\"Direct link to What the badge does\" translate=\"no\">​</a></h2>\n<p>Starts as <strong>CHECKING...</strong>, then shows the active stream title. Multiple clients? You'll see something like <code>Dune (+2 more)</code>.</p>\n<p>Missing creds → <strong>NOT CONFIGURED</strong>. Fixable in thirty seconds once you stop procrastinating.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"why-this-pairs-well-with-lxc-status\">Why this pairs well with LXC status<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/plex-jellyfin-live-badges#why-this-pairs-well-with-lxc-status\" class=\"hash-link\" aria-label=\"Direct link to Why this pairs well with LXC status\" title=\"Direct link to Why this pairs well with LXC status\" translate=\"no\">​</a></h2>\n<p>Card shows Jellyfin is <strong>RUNNING</strong> <em>and</em> someone's watching <em>Blade Runner</em>. Now you know restarting would make someone mad. That's operational awareness, not just bookmarks.</p>\n<p>API keys get <strong>AES-GCM encrypted</strong> in SQLite at rest. Not sitting in plain text in a yaml file on disk.</p>\n<p>Details: <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/configuration\">/docs/configuration</a></p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/plex-jellyfin-live-badges",
            "title": "See What's Playing on Plex and Jellyfin Without Opening the App",
            "summary": "AMUD Dashboard polls /Sessions and /status/sessions in the background. Your media cards show live stream titles.",
            "date_modified": "2026-01-22T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Integrations",
                "Homelab"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/docker-homelab-35mb",
            "content_html": "<p>Not everyone runs Proxmox. Some of you are Docker-all-the-way-down and that's fine.</p>\n<p>AMUD Dashboard in Docker is two containers:</p>\n<ul>\n<li class=\"\"><strong><code>amud_app</code></strong> — web server + SQLite</li>\n<li class=\"\"><strong><code>amud_agent</code></strong> — telemetry, mounts Docker socket read-only</li>\n</ul>\n<p>They talk over a shared volume at <code>/var/run/amud/amud.sock</code>. Same IPC model as bare metal, just containerized.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"minimal-compose\">Minimal compose<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/docker-homelab-35mb#minimal-compose\" class=\"hash-link\" aria-label=\"Direct link to Minimal compose\" title=\"Direct link to Minimal compose\" translate=\"no\">​</a></h2>\n<div class=\"language-yaml codeBlockContainer_Ckt0 theme-code-block\" style=\"--prism-color:#F8F8F2;--prism-background-color:#282A36\"><div class=\"codeBlockContent_QJqH\"><pre tabindex=\"0\" class=\"prism-code language-yaml codeBlock_bY9V thin-scrollbar\" style=\"color:#F8F8F2;background-color:#282A36\"><code class=\"codeBlockLines_e6Vv\"><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token key atrule\">services</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\"></span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  </span><span class=\"token key atrule\">app</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\"></span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    </span><span class=\"token key atrule\">image</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\"> tradmss/amud</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\">dashboard</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\">latest</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    </span><span class=\"token key atrule\">ports</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\"></span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:rgb(255, 121, 198)\">\"8000:8000\"</span><span class=\"token plain\"></span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    </span><span class=\"token key atrule\">environment</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\"></span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\"> AMUD_AGENT_SECRET=use</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\">a</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\">long</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\">random</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\">string</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\">here</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\"> DB_PATH=/app/data/amud.db</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\"> AMUD_SOCKET_PATH=/var/run/amud/amud.sock</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    </span><span class=\"token key atrule\">volumes</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\"></span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\"> ./data</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\">/app/data</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\"> amud_run</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\">/var/run/amud</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  </span><span class=\"token key atrule\">agent</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\"></span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    </span><span class=\"token key atrule\">image</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\"> tradmss/amud</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\">dashboard</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\">latest</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    </span><span class=\"token key atrule\">entrypoint</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">[</span><span class=\"token string\" style=\"color:rgb(255, 121, 198)\">\"/app/amud-agent\"</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">]</span><span class=\"token plain\"></span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    </span><span class=\"token key atrule\">environment</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\"></span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\"> AMUD_AGENT_SECRET=use</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\">a</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\">long</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\">random</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\">string</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\">here</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\"> AMUD_DOCKER=1</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\"> AMUD_SOCKET_PATH=/var/run/amud/amud.sock</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">    </span><span class=\"token key atrule\">volumes</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\"></span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\"> amud_run</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\">/var/run/amud</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">-</span><span class=\"token plain\"> /var/run/docker.sock</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\">/var/run/docker.sock</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\">ro</span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\"></span><span class=\"token key atrule\">volumes</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><span class=\"token plain\"></span><br></div><div class=\"token-line\" style=\"color:#F8F8F2\"><span class=\"token plain\">  amud_run</span><span class=\"token punctuation\" style=\"color:rgb(248, 248, 242)\">:</span><br></div></code></pre></div></div>\n<p><strong>The secret must match in both containers.</strong> I cannot count how many issue reports were just mismatched <code>AMUD_AGENT_SECRET</code>.</p>\n<p>Link app cards to <strong>container names</strong> for running/stopped badges.</p>\n<p>Full guide: <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/installation/docker\">/docs/installation/docker</a></p>\n<p>RAM lands around 35–100MB depending on host. Still lighter than most PHP/Node dashboards I've run.</p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/docker-homelab-35mb",
            "title": "Docker Homelab Monitoring in ~35MB RAM",
            "summary": "Two containers, one shared socket volume, AMUD_DOCKER=1 on the agent. Not Proxmox-native but still lean.",
            "date_modified": "2026-01-20T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Docker",
                "Homelab",
                "Self-Hosted"
            ]
        },
        {
            "id": "https://boubli.github.io/AMUD-Dashboard/blog/lxc-status-badges",
            "content_html": "<p>A link list tells you where Jellyfin <em>should</em> be. It doesn't tell you Jellyfin is stopped because you updated the LXC last night and forgot to bring it back up.</p>\n<p>AMUD Dashboard app cards can bind to a Proxmox <strong>CTID</strong>. Badge flips between <strong>RUNNING</strong>, <strong>STOPPED</strong>, and the eternal <strong>CHECKING...</strong> when something's misconfigured.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"setup-checklist\">Setup checklist<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/lxc-status-badges#setup-checklist\" class=\"hash-link\" aria-label=\"Direct link to Setup checklist\" title=\"Direct link to Setup checklist\" translate=\"no\">​</a></h2>\n<ol>\n<li class=\"\"><code>amud-agent</code> running on the Proxmox host</li>\n<li class=\"\">API token in <strong>Settings → Proxmox VE</strong></li>\n<li class=\"\">App card has the correct LXC/VM ID field filled in</li>\n</ol>\n<p>That's it. If you're stuck on CHECKING..., 90% of the time it's the token. I wrote a whole troubleshooting post for that misery.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"power-controls\">Power controls<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/lxc-status-badges#power-controls\" class=\"hash-link\" aria-label=\"Direct link to Power controls\" title=\"Direct link to Power controls\" translate=\"no\">​</a></h2>\n<p>If your API role includes <code>VM.PowerMgmt</code>, admins get start/stop/restart on linked containers. Handy when you're on your phone and don't want the Proxmox mobile experience.</p>\n<p>Guest users see status only. No accidental <code>pct stop</code> from the kitchen tablet.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"dont-use-rootpam\">Don't use root@pam<a href=\"https://boubli.github.io/AMUD-Dashboard/blog/lxc-status-badges#dont-use-rootpam\" class=\"hash-link\" aria-label=\"Direct link to Don't use root@pam\" title=\"Direct link to Don't use root@pam\" translate=\"no\">​</a></h2>\n<p>Create a restricted <code>amud@pve</code> user with <code>VM.Audit</code>, <code>Sys.Audit</code>, and optionally <code>VM.PowerMgmt</code>. Paste that token into AMUD. Your dashboard doesn't need god-mode PVE access.</p>\n<p>Config details: <a class=\"\" href=\"https://boubli.github.io/AMUD-Dashboard/docs/configuration\">/docs/configuration</a></p>",
            "url": "https://boubli.github.io/AMUD-Dashboard/blog/lxc-status-badges",
            "title": "Green and Red LXC Badges (Plus Start/Stop From the Dashboard)",
            "summary": "Link an app card to a CTID, get live RUNNING/STOPPED status, and optionally power-cycle containers without opening Proxmox.",
            "date_modified": "2026-01-18T00:00:00.000Z",
            "author": {
                "name": "Youssef Boubli",
                "url": "https://github.com/boubli"
            },
            "tags": [
                "Proxmox",
                "Homelab"
            ]
        }
    ]
}