ops: paivana and caddy config refresh

This commit is contained in:
Hernâni Marques 2026-09-09 00:52:54 +02:00
parent d8dbc6242b
commit 56f814a6de
No known key found for this signature in database
74 changed files with 4517 additions and 79 deletions

View file

@ -0,0 +1,5 @@
# Live on koopa: ~/koopa-silverbullet/.env (not git)
# Allocate HOST_PORT only after live `ss` + Freigabe + ports.md update.
HOST_PORT=9028
# Optional SilverBullet app auth (prefer Caddy basicauth):
# SB_USER=hernani:changeme

View file

@ -0,0 +1,44 @@
# koopa-silverbullet — SilverBullet on CachyOS base + server binary
# Build on koopa (x86_64):
# bash ~/koopa-admin-log/scripts/notes/build.sh
# → localhost/koopa-silverbullet:cachyos
#
# Base: docker.io/cachyos/cachyos (Arch-derived). App binary from upstream
# silverbullet-server-linux-x86_64 release (not the Alpine ghcr image).
ARG CACHYOS_IMAGE=docker.io/cachyos/cachyos:latest
FROM ${CACHYOS_IMAGE}
ARG SB_VERSION=2.10.0
ARG SB_ZIP_URL=https://github.com/silverbulletmd/silverbullet/releases/download/${SB_VERSION}/silverbullet-server-linux-x86_64.zip
ENV SB_HOSTNAME=0.0.0.0 \
SB_FOLDER=/space \
SB_PORT=3000 \
SB_NAME=SilverBullet \
TZ=Europe/Zurich \
PATH=/usr/local/bin:$PATH
# catatonit = Arch/CachyOS container init (tini not in repos)
RUN pacman -Syu --noconfirm --needed \
bash curl git openssh catatonit unzip \
&& pacman -Scc --noconfirm \
&& rm -rf /var/cache/pacman/pkg/* /tmp/*
# Fetch + install server binary (build-time; no Deno in image)
RUN curl -fsSL "$SB_ZIP_URL" -o /tmp/sb.zip \
&& unzip -o /tmp/sb.zip -d /tmp \
&& install -m 755 /tmp/silverbullet /silverbullet \
&& /silverbullet --version || true \
&& rm -rf /tmp/sb.zip /tmp/silverbullet
COPY entrypoint.sh /docker-entrypoint.sh
RUN chmod 755 /docker-entrypoint.sh \
&& mkdir -p /space
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD curl -fsS "http://127.0.0.1:${SB_PORT}/.instance" || exit 1
WORKDIR /space
ENTRYPOINT ["/usr/bin/catatonit", "--", "/docker-entrypoint.sh"]

65
configs/notes/README.md Normal file
View file

@ -0,0 +1,65 @@
# SilverBullet — SilverBullet on CachyOS (koopa)
Cross-host markdown notes (magikoopa + clementine). Stack name **SilverBullet** (parked web UI). Product **FreeNotes** = separate native enc notes (not this stack).
| Item | Value |
|------|--------|
| Stack | [SilverBullet](https://silverbullet.md/) server binary |
| Image | `localhost/koopa-silverbullet:cachyos` (`FROM docker.io/cachyos/cachyos`) |
| Live dir | `/home/hernani/koopa-silverbullet/` |
| Container | `koopa-silverbullet` |
| Host port | **9028** = Paivana paywall; app backend **127.0.0.1:19128** |
| Public site | `silverbullet.hacktivism.ch` |
| Auth | Paivana (GOA:42); no Caddy basic_auth |
| Forgejo space backup | private `hernani/freenotes` (historical name; SB space only) |
## Cutover freenotes → silverbullet (koopa)
Live still may be `~/koopa-freenotes` / CT `koopa-freenotes`. Scripts default dry-run; `--apply` needs Freigabe.
```bash
bash /path/to/koopa-admin-log/scripts/notes/status.sh
bash /path/to/koopa-admin-log/scripts/notes/cutover-to-silverbullet.sh
# Freigabe:
bash /path/to/koopa-admin-log/scripts/notes/cutover-to-silverbullet.sh --apply
```
See `scripts/notes/README.md` for seed + Caddy order. DNS: `silverbullet.hacktivism.ch`.
## Build + recreate (koopa)
```bash
# clone koopa-admin-log from Forgejo when needed (no permanent ~/ clone)
bash /path/to/koopa-admin-log/scripts/notes/build.sh
cd ~/koopa-silverbullet
podman-compose down
podman-compose up -d
bash /path/to/koopa-admin-log/scripts/notes/up.sh
```
## Caddy apply (sudo on koopa)
```bash
sudo bash /path/to/koopa-admin-log/scripts/caddy/merge-notes-site.sh
# seed from secrets-enc SoT so apply does not rotate PASS
sudo NOTES_AUTH_SEED=/tmp/silverbullet-basicauth-seed.txt \
bash /path/to/koopa-admin-log/scripts/caddy/apply-notes-basicauth.sh
```
Runtime: `/etc/caddy/secrets/silverbullet-basicauth.txt` (root-only). Never recreate `~/koopa-secrets`.
## Space SoT (Forgejo)
Private `hernani/freenotes` — live tree `~/koopa-silverbullet/space/` (git). On-koopa push uses oneshot HTTP token (no hernani SSH key in `~/.ssh`); laptop push via `git@git.hacktivism.ch:hernani/freenotes.git` (ProxyJump).
## Client apps (hosts)
Notes-like **system apps** (standalone Brave/Chrome `--app=` window + own profile): `configs/notes/client-apps/`.
- magikoopa: `~/Applications/SilverBullet.app``bash client-apps/install-magikoopa.sh`
- clementine (on-box): `silverbullet.desktop``bash client-apps/install-clementine.sh`
- optional: browser **Install app** (PWA) for Dock identity
## Plugs (SB)
`space/_plug/`: `treeview.plug.js`, `silversearch.plug.js` — see `PLUGS.md`.

View file

@ -0,0 +1,23 @@
# SilverBullet — system Notes apps (hosts)
Goal: **like Apple Notes** — a real system app window on each laptop, not a browser bookmark and not SilverBullet plugs.
| Host | App | Behavior |
|------|-----|----------|
| magikoopa | `SilverBullet.app``~/Applications/` | Brave/Chrome **`--app=`** + own profile (`SilverBullet-BraveProfile`) — no tab bar |
| clementine | `silverbullet.desktop` | same `--app=` via Brave/Chromium + `~/.local/share/SilverBullet-browser` |
| both (optional) | Browser **Install app** / PWA | even closer to native Dock/menu identity |
**Not this:** `space/_plug/` (TreeView/SilverSearch) — those are in-editor extensions.
Install:
```bash
# magikoopa
bash configs/notes/client-apps/install-magikoopa.sh
# clementine (on-box)
bash configs/notes/client-apps/install-clementine.sh
```
First launch: log in once (Caddy basicauth); credentials stay in the app profile.

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key><string>SilverBullet</string>
<key>CFBundleDisplayName</key><string>SilverBullet</string>
<key>CFBundleIdentifier</key><string>ch.hacktivism.silverbullet</string>
<key>CFBundleVersion</key><string>1</string>
<key>CFBundleShortVersionString</key><string>1.0</string>
<key>CFBundleExecutable</key><string>SilverBullet</string>
<key>CFBundlePackageType</key><string>APPL</string>
<key>LSMinimumSystemVersion</key><string>12.0</string>
<key>CFBundleIconFile</key><string>AppIcon</string>
</dict>
</plist>

View file

@ -0,0 +1,31 @@
#!/bin/bash
# SilverBullet — Notes-like system app (standalone window, not a browser tab)
URL="https://silverbullet.hacktivism.ch/"
USER_DATA="${HOME}/Library/Application Support/SilverBullet-BraveProfile"
mkdir -p "$USER_DATA"
BRAVE="/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"
CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
# Dedicated Chromium profile so this feels like its own app (Dock, cookies, no tab chrome)
if [[ -x "$BRAVE" ]]; then
exec "$BRAVE" \
--user-data-dir="$USER_DATA" \
--class=SilverBullet \
--app="$URL" \
--name=SilverBullet
elif [[ -x "$CHROME" ]]; then
exec "$CHROME" \
--user-data-dir="$USER_DATA" \
--class=SilverBullet \
--app="$URL" \
--name=SilverBullet
else
# last resort: Safari has no --app; open dedicated window via osascript
exec osascript <<'OSA'
tell application "Safari"
activate
make new document with properties {URL:"https://silverbullet.hacktivism.ch/"}
end tell
OSA
fi

View file

@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Install SilverBullet XFCE launcher on clementine (on-box). No Freigabe (user home).
set -euo pipefail
SRC="$(cd "$(dirname "$0")" && pwd)/silverbullet.desktop"
APPDIR="${HOME}/.local/share/applications"
DESK="${HOME}/Desktop"
mkdir -p "$APPDIR" "$DESK"
install -m 0644 "$SRC" "$APPDIR/silverbullet.desktop"
install -m 0644 "$SRC" "$DESK/silverbullet.desktop"
# refresh menu cache if available
command -v update-desktop-database >/dev/null && update-desktop-database "$APPDIR" || true
echo "STATUS=ok DESKTOP=$APPDIR/silverbullet.desktop SHORTCUT=$DESK/silverbullet.desktop"
echo "TIP=open https://silverbullet.hacktivism.ch then browser Install app for PWA"

View file

@ -0,0 +1,34 @@
#!/usr/bin/env bash
# Install SilverBullet.app into ~/Applications (magikoopa). No Freigabe (user home).
set -euo pipefail
SRC="$(cd "$(dirname "$0")" && pwd)/SilverBullet.app"
DEST="${HOME}/Applications/SilverBullet.app"
URL="${HOME}/Desktop/SilverBullet.url"
mkdir -p "${HOME}/Applications" "${HOME}/Desktop"
if [[ -d "$SRC" ]]; then
rm -rf "$DEST"
cp -R "$SRC" "$DEST"
else
# bootstrap minimal app if scaffold app tree missing
mkdir -p "$DEST/Contents/MacOS" "$DEST/Contents/Resources"
cat >"$DEST/Contents/Info.plist" <<'PLIST'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key><string>SilverBullet</string>
<key>CFBundleDisplayName</key><string>SilverBullet</string>
<key>CFBundleIdentifier</key><string>ch.hacktivism.silverbullet</string>
<key>CFBundleVersion</key><string>1</string>
<key>CFBundleShortVersionString</key><string>1.0</string>
<key>CFBundleExecutable</key><string>SilverBullet</string>
<key>CFBundlePackageType</key><string>APPL</string>
<key>LSMinimumSystemVersion</key><string>12.0</string>
</dict>
</plist>
PLIST
printf '%s\n' '#!/bin/bash' 'open "https://silverbullet.hacktivism.ch/"' >"$DEST/Contents/MacOS/SilverBullet"
chmod +x "$DEST/Contents/MacOS/SilverBullet"
fi
printf '%s\n' '[InternetShortcut]' 'URL=https://silverbullet.hacktivism.ch/' >"$URL"
echo "STATUS=ok APP=$DEST URL=$URL"

View file

@ -0,0 +1,12 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=SilverBullet
Comment=Notes-like SilverBullet on koopa standalone window
TryExec=brave-browser
Exec=sh -c 'B=""; for c in brave-browser brave chromium chromium-browser google-chrome; do command -v "$c" >/dev/null && B="$c" && break; done; if [ -n "$B" ]; then exec "$B" --user-data-dir="$HOME/.local/share/SilverBullet-browser" --class=SilverBullet --app=https://silverbullet.hacktivism.ch/; else exec xdg-open https://silverbullet.hacktivism.ch/; fi'
Terminal=false
Categories=Office;Network;
Keywords=notes;todo;silverbullet;
StartupWMClass=SilverBullet
StartupNotify=true

38
configs/notes/compose.yml Normal file
View file

@ -0,0 +1,38 @@
# koopa-silverbullet — SilverBullet on CachyOS base (parked; FreeNotes = native enc)
# Live: /home/hernani/koopa-silverbullet/
# Build: bash ~/koopa-admin-log/scripts/notes/build.sh → localhost/koopa-silverbullet:cachyos
#
# Public :9028 = koopa-paivana-silverbullet (shared paivana image).
# Backend loopback only — Paivana DEST → 127.0.0.1:19128
services:
notes:
image: localhost/koopa-silverbullet:cachyos
build:
context: .
dockerfile: Containerfile
args:
SB_VERSION: "${SB_VERSION:-2.10.0}"
container_name: koopa-silverbullet
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Zurich
- SB_INDEX_PAGE=index
- SB_NAME=SilverBullet
- SB_SHELL_BACKEND=off
# Optional app-layer auth (prefer Caddy basicauth; leave empty in .env to skip):
# - SB_USER=${SB_USER}
volumes:
- ./space:/space
ports:
- "127.0.0.1:${BACKEND_PORT:-19128}:3000"
labels:
org.hacktivism.service: silverbullet
org.hacktivism.host_port: "9028"
org.hacktivism.backend_port: "${BACKEND_PORT:-19128}"
org.hacktivism.site: silverbullet.hacktivism.ch
org.hacktivism.managed_by: koopa-admin
org.hacktivism.port_status: backend-19128-paywall-9028
org.hacktivism.image_base: cachyos

View file

@ -0,0 +1,28 @@
# container-koopa-silverbullet.service
# Install on koopa as hernani (after compose create):
# mkdir -p ~/.config/systemd/user
# cp configs/notes/container-koopa-silverbullet.service ~/.config/systemd/user/
# systemctl --user daemon-reload
# systemctl --user enable --now container-koopa-silverbullet.service
# Requires: loginctl enable-linger hernani (root, once)
#
# Container must already exist (podman-compose up -d once).
[Unit]
Description=Podman container-koopa-silverbullet.service (SilverBullet)
Documentation=https://silverbullet.md/
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/run/user/1000/containers
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always
TimeoutStopSec=90
ExecStart=/usr/bin/podman start koopa-silverbullet
ExecStop=/usr/bin/podman stop -t 20 koopa-silverbullet
ExecStopPost=/usr/bin/podman stop -t 20 koopa-silverbullet
Type=forking
[Install]
WantedBy=default.target

36
configs/notes/entrypoint.sh Executable file
View file

@ -0,0 +1,36 @@
#!/bin/bash
# SilverBullet entrypoint (CachyOS/Arch user tools).
# Adapted from upstream docker-entrypoint.sh (busybox → shadow useradd).
set -euo pipefail
if [[ -f /space/CONTAINER_BOOT.md ]]; then
echo "Executing CONTAINER_BOOT.md script"
bash /space/CONTAINER_BOOT.md &
fi
SB_FOLDER="${SB_FOLDER:-/space}"
if [[ -z "${PUID:-}" && "$(id -u)" == "0" ]]; then
PUID=$(stat -c "%u" "$SB_FOLDER")
echo "Will run SilverBullet with UID $PUID (from owner of $SB_FOLDER)"
fi
if [[ -z "${PGID:-}" ]]; then
PGID=$(stat -c "%g" "$SB_FOLDER")
fi
if [[ "${PUID:-0}" == "0" || "$(id -u)" != "0" ]]; then
exec /silverbullet "$@"
fi
echo "Creating silverbullet user UID=$PUID GID=$PGID"
getent group silverbullet >/dev/null 2>&1 || groupadd -g "$PGID" silverbullet || groupadd -o -g "$PGID" silverbullet
getent passwd silverbullet >/dev/null 2>&1 || useradd -M -N -g silverbullet -u "$PUID" -d "$SB_FOLDER" -s /bin/bash silverbullet \
|| useradd -o -M -N -g silverbullet -u "$PUID" -d "$SB_FOLDER" -s /bin/bash silverbullet
echo "Running SilverBullet as PUID=$PUID PGID=$PGID"
# quote-safe: pass args via "$@" under su -c is awkward; use runuser when present
if command -v runuser >/dev/null 2>&1; then
exec runuser -u silverbullet -- /silverbullet "$@"
fi
args=$(printf '%q ' "$@")
exec su silverbullet -s /bin/bash -c "/silverbullet $args"

View file

@ -0,0 +1,12 @@
# Plugs (apps)
Third-party SilverBullet plugs in (loaded automatically).
| Plug | Role |
|------|------|
| treeview.plug.js | Folder sidebar (Apple Notes-like) |
| silversearch.plug.js | Full-text search |
Install/update: drop into , reload SilverBullet.
Builtin SB plugs stay in the image; only extras live here.

View file

@ -0,0 +1,31 @@
# TODO
Canonical ADHD todo (SilverBullet space SoT; FreeNotes = separate native enc).
## Now (max 3) — active quest board
- [x] magikoopa SilverBullet.app (`~/Applications`) + Desktop SilverBullet.url
- [ ] Install silverbullet.desktop on clementine (on-box: client-apps/install-clementine.sh)
- [ ] One-shot migrate: Apple Notes export + Dokumente/TODO.md → here (or FreeNotes later)
- [ ] Human sudo: confirm `sudo ls -la /etc/caddy/secrets/silverbullet-basicauth.txt`
- [ ] Live cutover Freigabe: dir/container → koopa-silverbullet; Caddy → silverbullet.hacktivism.ch; DNS
## Next
- [x] Private Forgejo backup remote for space/ (hernani/freenotes — historical name)
- [x] Seed notes space on koopa
- [x] Caddy merge + basicauth scripts (live cutover pending Freigabe)
- [ ] DNS / public hostname silverbullet.hacktivism.ch (human)
- [x] Update productivity-adhd-notes 02 / 02b → single SoT pointing here
- [x] Wire magikoopa SSH push to hernani/freenotes (ProxyJump) — clone ~/git/freenotes
## Someday / amnesty
- [ ] PWA install both laptops (browser Install app)
- [ ] Second-layer SB_USER if basicauth alone is not enough
- [ ] TreeView / SilverSearch UX polish after first week
## Stats (gamification — agent updates)
- Session streak: 1
- Quests finished today: 6
- XP today: 60
- Last win: rename stack freenotes → silverbullet
- Boss: silverbullet cutover
- Boss HP: 70%

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,13 @@
# Inbox
Apple **Quick Note** analogue. Dump here first; triage into [[TODO]] (Now / Next / Waiting / Someday) or a dedicated page.
Rules:
- Empty capture OK — fill the next `- [ ]` line and save.
- Do not create a new folder just to capture.
- After triage, clear or check off lines so Inbox stays short.
## Capture
- [ ]

View file

@ -0,0 +1,46 @@
---
# SilverBullet index page (SB_INDEX_PAGE=index)
# Apple-Notes-like home: pins + capture path + search
---
# Notes
Cross-host notes (magikoopa + clementine) via koopa SilverBullet.
Mental model = Apple Notes: **folders/pages · list · editor**, pin primary TODO, Quick Note → triage.
| Page | Apple analogue | Role |
|------|----------------|------|
| [[TODO]] | Pinned primary note | ADHD SoT: Now≤3 / Next / Waiting / Someday / Stats |
| [[inbox]] | Quick Note | Capture before triage |
## Pins
- [[TODO]]
- [[inbox]]
## How to use (Apple habits → here)
1. **Capture** into [[inbox]] (or SB quick-note if enabled) — do not invent folders first.
2. **Triage** into [[TODO]] sections (Now max 3). Same rules as former Apple Notes guide.
3. **Find** with Page Picker / search (**Cmd/Ctrl-K**).
4. **New page** when a topic is not a todo (meetings, dumps) — link from TODO by title, do not dump transcripts into TODO.
5. Optional later: TreeView plug (folder sidebar), Space Lua query page = “smart folder” for `#tag` open tasks.
## Shortcuts (target)
| Action | Typical SB |
|--------|------------|
| Open page / filter | Cmd/Ctrl-K (Page Picker) |
| Quick note | Ctrl-q (if client supports) → prefer landing in [[inbox]] |
| Search body | built-in search / SilverSearch plug |
## Hygiene (from Apple Notes ADHD pack)
- One primary [[TODO]] — no competing systems.
- Capture first; tags (`#taler` …) optional and light.
- On “Im back”: re-read **Now** only.
- No passwords/tokens in notes.
## Apps
- [[PLUGS]] — TreeView + SilverSearch