# Quadlet unit: open-notebook's SurrealDB (rootless, boot-persistent). # # Install path on dankclaw: ~/.config/containers/systemd/open-notebook-surrealdb.container # Unit name: open-notebook-surrealdb.service (container name: open-notebook-surrealdb) # # WHAT IT IS. open-notebook's only datastore: notebooks, notes, sources, # provider credentials and podcast episodes all live here. The app talks to it # over the WebSocket RPC on the private bridge (SURREAL_URL in # scripts/open-notebook.env), which is why the container NAME is part of the # contract — renaming it breaks the app's database URL, not just this file. # # IMAGE. `surrealdb/surrealdb:v2` pinned by manifest-list digest, resolved from # the registry on 2026-10-18 (that digest is SurrealDB 2.7.0, image built # 2026-09-23; `v2` itself is a MOVING tag, so the digest — not the tag — is what # makes this reproducible). Upstream open-notebook's own compose file pins the # same `v2` tag, and its Dockerfile copies /surreal out of the same image for # the retired single-container variant, so v2 is the version this app is built # against. Pull=never + the documented pull step (docs: [[Open Notebook]]): # # podman pull docker.io/surrealdb/surrealdb:v2@sha256:e5d7387e3727bbe2f7cd6d869e48cd34777272258572ead37c9656b25f745723 # # NO PUBLISHED PORT. 8000 is deliberately not published: the app reaches it by # name on systemd-open-notebook, and a published 8000 would put the RPC with # the root credentials on every interface (upstream publishes 127.0.0.1:8000 # "purely for local debugging" — a `podman exec` probe is enough here). The # binary binds 0.0.0.0:8000 INSIDE its own namespace via the image's # SURREAL_BIND env; without that image default it would bind loopback only and # the app could never connect, so no --bind flag belongs here. # # CREDENTIALS, AND WHY THEY ARE NOT IN THE COMMAND LINE. The `surreal start` # CLI reads its options from the environment (`--username` is [env: # SURREAL_USER=], `--password` is [env: SURREAL_PASS=] — verified against the # pinned image's own `start --help`), so the credentials arrive through the two # EnvironmentFile lines and the argv stays clean. Passing `--pass` instead — # what upstream's compose does — would put the database password in # /proc//cmdline, readable by any `ps` on the host. Note the two # spellings: the DATABASE reads SURREAL_PASS, the APP reads SURREAL_PASSWORD, # and scripts/open-notebook.env declares both because they must hold the same # value; the deployer writes that pair when it seeds the host secret file. # # NO USER= OVERRIDE. The image runs as uid 65532 (Chainguard glibc-dynamic # base). With a NAMED volume that works unmodified: podman creates the volume's # backing directory owned by the container's user (measured with this digest — # the host directory lands on the mapped subuid and the store starts clean), # which is exactly why upstream's `user: root` line is not repeated here: that # line is commented in upstream as being "required for bind mounts", and this # unit has none. The consequence is that the DB files are NOT readable by dank # without `podman unshare` — accepted for a datastore nobody edits by hand; # episode AUDIO is a host directory for the opposite reason (see the app unit). # # HEALTH. The base image is distroless: no shell, no curl, no wget, so no # CMD-SHELL probe and no wget/curl probe is possible here (same class of unit # as loki, whose probe had to move into the image). SurrealDB ships its own # probe instead — `surreal is-ready` connects to ws://localhost:8000 by default # and needs no credentials — verified against this digest: it prints `OK` and # exits 0 while the server is up. Argument-only HealthCmd, like every unit on # this host, because the quadlet generator splits it on spaces. [Unit] Description=SurrealDB (open-notebook datastore) After=network-online.target Wants=network-online.target [Container] ContainerName=open-notebook-surrealdb Image=docker.io/surrealdb/surrealdb:v2@sha256:e5d7387e3727bbe2f7cd6d869e48cd34777272258572ead37c9656b25f745723 Pull=never Network=open-notebook.network EnvironmentFile=/home/dank/serverAppConfigs/scripts/open-notebook.env EnvironmentFile=/home/dank/Containers/open-notebook/env Exec=start --log info rocksdb:/mydata/mydatabase.db Volume=open-notebook-db:/mydata HealthCmd=/surreal is-ready HealthInterval=30s HealthTimeout=10s HealthRetries=3 HealthStartPeriod=20s [Service] Restart=always RestartSec=5 [Install] WantedBy=default.target