docs: rename frank-default-large/small/sightsound to frank-large/small/npu across vault

Mechanical identity rename across the knowledge base, AGENTS.md, README, the
hermes config example, and homepage services.json. No behavior change; served
aliases on the LLM endpoints change with the deploy of commit 69f87c8.
This commit is contained in:
Frank
2026-09-03 16:17:14 -07:00
parent 5a083eee6c
commit 8212d4451a
68 changed files with 1053 additions and 1207 deletions
@@ -44,8 +44,9 @@ graph LR
```bash
./scripts/deploy.sh dankclaw
./scripts/deploy.sh dankserver
./scripts/deploy.sh frankbook-pro --service qbittorrent # podman-machine target
./scripts/deploy.sh dankclaw --service searxng
./scripts/deploy.sh dankserver --service frank-default-small
./scripts/deploy.sh dankserver --service frank-small
./scripts/deploy.sh dankclaw --dry-run
```
@@ -61,12 +62,12 @@ service on the other host.
|---|---|---|
| Dankclaw compose services | `podman-compose -f dankclaw/compose.yaml up -d --no-deps NAME` | Recreates only `NAME`; Caddy is handled separately because it fronts both hosts. |
| SearXNG, Gluetun, Valkey, OpenWebUI, Pi-hole, Gitea database/server | user Quadlet + `systemctl --user` | Installs the selected unit and restarts only the required dependency-coupled units. Gitea's web proxy is the canonical Caddy compose service. |
| `frank-default-large` | systemd + `systemctl` | Relinks and restarts only the large inference service; waits up to 20 minutes for `/health`. |
| `frank-default-small` | systemd + `systemctl` | Relinks and restarts only the small inference service; waits up to 20 minutes for `/health`. |
| `frank-large` | systemd + `systemctl` | Relinks and restarts only the large inference service; waits up to 20 minutes for `/health`. |
| `frank-small` | systemd + `systemctl` | Relinks and restarts only the small inference service; waits up to 20 minutes for `/health`. |
| Dankserver media stack (RomM trio, Jellyfin, Calibre-Web, Copyparty) | user Quadlet + `systemctl --user` | Installs `dankserver/<svc>/quadlet/*.container`, restarts the generated unit. The first cutover per service is idempotent: it retires the compose-era bare container, rescues any anonymous volume into the data root, and merge-moves `/opt/<svc>` to `/home/dank/Containers/<svc>` (mapped-uid roots move without chown). Steady state is restart-only. |
The shared chat template maps to the inference service on the selected target.
The inactive `frank-default-npu` unit is relink-only when explicitly selected;
The inactive `frank-npu` unit is relink-only when explicitly selected;
it is not restarted by an unrelated large-model deployment.
## Caddy safety
+4 -1
View File
@@ -2,7 +2,10 @@
ComfyUI is a node-based AI image generation engine. Workflows are built from nodes that load models, sample latents, and post-process images; everything is scriptable through a web UI and an API.
**Host:** Dankclaw — **Hostname:** `comfyui.dankclaw.local` — **Port:** 8188 — **Backend:** ROCm GPU (gfx1151) — **Docs:** https://github.com/Comfy-Org/ComfyUI
**Host:** Dankclaw — **Port:** `8188` published on the host; **no vhost and no
guard chain** — ComfyUI is LAN-only by construction (the Caddyfile routes no
name to it) — **Backend:** ROCm GPU (gfx1151) — **Docs:**
https://github.com/Comfy-Org/ComfyUI
## Facts
@@ -12,11 +12,12 @@ timestamp: 2026-08-26
# Dankclaw Stack
Dankclaw (192.168.0.143) runs the AI, search, and development stack. It
hosts the LLM inference endpoint (`frank-default-large`, `:7770`, CIRU
ROCmFPX llama.cpp), the agent tools, the privacy search, and the
observability stack. The llama.cpp endpoint (`frank-default-small`,
`:7770`) runs on Dankserver (192.168.0.235).
Dankclaw (192.168.0.143) runs the AI, search, development, and observability
stack. Its LLM inference endpoint `frank-large` (`:7770`) is a ROCmFPX
llama.cpp fork serving the kingjones Qwen3.8-Flash-Next-ROCmFP4-STRIX GGUF on
the card's pinned runtime; an NPU endpoint (`frank-npu`, `:7771`,
FLM v1.0.1) serves sight+sound models. The completion endpoint
`frank-small` (FreeToken, `:7770`) runs on Dankserver (192.168.0.235).
```mermaid
graph LR
@@ -29,29 +30,36 @@ graph LR
S --> V[Gluetun VPN]
O --> L[llama.cpp dankserver :7770]
O --> H[Hermes]
O --> E[CIRU llama.cpp :7770]
O --> E[frank-large :7770]
```
## Services
| Service | Hostname | Port | Docs |
|---------|----------|------|------|
| SearXNG | search.dankclaw.local | 8081 | [[SearXNG]] |
| ComfyUI | comfyui.dankclaw.local | 8188 | [[ComfyUI]] |
| OpenWebUI | chat.dankclaw.local | 3005 | [[OpenWebUI]] |
| Hermes | hermes.dankclaw.local | 8090 | [[Hermes]] |
| Gitea | gitea.dankclaw.local | 3000 | [[Gitea]] |
| Grafana | grafana.dankclaw.local | 3002 | [[Grafana]] |
| Prometheus | prometheus.dankclaw.local | 9090 | [[Prometheus]] |
| Homepage | dankclaw.local | 80/443 | — |
| frank-default-large (host service, Dankclaw) | — | 7770 | [[deployment]] |
| frank-default-small (host service, Dankserver) | — | 7770 | [[deployment]] |
| Service | Vhost (guard status) | Port/route | Docs |
|---------|----------------------|------------|------|
| SearXNG | `search.franksdank.cloud` (guarded: Anubis → Authentik) | published by gluetun at `8081:8080`; searxng itself has no published port | [[SearXNG]] |
| ComfyUI | none — LAN-only by construction | `8188` | [[ComfyUI]] |
| OpenWebUI | `ai.franksdank.cloud` (exempt — own auth) | `3005 → 8080` | [[OpenWebUI]] |
| Hermes | `hermes.franksdank.cloud` (exempt by construction; internal-only via DNS absence) | webui `8787`; gateway publishes none | [[Hermes]] |
| Gitea | `gitea.franksdank.cloud` (exempt — git smart HTTP) | `3000`, SSH `2222` | [[Gitea]] |
| Grafana | `grafana.franksdank.cloud` (guarded) | Caddy routes post-auth to `grafana:3000` | [[Grafana]] |
| Prometheus | `prometheus.franksdank.cloud` (guarded) | `9090` | [[Prometheus]] |
| Loki | `loki.franksdank.cloud` (guarded; dedicated loki-proxy outpost provider with `internal_host = caddy:8017`) | `3100` | [[Observability]] |
| Seerr | `seerr.franksdank.cloud` (guarded) | Caddy routes post-auth to `seerr:5055` | [[Seerr]] |
| Homepage | `franksdank.cloud` + `www.` (root site; guarded for admin actions) | served by Caddy itself from `/srv/homepage` | — |
| Pi-hole | `pihole.franksdank.cloud` (basicauth edge, not the guard chain) | admin UI `8083`; DNS on `:53` LAN-wide | [[Pi-hole]] |
| frank-large (host service) | — | `7770` | [[deployment]] |
| frank-npu (host service) | — | `7771` (`/v1/version` health) | [[frank-npu]] |
| frank-small (host service, Dankserver) | — | `7770` | [[deployment]] |
The last two rows are bare-metal systemd services, not containers. This
The LLM rows are bare-metal systemd services, not containers. This
repo owns their scripts, units, and knowledge base (see
[serverAppConfigs-docs/LLM/index.md](../LLM/index.md)). Current mapping (2026-08-22):
`frank-default-large` runs the CIRU ROCmFPX llama.cpp on Dankclaw;
`frank-default-small` runs the upstream llama.cpp on Dankserver.
[LLM fleet knowledge base](../LLM/index.md)). Current mapping (2026-09-03):
`frank-large` runs the kingjones Qwen3.8-Flash-Next-ROCmFP4-STRIX GGUF
on the card's pinned `kingjones30/ROCmFPX` llama.cpp build;
`frank-npu` runs FLM v1.0.1 on the XDNA2 NPU;
`frank-small` runs FreeToken v0.1.2 serving
Huihui-Qwen3.6-35B-A3B-abliterated-FP8 on Dankserver.
## Boot Persistence
+20 -8
View File
@@ -63,9 +63,16 @@ The containers use the quadlet fresh-start model. A stop removes the container (
## Secrets
The database password lives in `/opt/gitea/.env` on the host (mode 0600). The quadlet files reference it with `EnvironmentFile=`. The password never enters this repository. Placeholders live in [`dankclaw/gitea/.env.example`](../../dankclaw/gitea/.env.example).
The database password lives in `/home/dank/Containers/gitea/env` on the host
(mode 0600); `gitea-postgres.container` and `gitea-server.container` load it
via `EnvironmentFile=` (verified from the live units — the `${GITEA_DB_PASSWORD}`
placeholders are expanded by systemd at start). The password never enters this
repository. Placeholders live in
[`dankclaw/gitea/.env.example`](../../dankclaw/gitea/.env.example).
Do not change the password in place. Change the PostgreSQL role first, then update `/opt/gitea/.env` and the `[database] PASSWD` line in the app.ini (see Gotchas), then restart the stack.
Do not change the password in place. Change the PostgreSQL role first, then
update the env file and the `[database] PASSWD` line in the app.ini (see
Gotchas), then restart the stack.
## Configuration files
@@ -73,23 +80,28 @@ Do not change the password in place. Change the PostgreSQL role first, then upda
|------|----------|-----------|
| Quadlet units | `~/.config/containers/systemd/gitea-{postgres,server}.container`, `gitea.network` | [`dankclaw/gitea/quadlet/`](../../dankclaw/gitea/quadlet/) |
| Caddyfile | `/home/dank/Containers/caddy/Caddyfile` | [`dankclaw/Caddyfile`](../../dankclaw/Caddyfile) |
| Secrets | `/opt/gitea/.env` (0600) | [`dankclaw/gitea/.env.example`](../../dankclaw/gitea/.env.example) |
| Secrets | `/home/dank/Containers/gitea/env` (0600; loaded via `EnvironmentFile=`) | [`dankclaw/gitea/.env.example`](../../dankclaw/gitea/.env.example) |
After editing a repo copy, deploy through `scripts/deploy.sh dankclaw`. The Gitea database/server units are installed from this directory; the canonical Caddy and its rendered Caddyfile are deployed as the separate `caddy` service. Do not manually recreate the retired `gitea-caddy` unit.
## Data volumes
Per the live quadlet units (`Volume=` lines):
| Container path | Host path | Contents |
|----------------|-----------|----------|
| `/data` | `/opt/gitea/data/gitea-gitea` | Git repositories, app.ini, attachments |
| `/var/lib/postgresql/data` | `/opt/gitea/data/gitea-postgres` | PostgreSQL data |
| `/data` | `/home/dank/Containers/gitea/data` | Git repositories, app.ini, attachments |
| `/var/lib/postgresql/data` | `/home/dank/Containers/gitea/postgres` | PostgreSQL data |
Back up `/opt/gitea/data/` (tar) or `pg_dump` the database. See the knowledge base page [[Gitea]].
Back up `/home/dank/Containers/gitea/` (tar) or `pg_dump` the database. See the knowledge base page [[Gitea]].
## Gotchas
- **app.ini wins over env vars.** Gitea writes `/data/gitea/conf/app.ini` (host: `/opt/gitea/data/gitea-gitea/gitea/conf/app.ini`) on first start. The `[database] HOST` and `PASSWD` lines persist and override the `DATABASE_HOST`/`DATABASE_PASSWD` env vars. When you rename the database container, edit the `HOST` line.
- **The files in the data directory are owned by host UID 100999**, not `dank` (rootless ID mapping: container uid 1000 → host 100999). Edit them inside the container with `podman exec --user 1000 gitea-server ...`.
- **Data files are owned by `dank` (uid 1000), not root.** The quadlet units run
podman in the user manager with no `--user`/UserNS override, so container uid
1000 is literally dank's host uid — there is no subuid offset for these
containers. Edit files as the owning user with
`podman exec --user 1000 gitea-server ...`.
- **The host auto-reboots.** `unattended-upgrades` reboots Dankclaw when a package needs it. The quadlet units make Gitea survive that. See the 2026-08-16 incident below.
- **Port 3000 vs 3001.** The live host port is 3000. The full-stack [`dankclaw/compose.yaml`](../../dankclaw/compose.yaml) maps 3001. Align the two before deploying the full stack.
- **Legacy compose retired.** `/opt/gitea/podman-compose.yml` is retired to `/opt/gitea/.deprecated/`. Do not run it. Its containers collide with the Quadlet units on ports 3000 and 2222.
+8 -4
View File
@@ -2,7 +2,11 @@
Hermes is the self-improving AI agent from Nous Research. It runs in a terminal, Telegram, Discord, Slack, WhatsApp, or Signal, and keeps a persistent learning loop: it creates skills from experience, searches past conversations, and builds a model of the user across sessions.
**Host:** Dankclaw — **Hostname:** `hermes.dankclaw.local` — **Docs:** https://hermes-agent.nousresearch.com/docs
**Host:** Dankclaw — the gateway itself publishes **no port** (it runs in the
host network namespace and dials the Signal daemon at `127.0.0.1:8080`); the
user-facing web surface is [[Hermes-WebUI]] on `:8787`, reached via
`hermes.franksdank.cloud` — internal-only by DNS absence (no public Porkbun A
record) — **Docs:** https://hermes-agent.nousresearch.com/docs
**Persistent state:** `/home/dank/Containers/hermes/data` on Dankclaw, bind-mounted
at `/data` in all three Hermes containers (gateway, webui, dashboard). Each
@@ -33,9 +37,9 @@ is not durable. The tracked, sanitized configuration baseline is
`0.0.0.0:8080`, so the Signal HTTP API is reachable from the whole LAN.
- The data volume persists skills, memory, and session history.
- Hermes has two named local providers: `dankclaw-large` reaches
`http://192.168.0.143:7770/v1` and exposes `frank-default-large`;
`http://192.168.0.143:7770/v1` and exposes `frank-large`;
`dankserver-small` reaches `http://192.168.0.235:7770/v1` and exposes
`frank-default-small`.
`frank-small`.
- The live `config.yaml` contains secrets and user state and is not committed;
the tracked example is the sanitized backup of its non-secret settings.
@@ -50,7 +54,7 @@ is not durable. The tracked, sanitized configuration baseline is
## Gotchas
- Hermes is under active development; pin the image tag for reproducibility.
- Model choice drives quality; the local `frank-default-large` (Dankclaw, 7770) is the intended backend.
- Model choice drives quality; the local `frank-large` (Dankclaw, 7770) is the intended backend.
- Do not expose the gateway without auth — put it behind [[Caddy]] with basic auth.
## Browser automation (Chrome DevTools Protocol daemon)
+20 -10
View File
@@ -2,32 +2,42 @@
OpenWebUI is a self-hosted chat interface for LLMs. It connects to OpenAI-compatible endpoints (vLLM, llama.cpp, Ollama) and adds RAG, plugins, tool calling, and multi-user support.
**Host:** Dankclaw — **Port:** 3005 (host) → 8080 (container) — **Boot-persistent:** Quadlet — **Docs:** https://github.com/open-webui/open-webui
**Host:** Dankclaw — **Port:** 3005 (host) → 8080 (container) — **Vhost:**
`ai.franksdank.cloud` routes straight to `192.168.0.143:3005` (unguarded —
OpenWebUI enforces its own auth) — **Boot-persistent:** Quadlet — **Docs:**
https://github.com/open-webui/open-webui
## Facts
| Item | Value |
|------|-------|
| Image | `ghcr.io/open-webui/open-webui:main` (CPU build; Dankclaw is CPU-only) |
| Image | `ghcr.io/open-webui/open-webui:main` (verified from the live quadlet unit) |
| Port | 3005 (host) → 8080 (container). Port 3000 is Gitea's HTTP, so it is not usable. |
| Data volume | `/home/dank/Containers/open-webui/data` → `/app/backend/data` |
| Default backend | CIRU llama.cpp on Dankclaw `:7770` = `frank-default-large` (via host LAN IP `192.168.0.143:7770`) |
| Default backend | `frank-large` on Dankclaw `:7770` (ROCmFPX llama.cpp fork — see the LLM knowledge base below) — reached via host LAN IP `192.168.0.143:7770` |
| Network | Pinned bridge `systemd-open-webui` (`10.89.3.0/24`, gateway `10.89.3.1`) — see [History](#history) |
| Persistence | Quadlet unit `open-webui.service`; `[Install] WantedBy=default.target` |
| Deploy | `scripts/deploy-open-webui-quadlet.sh dankclaw` |
## The LLM backends
The fleet runs two OpenAI-compatible endpoints. This mapping is the **live** state (verified 2026-08-22). Both services listen on `:7770`, distinguished by host. On 2026-08-22 `frank-default-large` moved from `:52625` to `:7770`.
The fleet runs two OpenAI-compatible endpoints. This mapping is the **live**
state (verified 2026-09-03). Both services listen on `:7770`, distinguished by
host; `frank-large` moved from `:52625` to `:7770` on 2026-08-22.
| Endpoint | Model name | Host | Capability |
|----------|-----------|------|-----------|
| `:7770` (CIRU llama.cpp) | `frank-default-large` | Dankclaw | completion |
| `:7770` (llama.cpp) | `frank-default-small` | Dankserver | completion, multimodal |
|----------|-----------|------|------------|
| `:7770` (ROCmFPX llama.cpp fork) | `frank-large` | Dankclaw | completion |
| `:7770` (FreeToken v0.1.2) | `frank-small` | Dankserver | completion, multimodal |
The default connection points at the local vLLM (`frank-default-large`), so chat stays on-host. To add the other backend, open **Admin → Connections** in the UI and point an OpenAI connection at `http://192.168.0.235:7770/v1` (key `none`).
The default connection points at the on-host endpoint (`frank-large`).
To add the other backend, open **Admin → Connections** in the UI and point an
OpenAI connection at `http://192.168.0.235:7770/v1` (key `none`).
> Both endpoints are bare-metal systemd services managed by this repository (the former `vllmScripts` repo, merged in 2026-08-22). Model swaps, context sizing, and spec tuning happen here. See the [LLM knowledge base](../LLM/index.md).
> Both endpoints are bare-metal systemd services managed by this repository
(the former `vllmScripts` repo, merged in 2026-08-22). Model swaps, context
sizing, and spec tuning happen there. See the [LLM knowledge
base](../LLM/index.md).
## Boot persistence (Quadlet)
@@ -58,7 +68,7 @@ The quadlet carries a built-in healthcheck (30s interval, 3 retries, 300s start
## Gotchas
- Use the non-CUDA image on this CPU-only host.
- The image tracks upstream `main`; pin a digest in the quadlet unit if reproducible rollback matters more than tracking. (The old "CPU-only host" framing is stale: this APU runs the gfx1151 ROCm build — see [[ComfyUI]].)
- The default admin account is created on first login; secure it immediately.
- If the backend is loading (3–8 minute model load), OpenWebUI shows connection errors until the model is ready.
- The LLM is reached via the host LAN IP `192.168.0.143:7770`, not the bridge gateway: the gateway (`10.89.3.1`) lives in the rootless netns, while llama-server runs in the host netns, so the gateway refuses. `host.containers.internal` is slirp4netns-only and does not resolve on a bridge either. To reach the Dankserver backend, use the LAN address `192.168.0.235:7770`.
+7 -3
View File
@@ -10,7 +10,7 @@ PostgreSQL is the database backend for Gitea. It runs on the same podman network
|------|-------|
| Image | `docker.io/library/postgres:16-alpine` |
| Port | 5432 (internal only) |
| Data volume | bind mount at `/var/lib/postgresql/data` |
| Data volume | `/home/dank/Containers/gitea/postgres:/var/lib/postgresql/data` (live bind, verified from the unit) |
## Configuration
@@ -42,9 +42,13 @@ environment:
The live `app.ini` on the host overrides env vars. When you rename the database container, update its `[database] HOST` line. See [[Gitea]] Gotchas.
## Migration
## Layout (current)
The live Gitea stack on Dankclaw already runs this image with the data at `/opt/gitea/data/gitea-postgres`. The migration keeps the bind mount in place; see [[Gitea]].
The live `gitea-postgres` unit mounts its data at
`/home/dank/Containers/gitea/postgres:/var/lib/postgresql/data` — the old
`/opt/gitea/data/gitea-postgres` compose-era path is gone. Secrets come from
the host-local env file `/home/dank/Containers/gitea/env` (0600) via
`EnvironmentFile=`; `POSTGRES_PASSWORD` never enters this repo. See [[Gitea]].
## Healthcheck
+16 -6
View File
@@ -30,14 +30,19 @@ Port publishing happens on the **gluetun** unit, not on searxng. See [[Gluetun]]
The trio runs as quadlet units, not podman-compose, so it starts at boot. The unit files live in `searxng/quadlet/` and install to `~/.config/containers/systemd/`.
The units live in `dankclaw/searxng/quadlet/` and install to
`~/.config/containers/systemd/` on Dankclaw (verified live):
| Unit file | Service | Role |
|-----------|---------|------|
| `searxng.network` | `searxng-network.service` | DNS-enabled bridge, subnet pinned to 10.89.2.0/24 |
| `gluetun.container` | `gluetun.service` | WireGuard tunnel; publishes 8081:8080 |
| `searxng-valkey.container` | `searxng-valkey.service` | Valkey cache, alias `valkey` |
| `searxng.container` | `searxng.service` | Reuses gluetun's netns; publishes no port |
| `searxng.network` | generated network service | DNS-enabled bridge; the created network is named `systemd-searxng`, subnet pinned to 10.89.2.0/24 |
| `gluetun.container` | `gluetun.service` | WireGuard tunnel (env-file secrets); publishes `8081:8080` — the only published port in the trio |
| `searxng-valkey.container` | `searxng-valkey.service` | Valkey cache on the searxng network, alias `valkey` (see [[Valkey]]) |
| `searxng.container` | `searxng.service` | `Network=gluetun.container` — joins the tunnel's netns, so it publishes no port of its own; reached through gluetun's 8081 |
gluetun and valkey join the searxng network. searxng reuses gluetun's netns and reaches valkey by name on that network. Each unit sets `WantedBy=default.target`. User linger is on, so the units start at boot.
gluetun and valkey join the searxng network. searxng reuses gluetun's netns
and reaches valkey by name on that network. Each unit sets
`WantedBy=default.target`. User linger is on, so the units start at boot.
Deploy with `scripts/deploy-searxng-quadlet.sh dankclaw`. It copies the units, daemon-reloads, enables them, and starts them in dependency order.
@@ -112,7 +117,12 @@ Why so many ranges: rootless podman strips the client IP on published-port hits.
The rate limiter's JSON cap is `API_MAX = 4` requests per IP per hour. The constant is hardcoded in Python (`searx/botdetection/ip_limit.py`). It cannot be raised from `limiter.toml`. `pass_ip` is the only bypass. This is what lets 4 parallel subagents poll the JSON API at full rate without a 429.
Reach SearXNG through Caddy (`search.dankclaw.local`) for browser use. A local subagent can hit the published port directly because its slirp source is now trusted. The searxng subnet 10.89.2.0/24 is in `trusted_proxies`, so Caddy's `X-Forwarded-For` is honored. The subnet is pinned in `searxng.network`, so it stays stable across reboots.
Reach SearXNG through Caddy (`search.franksdank.cloud`, guarded) for browser
use. A local subagent can hit the published port directly because its
slirp/loopback/LAN sources are in `pass_ip`. The searxng network
(`systemd-searxng`, 10.89.2.0/24) is in `trusted_proxies`, so Caddy's
`X-Forwarded-For` is honored. The subnet is pinned in `searxng.network`, so it
stays stable across reboots.
## Unblocking Google & Search Providers
+84 -369
View File
@@ -1,8 +1,24 @@
---
type: reference
title: *arr Stack
description: The *arr automation stack (Prowlarr, Sonarr, Radarr, Lidarr, Readarr, qBittorrent) on FrankBook-Pro — topology, wiring, auth posture, and gotchas.
tags: [arr-stack, prowlarr, sonarr, radarr, lidarr, readarr, qbittorrent, frankbook-pro]
timestamp: 2026-09-03T00:00:00Z
---
# *arr Stack
The *arr suite is a collection of automated media management tools for Usenet and BitTorrent. For Dankserver — which runs Copyparty, Calibre-Web, RomM, and Jellyfin — the *arr stack provides automatic downloading and library management that Copyparty alone does not cover: quality profile enforcement, series/movie discovery, metadata enrichment, and automated file organization.
The *arr suite is a collection of automated media management tools for Usenet
and BitTorrent. The stack runs on **FrankBook-Pro** — the Mac mini that fronts
this household's downloads — as quadlet units inside its podman machine, not on
Dankserver. It provides automatic downloading and library management that
Copyparty alone does not cover: quality profile enforcement, series/movie
discovery, metadata enrichment, and automated file organization.
The core chain is: **Prowlarr** (indexer API aggregator) → **Sonarr/Radarr/Lidarr/Readarr** (media-specific managers) → **qBittorrent** (download client) → **Jellyfin** (media server scan → auto-refresh).
The core chain is: **Prowlarr** (indexer API aggregator) →
**Sonarr/Radarr/Lidarr/Readarr** (media-specific managers) → **qBittorrent**
(download client, sharing the [[Gluetun]] WireGuard tunnel netns) →
**Jellyfin** (media server scan → auto-refresh).
## Service Overview
@@ -12,334 +28,59 @@ The core chain is: **Prowlarr** (indexer API aggregator) → **Sonarr/Radarr/Lid
| Radarr | Movie management | `lscr.io/linuxserver/radarr:latest` | 7878 | 512 MB |
| Sonarr | TV show management | `lscr.io/linuxserver/sonarr:latest` | 8989 | 512 MB |
| Lidarr | Music management | `lscr.io/linuxserver/lidarr:latest` | 8686 | 256 MB |
| Readarr | Ebook/audiobook management | `lscr.io/linuxserver/readarr:latest` | 8787 | 256 MB |
| qBittorrent | Torrent download client | `lscr.io/linuxserver/qbittorrent:latest` | 8080 | 512 MB |
| Jackett | Indexer proxy (optional) | `lscr.io/linuxserver/jackett:latest` | 9117 | 256 MB |
| Whisparr | NSFW movie management (optional) | `lscr.io/linuxserver/whisparr:latest` | 6969 | 256 MB |
| Readarr | Ebook/audiobook management | `lscr.io/linuxserver/readarr:amd64-1.0.980` (pinned — LSIO ships no untagged `latest` for readarr) | 8787 | 256 MB |
| qBittorrent | Torrent download client | `lscr.io/linuxserver/qbittorrent:4.6.7` (pinned; see [[qBittorrent]]) | 8080 (published by the gluetun unit) | 512 MB |
**Minimum total RAM:** ~3 GB for full stack (headroom recommended).
Jackett and Whisparr were evaluated as optional extras but never deployed
(no unit, no vhost, no live container).
## Architecture
## Deployment shape (current)
```mermaid
graph LR
I[Indexers<br/>Torrents, Usenet] --> P[Prowlarr<br/>Indexer Manager]
P --> S[Sonarr<br/>TV]
P --> R[Radarr<br/>Movies]
P --> L[Lidarr<br/>Music]
P --> Rd[Readarr<br/>Books]
S --> Q[qBittorrent]
R --> Q
L --> Q
Rd --> Q
Q --> M1[/tv/]
Q --> M2[/movies/]
Q --> M3[/music/]
Q --> M4[/books/]
M1 --> J[Jellyfin]
M2 --> J
M3 --> J
M4 --> CW[Calibre-Web]
```
Each service is a quadlet `.container` unit in this repo under
`frankbook-pro/<svc>/quadlet/`, installed inside the podman machine at
`/home/core/.config/containers/systemd/<svc>.service` by the frankbook-pro
handler in `scripts/deploy-remote.sh`. Every unit runs with
`PUID=0 PGID=0 TZ=America/Los_Angeles UMASK_SET=022`, mounts its config root at
`/Volumes/COMPLETE/<svc>-data:/config`, publishes its API port on the host, and
runs `Restart=always` with `TimeoutStartSec=900`.
## Docker Compose
qBittorrent is special: it shares the [[Gluetun]] container's network namespace
(`Network=gluetun.container`) so torrent egress never touches the residential
IP. A netns-sharer publishes no ports of its own — qB's WebUI (8080) and
BitTorrent port (6881 TCP+UDP) are published on the gluetun unit instead.
```yaml
networks:
appnet:
driver: bridge
## Historical design-era compose (retired)
services:
prowlarr:
image: lscr.io/linuxserver/prowlarr:latest
container_name: prowlarr
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- UMASK_SET=022
volumes:
- /opt/prowlarr/config:/config
- /mnt/media/downloads:/downloads:ro
ports:
- "9696:9696"
networks: [appnet]
The original design deployed the stack on Dankserver via
`dankserver/compose.yaml` with `/opt/<svc>/config` data roots and
`TZ=America/New_York`. That layout is retired; `dankserver/compose.yaml` is
kept as reference only. Reality (unit files above) wins: data roots are the
Mac's `/Volumes/COMPLETE` (completed media) and `/Volumes/INCOMPLETE`
(in-flight downloads) volumes, mounted into qB at identical paths, and every
unit runs `TZ=America/Los_Angeles`.
radarr:
image: lscr.io/linuxserver/radarr:latest
container_name: radarr
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- UMASK_SET=022
volumes:
- /opt/radarr/config:/config
- /mnt/media/movies:/movies
- /mnt/media/downloads:/downloads
ports:
- "7878:7878"
networks: [appnet]
## Access / auth posture
sonarr:
image: lscr.io/linuxserver/sonarr:latest
container_name: sonarr
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- UMASK_SET=022
volumes:
- /opt/sonarr/config:/config
- /mnt/media/tv:/tv
- /mnt/media/downloads:/downloads
ports:
- "8989:8989"
networks: [appnet]
There is **no Caddy vhost for any arr app** — the *arr stack is exempt by
construction from the Anubis guard chain (its own auth). The stack is reached
directly by IP:port on the LAN (`http://<frankbook-pro>:8989` etc.).
lidarr:
image: lscr.io/linuxserver/lidarr:latest
container_name: lidarr
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- UMASK_SET=022
volumes:
- /opt/lidarr/config:/config
- /mnt/media/music:/music
- /mnt/media/downloads:/downloads
ports:
- "8686:8686"
networks: [appnet]
Auth-config history (verified live 2026-08-29): all five arrs shipped with
`AuthenticationMethod=None` **plus** `AuthenticationRequired=Enabled`. On the
v1 (.NET) apps that combo is self-contradictory — UI Save is permanently
disabled and any settings save throws `DryIoc.ScopedItemException` inside
`AuthorizationMiddleware` (500 sprawl on every page after restart). The valid
representation of "no auth" in v1 is **absence of the `<AuthenticationRequired>`
key**, not the literal string `Disabled` — readarr's config (key absent) booted
clean while its three siblings (key=`Disabled`) 500-sprawled, which is how it
was caught. Fix applied live: key deleted on sonarr/radarr/lidarr/prowlarr,
containers restarted, all five verified serving. Posture = zero-auth arrs on
LAN and WAN; the Anubis wall guards homepage/search/hermes/prometheus/romm/files
but **not** the arrs — first-account-wins is the current race condition if that
ever flips to `External` auth (needs an IdP first; auth method choice remains an
operator decision).
readarr:
image: lscr.io/linuxserver/readarr:latest
container_name: readarr
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- UMASK_SET=022
volumes:
- /opt/readarr/config:/config
- /mnt/media/books:/books
- /mnt/media/downloads:/downloads
ports:
- "8787:8787"
networks: [appnet]
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- UMASK_SET=022
volumes:
- /opt/qbittorrent/config:/config
- /mnt/media/downloads:/downloads
- /mnt/media/downloads/incomplete:/downloads/incomplete
ports:
- "8080:8080"
networks: [appnet]
# Optional: Jackett for niche indexers
jackett:
image: lscr.io/linuxserver/jackett:latest
container_name: jackett
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- UMASK_SET=022
volumes:
- /opt/jackett/config:/config
- /opt/jackett/torrences:/torrences
ports:
- "9117:9117"
networks: [appnet]
# Optional: Whisparr for adult content
whisparr:
image: lscr.io/linuxserver/whisparr:latest
container_name: whisparr
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- UMASK_SET=022
volumes:
- /opt/whisparr/config:/config
- /mnt/media/whisparr-movies:/whisparr-movies
- /mnt/media/downloads:/downloads
ports:
- "6969:6969"
networks: [appnet]
```
## Caddy Configuration
```caddy
radarr.dankserver.local {
reverse_proxy localhost:7878
}
sonarr.dankserver.local {
reverse_proxy localhost:8989
}
lidarr.dankserver.local {
reverse_proxy localhost:8686
}
readarr.dankserver.local {
reverse_proxy localhost:8787
}
prowlarr.dankserver.local {
reverse_proxy localhost:9696
}
qbittorrent.dankserver.local {
reverse_proxy localhost:8080
}
# Optional: Jackett
jackett.dankserver.local {
reverse_proxy localhost:9117
}
# Optional: Whisparr
whisparr.dankserver.local {
reverse_proxy localhost:6969
}
```
## Configuration Steps
### Phase 1: Download Client
1. Deploy qBittorrent first (or Transmission).
2. In the qBittorrent Web UI, set **No auth mode** for LAN (Settings → Web UI).
3. Create download categories: `movies`, `tv`, `music`, `books`.
4. Change the default Web UI password.
### Phase 2: Indexer Management
1. Deploy Prowlarr.
2. Add indexers (3–5 recommended for testing). Use the **Test** button on each.
3. Add qBittorrent as a download client in Prowlarr.
4. Verify search from the Prowlarr web UI.
### Phase 3: Arr Apps (one at a time)
1. Deploy Sonarr first (TV shows are the most common use case).
2. Add Prowlarr as the indexer source (Settings → Indexers → Add Prowlarr).
3. Add qBittorrent as the download client with categories.
4. Add a test series. Wait for the episode to download. Verify in `/tv/`.
5. Repeat for Radarr, Lidarr, Readarr.
### Phase 4: Media Server Integration
1. Configure Jellyfin libraries pointing to `/movies`, `/tv`, `/music`, `/books`.
2. Set **On Download** notifications in each arr app → Jellyfin webhook URL.
3. Test end-to-end: Add a movie in Radarr → download → verify in Jellyfin.
## Quality Profiles
Each arr app uses a hierarchical quality system:
1. **Quality Profile** — Defines tiers (e.g., 2160p → 1080p BluRay → 720p).
2. **Cutoff** — The quality target. Downloads at or above cutoff are accepted.
3. **Custom Formats** — Additional filters (e.g., "Has HDR", "Is Director's Cut").
4. **Search on Grab** — When content becomes available, all indexers are queried.
### Radarr (Movies)
```
Profile: Movies 4K
Tiers:
1. 2160p BluRay REMUX
2. 2160p BluRay
3. 2160p WEB-DL
4. 1080p BluRay
5. 1080p WEB-DL
6. 720p
Cutoff: 1080p BluRay
```
### Sonarr (TV)
```
Profile: TV - Standard
Tiers: 2160p → 1080p → 720p
Min Size: 500 MB
Max Size: 50 GB
Cutoff: 1080p
Language Profile: English audio preferred
```
### Lidarr (Music)
```
Profile: Music - Standard
Tiers: Lossless (FLAC) → 320 kbps → 192 kbps
Cutoff: 320 kbps (or Lossless)
```
## Metadata Sources
| App | Primary Source | Secondary |
|-----|---------------|-----------|
| Radarr | TMDB | TheMovieDB API |
| Sonarr | TMDB | TVDB |
| Lidarr | MusicBrainz | — |
| Readarr | Goodreads, StoryGraph | — |
| Whisparr | XH | TMDB |
## *arr Stack vs Copyparty
| Feature | Copyparty | *arr Stack |
|---------|-----------|------------|
| Auto-download from torrents | Basic (RSS + scripts) | Native, integrated |
| Quality profiles | No | Multi-tier, custom formats |
| Series/movie tracking | No | Watch lists, air dates |
| Manual library management | Yes | Yes, metadata-driven |
| Multi-user watchlists | No | Yes |
| Complexity | Low | Medium |
| Resource usage | Minimal | Moderate |
Use Copyparty for curated file collections. Use *arr for automatic downloads. Use both together for maximum functionality — point *arr download directories at Copyparty's watched folders.
## Live State (as-built, verified 2026-08-29)
Deployed shape differs from the design compose above — reality wins:
- Mounts are the real array paths (`/mnt/entropy/downloads`, case-exact dirs
like `Movies`/`TVShows`), not `/mnt/media/*`; TZ is `America/Los_Angeles`.
- Readarr runs `lscr.io/linuxserver/readarr:amd64-1.0.980` — LSIO ships no
untagged `latest` for readarr; the tag was pinned after a manifest probe.
- Prowlarr's `/config` mount was missing mid-deploy (off-by-one in an edit);
restored in commit `67695cf`.
- **Auth posture: every arr runs `AuthenticationMethod=None` +
`AuthenticationRequired=Enabled`** — verified live via each config.xml and by
probing `/api/v3/system/status` unauthenticated (401 on all five, local and
through the vhost). Net effect: a login screen with **zero users defined**;
whoever creates the first account owns the instance. Decide the auth method
(`None` behind the Anubis wall vs `External` via authentik) *before* WAN
exposure — first-account-wins is the current race condition.
- API keys live in each `/config/config.xml` (`<ApiKey>`); they are local-only
secrets and stop being secret the moment a vhost serves the API unauthenticated.
### Chain wiring (verified live 2026-08-29)
## Chain wiring (verified live 2026-08-30)
The download chain is wired and test-first verified: **indexers → Prowlarr →
per-arr qBittorrent clients (category = app name) → import**.
@@ -364,72 +105,46 @@ per-arr qBittorrent clients (category = app name) → import**.
and hand off to their own qB download client (category routing). Mappings
materialize at grab time — zero mappings right after wiring is expected,
not a fault.
**Chain complete (same day):** all four arr roots live — Sonarr `/tv`,
Radarr `/movies` (201), and Lidarr `/music` + Readarr `/books` created via
API after the v1 validator layers peeled back one at a time
(`defaultQualityProfileId`/`defaultMetadataProfileId` must reference an
*existing* profile id on v1 apps; v1 has no `/api/v1/profile` endpoint —
probe endpoints by status code, empty body = absent).
**Auth-config pitfall (found same day):** all five arrs shipped with
`AuthenticationMethod=None` **plus** `AuthenticationRequired=Enabled`. On the
v1 (.NET) apps that combo is self-contradictory — UI Save is permanently
disabled and any settings save throws
`DryIoc.ScopedItemException` inside `AuthorizationMiddleware` (500 sprawl on
every page after restart). The valid representation of "no auth" in v1 is
**absence of the `<AuthenticationRequired>` key**, not the literal string
`Disabled` — readarr's config (key absent) booted clean while its three
siblings (key=`Disabled`) 500-sprawled, which is how it was caught. Fix
applied live: key deleted on sonarr/radarr/lidarr/prowlarr, containers
restarted, all five verified serving. Posture = zero-auth arrs on LAN and
WAN; the Anubis wall guards homepage/search/hermes/prometheus/romm/files
but **not** the arrs — if WAN exposure of `/sonarr`, `/radarr` etc. is
undesired, guard them in the Anubis policy or flip auth to `External`
(needs an IdP first; auth method choice remains an operator decision).
## Disk Layout
## Disk layout (current)
```
/mnt/media/
├── movies/ → Radarr root
├── tv/ → Sonarr root
├── music/ → Lidarr root
├── books/ → Readarr root
├── whisparr-movies/ → Whisparr root
├── downloads/ → qBittorrent download dir
│ ├── movies/
│ ├── tv/
│ ├── music/
│ └── books/
└── incomplete/ → qBittorrent incomplete downloads
/Volumes/COMPLETE <- completed-media volume (Mac volume)
├── sonarr-data:/config <- per-app config roots, one per unit
├── radarr-data:/config
├── lidarr-data:/config
├── readarr-data:/config
├── qbittorrent-data:/config
└── <movie/tv/music/books roots> <- arr import roots live here
/Volumes/INCOMPLETE <- qB in-flight downloads (same path inside qB)
```
qB mounts both volumes at their identical host paths
(`Volume=/Volumes/COMPLETE:/Volumes/COMPLETE`,
`Volume=/Volumes/INCOMPLETE:/Volumes/INCOMPLETE`), so a category's download path
is the same string on every container that touches it — no remapping between
download and import.
## Gotchas
- **Timezone mismatch:** All containers should use the same TZ. Sonarr's scheduler is timezone-sensitive.
- **File permissions:** Set `umask=022` in qBittorrent. Ensure arr apps can read/move downloaded files.
- **Network conflicts:** *arr apps use many ports. Check for conflicts with existing Dankserver services.
- **Prowlarr API key rotation:** If rotated, update it in every arr app.
- **qBittorrent Web UI password:** Change default on first run.
- **Readarr stability:** Readarr is still in development. Do not rely on it for mission-critical collections.
- **Whisparr separate Jellyfin library:** Keep adult content separate from regular media.
- **RSS feed in qBittorrent:** Can auto-add torrents matching a pattern. Useful for podcast-like series.
- **Timezone:** every unit runs `TZ=America/Los_Angeles`; Sonarr's scheduler is timezone-sensitive — keep them uniform.
- **File permissions:** `UMASK_SET=022` on qBittorrent; arr apps run PUID=0 so they can read/move qB downloads.
- **Network conflicts:** *arr apps use many ports. On the machine VM, only the API ports (8989/7878/8686/8787/9696) and gluetun's published 8080 + 6881 are host-published; netns-sharers (qB) publish none of their own.
- **Prowlarr API key rotation:** If rotated, update it in every arr app (`Applications` table rows carry the real keys).
- **qBittorrent WebUI password:** generated at first boot, not a default — persist it via the PBKDF2 conf recipe in [[qBittorrent]] before any restart.
- **Readarr stability:** abandoned upstream (retired May 2026); its qB download client is parked pending a successor image. Do not rely on it for mission-critical collections.
## Best Practices
1. Use tags to route content to specific download clients or categories.
2. Enable the Blocklist in arr apps to prevent re-downloading failed torrents.
3. Set download limits in qBittorrent to avoid bandwidth saturation.
4. Back up arr configs regularly (they are small SQLite DBs + JSON).
4. Back up arr configs regularly (they are small SQLite DBs + JSON) — each lives at `/Volumes/COMPLETE/<svc>-data/config`.
5. Monitor Prowlarr indexer health — broken indexers hide new content.
6. Start with default quality profiles. Add custom formats gradually.
7. Back up arr configs: `./radarr/config`, `./sonarr/config`, etc.
## See Also
- [[Dankserver Stack]]
- [[Sonarr]] · [[Radarr]] · [[Lidarr]] · [[Readarr]] · [[Prowlarr]] · [[qBittorrent]] — per-service pages
- [[Jellyfin]] — media server that consumes *arr downloads
- [[Copyparty]] — alternative file viewer
- [[Calibre-Web]] — manual ebook management (Readarr auto-downloads into the same library)
- [Sonarr Wiki](https://wiki.servarr.com/sonarr)
- [Radarr Wiki](https://wiki.servarr.com/radarr)
@@ -2,14 +2,16 @@
Calibre-Web is a web application that browses, reads, and downloads eBooks from an existing Calibre library database. It serves as the web frontend for the Calibre e-book manager.
**Host:** Dankserver — **Hostname:** `books.dankserver.local` — **Docs:** https://github.com/linuxserver/docker-calibre-web
**Host:** Dankserver — **Access:** `books.franksdank.cloud` (unguarded Caddy
vhost — Calibre-Web serves its own login; direct proxy to
`192.168.0.235:8083`) — **Docs:** https://github.com/linuxserver/docker-calibre-web
## Facts
| Item | Value |
|------|-------|
| Latest version | 0.6.25-ls365 (live); 0.6.27-ls397 upstream |
| Image | `lscr.io/linuxserver/calibre-web:latest` (live: 0.6.25-ls365) |
| Running image | `lscr.io/linuxserver/calibre-web:0.6.27-ls397` — **pinned** (verified from the live quadlet unit; the pin was chosen so the cutover changed zero bits of application code) |
| Network | `pasta` (the default rootless-podman userslide network); only 8083 is host-published |
| Base OS | Ubuntu Noble (24.04 LTS, since 2024-12-05) |
| Port | 8083 (host) → 8083 (container) |
| Default login | `admin` / `admin123` |
@@ -34,7 +36,7 @@ Additional packages added: `libxfixes3` and `libasound2t64` to support epub-to-p
|----------|-------|-------------|
| `PUID` | `1000` | User ID |
| `PGID` | `1000` | Group ID |
| `TZ` | `Etc/UTC` | Timezone |
| `TZ` | `America/Vancouver` (live unit value — not `Etc/UTC`) |
| `DOCKER_MODS` | `linuxserver/mods:universal-calibre` | Optional: enables ebook conversion tools |
| `OAUTHLIB_RELAX_TOKEN_SCOPE` | `1` | Required for Google OAuth |
+9 -4
View File
@@ -25,16 +25,21 @@ Calibre 9.2.1 is the version on the live host (9.9.0 is the upstream latest). Ma
## Library Directory
| Purpose | Host path (convention) |
|---------|------------------------|
| Calibre library | `/opt/calibre-web/books` (bind-mounted to `/books` in the Calibre-Web container) |
The live Calibre-Web container bind-mounts the library at `/books`:
| Purpose | Host path (live) |
|---------|------------------|
| Calibre library | `/home/dank/Containers/calibre-web/books` → `/books` in the Calibre-Web container |
(The older `/opt/calibre-web/books` path was the compose-era location and is
gone; the quadlet unit mounts the Containers data root.)
## What the Container Needs
- Read/write access to the library directory. Calibre-Web edits metadata through the database file.
- Ownership matching `PUID=1000` / `PGID=1000` (the `dank` user on Dankserver).
## Optional: Calibre Content Server
## Optional: Calibre Content Server (not running)
Calibre includes a built-in HTTP content server (`calibre-server`) that can serve the library via OPDS feeds and a mobile-friendly web interface. This enables:
- OPDS feeds for mobile reading apps (FBReader, Moon+ Reader)
+16 -13
View File
@@ -2,14 +2,16 @@
Copyparty is a lightweight file server and media streamer that runs as a single Python binary. It handles large payloads, media streaming, resumable uploads, directory browsing, and WebDAV from one process.
**Host:** Dankserver — **Hostname:** `files.dankserver.local` — **Docs:** https://github.com/9001/copyparty
**Host:** Dankserver — **Access:** `files.franksdank.cloud` guarded by the
Anubis → Authentik chain ([[Caddy]] routes it post-auth to
`192.168.0.235:3923`); the published port itself stays unauthenticated on the
LAN — **Docs:** https://github.com/9001/copyparty
## Facts
| Item | Value |
|------|-------|
| Latest version | v1.20.21 (2026-08) |
| Image | `ghcr.io/9001/copyparty-ac:latest` (ac = full edition; the bare `copyparty:latest` tag does not exist — ghcr answers 403 on the token request for nonexistent repos) |
| Running image | `ghcr.io/9001/copyparty-ac:latest` (ac = full edition; the bare `copyparty:latest` tag does not exist — ghcr answers 403 on the token request for nonexistent repos). Version at research time (2026-08): v1.20.21 |
| Port | 3923 (host) → 3923 (container) |
| Volume | bind mount the shared root directory |
| Auth | Per-directory `.cpy` config files, HTTP basic auth, `dirkeys`, `filekeys` |
@@ -72,13 +74,12 @@ The `iv` edition is no longer available for arm32/armv6. Use `dj` for maximum co
## Volumes
Live deployment: the whole LUKS array is served at URL `/w` (the ac edition
takes its volume roots from argv plus `chdir: /w` in `/z/initcfg`, not from a
`/data` convention). Access is **read-only since 2026-08-31** (`-v /w::r:ra,dank`
— see [[#Command-line interface (ac edition)]] above). The compose bind mount is
`/mnt/entropy:/w` (host path → container path). Note the bind itself is still
rw on disk — copyparty enforces read-only at the application layer, so local
services (Jellyfin, Calibre) keep writing into the array directly.
Live deployment: the whole LUKS array is served at URL `/w` via
`Volume=/mnt/entropy:/w:ro` in the quadlet unit ([[Entropy Volume]]) —
read-only **at the mount level**, so no containerized consumer can write into
the array through this path regardless of account permissions. The ac edition
takes its volume roots from argv (`-v /w::r:ra,dank`), not from a `/data`
convention; see [[#Command-line interface (ac edition)]] above.
## Docker Compose (reference — retired 2026-09-01; live deployment is the quadlet unit below)
@@ -146,13 +147,15 @@ Upgrade to v1.20.19+ to cover all known CVEs. The dirkey fix (v1.20.17) matters
- **Large transfers:** Disable TLS inside the app and let Caddy terminate TLS. This avoids double encryption overhead.
- **Dedicated share directory:** Do not give Copyparty the whole disk. Mount only the intended share path.
- **Whole-disk share (live choice):** this deployment *does* serve the whole
91 T array from `/w`. Since 2026-08-31 the volume is application-level
read-only for every account, so no remote write path exists. But note:
~91 T array from `/w`. The volume is mounted `:ro` in the unit AND the
permission flags grant anonymous only `r`, so no remote write path exists at
all now. But note:
**LAN-direct `:3923` is unauthenticated browse/download** (anonymous holds
`r`) — Caddy + Anubis + authentik guard only `files.franksdank.cloud`, not
the published port. Tighten to `-v /w::r,dank` if anonymous LAN reads become
unacceptable. (Before 2026-08-31, `-v /w::A` made the array world-writable
on the LAN — see [[#Command-line interface (ac edition)]].)
on the LAN — see [[#Command-line interface (ac edition)]] — and the mount
was rw.)
- **Upload tokens scoped per folder:** Prevents accidental global write access.
- **CSP nonces (v1.20.17+):** Security hardening for JavaScript execution. May break third-party JS plugins (`--js-browser` / `--html-head`).
- **Custom thumbnail extractors (v1.20.19+):** New `thumbex` framework. Requires configuration in `initcfg`.
@@ -1,45 +1,40 @@
# Dankserver Stack
Dankserver (192.168.0.235) runs the media and library stack. Every service is reachable by hostname through the Caddy reverse proxy on the host.
Dankserver (192.168.0.235) runs the media and library stack. Public access
goes through the Caddy reverse proxy on Dankclaw; the *arr stack is exempt by
construction — it has no vhost and is reached directly by IP:port on the LAN.
```mermaid
graph LR
U[User] --> C[Caddy :80/:443]
C --> R[RomM]
C --> P[Copyparty]
C --> W[Calibre-Web]
C --> J[Jellyfin]
C --> S[Sonarr]
C --> D[Radarr]
C --> L[Lidarr]
C --> A[Readarr]
C --> O[Prowlarr]
W --> L2[Calibre library]
U[User] --> C[Caddy :80/:443 on Dankclaw]
C -->|guarded: Anubis + Authentik| R[RomM :8085]
C -->|guarded| P[Copyparty :3923]
C -->|unguarded| W[Calibre-Web :8083]
C -->|unguarded| J[Jellyfin :8096]
C -->|exempt by construction| X[Plex :32400]
U -->|direct IP:port, no vhost| S[ARR stack + Prowlarr + qBittorrent on FrankBook-Pro]
```
## Services
| Service | Hostname | Port | Docs |
|---------|----------|------|------|
| RomM | romm.dankserver.local | 8085 | [[RomM]] |
| Copyparty | files.dankserver.local | 3923 | [[Copyparty]] |
| Calibre-Web | books.dankserver.local | 8083 | [[Calibre-Web]] |
| Jellyfin | jellyfin.dankserver.local | 8096 | [[Jellyfin]] |
| Sonarr | sonarr.dankserver.local | 8989 | [[ARR-Stack]] |
| Radarr | radarr.dankserver.local | 7878 | [[ARR-Stack]] |
| Lidarr | lidarr.dankserver.local | 8686 | [[ARR-Stack]] |
| Readarr | readarr.dankserver.local | 8787 | [[ARR-Stack]] |
| Prowlarr | prowlarr.dankserver.local | 9696 | [[ARR-Stack]] |
| qBittorrent | qbittorrent.dankserver.local | 8080 | [[ARR-Stack]] |
| Service | Public route | Port | Docs |
|---------|--------------|------|------|
| RomM | `romm.franksdank.cloud` (guarded: Anubis → Authentik; post-auth route → 192.168.0.235:8085) | 8085 | [[RomM]] |
| Copyparty | `files.franksdank.cloud` (guarded; post-auth route → 192.168.0.235:3923) | 3923 | [[Copyparty]] |
| Calibre-Web | `books.franksdank.cloud` (unguarded — own login) | 8083 | [[Calibre-Web]] |
| Jellyfin | `jelly.franksdank.cloud` (unguarded — own auth) | 8096 | [[Jellyfin]] |
| Plex | `plex.franksdank.cloud` (+ legacy plain-HTTP `plex.franksdank.casa`) | 32400 | [[Plex]] |
## Optional Services
The *arr stack (Sonarr 8989, Radarr 7878, Lidarr 8686, Readarr 8787,
Prowlarr 9696) and qBittorrent (8080, behind the [[Gluetun]] tunnel netns)
run on **FrankBook-Pro**, not on this host — see [[ARR-Stack]]; none of them
have a Caddy vhost.
These services are included in the compose file but may be disabled.
## Never-deployed services
| Service | Hostname | Port | Docs |
|---------|----------|------|------|
| Jackett | jackett.dankserver.local | 9117 | [[ARR-Stack]] |
| Whisparr | whisparr.dankserver.local | 6969 | [[ARR-Stack]] |
Jackett and Whisparr were evaluated during the ARR-stack design phase and
never deployed (no unit, no vhost, no live container). Prowlarr covers the
indexer-aggregation role — see [[Prowlarr]].
## Removed Services
+49 -207
View File
@@ -1,226 +1,68 @@
---
type: reference
title: Jellyfin
description: Jellyfin media server on Dankserver — quadlet unit, entropy-volume data layout, ports, client access, and hardware-transcode status.
tags: [jellyfin, dankserver, media-server]
timestamp: 2026-09-03T00:00:00Z
---
# Jellyfin
Jellyfin is a free, open-source media server and suite of applications for organizing, managing, and streaming personal media collections (movies, TV shows, music, photos) to networked devices. It is a community fork of Emby, written in C# (.NET), and uses FFmpeg for transcoding.
Jellyfin is the free media server on Dankserver — a podman quadlet service
(`jellyfin.service`, generated from `dankserver/jellyfin/quadlet/jellyfin.container`)
serving music, movies, and shows over LAN. It replaced the earlier research
brief; it runs alongside [[Plex]], which remains the primary server for some
clients.
**Host:** Dankserver — **Hostname:** `jellyfin.dankserver.local` — **Docs:** https://jellyfin.org
**Host:** Dankserver (192.168.0.235) — **Access:** `http://192.168.0.235:8096`,
public vhost `jelly.franksdank.cloud` behind the [[Anubis]] guard chain →
[[Authentik]] outpost (post-auth route proxies `localhost:8096`).
## Facts
## Facts (verified from the live unit, 2026-09-03)
| Item | Value |
|------|-------|
| Latest version | Check https://jellyfin.org/downloads |
| Image | `jellyfin/jellyfin:latest` (Docker Hub) or `ghcr.io/jellyfin/jellyfin` |
| Base | Debian-based |
| Primary port | 8096 (HTTP, web UI + API) |
| HTTPS port | 8920 (optional) |
| Client discovery | 7359/udp |
| DLNA | 1900/udp (optional) |
| GPU passthrough | `/dev/dri` (Intel QSV / AMD VA-API) or NVIDIA NVENC |
| License | MIT |
| Unit | `~/.config/containers/systemd/jellyfin.container` → `jellyfin.service` (user manager), `Restart=always`, `RestartSec=5` |
| Image | `ghcr.io/jellyfin/jellyfin:latest` |
| Network | `dankserver_appnet`; publishes 8096/tcp, 8920/tcp, 7359/udp, 1900/udp |
| Data roots | `/home/dank/Containers/jellyfin/config:/config`, `/home/dank/Containers/jellyfin/cache:/cache` |
| Media | `Volume=/mnt/entropy:/data:ro` — the whole [[Entropy Volume]] mounted read-only; nothing automated writes to it |
| GPU | none — no `AddDevice`; CPU decode only (jellyfin-ffmpeg path) |
| Env quirks | `DOTNET_SYSTEM_IO_DISABLEFILELOCKING=true`, `LD_PRELOAD=libjemalloc.so.2`, `MALLOC_TRIM_THRESHOLD_=131072` kept verbatim from the compose-era container (zero-drift cutover) |
| Health | `curl -f http://localhost:8096/health` every 30 s |
## Architecture
## Data layout
```mermaid
graph LR
U[User] --> C[Caddy :80/:443]
C --> J[Jellyfin :8096]
J --> Lib[/media/movies]
J --> Lib2[/media/shows]
J --> Lib3[/media/music]
J --> Conf[Jellyfin config]
J --> Cache[Jellyfin cache]
```
/home/dank/Containers/jellyfin/config -> /config (JELLYFIN_DATA_DIR)
/home/dank/Containers/jellyfin/cache -> /cache (JELLYFIN_CACHE_DIR, XDG_CACHE_HOME)
/mnt/entropy -> /data (read-only media volume)
```
## Docker Compose (reference — retired 2026-09-01; live mounts use `/home/dank/Containers/jellyfin`, see Deployment below)
Library folders point at `/data` paths; because the mount uses the same
absolute path as on the host, library paths survive container recreation.
```yaml
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
user: "1000:1000"
ports:
- "8096:8096/tcp"
- "8920:8920/tcp"
- "7359:7359/udp"
- "1900:1900/udp"
environment:
- JELLYFIN_PublishedServerUrl=http://192.168.0.235:8096
- DOTNET_SYSTEM_IO_DISABLEFILELOCKING=true
volumes:
- /opt/jellyfin/config:/config
- /opt/jellyfin/cache:/cache
- /mnt/media/movies:/data/movies:ro
- /mnt/media/shows:/data/shows:ro
devices:
- /dev/dri:/dev/dri
group_add:
- "992" # Host render group GID — verify with `getent group render`
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8096/health"]
interval: 30s
timeout: 10s
retries: 3
```
## Ports & access
## Caddy Configuration
| Port | Proto | Purpose |
|------|-------|---------|
| 8096 | TCP | Web UI + API (`JELLYFIN_PublishedServerUrl=http://192.168.0.235:8096`) |
| 8920 | TCP | DLNA/UPnP root device control |
| 7359 | UDP | service discovery (client auto-discovery) |
| 1900 | UDP | SSDP discovery |
```caddy
jellyfin.dankserver.local {
reverse_proxy 127.0.0.1:8096
Client access paths and the public-exposure policy (auth wall required before
any public vhost; Plex-style claim tokens do not exist here — Jellyfin uses its
own users/API keys) follow the fleet [[Authentik]]/[[Anubis]] chain pattern.
transport http {
versions h2c 1.1
}
}
```
## Configuration workflow
Set **Base URL** to `/` (or the path you configure) in Jellyfin Dashboard → Networking. Add `127.0.0.1` to **Known Proxies**.
## Storage
| Mount | Purpose | Size Estimate |
|-------|---------|---------------|
| `/home/dank/Containers/jellyfin/config` | SQLite database, settings, cached images | 10–100 GB |
| `/home/dank/Containers/jellyfin/cache` | Transcoding segments, extracted posters | Self-cleaning per session |
| `/mnt/entropy/Movies`, `/mnt/entropy/TVShows` | Media, **read-only binds** (`:ro`) — no automated write path | — |
The database must be on local storage (SSD/NVMe preferred). Media libraries can be on NFS/mergerfs. If media is on NFS, set `DOTNET_SYSTEM_IO_DISABLEFILELOCKING=true`.
## Deployment (Quadlet)
Since 2026-09-01: `dankserver/jellyfin/quadlet/jellyfin.container` →
`jellyfin.service` (generator-enabled), deployed with
`./scripts/deploy.sh dankserver --service jellyfin`. GPU passthrough uses
`AddDevice=/dev/dri` — plain `Device=` is **not** a quadlet key and makes the
v1 generator reject the whole unit (learned live: "unsupported key 'Device'
in group 'Container'"). Entropy mounts stay `:ro`; the container runs as
root inside the user namespace, so the render-node ACLs apply via the device
cgroup regardless of `GroupAdd=keep-groups`.
## Authentication
- **Built-in auth:** per-user libraries, parental controls, max bitrate
limits. The local `dank` admin account is built-in; its password is
Frank's bootstrap value — never recorded in this repo. (2026-09-01: a
corrupted session-archive reading briefly suggested the password had
changed; verified offline against the stored PBKDF2-SHA512 hash, the
bootstrap value still authenticates.)
- **LDAP via Authentik (live 2026-09-01):** the LDAP-Auth plugin
authenticates users against the authentik LDAP outpost on Dankclaw — see
[[Authentik]] for the outpost unit, provider, and RBAC objects.
### LDAP-Auth plugin (v23.0.0.0, live 2026-09-01)
- **Install from the GitHub releases zip** — `repo.jellyfin.org`'s stable
manifest path 404s here, so fetch
`jellyfin/jellyfin-plugin-ldapauth` release asset
`ldap-authentication_23.0.0.0.zip` from GitHub and unzip into
`config/plugins/LDAP-Auth_23.0.0.0/`. The config lives at
`config/plugins/configurations/LDAP-Auth.xml` — write it directly, then
restart the service.
- **Live config:** server `192.168.0.143:389`, base DN
`dc=franksdank,dc=cloud`, bind DN
`cn=svc-jellyfin-ldap,ou=users,dc=franksdank,dc=cloud`, bind password =
the authentik outpost token (secret — the XML lives on the host only,
never in the repo), search filter
`(memberOf=cn=jellyfin_users,ou=groups,dc=franksdank,dc=cloud)`, admin
filter on `cn=jellyfin_admins,ou=groups,…`, `CreateUsersFromLdap=true`
(auto-create on first login).
- **Attribute separator is a comma.** `LdapSearchAttributes` is
`Split(',')` in the plugin source — a semicolon-separated list
(`uid;cn;mail;displayName`) parses as ONE bogus attribute, the search
silently matches nothing, and the log says `Found no users matching X`.
Use `uid,cn,mail,displayName`.
- **Username attribute is `cn`.** Authentik 2026.x maps `uid` to an opaque
per-user hash, not the username, so `uid=<name>` never matches. Set
`LdapUsernameAttribute=cn` (authentik exposes the username as `cn`).
- **Verify with a throwaway user:** create a test member of
`jellyfin_users` in authentik, then
`POST /Users/AuthenticateByName` with headers `Content-Type:
application/json` **and** `X-Emby-Authorization: MediaBrowser
Client="…", Device="…", DeviceId="…", Version="10.11.0"` — both are
required in 10.11 (missing `X-Emby-Authorization` → 400). 200 + non-admin
policy = LDAP path works. Delete the test user from authentik **and**
Jellyfin afterward.
- **Plugin load lines only show in `journalctl --user -u jellyfin.service`**
(`Loaded plugin: LDAP-Auth 23.0.0.0`) — `podman logs` does not carry the
loader lines in this image.
## Metadata Scraping
| Provider | Content | Type |
|----------|---------|------|
| TheMovieDb (TMDb) | Movies, TV shows, posters, fan art, overviews | Default |
| OMDb API | Movies only, English metadata | Default |
| TheTVDB | TV shows, episodes | Plugin |
| fanart.tv | Extra artwork, banners, thumbnails | Plugin |
| AniDB | Anime metadata | Plugin |
| MusicBrainz | Music metadata | Plugin |
| Open Subtitles | Subtitle downloads | Plugin |
| Intro Skipper | TV show intro detection | Plugin |
## Clients
| Platform | App | Quality |
|----------|-----|---------|
| Web | Jellyfin Web | Excellent |
| Android | Jellyfin (Google Play / F-Droid) | Excellent |
| Android TV / Fire TV | Jellyfin | Good |
| iOS / iPadOS | Swiftfin (third-party) | Good |
| Desktop | Jellyfin Media Player (mpv-based) | Excellent |
| Roku | Jellyfin (Channel Store) | Good |
| Kodi | Jellyfin addon | Excellent |
| Samsung/LG Smart TVs | TV browser | Fair |
## Jellyfin vs Plex
| Feature | Jellyfin | Plex |
|---------|----------|------|
| Cost | Free, no tiers | Free core; Plex Pass ($5/mo or $120 lifetime) |
| License | MIT | Proprietary |
| Account required | No | Yes |
| Hardware transcoding | Free | Plex Pass required |
| Mobile sync | Free | Plex Pass |
| Live TV / DVR | Free | Plex Pass |
| Client apps | Good, improving | Excellent, widest device support |
Run Jellyfin alongside Plex for an incremental migration. Point Jellyfin at the same media folders as Plex. Watch history and metadata will not transfer cleanly.
## Resource Requirements
- **Idle / Direct Play:** ~200–500 MB RAM, <5% CPU. Negligible.
- **1080p transcode (CPU):** 40–60% CPU on a modern multi-core CPU.
- **1080p transcode (with QSV):** 3–5% CPU.
- **4K HDR transcode (with QSV):** 5–15% CPU.
- **Minimum host RAM:** 4 GB. 8 GB comfortable for transcoding.
## Deployment Checklist
1. Verify GPU on host: `ls -l /dev/dri/`, `lspci | grep -i vga`, `getent group render`.
2. Install media drivers: `sudo apt install intel-media-va-driver-non-free vainfo intel-gpu-tools`.
3. Create directories: `/home/dank/Containers/jellyfin/config`, `/home/dank/Containers/jellyfin/cache`.
4. Write compose file, verify device and GID.
5. Deploy: `podman compose up -d`.
6. Test GPU passthrough: `podman exec jellyfin /usr/lib/jellyfin-ffmpeg/vainfo --display drm --device /dev/dri/renderD128`.
7. Configure Caddy reverse proxy. Set Known Proxies in Jellyfin.
8. Add media libraries in Dashboard.
9. Install plugins: Open Subtitles, fanart.tv, Intro Skipper.
10. Test playback on Android/Chrome.
## Gotchas
- **GPU passthrough silently failing:** `/dev/dri` must be passed and the correct render node used. Verify with `vainfo` inside the container.
- **Wrong render group GID:** Common GID is 992, but varies per host. Run `getent group render` to find it.
- **Subtitle burn-in triggers full transcode:** PGS (image-based) subtitles force full video transcoding. SRT/ASS (text-based) play fine.
- **Database on NFS:** SQLite on network storage causes slow startup and corruption risk. Keep `/config` on local storage.
- **Client bitrate limit too low:** Many clients default to 20 Mbps. Set Max Streaming Bitrate to Original or Maximum.
- **Naming convention mismatches:** Non-standard folder/file names cause missing metadata. Use `Movie Title (Year)` for movies and `Show Name/Season 01/Show Name S01E01.mkv` for TV.
1. Create libraries pointing at `/data` folders (movies, shows, audio).
2. Set metadata/language preferences (`LANG=en_US.UTF-8` pinned in the unit).
3. Configure clients to use `http://192.168.0.235:8096` or the guarded vhost.
## See Also
- [[Dankserver Stack]]
- [[ARR-Stack]] — automated download into Jellyfin libraries
- [[Copyparty]] — alternative file viewer for existing collections
- Plex — existing media server on this host
- [[Plex]] — co-resident media server on the same volume
- [[Entropy Volume]] — the 91 T array mounted read-only at `/data`
- [[Caddy]] · [[Anubis]] · [[Authentik]] — edge chain for `jelly.franksdank.cloud`
+6 -6
View File
@@ -1,10 +1,10 @@
# Plex
Plex Media Server is the **containerized media server on Dankserver**: a
podman quadlet (`plex.service`) under the systemd **user** generator,
generated from `dankserver/plex/quadlet/plex.container`. It is the only media
server actually listening on this host. Jellyfin, by contrast, is a research
brief on this host, not a running service (see [[Jellyfin]]).
Plex Media Server is a **containerized media server on Dankserver**: a podman
quadlet (`plex.service`) under the systemd **user** generator, generated from
`dankserver/plex/quadlet/plex.container`. It shares the host with a second live
media server, [[Jellyfin]] (`jellyfin.service`, listening on 8096); both serve
from the same read-only Entropy Volume mount.
**Host:** Dankserver — **Ports:** 32400/tcp (PMS web + API), 32400 is the
only port PMS needs for client streaming; LAN clients connect directly,
@@ -21,7 +21,7 @@ public traffic can be fronted by Caddy like every other vhost.
| Identity | fleet rootless model — container root maps to the `dank` user (1000:1000); the deployer chowns the data root on first cutover |
| Port | `32400/tcp` published on `0.0.0.0` — zero client reconfiguration |
| Network | `dankserver_appnet`, alias `plex`; Tautulli reaches it at `http://plex:32400` |
| GPU | none by decision — CPU decode only; the RTX 3090 stays dedicated to `frank-default-small` |
| GPU | none by decision — CPU decode only; the RTX 3090 stays dedicated to `frank-small` |
| Deploy | `./scripts/deploy.sh dankserver --service plex` |
| Docs | https://support.plex.tv |
+15 -12
View File
@@ -2,14 +2,15 @@
RomM (ROM Manager) is a self-hosted ROM library manager and player. It scans a ROM collection, enriches it with metadata and cover art from multiple providers, and serves it through a clean web interface. RomM also supports browser-based emulation via EmulatorJS and native emulator streaming.
**Host:** Dankserver — **Hostname:** `romm.dankserver.local` — **Docs:** https://docs.romm.app
**Host:** Dankserver — **Access:** `romm.franksdank.cloud` guarded by the
Anubis → Authentik chain ([[Caddy]] routes it post-auth to
`192.168.0.235:8085`) — **Docs:** https://docs.romm.app
## Facts
| Item | Value |
|------|-------|
| Latest version | 5.2.0 (released 2026-07-29) |
| Image | `ghcr.io/rommapp/romm:latest` |
| Running image | `ghcr.io/rommapp/romm:latest` (rolling tag — no pin; the version claims on this page were true at research time; verify against the live container before relying on them) |
| Port | 8085 (host) → 8080 (container) |
| Database | MariaDB (default); PostgreSQL optional |
| Cache / Queue | Redis or Valkey (required for task queue) |
@@ -21,7 +22,9 @@ RomM (ROM Manager) is a self-hosted ROM library manager and player. It scans a R
## Architecture
RomM 5.2.0 requires three supporting services. The compose stack includes `romm`, `mariadb`, and `redis` (or `valkey`).
Current RomM releases require MariaDB plus Redis (or Valkey) for the task
queue; this deployment runs **redis** (`REDIS_HOST=redis` in the live unit),
not valkey.
```mermaid
graph LR
@@ -68,7 +71,7 @@ These are set via environment variables or in `config.yml`:
| `MOBYGAMES_API_KEY` | MobyGames | Paid hobbyist API. Note: RomM recommends Screenscraper as free alternative. |
| `RETROACHIEVEMENTS_API_KEY` | RetroAchievements | Hash-based achievements via bundled RAHasher binary. |
| `STEAMGRIDDB_API_KEY` | SteamGridDB | Custom cover art via the search cover button. |
| `HASHEOUS_API_ENABLED` | Hasheous | Set to `true`. Free, hash-based, proxies IGDB data. Fast scans. |
| `HASHEOUS_API_ENABLED` | Hasheous | Set to `true` in the live unit env file. Free, hash-based, proxies IGDB data. Fast scans. |
| `PLAYMATCH_API_ENABLED` | Playmatch | Set to `true`. Multi-provider hash matching (IGDB, SS, SteamGridDB, RA). |
### Config File
@@ -117,15 +120,15 @@ Since 2026-09-01 the trio runs as repo-tracked quadlet units, deployed with
## Volumes
The live unit mounts one root bind — `Volume=/home/dank/Containers/romm:/romm`
— so `/romm/config`, `/romm/library`, `/romm/resources`, and `/romm/assets`
all resolve inside a single host-side data root:
| Container path | Host path |
|----------------|-----------|
| `/romm/library` | `/home/dank/Containers/romm/library` |
| `/romm/resources` | `/home/dank/Containers/romm/resources` |
| `/romm/config` | `/home/dank/Containers/romm/config` |
| `/var/lib/mysql` | `/home/dank/Containers/romm/mariadb` (mapped subuid owner — never chown) |
| `/data` (redis) | `/home/dank/Containers/romm/redis` (mapped subuid owner) |
The library volume contains ROM files and subdirectories per platform. The resources volume stores cached artwork, metadata, and the asset cache. The config volume holds `config.yml` and other configuration.
| `/romm/*` (single root bind) | `/home/dank/Containers/romm/*` |
| `/var/lib/mysql` (romm-mariadb) | `/home/dank/Containers/romm/mariadb` (mapped subuid owner — never chown) |
| `/data` (romm-redis) | `/home/dank/Containers/romm/redis` (mapped subuid owner) |
The cutover rescued RomM's anonymous `/romm` volume (assets, plus empty
mountpoint stubs that shadowed nothing) into the data root before first unit
+39 -23
View File
@@ -1,8 +1,19 @@
---
type: reference
title: Lidarr
description: Lidarr music manager in the *arr stack on FrankBook-Pro — live quadlet deployment, ports, volumes, and wiring facts.
tags: [lidarr, arr-stack, frankbook-pro]
timestamp: 2026-09-03T00:00:00Z
---
# Lidarr
Lidarr manages music albums in the *arr stack on Dankserver. It automatically searches, downloads, and organizes albums from indexers into the Jellyfin music library.
Lidarr manages music albums in the *arr stack. The stack runs on
**FrankBook-Pro** (the Mac mini) as quadlet units inside its podman machine —
not on Dankserver. It searches, downloads, and organizes albums from indexers
into the Jellyfin music library.
**Host:** Dankserver — **Hostname:** `lidarr.dankserver.local` — **Docs:** https://wiki.servarr.com/lidarr
**Host:** FrankBook-Pro (podman machine) — **Access:** direct port `8686` (no reverse-proxy vhost; the *arr stack is exempt by construction from the Anubis guard chain) — **Docs:** https://wiki.servarr.com/lidarr
## Facts
@@ -10,36 +21,41 @@ Lidarr manages music albums in the *arr stack on Dankserver. It automatically se
|------|-------|
| Image | `lscr.io/linuxserver/lidarr:latest` |
| Port | 8686 (host) → 8686 (container) |
| Env | `PUID=0`, `PGID=0`, `TZ=America/Los_Angeles`, `UMASK_SET=022` |
| Config root | `/Volumes/COMPLETE/lidarr-data:/config` |
| Min RAM | 256 MB |
| Metadata | MusicBrainz |
## Docker Compose
## Deployment (current)
```yaml
lidarr:
image: lscr.io/linuxserver/lidarr:latest
container_name: lidarr
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- UMASK_SET=022
volumes:
- /opt/lidarr/config:/config
- /mnt/media/music:/music
- /mnt/media/downloads:/downloads
ports:
- "8686:8686"
networks: [appnet]
Quadlet unit `lidarr.container` from this repo (`frankbook-pro/lidarr/quadlet/`)
is installed inside the podman machine at
`/home/core/.config/containers/systemd/lidarr.service` by the frankbook-pro
handler in `scripts/deploy-remote.sh`. Unit shape:
```ini
[Container]
ContainerName=lidarr
Image=lscr.io/linuxserver/lidarr:latest
Environment=PUID=0
Environment=PGID=0
Environment=TZ=America/Los_Angeles
Environment=UMASK_SET=022
Volume=/Volumes/COMPLETE/lidarr-data:/config
PublishPort=8686:8686
[Service]
TimeoutStartSec=900
Restart=always
```
## Configuration
1. Add Prowlarr as the indexer source (prefer torrent-based indexers for FLAC).
2. Add qBittorrent as the download client with the `music` category.
1. Add Prowlarr as the indexer source (prefer torrent-based indexers for FLAC —
the Nyaa feed carries music categories; see [[Prowlarr]]).
2. Add qBittorrent as the download client with the `music` category ([[qBittorrent]]).
3. Set quality profile (Lossless → High Bitrate → Standard).
4. Set root folder to `/music`.
4. Set the root folder to the music root under the COMPLETE volume.
5. Add artists and verify downloads.
## Gotchas
+62 -27
View File
@@ -1,47 +1,82 @@
---
type: reference
title: MariaDB (RomM Backend)
description: MariaDB 11 database backend for RomM on Dankserver — quadlet unit, network alias, env-file secret handling, and backup path.
tags: [mariadb, romm, dankserver]
timestamp: 2026-09-03T00:00:00Z
---
# MariaDB (RomM Backend)
MariaDB 11 provides the database backend for RomM on Dankserver. RomM 5.2.0 requires MariaDB (or PostgreSQL) for its data store.
MariaDB 11 provides the database backend for [[RomM]] on Dankserver. RomM's
current release requires MariaDB (or PostgreSQL) for its data store; this
deployment uses MariaDB.
**Host:** Dankserver — **Docs:** https://mariadb.com/kb/en/docker-mariadb-information/
**Host:** Dankserver — container name `romm-mariadb`, unit
`romm-mariadb.service` (user-manager quadlet from
`dankserver/romm/quadlet/romm-mariadb.container`).
## Facts
## Facts (verified from the live unit)
| Item | Value |
|------|-------|
| Image | `docker.io/mariadb:11` |
| Port | 3306 (internal, within `appnet`) |
| Database name | `romm` |
| Data volume | `/opt/romm/mariadb` |
| Image | `docker.io/library/mariadb:11` |
| Port | 3306 — internal only; the unit publishes **no** port, so the DB is unreachable from the host network by construction |
| Network | `dankserver_appnet` with `alias=mariadb` — RomM reaches it via `DB_HOST=mariadb` |
| Database / user | `romm` / `romm` |
| Data volume | `/home/dank/Containers/romm/mariadb:/var/lib/mysql` |
| Secrets | supplied via `EnvironmentFile=/home/dank/Containers/romm/env` (mode 0600, host-local — `MARIADB_ROOT_PASSWORD` and friends never enter the repo) |
## Docker Compose
## Unit shape (as deployed)
```yaml
mariadb:
image: docker.io/mariadb:11
container_name: romm-mariadb
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: "${MARIADB_ROOT_PASSWORD}"
MARIADB_DATABASE: romm
MARIADB_USER: "${ROMM_DB_USER}"
MARIADB_PASSWORD: "${ROMM_DB_PASSWD}"
volumes:
- /opt/romm/mariadb:/var/lib/mysql
healthcheck:
test: ["CMD", "mariadb-admin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 3
```ini
[Unit]
Description=RomM mariadb container
After=network.target
Wants=romm-redis.service
[Container]
ContainerName=romm-mariadb
Image=docker.io/library/mariadb:11
Network=dankserver_appnet:alias=mariadb
EnvironmentFile=/home/dank/Containers/romm/env
Environment=MARIADB_DATABASE=romm
Environment=MARIADB_USER=romm
Volume=/home/dank/Containers/romm/mariadb:/var/lib/mysql
HealthCmd=mariadb-admin ping -h localhost
HealthInterval=30s
HealthTimeout=10s
HealthRetries=3
[Service]
Restart=always
RestartSec=5
```
`MARIADB_ROOT_PASSWORD` and `MARIADB_PASSWORD` are read from the env file at
container-create time (`EnvironmentFile=` appears in both `[Container]` and
`[Service]` so `podman generate systemd`-style regeneration keeps them). The
root password is a real secret — per repo secret rules it lives only in the
host-local env file, never in git.
## Boot order
RomM declares `Wants=romm-mariadb.service` + `After=romm-mariadb.service`, so
a cold boot starts the database first; the health ping (`mariadb-admin ping`)
is what marks the unit healthy for anything gating on it.
## Backup
Back up the volume directory periodically:
Back up the volume directory periodically (stop-free: rsync of a quiet DB dir):
```bash
sudo rsync -a /opt/romm/mariadb /mnt/backup/romm-mariadb/
sudo rsync -a /home/dank/Containers/romm/mariadb /mnt/backup/romm-mariadb/
```
For consistency-critical dumps prefer `mariadb-dump` over file copy; the data
dir copy is only safe while RomM traffic is idle.
## See Also
- [[RomM]] — service that uses this database
- [[redis]] — the sibling cache/queue container on the same network
+54 -39
View File
@@ -1,20 +1,55 @@
---
type: reference
title: Prowlarr
description: Prowlarr indexer-management layer for the *arr stack on FrankBook-Pro — feed routes, sync model, API surface, and verified live gotchas.
tags: [prowlarr, arr-stack, frankbook-pro]
timestamp: 2026-09-03T00:00:00Z
---
# Prowlarr
Prowlarr is the indexer management layer for the *arr stack. It hosts the
indexer definitions and exposes them as Torznab feeds and downloads;
Sonarr, Radarr, Lidarr, and Readarr query those feeds and receive results.
**Host:** Dankserver — **Hostname:** `prowlarr.dankserver.local` — **Docs:** https://wiki.servarr.com/prowlarr
**Host:** FrankBook-Pro (podman machine) — **Access:** direct port `9696` (no
reverse-proxy vhost; the *arr stack is exempt by construction from the Anubis
guard chain) — **Docs:** https://wiki.servarr.com/prowlarr
## Facts
| Item | Value |
|------|-------|
| Image | `lscr.io/linuxserver/prowlarr:latest` |
| Image | `lscr.io/linuxserver/prowlarr:latest` (runs v2.5.2 line) |
| Port | 9696 (host) → 9696 (container) |
| Env | `PUID=0`, `PGID=0`, `TZ=America/Los_Angeles`, `UMASK_SET=022` |
| Config root | `/Volumes/COMPLETE/prowlarr-data:/config` |
| Min RAM | 256 MB |
| Auth | Forms (web UI) + API key (`/api/v1/...` and feed routes) |
## Deployment (current)
Quadlet unit `prowlarr.container` from this repo
(`frankbook-pro/prowlarr/quadlet/`), installed inside the podman machine at
`/home/core/.config/containers/systemd/prowlarr.service` by the frankbook-pro
handler in `scripts/deploy-remote.sh`:
```ini
[Container]
ContainerName=prowlarr
Image=lscr.io/linuxserver/prowlarr:latest
Environment=PUID=0
Environment=PGID=0
Environment=TZ=America/Los_Angeles
Environment=UMASK_SET=022
Volume=/Volumes/COMPLETE/prowlarr-data:/config
PublishPort=9696:9696
[Service]
TimeoutStartSec=900
Restart=always
```
## Live wiring (verified end-to-end 2026-08-30)
Indexer queries flow **through** Prowlarr; a grab hands off to the querying
@@ -35,35 +70,17 @@ http://prowlarr:9696/{indexerId}/download?link=...&file=... (torrent handoff)
The global API key is in `config.xml` (`<ApiKey>`); per-application keys are
only used by Prowlarr's own sync calls, NOT by the feeds. The arr download
clients authenticate to qBittorrent with the permanent WebUI password stored
in `/home/dank/.qbpass` (mode 600) on Dankserver.
in `/home/dank/.qbpass` (mode 600, owner `dank`) on Dankserver — see
[[qBittorrent]] for why that password must be pinned in the conf file.
**Readarr caveat:** Readarr is abandoned upstream (last release 0.4.x); its
qBittorrent client cannot authenticate against qB 5 (`Authentication
failure` on the connection test while Sonarr/Lidarr/Radarr pass with the
same credentials). The books pipeline is parked pending a Readarr successor;
the indexer row itself is healthy.
**Readarr caveat:** Readarr is abandoned upstream; its qBittorrent client
cannot authenticate against newer qB Web-API versions (`Authentication
failure` on the connection test while Sonarr/Lidarr/Radarr pass with the same
credentials — root cause: qB ≥ 5's 204 empty-body login success, fixed fleet-
wide by pinning qB to 4.6.7). The books pipeline is parked pending a Readarr
successor; the indexer row itself is healthy.
## Docker Compose
```yaml
prowlarr:
image: lscr.io/linuxserver/prowlarr:latest
container_name: prowlarr
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- UMASK_SET=022
volumes:
- /opt/prowlarr/config:/config
- /mnt/media/downloads:/downloads:ro
ports:
- "9696:9696"
networks: [appnet]
```
## Gotchas (all verified live 2026-08-30)
## Gotchas (verified live 2026-08-30)
- **The feed route is `/{indexerId}/api`.** There is no `/torznab/{id}/feed`
— that path (and any other unmatched path) hits the Forms-auth catch-all
@@ -92,12 +109,13 @@ prowlarr:
- Instance name/`InstanceName=Prowlarr` in `config.xml` does NOT prefix the
API/feed routes on this build (they answer at root; the `/Prowlarr/...`
prefix 302s to the SPA).
- **Application auto-sync cannot manage these rows** (they carry
`SyncLevel=2`): `POST /api/v1/applications/test` fails with
`Unable to cast object of type 'NzbDrone.Core.Thing…'` — Prowlarr v1
cannot deserialize Radarr 6.3's newer response types. The manual Torznab
rows above are therefore the real integration; sync neither duplicates
nor clobbers them.
- **Application auto-sync model (v2):** Applications are first-class rows in
the `Applications` table; each of the four app rows (sonarr/radarr/lidarr/
readarr) carries the real baseUrl+apiKey with `SyncLevel=FullSync`. The
earlier v1-era failure where `POST /api/v1/applications/test` threw
`Unable to cast object of type 'NzbDrone.Core.Thing…'` (v1 could not
deserialize Radarr 6.3's newer response types) is historical — it was the
reason the manual Torznab rows were created in the first place.
- Prowlarr runs `AuthenticationMethod=Forms` + `AuthenticationRequired=Enabled`
healthily — the DryIoc crash combo was `None`+`Enabled` only (see
[[radarr]] auth notes).
@@ -105,7 +123,4 @@ prowlarr:
## See Also
- [[ARR-Stack]] — full *arr stack documentation
- [[radarr]]
- [[sonarr]]
- [[lidarr]]
- [[readarr]]
- [[Radarr]] · [[Sonarr]] · [[Lidarr]] · [[Readarr]] · [[qBittorrent]]
+66 -38
View File
@@ -1,27 +1,44 @@
---
type: reference
title: qBittorrent
description: qBittorrent download client for the *arr stack — pinned 4.6.7 on FrankBook-Pro, shares the Gluetun WireGuard netns, PBKDF2 WebUI credential recipe.
tags: [qbittorrent, arr-stack, frankbook-pro, gluetun]
timestamp: 2026-09-03T00:00:00Z
---
# qBittorrent
qBittorrent is the torrent download client for the *arr stack on Dankserver. It receives download requests from Sonarr, Radarr, Lidarr, and Readarr via category tagging.
qBittorrent is the torrent download client for the *arr stack. The stack runs on
**FrankBook-Pro** (the Mac mini) as quadlet units inside its podman machine —
not on Dankserver. It receives download requests from Sonarr, Radarr, Lidarr,
and Readarr via category tagging.
**Host:** Dankserver — **Hostname:** `qbittorrent.dankserver.local` — **Docs:** https://www.qbittorrent.org
**Host:** FrankBook-Pro (podman machine) — **Access:** WebUI on port `8080`,
published by the [[Gluetun]] unit because qBittorrent shares that container's
network namespace (a netns-sharer publishes no ports of its own).
## Facts
| Item | Value |
|------|-------|
| Image | `lscr.io/linuxserver/qbittorrent:latest` |
| Port | 8080 (host) → 8080 (container) |
| Min RAM | 512 MB |
| Auth | Web UI username/password; LAN mode available |
| Image | `lscr.io/linuxserver/qbittorrent:4.6.7` — **pinned**, see the pin rationale below |
| Network | `Network=gluetun.container` (torrent egress exits via the WireGuard/ProtonVPN tunnel) |
| Ports | 8080 (WebUI) and 6881 TCP+UDP published on the gluetun unit |
| Env | `PUID=0`, `PGID=0`, `TZ=America/Los_Angeles`, `UMASK_SET=022` |
| Volumes | `/Volumes/COMPLETE/qbittorrent-data:/config`, plus `/Volumes/COMPLETE` and `/Volumes/INCOMPLETE` mounted at identical paths |
| Auth | Web UI username/password (`admin` + generated password); LAN bypass not used |
## Configuration
## Why the 4.6.7 pin exists (2026-09-01)
1. Keep Web UI authentication ON (LAN bypass not needed — the arr apps
authenticate with the API) and give them a permanent password.
2. Create download categories per app (`radarr`, `sonarr`, `lidarr`,
`readarr`): the arr download clients route category-per-app, and Prowlarr
feeds hand grabs to each app's own client.
3. Set max active downloads: Settings → Downloads (recommended: 5 global,
3 per category).
Readarr's abandoned qBittorrent client rejects qB ≥ 5's **204 empty-body login
success** as `Authentication failure` — a runtime break, not just an API-create
issue. The fleet pins `lscr.io/linuxserver/qbittorrent:4.6.7` while Readarr is
in the stack. **Never unpin to `latest` while Readarr is in the fleet.**
Second trap on any version flip: qB 5.x's shutdown conf rewrite leaves a
`WebUI\Password_PBKDF2=@ByteArray(...)` line that 4.6.7 rejects — every login
then returns "invalid credentials" (the arrs included). Fix = rewrite the same
conf line with the same password while qB is stopped.
## Persistent WebUI credentials (verified 2026-08-30)
@@ -46,31 +63,34 @@ val = (base64.b64encode(salt) + b":" + base64.b64encode(h)).decode()
Then `podman start qbittorrent` and confirm login survives a
`podman restart` — the temp-password rotation stops the moment stored
credentials verify. The chosen value lives host-local in
`/home/dank/.qbpass` (mode 600, owner `dank`) — never in git; every arr
download client and `prowlarr.md` reference it. (The classic
`@ByteArray(salt+hash)` form is WRONG for qb5: login 401s on it; verify()
base64-decodes the two halves separately.)
credentials verify. The chosen value lives host-local in `/home/dank/.qbpass`
(mode 600, owner `dank`) — never in git; every arr download client and
[[Prowlarr]] reference it. (The classic `@ByteArray(salt+hash)` form is WRONG
for qb5: login 401s on it; verify() base64-decodes the two halves separately.)
## Docker Compose
## Deployment (current)
```yaml
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- UMASK_SET=022
volumes:
- /opt/qbittorrent/config:/config
- /mnt/media/downloads:/downloads
- /mnt/media/downloads/incomplete:/downloads/incomplete
ports:
- "8080:8080"
networks: [appnet]
Quadlet unit `qbittorrent.container` from this repo
(`frankbook-pro/qbittorrent/quadlet/`), installed inside the podman machine at
`/home/core/.config/containers/systemd/qbittorrent.service` by the
frankbook-pro handler in `scripts/deploy-remote.sh`:
```ini
[Container]
ContainerName=qbittorrent
Image=lscr.io/linuxserver/qbittorrent:4.6.7
Network=gluetun.container
Environment=PUID=0
Environment=PGID=0
Environment=TZ=America/Los_Angeles
Environment=UMASK_SET=022
Volume=/Volumes/COMPLETE/qbittorrent-data:/config
Volume=/Volumes/COMPLETE:/Volumes/COMPLETE
Volume=/Volumes/INCOMPLETE:/Volumes/INCOMPLETE
[Service]
TimeoutStartSec=900
Restart=always
```
## Gotchas (verified live)
@@ -81,9 +101,17 @@ qbittorrent:
download queue" in the arr logs) after any restart.
- API login from `curl` needs a `Referer: http://<host>:<port>/` header
(CSRF protection) or POSTs get rejected even with a valid SID.
- Cookie-name quirk by version: qB 5.x names its WebUI session cookie
`QBT_SID_<port>`; 4.6.7 uses plain `SID`. Any automation must parse the
cookie generically (e.g. `grep -oE '[A-Za-z_]*SID[A-Za-z0-9_]*=[^;[:space:]]*'`)
instead of hard-coding a port-suffixed name, or it fails with 403 cascades
that never reach qB as failed logins.
- Egress verification for this stack must run **inside the gluetun container**
(`podman exec gluetun wget -qO- https://ipinfo.io/json`); running the same
probe one ssh-context out returns the residential IP — a false leak alarm.
- Ensure umask is set to `022` so downloaded files are readable by arr apps.
- Monitor bandwidth limits to avoid saturating the network.
## See Also
- [[ARR-Stack]] — full *arr stack documentation
- [[Gluetun]] — the WireGuard tunnel this container shares
+42 -25
View File
@@ -1,52 +1,69 @@
---
type: reference
title: Radarr
description: Radarr movie manager in the *arr stack on FrankBook-Pro — live quadlet deployment, ports, volumes, and wiring facts.
tags: [radarr, arr-stack, frankbook-pro]
timestamp: 2026-09-03T00:00:00Z
---
# Radarr
Radarr manages movies in the *arr stack on Dankserver. It automatically searches, downloads, and organizes movies from indexers into the Jellyfin media library.
Radarr manages movies in the *arr stack. The stack runs on **FrankBook-Pro**
(the Mac mini) as quadlet units inside its podman machine — not on Dankserver.
It searches, downloads, and organizes movies from indexers into the Jellyfin
movie library.
**Host:** Dankserver — **Hostname:** `radarr.dankserver.local` — **Docs:** https://wiki.servarr.com/radarr
**Host:** FrankBook-Pro (podman machine) — **Access:** direct port `7878` (no reverse-proxy vhost; the *arr stack is exempt by construction from the Anubis guard chain) — **Docs:** https://wiki.servarr.com/radarr
## Facts
| Item | Value |
|------|-------|
| Image | `lscr.io/linuxserver/radarr:latest` (v6 stable) |
| Image | `lscr.io/linuxserver/radarr:latest` (v6 line; v6.3.x verified live 2026-08-30) |
| Port | 7878 (host) → 7878 (container) |
| Env | `PUID=0`, `PGID=0`, `TZ=America/Los_Angeles`, `UMASK_SET=022` |
| Config root | `/Volumes/COMPLETE/radarr-data:/config` |
| Min RAM | 512 MB |
| Metadata | TMDB / TheMovieDB API |
## Docker Compose
## Deployment (current)
```yaml
radarr:
image: lscr.io/linuxserver/radarr:latest
container_name: radarr
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- UMASK_SET=022
volumes:
- /opt/radarr/config:/config
- /mnt/media/movies:/movies
- /mnt/media/downloads:/downloads
ports:
- "7878:7878"
networks: [appnet]
Quadlet unit `radarr.container` from this repo (`frankbook-pro/radarr/quadlet/`)
is installed inside the podman machine at
`/home/core/.config/containers/systemd/radarr.service` by the frankbook-pro
handler in `scripts/deploy-remote.sh`. Unit shape:
```ini
[Container]
ContainerName=radarr
Image=lscr.io/linuxserver/radarr:latest
Environment=PUID=0
Environment=PGID=0
Environment=TZ=America/Los_Angeles
Environment=UMASK_SET=022
Volume=/Volumes/COMPLETE/radarr-data:/config
PublishPort=7878:7878
[Service]
TimeoutStartSec=900
Restart=always
```
## Configuration
1. Add Prowlarr as the indexer source.
2. Add qBittorrent as the download client with the `movies` category.
1. Add Prowlarr as the indexer source (the YTS indexer row feeds Radarr — see [[Prowlarr]]).
2. Add qBittorrent as the download client with the `movies` category ([[qBittorrent]]).
3. Set quality profile and cutoff quality.
4. Set root folder to `/movies`.
4. Set the root folder to the movies root under the COMPLETE volume (Radarr
imports from where [[qBittorrent]] drops completed downloads; first verified
grab+import was a 2160p Dark Knight test on 2026-08-30).
5. Add movies and verify downloads.
## Gotchas
- Radarr v6 is the current stable (v6.3.x as of 2026-08). `:latest` points to the current release.
- Movie renaming produces `Title (Year)` format. Jellyfin scanner handles this.
- File permissions: qBittorrent downloads as PUID; arr apps must read/move files.
- File permissions: qBittorrent downloads as PUID=0; arr apps must read/move files.
## See Also
+56 -30
View File
@@ -1,55 +1,81 @@
---
type: reference
title: Readarr
description: Readarr ebook/audiobook manager in the *arr stack on FrankBook-Pro — retired upstream, pinned image, parked qB download client.
tags: [readarr, arr-stack, frankbook-pro]
timestamp: 2026-09-03T00:00:00Z
---
# Readarr
> **RETIRED (May 2026).** The Servarr Team retired Readarr: its metadata became unusable and the community migration to Open Library stalled. There is no upstream development. Alternatives: the Bookshelf community fork, or the Calibre content server. See [Readarr (Retired)](https://wiki.servarr.com/readarr).
> **RETIRED UPSTREAM (May 2026).** The Servarr Team retired Readarr: its
> metadata became unusable and the community migration to Open Library stalled.
> There is no upstream development. Alternatives: the Bookshelf community fork,
> or the Calibre content server. This instance still runs on a pinned image
> tag; see below.
Readarr manages ebooks and audiobooks in the *arr stack on Dankserver. It automatically searches, downloads, and organizes books into the Calibre library.
Readarr manages ebooks and audiobooks in the *arr stack. The stack runs on
**FrankBook-Pro** (the Mac mini) as quadlet units inside its podman machine —
not on Dankserver. It organizes books into the Calibre library that
[[Calibre-Web]] serves.
**Host:** Dankserver — **Hostname:** `readarr.dankserver.local` — **Docs:** https://wiki.servarr.com/readarr
**Host:** FrankBook-Pro (podman machine) — **Access:** direct port `8787` (no reverse-proxy vhost; the *arr stack is exempt by construction from the Anubis guard chain) — **Docs:** https://wiki.servarr.com/readarr
## Facts
| Item | Value |
|------|-------|
| Image | `lscr.io/linuxserver/readarr:latest` (v0.2.x development) |
| Image | `lscr.io/linuxserver/readarr:amd64-1.0.980` — **pinned tag** (LSIO ships no untagged `latest` for readarr; the tag was pinned after a manifest probe) |
| Port | 8787 (host) → 8787 (container) |
| Env | `PUID=0`, `PGID=0`, `TZ=America/Los_Angeles`, `UMASK_SET=022` |
| Config root | `/Volumes/COMPLETE/readarr-data:/config` |
| Min RAM | 256 MB |
| Metadata | Goodreads / StoryGraph |
| Metadata | Goodreads / StoryGraph (provider status at retirement) |
## Docker Compose
## Deployment (current)
```yaml
readarr:
image: lscr.io/linuxserver/readarr:latest
container_name: readarr
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- UMASK_SET=022
volumes:
- /opt/readarr/config:/config
- /mnt/media/books:/books
- /mnt/media/downloads:/downloads
ports:
- "8787:8787"
networks: [appnet]
Quadlet unit `readarr.container` from this repo (`frankbook-pro/readarr/quadlet/`)
is installed inside the podman machine at
`/home/core/.config/containers/systemd/readarr.service` by the frankbook-pro
handler in `scripts/deploy-remote.sh`. Unit shape:
```ini
[Container]
ContainerName=readarr
Image=lscr.io/linuxserver/readarr:amd64-1.0.980
Environment=PUID=0
Environment=PGID=0
Environment=TZ=America/Los_Angeles
Environment=UMASK_SET=022
Volume=/Volumes/COMPLETE/readarr-data:/config
PublishPort=8787:8787
[Service]
TimeoutStartSec=900
Restart=always
```
## Configuration
1. Add Prowlarr as the indexer source (torrent indexers with book content).
2. Add qBittorrent as the download client with the `books` category.
1. Add Prowlarr as the indexer source (torrent indexers with book content;
the Byrutor row feeds Readarr — see [[Prowlarr]]).
2. The qBittorrent download client is **parked**: Readarr's abandoned client
fails auth against newer qB Web-API versions (see [[qBittorrent]] for the
4.6.7 pin rationale); re-enable only after the image changes. Until then,
books are imported manually or via Calibre tooling.
3. Set author profile (format preference: epub, mobi, etc.).
4. Set quality profile for audiobooks (320 kbps MP3, 128 kbps, lossless).
5. Set root folder to `/books`.
6. Add authors and verify downloads.
5. Set the root folder to the books root under the COMPLETE volume.
## Gotchas
- Readarr is in development (~v0.2.x). Some features may be incomplete.
- Calibre integration is folder-based, not API-based. Readarr drops files into `/books` which Calibre-Web serves.
- Not all indexers have all formats (epub, mobi, pdf). Goodreads/StoryGraph metadata helps match editions.
- Readarr is abandoned upstream (retired May 2026; last line was 0.4.x before
the final tags). The pinned `amd64-1.0.980` tag exists precisely because
`:latest` does not exist for this image on LSIO.
- Calibre integration is folder-based, not API-based. Readarr drops files into
the books root which [[Calibre-Web]] serves.
- Not all indexers carry all formats (epub, mobi, pdf). Goodreads/StoryGraph
metadata helps match editions while those providers still respond.
## See Also
+48 -21
View File
@@ -1,40 +1,67 @@
---
type: reference
title: Redis (RomM Cache / Queue)
description: Redis 7-alpine cache and task-queue backend for RomM on Dankserver — quadlet unit, network alias topology, and backup path.
tags: [redis, romm, dankserver]
timestamp: 2026-09-03T00:00:00Z
---
# Redis (RomM Cache / Queue)
Redis 7 provides the caching and task queue backend for RomM on Dankserver. RomM 5.2.0 requires Redis (or Valkey) for its task queue.
Redis 7 provides the caching and task-queue backend for [[RomM]] on Dankserver.
RomM requires Redis (or Valkey) for its task queue; this deployment runs
stock `redis:7-alpine` — no Valkey here, unlike the SearXNG cache on
Dankclaw ([[Valkey]]).
**Host:** Dankserver — **Docs:** https://redis.io/docs/
**Host:** Dankserver — container name `romm-redis`, unit `romm-redis.service`
(user-manager quadlet from `dankserver/romm/quadlet/romm-redis.container`).
## Facts
## Facts (verified from the live unit)
| Item | Value |
|------|-------|
| Image | `docker.io/redis:7-alpine` |
| Port | 6379 (internal, within `appnet`) |
| Data volume | `/opt/romm/redis` |
| Auth | None (local-only, no password needed) |
| Image | `docker.io/library/redis:7-alpine` |
| Port | 6379 — internal only; no `PublishPort`, so it is unreachable from the host network by construction |
| Network | `dankserver_appnet` with `alias=redis` — that alias is what makes `REDIS_HOST=redis` in the RomM unit resolve |
| Data volume | `/home/dank/Containers/romm/redis:/data` |
| Auth | None — safe precisely because the container is not published anywhere; only appnet members can reach it |
## Docker Compose
## Unit shape (as deployed)
```yaml
redis:
image: docker.io/redis:7-alpine
container_name: romm-redis
restart: unless-stopped
volumes:
- /opt/romm/redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
```ini
[Container]
ContainerName=romm-redis
Image=docker.io/library/redis:7-alpine
Network=dankserver_appnet:alias=redis
Volume=/home/dank/Containers/romm/redis:/data
HealthCmd=redis-cli ping
HealthInterval=10s
HealthTimeout=5s
HealthRetries=3
[Service]
Restart=always
RestartSec=5
[Install]
WantedBy=default.target
```
No `EnvironmentFile` — there is nothing secret in this unit; the auth-less
posture is enforced by network topology (alias-only reachability), not by a
password. If a future client ever needs Redis from outside the appnet, add
`PublishPort` **and** a `requirepass` in the same change — never just the port.
## Backup
```bash
sudo rsync -a /opt/romm/redis /mnt/backup/romm-redis/
sudo rsync -a /home/dank/Containers/romm/redis /mnt/backup/romm-redis/
```
Redis here is cache + queue state; losing it costs queued jobs and cache warm,
not the library (the database lives in [[MariaDB]]).
## See Also
- [[RomM]] — service that uses this cache
- [[Valkey]] — the SearXNG-side equivalent on Dankclaw
+43 -26
View File
@@ -1,53 +1,70 @@
---
type: reference
title: Sonarr
description: Sonarr TV manager in the *arr stack on FrankBook-Pro — live quadlet deployment, ports, volumes, and wiring facts.
tags: [sonarr, arr-stack, frankbook-pro]
timestamp: 2026-09-03T00:00:00Z
---
# Sonarr
Sonarr manages TV shows in the *arr stack on Dankserver. It automatically searches, downloads, and organizes episodes from indexers into the Jellyfin media library.
Sonarr manages TV shows in the *arr stack. The stack runs on **FrankBook-Pro**
(the Mac mini) as quadlet units inside its podman machine — not on Dankserver.
It searches, downloads, and organizes episodes from indexers into the Jellyfin
TV library.
**Host:** Dankserver — **Hostname:** `sonarr.dankserver.local` — **Docs:** https://wiki.servarr.com/sonarr
**Host:** FrankBook-Pro (podman machine) — **Access:** direct port `8989` (no reverse-proxy vhost; the *arr stack is exempt by construction from the Anubis guard chain) — **Docs:** https://wiki.servarr.com/sonarr
## Facts
| Item | Value |
|------|-------|
| Image | `lscr.io/linuxserver/sonarr:latest` (v4 stable) |
| Image | `lscr.io/linuxserver/sonarr:latest` (v4 line) |
| Port | 8989 (host) → 8989 (container) |
| Env | `PUID=0`, `PGID=0`, `TZ=America/Los_Angeles`, `UMASK_SET=022` |
| Config root | `/Volumes/COMPLETE/sonarr-data:/config` |
| Min RAM | 512 MB |
| Metadata | TMDB / TVDB |
## Docker Compose
## Deployment (current)
```yaml
sonarr:
image: lscr.io/linuxserver/sonarr:latest
container_name: sonarr
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- UMASK_SET=022
volumes:
- /opt/sonarr/config:/config
- /mnt/media/tv:/tv
- /mnt/media/downloads:/downloads
ports:
- "8989:8989"
networks: [appnet]
Quadlet unit `sonarr.container` from this repo (`frankbook-pro/sonarr/quadlet/`)
is installed inside the podman machine at
`/home/core/.config/containers/systemd/sonarr.service` by the frankbook-pro
handler in `scripts/deploy-remote.sh`. Unit shape:
```ini
[Container]
ContainerName=sonarr
Image=lscr.io/linuxserver/sonarr:latest
Environment=PUID=0
Environment=PGID=0
Environment=TZ=America/Los_Angeles
Environment=UMASK_SET=022
Volume=/Volumes/COMPLETE/sonarr-data:/config
PublishPort=8989:8989
[Service]
TimeoutStartSec=900
Restart=always
```
## Configuration
1. Add Prowlarr as the indexer source.
2. Add qBittorrent as the download client with the `tv` category.
1. Add Prowlarr as the indexer source (see [[Prowlarr]] — the feed route is `/{indexerId}/api`).
2. Add qBittorrent as the download client with the `tv` category ([[qBittorrent]]).
3. Set quality profile, cutoff, and minimum/maximum episode sizes.
4. Set root folder to `/tv`.
5. Add series and verify downloads.
4. Set the root folder to the TV root under the COMPLETE volume (Sonarr imports
from where [[qBittorrent]] drops completed downloads).
5. Add a test series and verify the grab → download → import chain end-to-end.
## Gotchas
- Sonarr v4 is the current stable. The v3 branch uses the `:v3` tag.
- Anime has different quality profiles and naming conventions than Standard series.
- Missing episodes: set "Unmonitor Missing Episodes" to auto-unmonitor old episodes.
- Timezone-sensitive scheduler: ensure all containers use the same TZ.
- Timezone-sensitive scheduler: every unit in the stack runs
`TZ=America/Los_Angeles`; keep them uniform.
## See Also
@@ -4,9 +4,9 @@ A password-protected web site on Dankclaw lists the services that are up, with a
**Served by:** Caddy, `file_server` + `forward_auth` (Authentik SSO) — **Docs:** this page
## Status — 2026-08-23: deployed to production
## Status — deployed to production (2026-08-23), on the naked domain since 2026-08-24
The homepage is live on Dankclaw. `./scripts/deploy.sh dankclaw` copies the static assets to `/srv/homepage/`, installs the status checker (systemd timer, every 3 min, writes `status.json`), writes `deployed.js` (the last master deployment datetime), renders the Caddyfile (the shared basicauth hash from the host `.env`), reloads Caddy, and checks health. 146 tests pass. The Caddyfile auth uses a `route` block with `forward_auth` (see [Auth](#auth)); the caddy container mounts the host's `/srv/homepage` (not the repo source) so the generated files serve.
The homepage is live on Dankclaw. `./scripts/deploy.sh dankclaw` copies the static assets to `/srv/homepage/`, installs the status checker (systemd timer, every 3 min, writes `status.json`), writes `deployed.js` (the last master deployment datetime), renders the Caddyfile (the shared basicauth hash from the host `.env`), reloads Caddy, and checks health. The Caddyfile auth uses a `route` block with `forward_auth` (see [Auth](#auth)); the caddy container mounts the host's `/srv/homepage` (not the repo source) so the generated files serve.
**Moved to the naked domain (2026-08-24):** the homepage now serves `franksdank.cloud` and `www.franksdank.cloud`. The old names `dankclaw.franksdank.cloud` and `dankserver.franksdank.cloud` redirect to it. Authentication moved from per-page basicauth to Authentik `forward_auth` (see [Authentik](Authentik.md)).
@@ -28,7 +28,7 @@ The site has two pages. The root page lists the user services. The `/admin/` pag
```mermaid
graph TD
subgraph site["dankclaw.franksdank.cloud (Caddy)"]
subgraph site["franksdank.cloud + www (Caddy)"]
ROOT["/ user services<br/>(shared password)"]
ADMIN["/admin/ admin services<br/>(operator password)"]
HOW["/how/ how it is built<br/>(deferred)"]
@@ -85,7 +85,9 @@ flowchart TD
**Admin services** (`/admin/`): Hermes, Grafana, Prometheus, Loki, Caddy, Pi-hole, Gluetun, the LLM fleet, and the low-level backends (mariadb, redis, Postgres, node-exporter, alloy). The backends show status only. They get a link only where a UI is meaningful.
**Excluded for now:** the *arr stack (Radarr, Sonarr, Lidarr, Readarr, Prowlarr, qBittorrent). It is not started. It is a separate effort, possibly on a different host.
**Excluded from the listing:** the *arr stack + qBittorrent (Prowlarr, Sonarr,
Radarr, Lidarr, Readarr, qB) — live on FrankBook-Pro but operator-only: no
vhosts, direct IP:port access only. See [[FrankBook-Pro]].
## Layout
@@ -2,7 +2,9 @@
Prometheus collects metrics from every service on Dankclaw by scraping their `/metrics` endpoints. It feeds the Grafana dashboards. The `node-exporter` containers may add podman/cgroup metrics for full host visibility.
**Host:** Dankclaw — **Hostname:** `prometheus.dankclaw.local` — **Port:** 9090 — **Docs:** https://prometheus.io/docs
**Host:** Dankclaw — **Vhost:** `prometheus.franksdank.cloud` (guarded: Anubis →
Authentik; post-auth the Caddy vhost routes straight to `prometheus:9090`) —
**Port:** 9090 — **Docs:** https://prometheus.io/docs
## Facts
@@ -160,9 +160,9 @@ The DFlash draft is not a standalone model. It must pair with its target model.
## Deployment on Dankserver (NVIDIA RTX 3090)
The Dankserver llama.cpp deployment (`frank-default-small`, Qwen3.6-35B-A3B) is **active** on Dankserver (port 7770) as of the 2026-08-17 redo (the earlier 2026-08-16/17 retirement of this service was reversed when the PP split was retired). The vLLM material below documents the archived AWQ/DFlash path on the same hardware.
The Dankserver llama.cpp deployment (`frank-small`, Qwen3.6-35B-A3B) is **active** on Dankserver (port 7770) as of the 2026-08-17 redo (the earlier 2026-08-16/17 retirement of this service was reversed when the PP split was retired). The vLLM material below documents the archived AWQ/DFlash path on the same hardware.
> **DFlash retired from active service.** `DFlash` (draft-dflash) was tested initially but did not deliver the desired speed gains under the `frank-default-small` workload (see ngram-mod benchmarks below). The `Alittlehammmer/Qwen3.6-35B-A3B-DFlash` draft GGUF remains in `/home/dank/models/` as reference material only.
> **DFlash retired from active service.** `DFlash` (draft-dflash) was tested initially but did not deliver the desired speed gains under the `frank-small` workload (see ngram-mod benchmarks below). The `Alittlehammmer/Qwen3.6-35B-A3B-DFlash` draft GGUF remains in `/home/dank/models/` as reference material only.
The vLLM material below documents the archived AWQ/DFlash path on the same hardware. The RTX 3090 is Ampere (compute capability 8.6). Use these conditions:
@@ -195,7 +195,7 @@ docker run --rm --name vllm-qwen36-dflash \
## Deployment on Dankclaw (AMD Strix Halo gfx1151)
`frank-default-large` on Dankclaw runs the llama.cpp pipeline-parallel head (Qwen3.8-27B-Uncensored Q6_K) on port 7770, RPC-split with the Dankserver worker. Spec is the standalone MTP draft over the ngram-mod fallback, 1 slot at 262144 ctx, q8_0/f16 KV, head GPU side ROCm0. See [[qwen3.8-spec-matrix]] and [[Qwen3.8 PP Deployment]] for the current state and the 2026-08-15 Vulkan0/ROCm0 high-context bench.
`frank-large` on Dankclaw ran the llama.cpp pipeline-parallel head (Qwen3.8-27B-Uncensored Q6_K) on port 7770, RPC-split with the Dankserver worker. Spec was the standalone MTP draft over the ngram-mod fallback, 1 slot at 262144 ctx, q8_0/f16 KV, head GPU side ROCm0. This page is a historical record of that era (mid-August 2026); for the current deployment see [[kingjones-strix-rocmfp4]].
History: before `--spec-default`, the box ran DSpark (`draft-dspark`, retired 2026-08-15 after a ROCm illegal-memory-access crash under two concurrent 16k prompts) and before that bundled MTP (`draft-mtp`, retired same day). DFlash was retired on 2026-08-14 (premature-EOS under parallel load). The old DFlash draft GGUF (`Qwen3.6-27B-DFlash-Q8_0.gguf`), the MTP-only drafter (`Qwen3.6-27B-MTP-ONLY-Q8_0.gguf`), and the DSpark draft (`Qwen3.8-27B-DSpark-Q8_0.gguf`) remain in `/home/dank/models/` as reference only.
@@ -14,7 +14,7 @@ marked "verify first". Re-verified 2026-08-15/16; corrections marked below.
(b10433): Vulkan 25.13 t/s vs ROCm 24.33 t/s decode at 16k; at 262k ctx
Vulkan decodes 48% faster (5.68 vs 3.83 t/s). ROCm wins prefill (410 vs
302 t/s @64k). The "HIP out-performs Vulkan for decode" claim did not
hold on the 8060S. See [[frank-default-large-benchmark]].
hold on the 8060S. See [[frank-large-benchmark]].
- **Power profile**: the `/sys/class/drm/card0/device/power_profile` file
does not exist on this machine (checked 2026-08-15). GPU DPM is already
`performance`, forced level `auto`. This item is N/A.
@@ -40,7 +40,7 @@ lifted to 114 GiB. ROCm/SMI still reports a 96 GiB VRAM carve-out (VGM) — a
different, driver-reported figure that has always been larger than the kernel
cap.
This split is the Strix Halo GTT/VGM design. It drives the batch/ubatch memory
limits documented in [[frank-default-large-benchmark]].
limits documented in [[frank-large-benchmark]].
## 1. Self-Hosted Agentic Tools
@@ -98,7 +98,7 @@ All require root and a reboot for the modprobe change.
## Sources
- [[frank-default-large-benchmark]] — measured backend/spec numbers
- [[frank-large-benchmark]] — measured backend/spec numbers
- [[deployment]] — deploy and update process
- AMD ROCm RDNA3.5 system optimization guide (gfx1151 memory/BIOS)
- llama.cpp source: `ggml/CMakeLists.txt`, `ggml/src/ggml-hip/CMakeLists.txt`,
@@ -107,7 +107,7 @@ All require root and a reboot for the modprobe change.
## See Also
- [[frank-default-large-benchmark]]
- [[frank-large-benchmark]]
- [[DFlash DSpark Speculative Decoding]]
- [[deployment]]
- [[index]]
@@ -38,7 +38,7 @@ Dankclaw is an AMD APU server for CIRU ROCmFPX llama.cpp inference. The host run
| Runtime | FastFlowLM 0.9.45 + XRT (installed 2026-08-16; **retired 2026-08-17**) |
| Status | Not in service. Research only. See [[FastFlowLM NPU Inference]] |
The NPU is retired; the 52625 port and the `frank-default-small` name now serve the CIRU ROCmFPX llama.cpp runtime (see [[ciru-activefpx-promptforge]]).
The NPU is retired; the 52625 port and the `frank-small` name now serve the CIRU ROCmFPX llama.cpp runtime (see [[ciru-activefpx-promptforge]]).
### ROCm
@@ -93,7 +93,7 @@ cable between claw and server is required for 10G.
- Unified memory eliminates separate VRAM limits. The GPU uses system RAM.
- The GPU budget is the rocm-smi figure: 64 GiB VRAM reported by rocm-smi (SVM-backed). The older 96 GiB figure was the addressable SVM pool, not the budget. Trust rocm-smi and the runtime; do not use `free` or `dmidecode` for the GPU budget.
- The active service is `frank-default-large` on port 7770 (moved from 52625 on 2026-08-22): CIRU ROCmFPX llama.cpp serving kingjones/Qwen3.8-27B-Uncensored-ROCmFP4-STRIX-MTP (Q6 AGENT dense, 262144 ctx, standalone MTP Q4_0 head). See [[kingjones-strix-mtp]].
- The active service is `frank-large` on port 7770 (moved from 52625 on 2026-08-22): CIRU ROCmFPX llama.cpp serving kingjones/Qwen3.8-27B-Uncensored-ROCmFP4-STRIX-MTP (Q6 AGENT dense, 262144 ctx, standalone MTP Q4_0 head). See [[kingjones-strix-mtp]].
- The runtime requires ROCm 7.15 (model card requirement). The system ROCm is 7.2.4; the retired ling3-ciru venv bundles a self-contained TheRock ROCm 7.15 SDK that the serve script puts first in `LD_LIBRARY_PATH`.
- The retired vLLM venvs (`/home/dank/vllm-venv`, `/home/dank/vllm-vk-venv`) were moved to `/home/dank/.AGENTTRASH/` on 2026-08-18.
- 1.1 TB free disk space is ample for model storage.
@@ -60,7 +60,7 @@ Dankserver is an NVIDIA GPU server for vLLM inference. The host runs Ubuntu 26.0
### Active Services
The active service on Dankserver is `frank-default-small.service`: the llama.cpp Ornith-1.5-35B-A3B CRACK (Q6_K) on port 7770, with expert tensors selected by `--override-tensor`; every full-attention block plus blocks 35–40 remain on CUDA. The earlier PP worker (`frank-pp-worker.service`) was retired with the 2026-08-17 redo. See [[deployment]].
The active service on Dankserver is `frank-small.service`: the llama.cpp Ornith-1.5-35B-A3B CRACK (Q6_K) on port 7770, with expert tensors selected by `--override-tensor`; every full-attention block plus blocks 35–40 remain on CUDA. The earlier PP worker (`frank-pp-worker.service`) was retired with the 2026-08-17 redo. See [[deployment]].
## Hardware Relevance
@@ -1,7 +1,7 @@
> **SUPERSEDED 2026-08-17.** The Frank redo retired this topology.
> See [frank-redo-2026-08-17.md](frank-redo-2026-08-17.md) and
> [deployment.md](deployment.md) for the active configuration.
> The `frank-default-small` name and port 52625 now belong to the vLLM
> The `frank-small` name and port 52625 now belong to the vLLM
> service on Dankclaw (nameistoken Quark W8A8); this page is archive.
---
@@ -19,7 +19,7 @@ timestamp: 2026-08-16
# FastFlowLM NPU Inference
FastFlowLM (FLM) runs LLMs entirely on the AMD Ryzen AI NPU. It targets XDNA2 chips: Strix, Strix Halo, Kraken, and Gorgon Point. The project describes itself as "Ollama, but deeply optimized for NPUs." As of 2026-08-16, FLM is installed on Dankclaw, the NPU validates, and `frank-default-small` (port 52625) serves in production. See Promotion.
FastFlowLM (FLM) runs LLMs entirely on the AMD Ryzen AI NPU. It targets XDNA2 chips: Strix, Strix Halo, Kraken, and Gorgon Point. The project describes itself as "Ollama, but deeply optimized for NPUs." As of 2026-08-16, FLM is installed on Dankclaw, the NPU validates, and `frank-small` (port 52625) serves in production. See Promotion.
## Verdict (2026-08-16)
@@ -168,7 +168,7 @@ Proposed role: a small, always-on, low-power endpoint for triage, summarization,
- `gpt-oss:20b` pulled (4/4 files verified, 13.8 GB `model.q4nx` + tokenizer) into `~/.config/flm/models/GPT-OSS-20B-NPU2/`.
- `qwythos:9b` (Huihui-Qwythos-9B-Claude-Mythos-5-1M-abliterated-NPU2) installed 2026-08-17 via `flm-add.py` (downloaded from the HF repo; stdlib-only, no pip needed). Tag registered in the user registry `~/.config/flm/model_list.json` (a copy of the v1.0.1 system registry + the custom entry); kernels symlinked `~/.config/flm/xclbins/Huihui-...-NPU2 -> /opt/fastflowlm/share/flm/xclbins/Qwen3.5-9B-NPU2`. The service env exports `FLM_CONFIG_PATH` and `FLM_XCLBIN_PATH` so the tag resolves (without them flm hits the unknown-tag fallback, see the incident below).
- `flm serve gpt-oss:20b --host 0.0.0.0 -p 52625 --pmode performance` runs as a nohup process. It is not a systemd unit. It does not survive a reboot.
- The `llama-server` (frank-default-large, the PP head) holds an fd on `/dev/accel/accel0` from its own startup (device enumeration, not compute). FLM opened the same device concurrently without conflict. Verified live 2026-08-16.
- The `llama-server` (frank-large, the PP head) holds an fd on `/dev/accel/accel0` from its own startup (device enumeration, not compute). FLM opened the same device concurrently without conflict. Verified live 2026-08-16.
## Measured Results (2026-08-16, gpt-oss-20b on the Dankclaw NPU)
@@ -186,7 +186,7 @@ Long-context prefill is not yet measured (runs 1-3 used under 200 prompt tokens)
## Model Bakeoff (measured 2026-08-16, 4 models)
All runs on the Dankclaw NPU (50 TOPS Strix Halo), single stream, `--pmode performance`, PP head (frank-default-large) serving concurrently on 7770. Decode t/s is the FLM-reported rate. Vision accuracy = ground-truth elements out of 4 (text SPECTRUM, red circle left, blue square right, three green triangles bottom).
All runs on the Dankclaw NPU (50 TOPS Strix Halo), single stream, `--pmode performance`, PP head (frank-large) serving concurrently on 7770. Decode t/s is the FLM-reported rate. Vision accuracy = ground-truth elements out of 4 (text SPECTRUM, red circle left, blue square right, three green triangles bottom).
| Model | Tag | Weights | Decode t/s (short) | 8k prefill t/s | 8k decode t/s | Vision decode t/s | Vision accuracy | Max ctx (registry) |
|-------|-----|---------|-------------------:|---------------:|--------------:|------------------:|----------------|--------------------|
@@ -204,21 +204,21 @@ Notes:
## Promotion (2026-08-16)
`frank-default-small` now runs the NPU endpoint on Dankclaw (was the Dankserver llama.cpp service). Unit: `scripts/frank-default-small.service` (symlinked into `/etc/systemd/system`), wrapper `scripts/serve-flm-small.sh`, tunables `scripts/frank-default-small.env`. `LimitMEMLOCK=infinity` is set in the unit. Default model: `gemma4-it:e4b`. Swap `FLM_MODEL` in the env to switch.
`frank-small` now runs the NPU endpoint on Dankclaw (was the Dankserver llama.cpp service). Unit: `scripts/frank-small.service` (symlinked into `/etc/systemd/system`), wrapper `scripts/serve-flm-small.sh`, tunables `scripts/frank-small.env`. `LimitMEMLOCK=infinity` is set in the unit. Default model: `gemma4-it:e4b`. Swap `FLM_MODEL` in the env to switch.
### Boot policy (2026-08-17)
The `frank-default-small` unit is disabled for boot. Only the PP pair (`frank-default-large` + `frank-pp-worker`) starts at boot. The unit file was removed from `/etc/systemd/system`; the running FLM service keeps serving until stopped or rebooted. To restore the endpoint, run these commands on Dankclaw:
The `frank-small` unit is disabled for boot. Only the PP pair (`frank-large` + `frank-pp-worker`) starts at boot. The unit file was removed from `/etc/systemd/system`; the running FLM service keeps serving until stopped or rebooted. To restore the endpoint, run these commands on Dankclaw:
```
sudo ln -sf /home/dank/vllmScripts/scripts/frank-default-small.service /etc/systemd/system/frank-default-small.service
sudo ln -sf /home/dank/vllmScripts/scripts/frank-small.service /etc/systemd/system/frank-small.service
sudo systemctl daemon-reload
sudo systemctl enable frank-default-small
sudo systemctl enable frank-small
```
Live config (2026-08-16): `FLM_PMODE=turbo`, `FLM_ASR=1` (loads Whisper-V3-Turbo-NPU2; exposes `/v1/audio/transcriptions`), `FLM_CTX_LEN=131072` (verified max — Gemma4 natively supports 128K and the NPU budget fits it; KV occupancy measured at 0.11% for a 123-token exchange, decode 12.0 t/s, 13 GiB headroom).
The PP split was renamed `frank-pp-head` → `frank-default-large` (2026-08-16, commit `48142f5`).
The PP split was renamed `frank-pp-head` → `frank-large` (2026-08-16, commit `48142f5`).
Model swap (2026-08-16, commit `50c55ee`): `FLM_MODEL=qwen3.6-moe:35b-a3b`, `FLM_CTX_LEN=262144` (native max), `FLM_PMODE=turbo`, `FLM_ASR=1` kept. Decode measured 12.5-13.1 t/s. The Gemma4 live config above (131072 ctx) applied to `gemma4-it:e4b`. Swap `FLM_MODEL` and `FLM_CTX_LEN` back to restore it.
@@ -277,7 +277,7 @@ graph TD
Symptom: a client on dankware could not reach `qwen3.6-moe:35b-a3b` on port 52625. The journal shows three separate causes in the 14:19-15:03 window.
1. **EXEC 203 crash loop (14:19-14:20).** The exec bit was lost on `serve-flm-small.sh` on the target. The unit failed `status=203/EXEC: Permission denied` four times, then started after the bit was restored. The git mode is `100755` (commit `3f42210`), and a `git pull` restores the bit. Verify with `git ls-files -s scripts/serve-flm-small.sh`.
2. **Wrong model ID (14:29-14:52).** The client config still used the model ID `frank-default-small` (a service alias). FLM rejects that tag with `[ERROR] Model tag 'frank-default-small' is not supported.` Each such request also triggered the unknown-tag fallback below.
2. **Wrong model ID (14:29-14:52).** The client config still used the model ID `frank-small` (a service alias). FLM rejects that tag with `[ERROR] Model tag 'frank-small' is not supported.` Each such request also triggered the unknown-tag fallback below.
3. **Swap churn (14:48-15:03).** The swap `gemma4-it:e4b` → `qwen3.6-moe:35b-a3b` restarted the service several times. Each load of the 23 GB model takes about 1.5-2.5 minutes at 262144 ctx. The endpoint does not serve during a load.
Fix: the client model ID must be the FLM registry tag `qwen3.6-moe:35b-a3b`. The working pi agent entry in `~/.pi/agent/models.json` is `baseUrl http://192.168.0.143:52625/v1`, `id qwen3.6-moe:35b-a3b`, `contextWindow 262144`, `reasoning true`, `input [text, image]`. Verified end-to-end from dankware (192.168.0.226) at 15:32 on 2026-08-16.
@@ -314,7 +314,7 @@ pi sessions failed against this endpoint with `Stream ended without finish_reaso
- **The FLM serve process is not under systemd.** A reboot of Dankclaw kills it. The PP head service is enabled and returns. The FLM process must be restarted by hand. A unit file is a natural next step.
- **gpt-oss reasoning budget.** The model can spend its full token budget on `reasoning_content` and return empty content. Clients must handle or cap this.
- **No llama.cpp GGUF path.** FLM uses its own pre-compiled kernels. Our UD-Q8_K_XL and HauhauCS builds are not importable. NPU work means FLM-specific model tags.
- **NPU production role (2026-08-16).** `frank-default-small` serves `qwen3.6-moe:35b-a3b` on port 52625 (swap churn and the unknown-tag incident are recorded above). The remaining NPU content (benchmarks, runbook steps) is still research until a step lands and is recorded.
- **NPU production role (2026-08-16).** `frank-small` serves `qwen3.6-moe:35b-a3b` on port 52625 (swap churn and the unknown-tag incident are recorded above). The remaining NPU content (benchmarks, runbook steps) is still research until a step lands and is recorded.
## Citations
@@ -26,7 +26,7 @@ conclusions.
| Blocks | 65 (45 on worker, 20 on head) | `--tensor-split 0.68,0.32` |
| FA layers | 16 total, interval 4 (11 worker / 5 head) | GGUF `full_attention_interval` |
| KV per FA layer per token | 3136 B (K q8_0 1088 + V f16 2048) | env file comment, confirmed |
| ubatch | 256 | `UBATCH_SIZE` in `frank-default-large.env` |
| ubatch | 256 | `UBATCH_SIZE` in `frank-large.env` |
| MTP verify step positions | 5 (1 + n_max 4) | `SPEC_DRAFT_N_MAX=4` |
| Link (old path) | 1 GbE via USB-C adapter on claw | `enx00e04cc2e1e5`, negotiated 1000 Mb/s |
| Link (current path) | 2.5 GbE eno1 to eno1 | negotiated 2500 Mb/s both ends |
@@ -189,7 +189,7 @@ For the 2-node pipeline-parallel split (RTX 3090 24 GB + Strix Halo 96 GB):
- **Kept:** Qwen official config.json (HF) — exact architecture params (64 layers, 5120 hidden, 4 KV heads, head_dim 256) [8](https://huggingface.co/Qwen/Qwen3.6-27B/blob/main/config.json)
- **Kept:** bartowski/Qwen_Qwen3.6-27B-GGUF — Q8_0 at 29.12 GB, imatrix calibration [2](https://huggingface.co/bartowski/Qwen_Qwen3.6-27B-GGUF)
- **Kept:** Alittlehammmer/Qwen3.6-27B-DFlash-GGUF-llama.cpp — DFlash 2B draft GGUF model [4](https://huggingface.co/Alittlehammmer/Qwen3.6-27B-DFlash-GGUF-llama.cpp)
- **Kept:** frank-default-large-benchmark.md — Project spec benchmarks (MTP, DFlash, ngram-mod comparison) [5](../frank-default-large-benchmark.md)
- **Kept:** frank-large-benchmark.md — Project spec benchmarks (MTP, DFlash, ngram-mod comparison) [5](../frank-large-benchmark.md)
- **Kept:** a4lg/Qwen3.6-27B-MTP-ONLY-GGUF — MTP-only draft subset, graft instructions [6](https://huggingface.co/a4lg/Qwen3.6-27B-MTP-ONLY-GGUF)
- **Kept:** llama.cpp tools/rpc/README.md — RPC backend, weight/KV split, remote host setup [7](https://github.com/ggerganov/llama.cpp/blob/master/tools/rpc/README.md)
- **Kept:** Unsloth Qwen3.6-27B-MTP-GGUF — MTP command-line usage for llama.cpp [9](https://huggingface.co/unsloth/Qwen3.6-27B-MTP-GGUF)
@@ -11,7 +11,7 @@ morning-of runbook. Research background:
## Production state (2026-08-17: Q6_K, q8_0/f16 KV, split 0.68)
This split is the production `frank-default-large` service. Current
This split is the production `frank-large` service. Current
state, verified against the live journal and output smoke tests
(2026-08-17, load 02:06):
@@ -32,17 +32,17 @@ state, verified against the live journal and output smoke tests
Vulkan).
- Worker steady state: 23854/24576 MiB used, ~273 MiB free (tight but
stable; all allocations are upfront).
- Unit `frank-default-large.service`, launched through
`serve-pp-head.sh` + `frank-default-large.env`.
- Unit `frank-large.service`, launched through
`serve-pp-head.sh` + `frank-large.env`.
## Service enablement (2026-08-17)
The PP pair is the only inference service enabled for boot. Both units
(`frank-default-large` on Dankclaw, `frank-pp-worker` on Dankserver) are
enabled. The NPU unit (`frank-default-small` on Dankclaw) and all retired
(`frank-large` on Dankclaw, `frank-pp-worker` on Dankserver) are
enabled. The NPU unit (`frank-small` on Dankclaw) and all retired
units are disabled. Restart order: worker first, then head. The Dankserver
helper `frank-restart-small.sh` is obsolete (it restarts the removed
`frank-default-small` unit); restart the worker with
`frank-small` unit); restart the worker with
`sudo systemctl restart frank-pp-worker`. The Dankclaw helper
`frank-restart-large.sh` (sync + cache drop + restart) is correct for the
head. `deploy.sh dankserver` is broken until retargeted. See
@@ -164,9 +164,9 @@ llama-server b10433 ggml-rpc-server b10433
|------|---------|---------|
| `scripts/frank-pp-worker.env` | server | worker tunables (bind, port, device, cache) |
| `scripts/serve-pp-worker.sh` | server | runs `ggml-rpc-server` from the b10433 worktree build |
| `scripts/frank-default-large.env` | claw | head tunables (split, ctx, spec, KV, I/O); was `frank-pp-head.env` before the 2026-08-16 rename |
| `scripts/frank-large.env` | claw | head tunables (split, ctx, spec, KV, I/O); was `frank-pp-head.env` before the 2026-08-16 rename |
| `scripts/serve-pp-head.sh` | claw | runs `llama-server --rpc ...` (see "Gotchas") |
| `scripts/frank-default-large.service` / `frank-pp-worker.service` | both | optional systemd units (manual install); the head unit was renamed from `frank-pp-head.service` on 2026-08-16 and is symlinked from the repo into `/etc/systemd/system` |
| `scripts/frank-large.service` / `frank-pp-worker.service` | both | optional systemd units (manual install); the head unit was renamed from `frank-pp-head.service` on 2026-08-16 and is symlinked from the repo into `/etc/systemd/system` |
| `scripts/pp-test.sh` | any box with ssh to both | test orchestrator (preflight/start/verify/bench/stop-pp/restore) |
| `scripts/pp-bench.py` | claw | API driver; reports server-side `print_timing` |
@@ -220,7 +220,7 @@ FRANK_SUDO_PW=<pw> ./scripts/pp-test.sh stop-pp
FRANK_SUDO_PW=<pw> ./scripts/pp-test.sh restore
```
Config variants: edit `scripts/frank-default-large.env` on the claw (git commit +
Config variants: edit `scripts/frank-large.env` on the claw (git commit +
pull if the bench runs from the repo), then re-run `start` + `bench`:
- No spec baseline: `SPEC_NONE=1`
@@ -76,6 +76,6 @@ graph LR
## See Also
- [[DFlash DSpark Speculative Decoding]]
- [[frank-default-small-benchmark]]
- [[frank-small-benchmark]]
- [[Dankserver System Specs]]
- [[Dankclaw System Specs]]
@@ -47,7 +47,7 @@ The FP8 variant requires approximately 16-17 GB. ThinkingCap-FP8 requires ~29 GB
## Prerequisites
> **Production note:** Dankclaw's primary service now runs vLLM-ROCm with the Ling-3.0-flash CIRU INT4 model (see `scripts/frank-default-large.service`). This page documents the alternative vLLM FP8 deployment of Qwen3.6-27B.
> **Production note:** Dankclaw's primary service now runs vLLM-ROCm with the Ling-3.0-flash CIRU INT4 model (see `scripts/frank-large.service`). This page documents the alternative vLLM FP8 deployment of Qwen3.6-27B.
Install vLLM for ROCm. Version 0.24.0+ is required for Qwen3.6 with speculative decoding:
@@ -114,7 +114,7 @@ export HF_HOME=/mnt/entropy/huggingface
### Active Service Conflict
The retired `frank-default-small` service (llama.cpp) used about 22 GB of the 24 GB VRAM. The current PP worker holds ~23.8 GiB. The `vllm-awq-qwen36` (Podman) and `vllm-qwen36` units are disabled. Before starting any research service, verify that the GPU is free:
The retired `frank-small` service (llama.cpp) used about 22 GB of the 24 GB VRAM. The current PP worker holds ~23.8 GiB. The `vllm-awq-qwen36` (Podman) and `vllm-qwen36` units are disabled. Before starting any research service, verify that the GPU is free:
```
nvidia-smi # verify GPU is free
@@ -1,7 +1,7 @@
---
type: reference
title: agentionai Qwen3.8-Flash-Next ROCmFP4-FAST imatrix on Dankclaw
description: agentionai/Qwen3.8-Flash-Next-ROCmFP4-FAST-imatrix-GGUF served by the charlie12345/ROCmFPX llama.cpp runtime (build-qwen38). 87.06 GiB Q4_0_ROCMFP4_FAST imatrix (v2 joined PLE layout), own MTP draft head (ROCmFP4-FAST, 2.28 GiB). frank-default-large.
description: agentionai/Qwen3.8-Flash-Next-ROCmFP4-FAST-imatrix-GGUF served by the charlie12345/ROCmFPX llama.cpp runtime (build-qwen38). 87.06 GiB Q4_0_ROCMFP4_FAST imatrix (v2 joined PLE layout), own MTP draft head (ROCmFP4-FAST, 2.28 GiB). frank-large.
tags:
- llama.cpp
- rocm
@@ -26,7 +26,7 @@ timestamp: 2026-08-29
> `--flash-attn on` work on the charlie build-qwen38 tree — all still
> true for that binary + model pair, which remains the rollback target.
`frank-default-large` (port 7770) served
`frank-large` (port 7770) served
`agentionai/Qwen3.8-Flash-Next-ROCmFP4-FAST-imatrix-GGUF` (main,
`Qwen3.8-Flash-Next-ROCmFP4-FAST-imatrix-v2.gguf`, the `v2/` joined layout)
with the author's own MTP draft head
@@ -166,7 +166,7 @@ best: 32.4 t/s, 0.612 acceptance; adaptive p-split measured worse).
## Config files
- Env: `scripts/frank-default-large.env`
- Env: `scripts/frank-large.env`
- Serve: `scripts/serve-frank-large.sh`
- Chat template: `scripts/chat-template.jinja` (unchanged, Qwen-Sharp)
- Fork patch: `scripts/patches/qwen4exp-qsa-f32-mask.patch` (re-apply after
@@ -175,10 +175,10 @@ best: 32.4 t/s, 0.612 acceptance; adaptive p-split measured worse).
## Swap procedure
```bash
sudo systemctl stop frank-default-large
# edit scripts/frank-default-large.env + scripts/serve-frank-large.sh, commit, push
# on Dankclaw: git pull --ff-only && scripts/deploy.sh dankclaw --service frank-default-large
sudo systemctl start frank-default-large # or via deploy.sh
sudo systemctl stop frank-large
# edit scripts/frank-large.env + scripts/serve-frank-large.sh, commit, push
# on Dankclaw: git pull --ff-only && scripts/deploy.sh dankclaw --service frank-large
sudo systemctl start frank-large # or via deploy.sh
curl http://192.168.0.143:7770/health
```
@@ -1,7 +1,7 @@
---
type: reference
title: CIRU ActiveFPX PromptForge on Dankclaw
description: jcbtc/Qwen3.8-27B-CIRU-ActiveFPX-PromptForge (v3) served by the CIRU ROCmFPX llama.cpp runtime on the Strix Halo iGPU. Install runbook, ROCm 7.15 toolchain, and the frank-default-large service.
description: jcbtc/Qwen3.8-27B-CIRU-ActiveFPX-PromptForge (v3) served by the CIRU ROCmFPX llama.cpp runtime on the Strix Halo iGPU. Install runbook, ROCm 7.15 toolchain, and the frank-large service.
tags:
- llama.cpp
- rocm
@@ -14,12 +14,12 @@ timestamp: 2026-08-22
# CIRU ActiveFPX PromptForge on Dankclaw
> **Active 2026-08-22.** `frank-default-large` serves this v3 model again
> **Active 2026-08-22.** `frank-large` serves this v3 model again
> after a same-day Kairic Edge IU4 experiment was reverted (operator
> decision). Commit `c60156f` restored the v3 script pair. See
> [[kairic-edge]] for the retired experiment reference.
`frank-default-large` (port 7770, moved from 52625 on 2026-08-22) serves
`frank-large` (port 7770, moved from 52625 on 2026-08-22) serves
`jcbtc/Qwen3.8-27B-CIRU-ActiveFPX-PromptForge` **v3** through the CIRU
ROCmFPX llama.cpp runtime. This replaced the retired vLLM service that
previously occupied the slot. The v2 deployment moved to v3 on 2026-08-21.
@@ -135,7 +135,7 @@ graph TD
C --> D[Build llama-server]
D --> E[Verify --list-devices shows gfx1151]
E --> F[Download v3 GGUF + FFN/GDN/Output-K8 + mmproj]
F --> G[Deploy frank-default-large]
F --> G[Deploy frank-large]
G --> H[Health check + chat completion]
```
@@ -150,8 +150,8 @@ against the model card before the service restart.
## Service
- Unit: `frank-default-large.service`, port 7770
- Script: `scripts/serve-frank-large.sh`, env `scripts/frank-default-large.env`
- Unit: `frank-large.service`, port 7770
- Script: `scripts/serve-frank-large.sh`, env `scripts/frank-large.env`
- The script exports the ROCm 7.15 SDK libraries in `LD_LIBRARY_PATH` before
the system ROCm. `ROCM_PATH` points at the devel SDK.
@@ -5,7 +5,7 @@
---
type: reference
title: Dankserver VRAM and RAM Growth Under Load
description: Investigation of the recurring cuBLAS crash on frank-default-small. What grows, what does not, and what to do next.
description: Investigation of the recurring cuBLAS crash on frank-small. What grows, what does not, and what to do next.
tags:
- dankserver
- llamacpp
@@ -18,7 +18,7 @@ tags:
# Dankserver VRAM and RAM Growth Under Load
This page records the investigation of the recurring cuBLAS crash on
`frank-default-small` (llama.cpp, RTX 3090 24 GiB). The service aborts
`frank-small` (llama.cpp, RTX 3090 24 GiB). The service aborts
with `CUDA error: an unsupported value or parameter was passed to the
function` in `cublasSgemm_v2` at `ggml-cuda.cu:1541` during
`update_slots` -> `decode` -> `process_ubatch`. It crashed on 2026-08-13
@@ -116,7 +116,7 @@ Verified 2026-08-14 after deploy: flash attention enabled, warmup clean, decode
## Mitigation Options
The documentation for the benchmark ([[frank-default-small-benchmark]])
The documentation for the benchmark ([[frank-small-benchmark]])
prescribes the first option for this crash class. None of these change
the model.
@@ -135,6 +135,6 @@ PR #25649 (slot checkpoints freed on prompt clear, merged), issue #26119
## See Also
- [[frank-default-small-benchmark]]
- [[frank-small-benchmark]]
- [[Dankserver System Specs]]
- [[deployment]]
@@ -1,7 +1,7 @@
---
type: reference
title: dealign Ornith-1.5-35B-A3B CRACK on Dankserver
description: dealignai/Ornith-1.5-35B-A3B-UNCENSORED (CRACK Q6_K) served by upstream llama.cpp on the RTX 3090. MoE model with ngram-mod speculative decoding; selected expert weights offloaded to CPU with an explicit --override-tensor. frank-default-small.
description: dealignai/Ornith-1.5-35B-A3B-UNCENSORED (CRACK Q6_K) served by upstream llama.cpp on the RTX 3090. MoE model with ngram-mod speculative decoding; selected expert weights offloaded to CPU with an explicit --override-tensor. frank-small.
tags:
- llamacpp
- cuda
@@ -14,12 +14,12 @@ timestamp: 2026-08-24
# dealign Ornith-1.5-35B-A3B CRACK on Dankserver
> **Active 2026-08-25.** `frank-default-small` serves this model. It
> **Active 2026-08-25.** `frank-small` serves this model. It
> replaced the CRACK Q8_0 file on the same upstream llama.cpp binary (b10121).
> The Q6_K file was downloaded from the model repository and validated with
> `llama-gguf` before installation.
`frank-default-small` (port 7770) serves
`frank-small` (port 7770) serves
`Ornith-1.5-35B-A3B-CRACK-Q6_K.gguf` from `dealignai` on Hugging Face. It is
a **MoE** model (256 experts, 8 active) with a hybrid GatedDeltaNet (SSM) +
attention architecture, abliterated (uncensored). The GGUF also contains a
+24 -18
View File
@@ -19,8 +19,9 @@ SearXNG, Caddy, or another container service does **not** restart inference.
| Target | Host | Service | Port |
|---|---|---|---:|
| Dankserver | `dank@dankserver` | `frank-default-small` | 7770 |
| Dankclaw | `dank@dankclaw` | `frank-default-large` | 7770 |
| Dankserver | `dank@dankserver` | `frank-small` | 7770 |
| Dankclaw | `dank@dankclaw` | `frank-large` | 7770 |
| Dankclaw | `dank@dankclaw` | `frank-npu` (FLM on the XDNA2 NPU) | 7771 |
## Scoped workflow
@@ -38,34 +39,39 @@ graph LR
Run the unified deployer from the repository root:
```bash
./scripts/deploy.sh dankserver --service frank-default-small
./scripts/deploy.sh dankclaw --service frank-default-large
./scripts/deploy.sh dankserver --service frank-small
./scripts/deploy.sh dankclaw --service frank-large
./scripts/deploy.sh dankclaw --dry-run
```
Without `--service`, `scripts/deploy-plan.py` maps changed files to the service
on the selected host. The following files select the corresponding service:
- `scripts/frank-default-small.env`, `frank-default-small.service`, and
`serve-frank-small.sh` select `frank-default-small` on Dankserver.
- `scripts/frank-default-large.env`, `frank-default-large.service`, and
`serve-frank-large.sh` select `frank-default-large` on Dankclaw.
- `scripts/frank-small.env`, `frank-small.service`, and
`serve-frank-small.sh` select `frank-small` on Dankserver.
- `scripts/frank-large.env`, `frank-large.service`, and
`serve-frank-large.sh` select `frank-large` on Dankclaw.
- `scripts/frank-npu.env`, `frank-npu.service`,
and `serve-frank-npu.sh` select `frank-npu`
on Dankclaw.
- `scripts/chat-template.jinja` selects the LLM on the selected host only.
- Documentation, tests, deployment tooling, and unrelated container changes
do not select either inference service.
The target-side `scripts/deploy-remote.sh` relinks the selected unit into
`/etc/systemd/system/`, reloads systemd, enables it, restarts it, and waits for
`http://127.0.0.1:7770/health`. The wait budget is 20 minutes because cold model
loads can be slow. A failed handler does not advance its per-service state.
that service's health endpoint (`http://127.0.0.1:7770/health` for the two
inference services; `/v1/version` for the NPU sight+sound endpoint — FLM has no
`/health` route). The wait budget is 20 minutes because cold model loads can be
slow. A failed handler does not advance its per-service state.
## Unit and artifact paths
Both units point into the stable target checkout:
```text
/home/dank/serverAppConfigs/scripts/frank-default-small.service
/home/dank/serverAppConfigs/scripts/frank-default-large.service
/home/dank/serverAppConfigs/scripts/frank-small.service
/home/dank/serverAppConfigs/scripts/frank-large.service
```
The unit files and serve scripts validate their model/runtime artifacts before
@@ -74,8 +80,8 @@ the unit absolute paths and the deployment tests in the same change.
## NPU unit
`frank-default-npu` is an inactive, historical Dankclaw endpoint. It is
relinked only when explicitly selected with `--service frank-default-npu`; the
`frank-npu` is an inactive, historical Dankclaw endpoint. It is
relinked only when explicitly selected with `--service frank-npu`; the
large-model handler never restarts it. This is intentional: the NPU is not part
of the active inference path and should not be disturbed by a large-model
change.
@@ -99,16 +105,16 @@ change in that service's inputs.
If the LLM handler fails after the target pull:
1. Inspect `journalctl -u frank-default-small -n 200` or
`journalctl -u frank-default-large -n 200`.
1. Inspect `journalctl -u frank-small -n 200` or
`journalctl -u frank-large -n 200`.
2. Confirm the model files, custom runtime binary, and chat template are
readable by `dank`.
3. Retry only the affected service:
```bash
./scripts/deploy.sh dankserver --service frank-default-small
./scripts/deploy.sh dankserver --service frank-small
# or
./scripts/deploy.sh dankclaw --service frank-default-large
./scripts/deploy.sh dankclaw --service frank-large
```
4. Verify the matching health endpoint before declaring recovery.
@@ -1,6 +1,6 @@
---
type: reference
title: DFlash2 on Dankclaw (frank-default-large)
title: DFlash2 on Dankclaw (frank-large)
description: ARCHIVED - unsloth Qwen3.8-27B-UD-Q8_K_XL served by upstream llama.cpp PR #27342 with a z-lab DFlash2 drafter on the Vulkan backend. Retired 2026-08-21 for speed; kept as a runbook.
tags:
- llama.cpp
@@ -13,14 +13,14 @@ tags:
timestamp: 2026-08-21
---
# DFlash2 on Dankclaw (frank-default-large) — ARCHIVED
# DFlash2 on Dankclaw (frank-large) — ARCHIVED
> **Archived 2026-08-21.** This DFlash2 Vulkan deployment was retired the
> same day it shipped because it was slower than the CIRU runtime it
> replaced. `frank-default-large` is back on CIRU. This page stays as the
> replaced. `frank-large` is back on CIRU. This page stays as the
> runbook and provenance for the DFlash2 attempt.
`frank-default-large` (port 52625) briefly served
`frank-large` (port 52625) briefly served
`unsloth/Qwen3.8-27B-UD-Q8_K_XL` with a DFlash2 drafter from z-lab. The
runtime was upstream llama.cpp PR #27342 built with `GGML_VULKAN=ON`.
@@ -114,14 +114,14 @@ graph TD
C --> D[Build llama-server]
D --> E[Verify Vulkan0 device]
E --> F[Add DFlash2 drafter]
F --> G[Swap frank-default-large]
F --> G[Swap frank-large]
G --> H[Health check + completion]
```
## Service
- Unit: `frank-default-large.service`, port 52625
- Script: `scripts/serve-frank-large.sh`, env `scripts/frank-default-large.env`
- Unit: `frank-large.service`, port 52625
- Script: `scripts/serve-frank-large.sh`, env `scripts/frank-large.env`
- Binary: `/home/dank/llama.cpp-dflash2/build-dflash2/bin/llama-server`
### Launch profile
+10 -10
View File
@@ -1,7 +1,7 @@
---
type: reference
title: caf-eemin Qwen3.8-27B ROCmI4 embedded MTP on Dankclaw
description: caf-eemin/Qwen3.8-27B-ROCmI4-MTP-GGUF (Q4_0_ROCMI4, embedded NextN/MTP head) served by the charlie12345/ROCmFPX llama.cpp runtime (ROCmI4 W4A4) on the Strix Halo iGPU. frank-default-large.
description: caf-eemin/Qwen3.8-27B-ROCmI4-MTP-GGUF (Q4_0_ROCMI4, embedded NextN/MTP head) served by the charlie12345/ROCmFPX llama.cpp runtime (ROCmI4 W4A4) on the Strix Halo iGPU. frank-large.
tags:
- llama.cpp
- rocm
@@ -15,12 +15,12 @@ timestamp: 2026-08-25
# caf-eemin Qwen3.8-27B ROCmI4 embedded MTP on Dankclaw
> **Active 2026-08-25.** `frank-default-large` serves this model. It replaced
> **Active 2026-08-25.** `frank-large` serves this model. It replaced
> the kingjones777 ROCmFP4 STRIX MTP payload on the same port and the same
> Strix Halo iGPU, running the new charlie12345/ROCmFPX ROCmI4 W4A4 build. See
> [[kingjones-strix-mtp]] for the retired page.
`frank-default-large` (port 7770) serves
`frank-large` (port 7770) serves
`cafonz/Qwen3.8-27B-ROCmI4-MTP-GGUF` (published under the public
`eemin` namespace) from the **charlie12345/ROCmFPX** llama.cpp fork built with
the opt-in `ROCmI4 W4A4` path. The model is `Q4_0_ROCMI4`: signed four-bit
@@ -127,8 +127,8 @@ path's greedy decisions; it does not remove the W4A4 activation approximation.
### Service
- Unit: `frank-default-large.service`, port 7770
- Script: `scripts/serve-frank-large.sh`, env `scripts/frank-default-large.env`
- Unit: `frank-large.service`, port 7770
- Script: `scripts/serve-frank-large.sh`, env `scripts/frank-large.env`
## Tuning MTP
@@ -142,14 +142,14 @@ Decode throughput depends on the ubatch (per-eval token batch). Run the sweep
on 8k contexts, 512 → 4096 in steps of 512, with a fixed batch:
```
sudo systemctl stop frank-default-large
sudo systemctl stop frank-large
./scripts/bench-ubatch.sh
sudo systemctl start frank-default-large
sudo systemctl start frank-large
```
The script stops `frank-default-large` for a clean GPU, boots one server
The script stops `frank-large` for a clean GPU, boots one server
instance per ubatch on a scratch port, reads authoritative `print_timing` tok/s,
and restarts the service. See [[frank-default-large-benchmark]].
and restarts the service. See [[frank-large-benchmark]].
## Known Issues
@@ -183,4 +183,4 @@ The ubatch sweep above gives the production ubatch choice.
- [[kingjones-strix-mtp]] — the retired ROCmFP4 predecessor on this slot
- [[ciru-activefpx-promptforge]] — the retired v3 CIRU PromptForge page
- [[Dankclaw System Specs]] — the box
- [[frank-default-large-benchmark]] — backend/spec benchmark history
- [[frank-large-benchmark]] — backend/spec benchmark history
@@ -2,10 +2,10 @@
> See [frank-redo-2026-08-17.md](frank-redo-2026-08-17.md) and
> [deployment.md](deployment.md) for the active configuration.
# frank-default-large — Backend and Spec Benchmark
# frank-large — Backend and Spec Benchmark
This page records the benchmarks that chose the runtime for
`frank-default-large` on Dankclaw. Every number came from the live
`frank-large` on Dankclaw. Every number came from the live
llama.cpp build on that machine (upstream, b10133+).
## Summary
+11 -11
View File
@@ -1,6 +1,6 @@
---
type: configuration
title: frank-default-sightsound Runbook
title: frank-npu Runbook
description: FastFlowLM (FLM) NPU sight+sound endpoint on Dankclaw — XDNA2 NPU serving Qwen3.8 Distilled Heretic vision+text pack on port 7771, including the IOMMU/SVA root cause that took it down at first deploy.
tags:
- flm
@@ -8,17 +8,17 @@ tags:
- xdna2
- npu
- dankclaw
- frank-default-sightsound
- frank-npu
timestamp: 2026-09-01
---
# frank-default-sightsound — FLM NPU sight+sound Runbook
# frank-npu — FLM NPU sight+sound Runbook
`frank-default-sightsound` is the third inference endpoint on Dankclaw: a
`frank-npu` is the third inference endpoint on Dankclaw: a
FastFlowLM (FLM) v1.0.1 server (`/usr/bin/flm`, dpkg package `fastflowlm`)
running on the **XDNA2 NPU** (50 TOPS). It serves *sight* (vision) —
which the iGPU llama.cpp fleet ([[kingjones-strix-rocmfp4]],
`frank-default-large`) does not do. The model-selection tradeoff: the only
`frank-large`) does not do. The model-selection tradeoff: the only
NPU2 pack family on this box with BOTH a vision and an audio tower is the
Gemma4 E4B IT pack; the uncensored candidate (`qwythos:9b`, 8.94 GB, 262k ctx)
is text-only and fails the hard modality requirement, so this endpoint trades
@@ -29,9 +29,9 @@ is text-only and fails the hard modality requirement, so this endpoint trades
| Field | Value |
|-------|-------|
| Runtime | FLM v1.0.1 (`/usr/bin/flm`, dpkg `fastflowlm`) on the XDNA2 NPU |
| Service | `frank-default-sightsound.service` (systemd system unit, `User=dank`, `Restart=on-failure`, `RestartSec=10`, `LimitMEMLOCK=infinity`) |
| Files | `scripts/frank-default-sightsound.env`, `scripts/serve-frank-default-sightsound.sh`, `scripts/frank-default-sightsound.service` |
| Deploy | `scripts/deploy.sh dankclaw --service frank-default-sightsound` (relink + daemon-reload + enable + restart; health gate polls `/v1/version`, 300 s cap — FLM has **no `/health` route**) |
| Service | `frank-npu.service` (systemd system unit, `User=dank`, `Restart=on-failure`, `RestartSec=10`, `LimitMEMLOCK=infinity`) |
| Files | `scripts/frank-npu.env`, `scripts/serve-frank-npu.sh`, `scripts/frank-npu.service` |
| Deploy | `scripts/deploy.sh dankclaw --service frank-npu` (relink + daemon-reload + enable + restart; health gate polls `/v1/version`, 300 s cap — FLM has **no `/health` route**) |
| Port | `7771` on `0.0.0.0` (52625/52626 left free for ad-hoc `flm serve` experiments) |
| Power mode | `FLM_PMODE=turbo` — no other tenant uses the NPU on this host (the large model runs on the iGPU), so the top power mode costs no neighbour anything; drop to `performance` if iGPU power-budget contention ever shows |
| Context | `FLM_CTX_LEN=131072 (128K; verified max on this box; native context length.) |
@@ -57,8 +57,8 @@ clients choose, send requests with the desired `model` field.
**To swap the active model** (changes what the service loads at start):
```
sed -i 's/^FLM_MODEL=.*/FLM_MODEL=<tag>/' scripts/frank-default-sightsound.env
./scripts/deploy.sh dankclaw --service frank-default-sightsound
sed -i 's/^FLM_MODEL=.*/FLM_MODEL=<tag>/' scripts/frank-npu.env
./scripts/deploy.sh dankclaw --service frank-npu
```
**To switch per-request** (service stays loaded, client sends the tag):
@@ -119,7 +119,7 @@ chain, all live-verified on the host:
3. Fix: replace `iommu=off` with **`iommu=pt`** in `GRUB_CMDLINE_LINUX_DEFAULT`
on `/etc/default/grub`, `update-grub`, reboot. Passthrough mode keeps the
iGPU default domain identity-mapped (zero DMA-translation overhead for
`frank-default-large`) while enabling IOMMU hardware + PASID, which is what
`frank-large`) while enabling IOMMU hardware + PASID, which is what
the NPU driver's SVA bind requires — PASID domains are paged regardless of
the default-domain type.
4. Post-boot verification: `/sys/kernel/iommu_groups/` populated (30 groups),
@@ -8,15 +8,15 @@ The old scripts moved to `old/scripts/` in this repository.
| Service | Host | Runtime | Model | Port |
|---------|------|---------|-------|------|
| frank-default-large | Dankserver | llama.cpp (patched FastMTP) | HauhauCS Qwen3.8-27B-Uncensored-Aggressive IQ4_XS | 7770 |
| frank-default-small | Dankclaw | vLLM ROCm | nameistoken Qwen3.6-35B-A3B Quark W8A8 INT8 | 52625 |
| frank-large | Dankserver | llama.cpp (patched FastMTP) | HauhauCS Qwen3.8-27B-Uncensored-Aggressive IQ4_XS | 7770 |
| frank-small | Dankclaw | vLLM ROCm | nameistoken Qwen3.6-35B-A3B Quark W8A8 INT8 | 52625 |
The RTX 3090 runs the whole 27B model standalone. No RPC worker, no
tensor split, no NPU.
## Models
### frank-default-large — HauhauCS/Qwen3.8-27B-Uncensored-HauhauCS-Aggressive-MTP-GGUF:IQ4_XS
### frank-large — HauhauCS/Qwen3.8-27B-Uncensored-HauhauCS-Aggressive-MTP-GGUF:IQ4_XS
- Base: Qwen3.8-27B (dense 27B, 64 layers: 48 GatedDeltaNet + 16
gated-attention, hidden 5120, 24 Q heads / 4 KV heads, head dim 256,
@@ -31,7 +31,7 @@ tensor split, no NPU.
`--spec-draft-ngl all`, `--spec-draft-p-min 0`) then ngram-mod fallback
(48/64/24).
### frank-default-small — nameistoken/Qwen3.6-35B-A3B-Quark-W8A8-INT8
### frank-small — nameistoken/Qwen3.6-35B-A3B-Quark-W8A8-INT8
- Base: Qwen3.6-35B-A3B (hybrid MoE, 256 experts top-8, ~3B active, 40
layers: 10 blocks of 3 DeltaNet + 1 Attention, native 262144 ctx).
@@ -46,7 +46,7 @@ tensor split, no NPU.
instead of the Qwen3 XML structure). The Quark quant follows the format
cleanly; swapped in the evening of 2026-08-17.
## Context Math (frank-default-large, RTX 3090)
## Context Math (frank-large, RTX 3090)
KV per token: 16 attention layers x 4 KV heads x 256 dim.
K q8_0 = 1088 B/token, V f16 = 2048 B/token, total 50176 B/token.
@@ -63,11 +63,11 @@ Budget (MiB): 24576 total - 14982 weights - 861 draft - 1024 fixed
Production choice: **131072 (128K)** — the maximum that keeps about
1.4 GiB headroom for checkpoints. Lower `CTX_SIZE` in
`scripts/frank-default-large.env` to 122880 for ~1.8 GiB headroom.
`scripts/frank-large.env` to 122880 for ~1.8 GiB headroom.
## Install Runbook
### Dankserver (frank-default-large)
### Dankserver (frank-large)
1. Stop the old worker: `sudo systemctl stop frank-pp-worker`.
2. Download the model and draft to `/home/dank/models/hauhaucs-qwen38/`.
@@ -87,17 +87,17 @@ Production choice: **131072 (128K)** — the maximum that keeps about
measured 95 t/s vs 1300+ t/s at 8K on the 3090).
4. Symlink the unit, reload, enable, restart:
```
sudo ln -sf /home/dank/vLLM/scripts/frank-default-large.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable frank-default-large
sudo systemctl restart frank-default-large
sudo ln -sf /home/dank/vLLM/scripts/frank-large.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable frank-large
sudo systemctl restart frank-large
```
5. Verify: `curl -sf http://127.0.0.1:7770/health` and a chat completion.
6. Confirm VRAM headroom with `nvidia-smi`.
### Dankclaw (frank-default-small)
### Dankclaw (frank-small)
1. Stop the old services: `sudo systemctl stop frank-default-large
frank-default-small` (retired PP head and NPU endpoint).
1. Stop the old services: `sudo systemctl stop frank-large
frank-small` (retired PP head and NPU endpoint).
2. Install uv and create the venv:
```
curl -LsSf https://astral.sh/uv/install.sh | sh
@@ -122,9 +122,9 @@ Production choice: **131072 (128K)** — the maximum that keeps about
vision encoder falls back to torch SDPA and engine init OOMs.
5. Symlink the unit, reload, enable, restart:
```
sudo ln -sf /home/dank/vllmScripts/scripts/frank-default-small.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable frank-default-small
sudo systemctl restart frank-default-small
sudo ln -sf /home/dank/vllmScripts/scripts/frank-small.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable frank-small
sudo systemctl restart frank-small
```
6. Verify: `curl -sf http://127.0.0.1:52625/health` and a chat completion.
@@ -150,7 +150,7 @@ on gfx1151; newer vLLM releases may already include it.
Three changes landed after the initial deployment:
### 1. Tool calling on frank-default-small (HTTP 400 fix)
### 1. Tool calling on frank-small (HTTP 400 fix)
Clients (pi) send `tool_choice: "auto"`. vLLM rejects it with HTTP 400
unless the server enables tool calling. Fixes applied:
@@ -175,7 +175,7 @@ model behavior, which motivated the swap.
### 2. Model swap: Avesed INT8 W8A8 -> Quark W8A8 INT8
`frank-default-small` now serves
`frank-small` now serves
`nameistoken/Qwen3.6-35B-A3B-Quark-W8A8-INT8` (AMD Quark 0.11.1, ~35 GB,
vLLM-native expert layout). The Avesed compressed-tensors quant's
Qwen3-XML tool fidelity was poor. Verified with the Quark model: plain
@@ -1,6 +1,6 @@
---
type: reference
title: frank-default-small Benchmark — ncmoe and Batch Tuning
title: frank-small Benchmark — ncmoe and Batch Tuning
description: llama-bench sweep of MoE CPU offload (ncmoe) and batch/ubatch on the RTX 3090 for Qwen3.6-35B-A3B Q6_K_P.
tags:
- benchmark
@@ -10,11 +10,11 @@ tags:
- dankserver
---
# frank-default-small Benchmark — ncmoe and Batch/Ubatch Tuning
# frank-small Benchmark — ncmoe and Batch/Ubatch Tuning
This page records a llama-bench sweep on Dankserver (RTX 3090, 24 GiB) for
the HauhauCS Qwen3.6-35B-A3B Q6_K_P model. The sweep decided the final
`--n-cpu-moe` and `--ubatch-size` values for `frank-default-small`.
`--n-cpu-moe` and `--ubatch-size` values for `frank-small`.
Run date: 2026-08-13. Build: llama.cpp `555881ebc` (10121). CUDA, 7 threads,
`--cache-type-k q8_0 --cache-type-v f16`, `--fit-target 0` (KV auto-sized to
@@ -105,7 +105,7 @@ service runs 700416 cells (13,680 MiB).
## Chosen State
> **Live drift (2026-08-22 audit):** the deployed `frank-default-small` now runs `--n-cpu-moe 38`, `--batch-size 4096`, `--ubatch-size 2048` (ncmoe raised from 36 for stability; batch lowered). The values below are the original benchmark recommendation.
> **Live drift (2026-08-22 audit):** the deployed `frank-small` now runs `--n-cpu-moe 38`, `--batch-size 4096`, `--ubatch-size 2048` (ncmoe raised from 36 for stability; batch lowered). The values below are the original benchmark recommendation.
Prefill speed is the priority, so the state keeps the top prefill tier and
moves one expert layer to CPU for stability:
@@ -6,7 +6,7 @@ tags:
- freetoken
- benchmark
- dankserver
- frank-default-small
- frank-small
- qwen3.6
timestamp: 2026-09-02
---
@@ -90,5 +90,5 @@ Tiel-Coder finetune.
## See Also
- [[freetoken-frank-default-small]] — production runbook
- [[freetoken-frank-small]] — production runbook
- [[dealign-ornith-crack]] — the prior llama.cpp deployment (retired)
@@ -1,20 +1,20 @@
---
type: configuration
title: FreeToken frank-default-small Runbook
description: FreeToken v0.1.2 serving batsclamp/Huihui-Qwen3.6-35B-A3B-abliterated-FP8 as frank-default-small on Dankserver (RTX 3090).
title: FreeToken frank-small Runbook
description: FreeToken v0.1.2 serving batsclamp/Huihui-Qwen3.6-35B-A3B-abliterated-FP8 as frank-small on Dankserver (RTX 3090).
tags:
- freetoken
- dankserver
- frank-default-small
- frank-small
- qwen3.6
- moe
- fp8
timestamp: 2026-08-30
---
# FreeToken frank-default-small Runbook
# FreeToken frank-small Runbook
The `frank-default-small` service on Dankserver is served by
The `frank-small` service on Dankserver is served by
**FreeToken v0.1.2** — an edge-native MoE serving engine that keeps
expert weights in host RAM with an LRU GPU cache. Model history on this
runtime: official `Qwen/Qwen3.6-35B-A3B-FP8` (since 2026-09-02) →
@@ -130,8 +130,8 @@ modelopt block-fp8 remains the only FP8 path that loads.
| File | Purpose |
|------|---------|
| `scripts/serve-frank-small.sh` | Serve script (launches `ft serve`) |
| `scripts/frank-default-small.env` | Tunables (model path, pool sizes) |
| `scripts/frank-default-small.service` | Systemd unit |
| `scripts/frank-small.env` | Tunables (model path, pool sizes) |
| `scripts/frank-small.service` | Systemd unit |
## Limitations
@@ -150,7 +150,7 @@ modelopt block-fp8 remains the only FP8 path that loads.
- **`model` field is required** in `/v1/chat/completions` bodies —
FreeToken rejects requests without it with a 422 (`Field required`),
unlike llama.cpp's server which defaults to the loaded model. Send
`"model": "frank-default-small"`.
`"model": "frank-small"`.
- Load on this swap took well under the old llama.cpp numbers:
weights → experts (parallel build) → CUDA graph capture → Uvicorn
in ~2 minutes; the 2026-08-30 swap verified ~40 tok/s decode on a
@@ -1,7 +1,7 @@
---
type: reference
title: ik_llama.cpp on Dankserver (Ornith Q8_0)
description: ikawrakow/ik_llama.cpp replaces upstream llama.cpp for frank-default-small on the RTX 3090. Q8_0 model, KV K default f16 / V q6_0 with Hadamard on V only (iq5_k is not a KV-cache type in this build; q8_KV crashes on this arch), split-mode none, speculative decoding disabled, 3 parallel slots x 163840 ctx, the Qwen-Sharp template rendered with --jinja, and explicit CPU-expert offload. Includes the mandatory CUDA/IQK FA_ALL_QUANTS build flags.
description: ikawrakow/ik_llama.cpp replaces upstream llama.cpp for frank-small on the RTX 3090. Q8_0 model, KV K default f16 / V q6_0 with Hadamard on V only (iq5_k is not a KV-cache type in this build; q8_KV crashes on this arch), split-mode none, speculative decoding disabled, 3 parallel slots x 163840 ctx, the Qwen-Sharp template rendered with --jinja, and explicit CPU-expert offload. Includes the mandatory CUDA/IQK FA_ALL_QUANTS build flags.
tags:
- ikllama
- llamacpp
@@ -16,7 +16,7 @@ timestamp: 2026-08-26
# ik_llama.cpp on Dankserver (Ornith-1.5-35B-A3B CRACK)
> **Active 2026-08-26.** `frank-default-small` switched from upstream
> **Active 2026-08-26.** `frank-small` switched from upstream
> llama.cpp (b10121) to `ikawrakow/ik_llama.cpp` (commit `b166e269`) on the
> RTX 3090. This page documents the build, the mandatory FA build flags, and
> the MoE / CPU-offload runtime arguments.
@@ -101,8 +101,8 @@ a hard compile error.
## Runtime configuration
Files: `scripts/serve-frank-small.sh`, `scripts/frank-default-small.env`,
`scripts/frank-default-small.service` in the repo. The service just calls
Files: `scripts/serve-frank-small.sh`, `scripts/frank-small.env`,
`scripts/frank-small.service` in the repo. The service just calls
the serve script; the env file holds all tunables.
### KV cache: K default f16 / V q6_0 + Hadamard (V only)
@@ -241,7 +241,7 @@ apply.
The previous runtime `upstream llama.cpp b10121` and its binary
(`/home/dank/llama.cpp/build/bin/llama-server`) are **left untouched**. To
rollback to the old stack, change `LLAMA_SERVER=` in
`scripts/frank-default-small.env` back to that path and
`scripts/frank-small.env` back to that path and
`CACHE_TYPE_K/V` back to `f16` with Hadamard off, and re-enable the ngram
spec / `--spec-type` flags. The model file is not changed either way.
+20 -17
View File
@@ -1,9 +1,9 @@
# LLM Fleet — Knowledge Base
Documentation for the LLM inference fleet on two local machines
(2026-08-30): FreeToken v0.1.2 on Dankserver (frank-default-small,
(2026-08-30): FreeToken v0.1.2 on Dankserver (frank-small,
Huihui-Qwen3.6-35B-A3B-abliterated-FP8) and kingjones30/ROCmFPX
llama.cpp on Dankclaw (frank-default-large, kingjones777
llama.cpp on Dankclaw (frank-large, kingjones777
Qwen3.8-Flash-Next ROCmFP4-STRIX). Both services run the Qwen-Sharp chat template.
> 2026-08-22: the former `vllmScripts` repository is merged into the
@@ -18,7 +18,7 @@ graph LR
subgraph Dankserver[NVIDIA Dankserver - Ubuntu 26.04]
A[RTX 3090 24GB + 60GB RAM]
B2[FreeToken v0.1.2
frank-default-small, port 7770]
frank-small, port 7770]
C[Huihui-Qwen3.6-35B-A3B-abliterated-FP8
block-fp8, 20% MoE residency, 453k KV / 4 streams]
A --> B2 --> C
@@ -27,7 +27,7 @@ block-fp8, 20% MoE residency, 453k KV / 4 streams]
subgraph Dankclaw[AMD Strix Halo - Ubuntu 26.04]
E2[gfx1151 iGPU 64 GiB unified memory]
E[kingjones30/ROCmFPX build
frank-default-large, port 7770]
frank-large, port 7770]
F[kingjones777 Qwen3.8-Flash-Next
ROCmFP4-STRIX, 401k ctx / 2 slots, mmap PLE]
E2 --> E --> F
@@ -46,18 +46,18 @@ ROCmFP4-STRIX, 401k ctx / 2 slots, mmap PLE]
## Active Deployment
- [[freetoken-frank-default-small]] — the active frank-default-small
- [[freetoken-frank-small]] — the active frank-small
runbook: FreeToken v0.1.2 serving batsclamp/Huihui-Qwen3.6-35B-A3B-
abliterated-FP8 on Dankserver (swapped 2026-08-30; same format/pools)
- [[freetoken-benchmark-sweep]] — KV pool vs decode speed sweep
(bs1/bs3/bs4/bs6, 8k–700k KV) on Dankserver RTX 3090
- [[deployment]] — deploy and update process for both servers
- [[frank-redo-2026-08-17]] — the 2026-08-17 topology change
- [[kingjones-strix-rocmfp4]] — ACTIVE frank-default-large runbook:
- [[kingjones-strix-rocmfp4]] — ACTIVE frank-large runbook:
kingjones777/Qwen3.8-Flash-Next-ROCmFP4-STRIX-GGUF, 177B params
(56B MoE + 51.2B PLE), single 113.47 GiB GGUF, on the card's pinned
kingjones30/ROCmFPX fork (swapped 2026-08-30)
- [[agentionai-fast-imatrix]] — retired frank-default-large runbook:
- [[agentionai-fast-imatrix]] — retired frank-large runbook:
agentionai/Qwen3.8-Flash-Next-ROCmFP4-FAST-imatrix (87.06 GiB
Q4_0_ROCMFP4_FAST imatrix, v2 joined PLE) on build-qwen38
(2026-08-29 → 2026-08-30); rollback binary + payload retained
@@ -66,9 +66,9 @@ ROCmFP4-STRIX, 401k ctx / 2 slots, mmap PLE]
- [[eemin-rocmi4-mtp]] — the former caf-eemin Qwen3.8-27B embedded-MTP model
on Dankclaw (retired)
- [[dealign-ornith-crack]] — the retired Ornith-1.5-35B-A3B CRACK model on
Dankserver (frank-default-small, retired 2026-09-02)
Dankserver (frank-small, retired 2026-09-02)
- [[ikllama-ornith-dankserver]] — the retired ik_llama.cpp runtime for
frank-default-small (2026-08-26): q8_0 + Hadamard KV cache,
frank-small (2026-08-26): q8_0 + Hadamard KV cache,
split-mode none (single-GPU), mandatory FA_ALL_QUANTS build flags
- [[kingjones-strix-mtp]] — the former Q6 AGENT runbook (restored 2026-09-01
after Q8_0 failure, then superseded by the STRIX deployment on 2026-08-27)
@@ -76,9 +76,10 @@ ROCmFP4-STRIX, 401k ctx / 2 slots, mmap PLE]
on Dankclaw (superseded 2026-08-24 by the kingjones ROCmFP4 model)
- [[kairic-edge]] — the retired Kairic Edge IU4 experiment
(deployed and reverted 2026-08-22)
- [[Dankserver System Specs]] — the RTX 3090 box (frank-default-small)
- [[Dankclaw System Specs]] — the CIRU ROCmFPX box (frank-default-large)
- [[frank-default-sightsound]] — ACTIVE FLM NPU sight+sound runbook on
- [[Dankserver System Specs]] — the RTX 3090 box (frank-small)
- [[Dankclaw System Specs]] — the Strix Halo gfx1151 box (frank-large,
served on the pinned kingjones30/ROCmFPX llama.cpp fork since 2026-08-30)
- [[frank-npu]] — ACTIVE FLM NPU sight+sound runbook on
Dankclaw: Gemma4 E4B vision+audio pack on the XDNA2 NPU (FLM v1.0.1, port
7771, whole-registry serving, per-request model routing), incl. the
IOMMU/SVA root cause and the `iommu=pt` fix behind its first-deploy crash
@@ -101,8 +102,10 @@ ROCmFP4-STRIX, 401k ctx / 2 slots, mmap PLE]
- [[VLLM Overview]] — installation, CLI, API, architecture, quantization, parallelism
- [[VLLM Index]] — quick reference with commands, endpoints, and parameter table
- [[Running Qwen3.6 35B A3B FP8 on Dankserver]] — Qwen3.6-35B-A3B hardware
notes and sizing (the historical family; frank-default-small now serves
Ornith-1.5-35B-A3B, see [[dealign-ornith-crack]])
notes and sizing (this architecture family is what frank-small
serves today in the Huihui abliterated FP8 variant — see
[[freetoken-frank-small]]; the Ornith-1.5-35B-A3B CRACK checkpoint
that preceded it is archived at [[dealign-ornith-crack]])
## Memory Management
@@ -115,7 +118,7 @@ ROCmFP4-STRIX, 401k ctx / 2 slots, mmap PLE]
- [[Qwen3.8 PP Deployment]] — the retired pipeline-parallel head + worker
- [[qwen3.8-spec-matrix]] — Qwen3.8-27B spec history (superseded by FastMTP)
- [[FastFlowLM NPU Inference]] — the retired FastFlowLM NPU endpoint
- [[frank-default-large-benchmark]] — backend/spec benchmark behind the old head
- [[frank-large-benchmark]] — backend/spec benchmark behind the old head
- [[dankserver-vram-growth]] — VRAM/RAM growth behind the retired cuBLAS crash
- [[DFlash DSpark Speculative Decoding]] — retired DFlash/DSpark drafting
- [[Quantization by Hardware Architecture]] — which quant format fits which GPU/CPU
@@ -134,7 +137,7 @@ ROCmFP4-STRIX, 401k ctx / 2 slots, mmap PLE]
## Related
- [Project knowledge base](../index.md) — the Podman app stacks on the same
two hosts. OpenWebUI consumes the `:7770` endpoint on Dankserver. The
Gitea instance on Dankclaw hosts this repository.
two hosts. OpenWebUI (Dankclaw) consumes the on-host `frank-large`
endpoint at `:7770`. The Gitea instance on Dankclaw hosts this repository.
- [Deployment Flow](../Architecture/Deployment%20Flow.md) — the service-scoped
git-based deploy with inference isolation
+4 -4
View File
@@ -17,10 +17,10 @@ timestamp: 2026-08-22
> **Retired 2026-08-22.** This experiment was deployed, benchmarks were
> collected, and the service reverted to v3 the same day (operator
> decision). `frank-default-large` serves v3 again. This page is kept as
> decision). `frank-large` serves v3 again. This page is kept as
> the retired experiment's build runbook and reference.
`frank-default-large` (port 52625) briefly served
`frank-large` (port 52625) briefly served
`jcbtc/Qwen3.8-27B-IU4-Kairic-Edge` through the Kairic Edge CIRU ROCmFPX
llama.cpp runtime. The runtime routes qualified prompt and multi-token
verification shapes through the RDNA 3.5 native
@@ -215,7 +215,7 @@ service restart confirms the fresh tree, then it is a deletion candidate
The service runs the pinned runner profile plus the local chat
deviations below. Tunables live in
`scripts/frank-default-large.env`; flags in `scripts/serve-frank-large.sh`.
`scripts/frank-large.env`; flags in `scripts/serve-frank-large.sh`.
See [[deployment]] for the update process.
| Setting | Value | Origin |
@@ -301,7 +301,7 @@ ubatches do not. Production runs the runner's qualified 2048/512.
The v3 payload and binary stay on the machine for rollback.
1. Stop the service: `sudo systemctl stop frank-default-large`
1. Stop the service: `sudo systemctl stop frank-large`
2. Restore the v3 scripts:
`git revert 4c43839 7aee1df 40d50fe` (or checkout the script pair from
commit `132e147`)
@@ -1,11 +1,11 @@
# frank-default-large: kingjones Qwen3.8-27B-ROCmFPX-Q8_0-AGENT
# frank-large: kingjones Qwen3.8-27B-ROCmFPX-Q8_0-AGENT
**Status:** Deployed on Dankclaw (since 2026-08-25). Serving is **BLOCKED by
the `set_rows` build bug** — the model loads but crashes in
`ggml_compute_forward_set_rows` before it can serve. All config goals are met;
a build fix is required for the model to run.
**Alias:** `frank-default-large`, port **7770**.
**Alias:** `frank-large`, port **7770**.
The large service serves the kingjones `Qwen3.8-27B-ROCmFPX-Q8_0-AGENT` GGUF
from `/home/dank/models/kingjones-Qwen3.8-27B-ROCMFPX-Q8_0-AGENT/` with a
@@ -26,7 +26,7 @@ fit in the lifted **114 GiB TTM/GTT** budget (see the 114 GiB change in
| Reasoning | on, `deepseek`, budget `-1`, `--reasoning-format none` |
| Chat template | Sharp (repo-tracked), `enable_thinking` + `preserve_thinking` on |
| Host path | `/home/dank/models/kingjones-Qwen3.8-27B-ROCMFPX-Q8_0-AGENT/` |
| Tunables | `scripts/frank-default-large.env` |
| Tunables | `scripts/frank-large.env` |
| Serve script | `scripts/serve-frank-large.sh` |
## Serving status: the `set_rows` build bug (blocks serving)
@@ -107,7 +107,7 @@ dl mtp-Qwen3.8-27B-Q4_0.gguf
```
The serve script checks each artifact is present and readable before launch
(`scripts/frank-default-large.env` -> the four `MODEL_*` files plus the chat
(`scripts/frank-large.env` -> the four `MODEL_*` files plus the chat
template). A missing file fails the artifact check with `missing or
unreadable required artifact`.
@@ -116,7 +116,7 @@ unreadable required artifact`.
`scripts/serve-frank-large.sh` builds the `llama-server` call from the env:
```
/dev/llama-server -m <main> --alias frank-default-large
/dev/llama-server -m <main> --alias frank-large
--host 0.0.0.0 --port 7770 --jinja
-dev ROCm0 -ngl 999 -np 1 -c 262144
-b 512 -ub 512 -fa on
@@ -197,7 +197,7 @@ and a 28 GB + 262k-KV load stalls. The GTT page-limit change is per the
## Env tunables
`scripts/frank-default-large.env`. Serving: `CTX_SIZE=262144`,
`scripts/frank-large.env`. Serving: `CTX_SIZE=262144`,
`PARALLEL=1`, `BATCH_SIZE=512`, `UBATCH_SIZE=512`, `NUM_THREADS=16`,
`THREAD_BATCH=32`, `CACHE_TYPE_K=f16`, `CACHE_TYPE_V=turbo4`,
`CTX_CHECKPOINTS=32`, `CACHE_RAM=8192`. Reasoning: `REASONING=on`,
@@ -1,7 +1,7 @@
---
type: reference
title: kingjones Qwen3.8-27B ROCmFP4 STRIX MTP on Dankclaw
description: kingjones777/Qwen3.8-27B-Uncensored-ROCmFP4-STRIX-MTP served by the CIRU ROCmFPX llama.cpp runtime on the Strix Halo iGPU. Dense model with a standalone MTP Q4_0 draft head. frank-default-large.
description: kingjones777/Qwen3.8-27B-Uncensored-ROCmFP4-STRIX-MTP served by the CIRU ROCmFPX llama.cpp runtime on the Strix Halo iGPU. Dense model with a standalone MTP Q4_0 draft head. frank-large.
tags:
- llama.cpp
- rocm
@@ -16,13 +16,13 @@ timestamp: 2026-08-24
# kingjones Qwen3.8-27B ROCmFP4 STRIX MTP on Dankclaw
> **Active again 2026-09-01.** The kingjones ROCmFP4 STRIX MTP payload is
> restored as `frank-default-large` after the Q8_0 AGENT experiment. The Q8_0
> restored as `frank-large` after the Q8_0 AGENT experiment. The Q8_0
> model was retired because it crashed before serving. The Q6 AGENT model,
> standalone MTP draft, Q8 projector, and PromptForge runtime are now active.
> This page documents the active model and its runbook.
`frank-default-large` (port 7770) serves
`frank-large` (port 7770) serves
`Qwen3.8-27B-Uncensored-ROCmFP4-STRIX-MTP` from `kingjones777` on Hugging
Face. It is a **dense** Qwen3.8-27B, abliterated (uncensored), quantized to
the ROCmFP4 Q6 AGENT format (ftype 114). The MTP speculative head ships as
@@ -1,7 +1,7 @@
---
type: reference
title: kingjones Qwen3.8-Flash-Next ROCmFP4 STRIX on Dankclaw
description: ACTIVE frank-default-large runbook. kingjones777/Qwen3.8-Flash-Next-ROCmFP4-STRIX-GGUF served by the card's pinned kingjones30/ROCmFPX fork. 177B params (56B MoE + 51.2B PLE streamed via mmap), single 113.47 GiB GGUF, 401408 ctx x 2 slots.
description: ACTIVE frank-large runbook. kingjones777/Qwen3.8-Flash-Next-ROCmFP4-STRIX-GGUF served by the card's pinned kingjones30/ROCmFPX fork. 177B params (56B MoE + 51.2B PLE streamed via mmap), single 113.47 GiB GGUF, 401408 ctx x 2 slots.
tags:
- llama.cpp
- rocm
@@ -23,10 +23,10 @@ timestamp: 2026-08-30
> decoding is OFF (the card ships no spec flags; the Flash-Next MTP heads
> do not load on this loader family — see MTP Draft Head).
`frank-default-large` (port 7770) serves
`frank-large` (port 7770) serves
`Qwen3.8-Flash-Next-Q4_0-ROCmFP4-STRIX.gguf` (single file, 113.47 GiB)
from `/home/dank/models/kingjones-Qwen3.8-Flash-Next-ROCmFP4-STRIX/`
via `scripts/serve-frank-large.sh` + `scripts/frank-default-large.env`
via `scripts/serve-frank-large.sh` + `scripts/frank-large.env`
and the Qwen-Sharp chat template.
## Model Architecture
@@ -178,7 +178,7 @@ cmake --build build --target llama-server llama-quantize -j16
## Serving Profile
Deployed args (`scripts/frank-default-large.env` — our validated
Deployed args (`scripts/frank-large.env` — our validated
profile, unchanged from the FAST deployment except the binary and model):
```
@@ -272,9 +272,9 @@ The file is 113.47 GiB. Allow ~20-30 minutes for download depending on network.
1. Build the runtime (see Runtime build) BEFORE touching the service.
2. Point the model file's directory at the canonical path (a plain `mv`
— never delete a 113 GiB payload to re-fetch it).
3. Edit `scripts/frank-default-large.env` (+ serve script defaults) via
3. Edit `scripts/frank-large.env` (+ serve script defaults) via
git: commit, push, `./scripts/deploy.sh dankclaw --service
frank-default-large`.
frank-large`.
4. Verify health: `curl http://192.168.0.143:7770/health` and a real
`/v1/chat/completions` probe.
@@ -284,7 +284,7 @@ binary and the agentionai payload remain on disk.
### Config files
- Env: `scripts/frank-default-large.env`
- Env: `scripts/frank-large.env`
- Serve: `scripts/serve-frank-large.sh`
- Chat template: `scripts/chat-template.jinja`
@@ -1,10 +1,6 @@
# Ling-3.0-flash Q6_K Trial on Dankclaw
> **RETIRED 2026-08-17.** The `frank-large-ling` unit is disabled under the boot policy. `frank-default-large` now runs the Qwen3.8-27B PP head, not the Qwen3.6-27B config described in the (obsolete) switch-back section below.
This page records the Ling-3.0-flash trial that temporarily replaced
`frank-default-large` on Dankclaw. It replaces the Qwen3.6-27B service on
port 7770 under the same API alias.
> **RETIRED 2026-08-17.** The `frank-large-ling` unit is disabled under the boot policy. At this page's retirement date `frank-large` ran the Qwen3.8-27B PP head (since superseded by the STRIX deployment — see [[kingjones-strix-rocmfp4]]), not the Qwen3.6-27B config described in the (obsolete) switch-back section below.
## Status
@@ -73,22 +69,22 @@ point varies (385-1588 tokens). Single streams never freeze.
`SPEC_TYPE=none`, `PARALLEL=2`. All concurrent streams complete (EOS).
Speed cost: ~10-13 t/s under contention vs ~28-32 t/s single-stream with
MTP. Fallback chain if spec-off regresses: A) `PARALLEL=1` keep MTP,
B) switch back to Qwen3.6-27B (frank-default-large, MTP n_max 3).
B) switch back to Qwen3.6-27B (frank-large, MTP n_max 3).
## Files
- `scripts/frank-large-ling.service` - systemd unit.
- `scripts/serve-ling-flash.sh` - serve script (fork binary, Vulkan,
draft-mtp).
- `scripts/frank-default-large.ling.env` - tunables.
- `scripts/frank-large.ling.env` - tunables.
Passwordless management is installed:
`/usr/local/sbin/frank-restart-ling.sh` and `/etc/sudoers.d/frank-ling`.
## Switch Back (obsolete)
The switch-back commands below are obsolete. `frank-default-large` now
runs the Qwen3.8-27B pipeline-parallel head. To restore a Ling trial,
The switch-back commands below are obsolete. At retirement time
`frank-large` ran the Qwen3.8-27B pipeline-parallel head. To restore a Ling trial,
re-enable `frank-large-ling` from the repo unit
(`scripts/frank-large-ling.service`) and serve script
(`scripts/serve-ling-flash.sh`), then start it on a non-conflicting port.
@@ -107,6 +103,6 @@ re-enable `frank-large-ling` from the repo unit
## See Also
- [[frank-default-large-benchmark]]
- [[frank-large-benchmark]]
- [[DFlash DSpark Speculative Decoding]]
- [[deployment]]
@@ -6,5 +6,5 @@ Dankclaw. The deployment never shipped. The actual Ling work used the
llama.cpp Q6_K fork trial instead: [[ling-3.0-flash-trial]].
The trial service (`frank-large-ling`) is retired and disabled under the
boot policy (2026-08-17). `frank-default-large` is the Qwen3.8-27B PP
boot policy (2026-08-17). `frank-large` is the Qwen3.8-27B PP
head, not the Ling path. See git history for the full decision table.
@@ -5,7 +5,7 @@
# Qwen3.8-27B Speculative-Decoding Matrix
This page records the speculative-decoding benchmark history and the
production tuning for the Qwen3.8-27B service (`frank-default-large`),
production tuning for the Qwen3.8-27B service (`frank-large`),
now a pipeline-parallel head with a Dankserver worker.
## Production state (2026-08-17: Q6_K, q8_0/f16 KV, split 0.68)
@@ -145,7 +145,7 @@ that is the long-context attention penalty, not a spec artifact.
## Production Configuration
The live tunables live in `scripts/frank-default-large.env` (head) and
The live tunables live in `scripts/frank-large.env` (head) and
`scripts/frank-pp-worker.env` (worker) in this repo. The Production
state section at the top of this page records the current values: Q6_K
model + standalone MTP draft, split 0.68/0.32, 262144 ctx, PARALLEL=1,
@@ -153,6 +153,6 @@ q8_0/f16 KV.
## See Also
- [[frank-default-large-benchmark]]
- [[frank-large-benchmark]]
- [[ling-3.0-flash-trial]]
- [[deployment]]
@@ -7,7 +7,7 @@ and the test matrix planned for 2026-08-16 morning.
Related pages:
- [Speculative-decoding matrix](qwen3.8-spec-matrix.md)
- [Backend and spec benchmark](frank-default-large-benchmark.md)
- [Backend and spec benchmark](frank-large-benchmark.md)
- [Dankclaw Improvements](Dankclaw%20Improvements.md) (OS-level items)
- [Pipeline Parallelism: Qwen3.8 PP Deployment](Pipeline%20Parallelism/Qwen3.8%20PP%20Deployment.md)
@@ -58,7 +58,7 @@ Consequences of the hybrid design:
## Current production state (baseline)
`frank-default-large` (Dankclaw, Vulkan0, 2026-08-15):
`frank-large` (Dankclaw, Vulkan0, 2026-08-15):
- Model: UD-Q8_K_XL, 31.5 GB, bundled MTP head.
- `--spec-default` (ngram-mod) with draft-mtp first in the chain.
@@ -225,7 +225,7 @@ tensor cache warm).
| E | A with n_max 3 and 5 | n_max curve on the split |
| F | A, plain Q8_0 model file | same-bit A/B |
| G | PP default proportional split (no `--tensor-split`) | confirms the 20/80 handicap |
| Ref | production frank-default-large (Vulkan, 2 slots) | the bar to beat |
| Ref | production frank-large (Vulkan, 2 slots) | the bar to beat |
Per config: `pp-test.sh bench 4` (4k prompt / 256 out) and `bench 16`
(16k / 256). Report: decode t/s (server print_timing), prefill t/s, MTP
@@ -245,5 +245,5 @@ production @16k) with the same 8-bit model.
`-dio` for RPC).
- llama.cpp b10433 source: `src/llama.cpp` (device selection),
`common/speculative.cpp` (MTP/ngram-mod), `ggml/src/ggml-rpc` (protocol).
- Local benchmarks: [frank-default-large-benchmark](frank-default-large-benchmark.md),
- Local benchmarks: [frank-large-benchmark](frank-large-benchmark.md),
[qwen3.8-spec-matrix](qwen3.8-spec-matrix.md).
@@ -1,6 +1,6 @@
---
type: benchmark plan
title: frank-default-large ubatch sweep
title: frank-large ubatch sweep
description: Standardized ubatch sweep for the active kingjones Qwen3.8 ROCmFPX deployment.
tags:
- llama.cpp
@@ -10,9 +10,9 @@ tags:
timestamp: 2026-09-01
---
# frank-default-large ubatch sweep
# frank-large ubatch sweep
This benchmark uses the active `frank-default-large` model on Dankclaw with
This benchmark uses the active `frank-large` model on Dankclaw with
`llama-bench`. It does not use `llama-server`, HTTP requests, or server-log
scraping. Stop the production service before running it and start the service
again afterward.
@@ -29,9 +29,9 @@ Each point runs three 128-token repetitions by default.
Run on Dankclaw from the repository checkout:
```bash
sudo systemctl stop frank-default-large
sudo systemctl stop frank-large
./scripts/bench-ubatch.sh
sudo systemctl start frank-default-large
sudo systemctl start frank-large
```
The script uses the active Q6 AGENT model, an 8K prompt workload, equal
@@ -1,6 +1,6 @@
# Service Research Brief
Consolidated research from the `frank-default-small` research subagents (2026-08-14) plus the pi agent knowledge base. This is the source material behind the per-service docs pages.
Consolidated research from the `frank-small` research subagents (2026-08-14) plus the pi agent knowledge base. This is the source material behind the per-service docs pages.
## Method
+19 -15
View File
@@ -51,8 +51,9 @@ covers both workloads).
- [[readarr]] — ebook/audiobook management
- [[prowlarr]] — indexer management
- [[qbittorrent]] — torrent download client
- [[Plex]] — native systemd media server on Dankserver (not a container)
- [[Tautulli]] — Plex statistics and notifications, snap-packaged
- [[Plex]] — media server on Dankserver (lscr.io/linuxserver/plex container via
quadlet; CPU decode only — no GPU passthrough)
- [[Tautulli]] — Plex statistics and notifications (v2.18.1-ls242, quadlet unit)
- [[mariadb]] — RomM database backend
- [[redis]] — RomM cache/queue backend
@@ -62,7 +63,7 @@ covers both workloads).
- [[SearXNG Providers]] — unblocking Google & other upstream engines behind the VPN
- [[Gluetun]] — the VPN tunnel container
- [[Valkey]] — SearXNG cache and limiter store
- [[ComfyUI]] — node-based AI image generation (CPU)
- [[ComfyUI]] — node-based AI image generation (ROCm GPU, gfx1151 build)
- [[OpenWebUI]] — chat UI for local LLMs
- [[Hermes]] — the Nous Research agent
- [[Hermes-Dashboard]] — the Hermes web management UI (config, keys, sessions)
@@ -112,35 +113,38 @@ The LLM inference fleet on the two hosts. Full index:
- [[deployment]] — unified deploy and update process for both servers
- [[frank-redo-2026-08-17]] — the 2026-08-17 topology change
- [[freetoken-frank-default-small]] — the active frank-default-small runbook: FreeToken v0.1.2 serving Qwen3.6-35B-A3B-FP8 on Dankserver (2026-09-02)
- [[freetoken-frank-small]] — the active frank-small runbook: FreeToken v0.1.2 serving Qwen3.6-35B-A3B-FP8 on Dankserver (2026-09-02)
- [[freetoken-benchmark-sweep]] — KV pool vs decode speed sweep (bs1/bs3/bs4/bs6, 8k–700k KV) on Dankserver RTX 3090
- [[kingjones-strix-mtp]] — the active kingjones Qwen3.8-27B ROCmFP4 STRIX MTP model on Dankclaw (restored 2026-09-01)
- [[agentionai-fast-imatrix]] — the ACTIVE frank-default-large runbook:
- [[kingjones-strix-mtp]] — the Qwen3.8-27B-Q6_0 ROCmFPX AGENT era with the
standalone MTP draft (Dankclaw, 2026-08-25 → 2026-08-29; historical)
- [[agentionai-fast-imatrix]] — the retired frank-large runbook:
agentionai/Qwen3.8-Flash-Next-ROCmFP4-FAST-imatrix (87.06 GiB,
Q4_0_ROCMFP4_FAST) + own MTP draft head, build-qwen38 (2026-08-29)
- [[kingjones-strix-rocmfp4]] — retired frank-default-large runbook:
kingjones777/Qwen3.8-Flash-Next-ROCmFP4-STRIX-GGUF (177B params, 113.47 GiB)
Q4_0_ROCMFP4_FAST) + own MTP draft, build-qwen38 (retired 2026-08-30;
rollback record)
- [[kingjones-strix-rocmfp4]] — the ACTIVE frank-large runbook since
2026-08-30: kingjones777/Qwen3.8-Flash-Next-ROCmFP4-STRIX-GGUF (177B params,
113.47 GiB) on the card's pinned kingjones30/ROCmFPX build
- [[kingjones-q8agent-rocmfpx]] — the retired Q8_0-AGENT investigation and `set_rows` failure
- [[eemin-rocmi4-mtp]] — the former caf-eemin Qwen3.8-27B ROCmI4 embedded-MTP model on Dankclaw
- [[ciru-activefpx-promptforge]] — the RETIRED v3 CIRU PromptForge runtime on Dankclaw (superseded 2026-08-24)
- [[kingjones-strix-mtp]] — the kingjones Qwen3.8-27B ROCmFP4 STRIX MTP model on Dankclaw (active)
- [[dealign-ornith-crack]] — the retired Ornith-1.5-35B-A3B CRACK model on Dankserver (retired 2026-09-02)
- [[ikllama-ornith-dankserver]] — the retired ik_llama.cpp runtime for frank-default-small (q8_0 + Hadamard KV cache, split-mode none; 2026-08-26)
- [[ikllama-ornith-dankserver]] — the retired ik_llama.cpp runtime for frank-small (q8_0 + Hadamard KV cache, split-mode none; 2026-08-26)
- [[kairic-edge]] — the retired Kairic Edge IU4 experiment (2026-08-22)
- [[dflash2-large-vulkan]] — the retired DFlash2 Vulkan deployment (2026-08-21)
- [[Dankserver System Specs]] — the RTX 3090 box hardware
- [[Dankclaw System Specs]] — the CIRU ROCmFPX box hardware
- [[Dankclaw Improvements]] — host-level changes on the CIRU box
- [[frank-default-sightsound]] — ACTIVE FLM NPU sight+sound runbook on Dankclaw:
- [[Dankclaw System Specs]] — the Strix Halo gfx1151 box (frank-large)
- [[Dankclaw Improvements]] — host-level changes on the Strix Halo box
- [[frank-npu]] — ACTIVE FLM NPU sight+sound runbook on Dankclaw:
Gemma4 E4B vision+audio pack on the XDNA2 NPU, port 7771; whole local
registry served on one port with per-request model routing; includes the
IOMMU/SVA root cause and the `iommu=pt` fix behind its first-deploy crash
### Benchmarks and Sizing
- [[frank-default-large-benchmark]] — backend/spec benchmark behind the old head
- [[frank-large-benchmark]] — backend/spec benchmark behind the old head
- [[ubatch-benchmark-large]] — active-model llama-bench ubatch sweep plan and results
- [[frank-default-small-benchmark]] — the small-model benchmark suite
- [[frank-small-benchmark]] — the small-model benchmark suite
- [[Running Qwen3.6 35B A3B FP8 on Dankserver]] — Qwen3.6-35B-A3B hardware notes
- [[Running Qwen3.6 27B FP8 on Dankclaw]] — Qwen3.6-27B sizing on the iGPU
- [[qwen3.8-strix-optimizations]] — Strix Halo tuning notes
+48 -13
View File
@@ -11,6 +11,41 @@ timestamp: 2026-09-14
# Bundle Change Log
## 2026-09-03 — full fact-check sweep of the docs tree (docs-only, deploy no-op)
- Scope: every page under `/serverAppConfigs-docs/` re-verified against live
hosts (read-only SSH), quadlet unit files, and the Caddyfile; surgical edits
only — no pages created, renamed, or deleted. Per the deploy planner, a
docs-only change is a deploy no-op.
- Dankserver core rewritten to live quadlet facts: the *arr stack + qBittorrent
+ gluetun run on **FrankBook-Pro** (units installed to
`/home/core/.config/containers/systemd/` via the frankbook-pro deploy
handler; `PUID=0/PGID=0`, data roots `/Volumes/COMPLETE/<svc>-data:/config`;
qB pinned `4.6.7` sharing gluetun's netns with 8080 + 6881 published on the
gluetun unit; readarr pinned `amd64-1.0.980`; no vhosts — direct IP:port,
exempt by construction from the guard chain). Jellyfin, Plex, RomM (8085→8080
guarded), Calibre-Web (`0.6.27-ls397` + universal-calibre mod; no standalone
calibre-server), mariadb/redis/Tautulli/Entropy verified against live units.
- Caddy guard chain documented to the live mechanism end-to-end: Anubis :8923 →
internal :8016 → post-auth :8017 routing; guarded vhosts (search, grafana,
prometheus, loki, seerr) route post-auth to container-name upstreams;
exemptions named by construction reason (auth/IdP itself, gitea smart-HTTP,
ai→:3005 own auth, hermes/hermesadmin internal-only via DNS absence, pihole
basicauth edge → :8083).
- `Gitea.md`: data roots + secrets corrected to the live unit paths
(`/home/dank/Containers/gitea/{data,postgres,env}`); UID gotcha corrected —
the units carry no `User=`/UserNS override, so container uid 1000 is literally
host uid 1000 (no subuid offset for these containers).
- Dedupe: `Prowlarr.md`/`prowlarr.md` collapsed into one canonical lowercase
page via rename (git history retains both versions; index link unchanged).
- LLM docs: archive pages (`DFlash DSpark Speculative Decoding`,
`ling-3.0-flash-trial`) reworded from current-tense to dated historical
framing with pointers to the active runbook [[kingjones-strix-rocmfp4]];
LLM `index.md` + `deployment.md` fleet tables and health-gate text updated to
the 2026-08-30 fleet state (STRIX on the pinned ROCmFPX fork; Huihui
abliterated FP8 on FreeToken; sightsound = FLM v1.0.1 on XDNA2, port 7771,
health `/v1/version` — FLM has no `/health` route).
- Suite green after the sweep: `./tests/run.sh` → 233 pass / 0 fail, including
the docs-completeness seam that requires every page to stay index-linked.
## 2026-09-01 (late) — FrankBook-Pro stack completed: tunnel live, qB wired into the arrs
- WireGuard credentials provisioned (second Proton config, server `PA-12`,
endpoint `51.179.177.2:51820`) → `/home/core/Containers/gluetun/env`
@@ -95,9 +130,9 @@ timestamp: 2026-09-14
rules), [[Jellyfin]] gained the LDAP-Auth plugin section. Docs-only
commit → deploy no-op.
## 2026-09-01 — frank-default-small: two compressed-tensors FP8 swaps fail to load; Huihui restored
- `/scripts/frank-default-small.env`, `/scripts/serve-frank-small.sh`,
`/scripts/frank-default-small.service` (`af6cd72` → `34ab6b4` → reverted
## 2026-09-01 — frank-small: two compressed-tensors FP8 swaps fail to load; Huihui restored
- `/scripts/frank-small.env`, `/scripts/serve-frank-small.sh`,
`/scripts/frank-small.service` (`af6cd72` → `34ab6b4` → reverted
in `4d5bea4`) — attempted model swaps on FreeToken v0.1.2, both
live-verified as loader failures and reverted the same day to the Huihui
FP8 checkpoint:
@@ -114,7 +149,7 @@ timestamp: 2026-09-14
- Both failed cleanly at load (37 GB fits RAM — no swap-thrash, no
outage); service was back on Huihui within the hour and re-verified with
a real completion (reasoning parses; `17*23 → 391`, natural stop).
- `/serverAppConfigs-docs/LLM/freetoken-frank-default-small.md` — quant
- `/serverAppConfigs-docs/LLM/freetoken-frank-small.md` — quant
matrix updated: modelopt block-fp8 is the ONLY FP8 path that loads; both
compressed-tensors shapes documented with their exact errors.
- **Deploy health-check trap (second occurrence)**: `deploy.sh` reported
@@ -164,8 +199,8 @@ timestamp: 2026-09-14
+ the two ownership regimes; [[Deployment Flow]] service-manager table
corrected (dankserver media is no longer "bare containers, inventory only").
## 2026-08-30 (night II) — frank-default-sightsound deployed; NPU SVA/IOMMU root cause
- **Deployed** `frank-default-sightsound` on Dankclaw: FLM v1.0.1 (`/usr/bin/flm`,
## 2026-08-30 (night II) — frank-npu deployed; NPU SVA/IOMMU root cause
- **Deployed** `frank-npu` on Dankclaw: FLM v1.0.1 (`/usr/bin/flm`,
dpkg `fastflowlm`) serving the whole local registry (36 tags) on port 52626;
primary model Gemma4 E4B IT NPU2 (vision + audio towers). First deploy
crash-looped every 10 s: `Open /dev/accel/accel0 failed (err=-19)`.
@@ -177,7 +212,7 @@ timestamp: 2026-09-14
kernel line — a consequence, not a GPU fault.
- **Fix**: `iommu=pt` in `GRUB_CMDLINE_LINUX_DEFAULT` + reboot (passthrough keeps
the iGPU default domain identity-mapped — zero DMA-translation overhead for
frank-default-large — while enabling IOMMU hardware + PASID, which SVA needs;
frank-large — while enabling IOMMU hardware + PASID, which SVA needs;
PASID domains are paged regardless of the default-domain type). Post-boot:
30 IOMMU groups, zero SVA-bind errors since boot, unit `enabled`,
`NRestarts=0` since boot.
@@ -187,18 +222,18 @@ timestamp: 2026-09-14
279 prompt tokens consumed); audio tower proven with a control pair (440 Hz
tone via `input_audio` = 37 prompt tokens vs 15 for the identical text-only
control). Health probe is `/v1/version` — FLM has no `/health` route.
- `/scripts/frank-default-sightsound.env`, `/scripts/serve-frank-default-sightsound.sh`,
`/scripts/frank-default-sightsound.service` + deployer allowlist entries
- `/scripts/frank-npu.env`, `/scripts/serve-frank-npu.sh`,
`/scripts/frank-npu.service` + deployer allowlist entries
(`c3ed3a6`, `cf0c541`) — service files and deploy wiring; unit is boot-persistent
(`WantedBy=multi-user.target`, enabled, `Restart=on-failure`, `RestartSec=10`,
`LimitMEMLOCK=infinity` — FLM requires unlimited memlock).
- **Docs**: new runbook [[frank-default-sightsound]] (linked from both indexes),
- **Docs**: new runbook [[frank-npu]] (linked from both indexes),
AGENTS.md fleet table + runtime section updated with the IOMMU/SVA hard
requirement. Client wiring: pi `models.json` registers the endpoint under the
Dankclaw provider with the exact FLM registry tag as model id.
## 2026-08-30 (night) — frank fleet double swap: STRIX on its pinned fork, Huihui on FreeToken
- **Dankclaw / frank-default-large**: swapped to
- **Dankclaw / frank-large**: swapped to
`kingjones777/Qwen3.8-Flash-Next-ROCmFP4-STRIX-GGUF` on the card's
pinned `kingjones30/ROCmFPX` runtime (built at
`/home/dank/GitPackages/kingjones-ROCmFPX/build`, `LLAMA_BUILD_WEBUI=OFF`
@@ -212,7 +247,7 @@ timestamp: 2026-09-14
git flow; manual-process race during validation caught and fixed
(unit was crash-looping on a bound port while its health check
passed — check MainPID, not just /health).
- **Dankserver / frank-default-small**: swapped the model within
- **Dankserver / frank-small**: swapped the model within
FreeToken v0.1.2 to `batsclamp/Huihui-Qwen3.6-35B-A3B-abliterated-FP8`
(native block-fp8, same loader path and pool plan; 35 GB downloaded
via `hf`, official checkpoint retained for rollback). Learned:
@@ -220,7 +255,7 @@ timestamp: 2026-09-14
tok/s verified post-deploy. Both `.service` Descriptions refreshed.
- Docs: [[kingjones-strix-rocmfp4]] reactivated as the large runbook
(runtime build + swap procedure + validation), [[agentionai-fast-imatrix]]
marked RETIRED (rollback record), [[freetoken-frank-default-small]]
marked RETIRED (rollback record), [[freetoken-frank-small]]
model sections updated, LLM index + AGENTS fleet tables refreshed.
## 2026-08-30 (late) — download chain proven end to end; qB credentials persisted