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

40
scripts/notes/README.md Normal file
View file

@ -0,0 +1,40 @@
# SilverBullet — scripts (koopa)
Product **FreeNotes** is separate (native enc). These scripts operate the parked **SilverBullet** web stack on port **9028**.
| Script | Role |
|--------|------|
| `status.sh` | Read-only dirs / containers / `:9028` |
| `build.sh` | `podman build``localhost/koopa-silverbullet:cachyos` |
| `up.sh` | `podman-compose up` in `~/koopa-silverbullet` + health |
| `cutover-to-silverbullet.sh` | Live freenotes → silverbullet (default **dry-run**; `--apply` mutates) |
| `prepare-basicauth-seed.sh` | SoT → `/tmp/silverbullet-basicauth-seed.txt` (no sudo) |
Caddy (sudo, separate): `scripts/caddy/merge-notes-site.sh`, `apply-notes-basicauth.sh`.
## Cutover order (needs Freigabe + DNS)
On koopa as `hernani` (admin-log clone from Forgejo when needed):
```bash
bash …/scripts/notes/status.sh
bash …/scripts/notes/cutover-to-silverbullet.sh # dry-run
bash …/scripts/notes/cutover-to-silverbullet.sh --apply # Freigabe
```
Then Caddy (root) + seed from laptop SoT:
```bash
# laptop (unlocked secrets-enc):
bash …/scripts/notes/prepare-basicauth-seed.sh
scp /tmp/silverbullet-basicauth-seed.txt hernani@koopa:/tmp/
# koopa root:
sudo bash …/scripts/caddy/merge-notes-site.sh
sudo NOTES_AUTH_SEED=/tmp/silverbullet-basicauth-seed.txt \
bash …/scripts/caddy/apply-notes-basicauth.sh
```
DNS: `silverbullet.hacktivism.ch` → koopa (human). Public: `https://silverbullet.hacktivism.ch/`.
Keeps on cutover: `space/`, `.env`. Refreshes compose/Containerfile/entrypoint/unit from `configs/notes/`.

23
scripts/notes/build.sh Executable file
View file

@ -0,0 +1,23 @@
#!/usr/bin/env bash
# Build SilverBullet image on CachyOS base (run on koopa).
# bash ~/koopa-admin-log/scripts/notes/build.sh
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
CTX="${ROOT}/configs/notes"
TAG="${IMAGE_TAG:-localhost/koopa-silverbullet:cachyos}"
SB_VERSION="${SB_VERSION:-2.10.0}"
cd "$CTX"
[[ -f Containerfile ]] || { echo "ERROR: missing $CTX/Containerfile" >&2; exit 1; }
[[ -f entrypoint.sh ]] || { echo "ERROR: missing $CTX/entrypoint.sh" >&2; exit 1; }
echo "build $TAG (SB_VERSION=$SB_VERSION) ctx=$CTX"
podman build \
--build-arg "SB_VERSION=${SB_VERSION}" \
-t "$TAG" \
-f Containerfile \
.
echo "OK: $TAG"
podman image inspect "$TAG" --format '{{.Id}} {{.Size}} {{.Architecture}}' 2>/dev/null || true

View file

@ -0,0 +1,162 @@
#!/usr/bin/env bash
# Cut over live stack freenotes → silverbullet on koopa (hernani).
# Default: dry-run. Mutate only with --apply.
#
# bash /path/to/koopa-admin-log/scripts/notes/cutover-to-silverbullet.sh
# bash /path/to/koopa-admin-log/scripts/notes/cutover-to-silverbullet.sh --apply
#
# Keeps: space/, .env. Refreshes: compose.yml, Containerfile, entrypoint.sh, systemd unit.
# Image: retag localhost/koopa-freenotes:cachyos → localhost/koopa-silverbullet:cachyos (no rebuild).
# Does NOT touch Caddy (sudo) — print next steps only.
set -euo pipefail
APPLY=0
for a in "$@"; do
case "$a" in
--apply) APPLY=1 ;;
-h|--help)
sed -n '2,12p' "$0"
exit 0
;;
*)
echo "ERROR: unknown arg: $a (use --apply)" >&2
exit 2
;;
esac
done
OLD_DIR="${HOME}/koopa-freenotes"
NEW_DIR="${HOME}/koopa-silverbullet"
OLD_CT=koopa-freenotes
NEW_CT=koopa-silverbullet
OLD_IMG=localhost/koopa-freenotes:cachyos
NEW_IMG=localhost/koopa-silverbullet:cachyos
PORT=9028
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
CFG="${ROOT}/configs/notes"
[[ -d "$CFG" ]] || { echo "ERROR: missing $CFG" >&2; exit 1; }
[[ -f "$CFG/compose.yml" ]] || { echo "ERROR: missing $CFG/compose.yml" >&2; exit 1; }
mode=dry-run
[[ "$APPLY" -eq 1 ]] && mode=apply
echo "STATUS=start MODE=$mode HOST=$(hostname -s) OLD_DIR=$OLD_DIR NEW_DIR=$NEW_DIR"
have_old=0
have_new=0
[[ -d "$OLD_DIR" ]] && have_old=1
[[ -d "$NEW_DIR" ]] && have_new=1
echo "STATUS=dirs OLD=$have_old NEW=$have_new"
ct_old=$(podman ps -a --format '{{.Names}}' 2>/dev/null | grep -Fx "$OLD_CT" || true)
ct_new=$(podman ps -a --format '{{.Names}}' 2>/dev/null | grep -Fx "$NEW_CT" || true)
echo "STATUS=containers OLD=${ct_old:-none} NEW=${ct_new:-none}"
img_old=$(podman images -q "$OLD_IMG" 2>/dev/null || true)
img_new=$(podman images -q "$NEW_IMG" 2>/dev/null || true)
echo "STATUS=images OLD=${img_old:-none} NEW=${img_new:-none}"
dir_err=0
if [[ "$have_old" -eq 0 && "$have_new" -eq 1 ]]; then
echo "STATUS=already_cutover DIR=$NEW_DIR"
elif [[ "$have_old" -eq 0 && "$have_new" -eq 0 ]]; then
echo "STATUS=warn neither $OLD_DIR nor $NEW_DIR (ok for laptop dry-run; apply needs koopa)"
dir_err=1
elif [[ "$have_old" -eq 1 && "$have_new" -eq 1 ]]; then
echo "STATUS=warn both dirs exist — resolve manually before --apply"
dir_err=1
fi
plan() { echo "PLAN: $*"; }
plan "stop+rm container $OLD_CT (if present)"
plan "mv $OLD_DIR$NEW_DIR (if old present)"
plan "copy compose/Containerfile/entrypoint/unit from $CFG (keep space .env)"
plan "podman tag $OLD_IMG $NEW_IMG (if new image missing)"
plan "podman-compose up -d in $NEW_DIR"
plan "health curl :$PORT"
plan "optional: systemctl --user enable container-koopa-silverbullet.service"
if [[ "$APPLY" -ne 1 ]]; then
echo "STATUS=dry-run NEXT=re-run on koopa with --apply (Freigabe)"
echo "STATUS=caddy_next sudo bash $ROOT/scripts/caddy/merge-notes-site.sh"
echo "STATUS=caddy_next sudo NOTES_AUTH_SEED=/tmp/silverbullet-basicauth-seed.txt bash $ROOT/scripts/caddy/apply-notes-basicauth.sh"
echo "STATUS=dns_need silverbullet.hacktivism.ch → koopa"
exit 0
fi
if [[ "$dir_err" -eq 1 ]]; then
echo "ERROR: refuse --apply with ambiguous/missing live dirs" >&2
exit 1
fi
if [[ -n "$ct_old" ]]; then
echo "STATUS=stop $OLD_CT"
podman stop -t 20 "$OLD_CT" || true
podman rm "$OLD_CT" || true
fi
if [[ "$have_old" -eq 1 ]]; then
echo "STATUS=mv $OLD_DIR$NEW_DIR"
mv "$OLD_DIR" "$NEW_DIR"
fi
cd "$NEW_DIR"
# Refresh stack files from admin-log; never overwrite space/ or .env
cp -a "$CFG/compose.yml" "$NEW_DIR/compose.yml"
cp -a "$CFG/Containerfile" "$NEW_DIR/Containerfile"
cp -a "$CFG/entrypoint.sh" "$NEW_DIR/entrypoint.sh"
chmod +x "$NEW_DIR/entrypoint.sh"
cp -a "$CFG/container-koopa-silverbullet.service" "$NEW_DIR/container-koopa-silverbullet.service"
cp -a "$CFG/.env.example" "$NEW_DIR/.env.example"
# Drop obsolete unit name if present
rm -f "$NEW_DIR/container-koopa-freenotes.service"
echo "STATUS=refreshed_stack_files DIR=$NEW_DIR"
if [[ -z "$img_new" ]]; then
if [[ -n "$img_old" ]]; then
echo "STATUS=tag $OLD_IMG$NEW_IMG"
podman tag "$OLD_IMG" "$NEW_IMG"
else
echo "STATUS=build missing image via build.sh"
bash "$ROOT/scripts/notes/build.sh"
fi
fi
if [[ -n "$ct_new" ]]; then
echo "STATUS=rm stale $NEW_CT"
podman stop -t 10 "$NEW_CT" || true
podman rm "$NEW_CT" || true
fi
echo "STATUS=compose_up"
podman-compose up -d
ok=0
for i in $(seq 1 40); do
code=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 5 "http://127.0.0.1:${PORT}/" || true)
echo "STATUS=health try=$i code=$code"
case "$code" in
2*|3*) ok=1; break ;;
esac
sleep 3
done
[[ "$ok" -eq 1 ]] || { echo "ERROR: no answer on :${PORT}" >&2; podman-compose ps; exit 1; }
# User systemd unit (optional; ignore failures)
UNIT_SRC="$NEW_DIR/container-koopa-silverbullet.service"
UNIT_DST="${HOME}/.config/systemd/user/container-koopa-silverbullet.service"
if [[ -f "$UNIT_SRC" ]] && command -v systemctl >/dev/null; then
mkdir -p "${HOME}/.config/systemd/user"
cp -a "$UNIT_SRC" "$UNIT_DST"
systemctl --user daemon-reload || true
systemctl --user disable --now container-koopa-freenotes.service 2>/dev/null || true
systemctl --user enable --now container-koopa-silverbullet.service 2>/dev/null || true
echo "STATUS=systemd_user unit=container-koopa-silverbullet.service"
fi
echo "STATUS=ok CONTAINER=$NEW_CT DIR=$NEW_DIR PORT=$PORT"
echo "STATUS=caddy_next sudo bash $ROOT/scripts/caddy/merge-notes-site.sh"
echo "STATUS=caddy_next sudo NOTES_AUTH_SEED=/tmp/silverbullet-basicauth-seed.txt bash $ROOT/scripts/caddy/apply-notes-basicauth.sh"
echo "STATUS=dns_need silverbullet.hacktivism.ch → koopa"

View file

@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Copy silverbullet basicauth SoT → /tmp seed for apply-notes-basicauth.sh.
# Run on magikoopa (or any host with unlocked koopa-admin-secrets-enc).
# Does NOT touch /etc/caddy (no sudo). Does NOT print secret contents.
#
# bash scripts/notes/prepare-basicauth-seed.sh
# # then on koopa (after scp seed or shared path):
# sudo NOTES_AUTH_SEED=/tmp/silverbullet-basicauth-seed.txt \
# bash …/scripts/caddy/apply-notes-basicauth.sh
set -euo pipefail
OUT="${NOTES_AUTH_SEED_OUT:-/tmp/silverbullet-basicauth-seed.txt}"
SOT_DEFAULT="${HOME}/git/koopa-admin-secrets-enc/koopa/home-hernani/caddy/silverbullet-basicauth.txt"
SOT="${NOTES_AUTH_SOT:-$SOT_DEFAULT}"
[[ -f "$SOT" ]] || {
echo "ERROR: missing SoT $SOT (unlock git-crypt / set NOTES_AUTH_SOT=)" >&2
exit 1
}
umask 077
cp -a "$SOT" "$OUT"
chmod 600 "$OUT"
echo "STATUS=ok OUT=$OUT BYTES=$(wc -c <"$OUT" | tr -d ' ') NEXT=scp_or_use_NOTES_AUTH_SEED"
echo "STATUS=hint scp $OUT hernani@koopa:/tmp/ && sudo NOTES_AUTH_SEED=$OUT bash …/apply-notes-basicauth.sh"

39
scripts/notes/status.sh Executable file
View file

@ -0,0 +1,39 @@
#!/usr/bin/env bash
# Thin status for SilverBullet stack on koopa (hernani). Safe read-only.
# bash scripts/notes/status.sh
set -euo pipefail
OLD_DIR="${HOME}/koopa-freenotes"
NEW_DIR="${HOME}/koopa-silverbullet"
OLD_CT=koopa-freenotes
NEW_CT=koopa-silverbullet
OLD_IMG=localhost/koopa-freenotes:cachyos
NEW_IMG=localhost/koopa-silverbullet:cachyos
PORT=9028
echo "STATUS=host HOST=$(hostname -s)"
echo "STATUS=dirs OLD=$([ -d "$OLD_DIR" ] && echo 1 || echo 0) NEW=$([ -d "$NEW_DIR" ] && echo 1 || echo 0)"
if command -v podman >/dev/null 2>&1; then
ct_old=$(podman ps -a --format '{{.Names}} {{.Status}}' 2>/dev/null | grep -E "^${OLD_CT} " || true)
ct_new=$(podman ps -a --format '{{.Names}} {{.Status}}' 2>/dev/null | grep -E "^${NEW_CT} " || true)
echo "STATUS=ct_old ${ct_old:-none}"
echo "STATUS=ct_new ${ct_new:-none}"
img_old=$(podman images -q "$OLD_IMG" 2>/dev/null || true)
img_new=$(podman images -q "$NEW_IMG" 2>/dev/null || true)
echo "STATUS=img_old ${img_old:-none}"
echo "STATUS=img_new ${img_new:-none}"
else
echo "STATUS=podman missing"
fi
code=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 3 "http://127.0.0.1:${PORT}/" 2>/dev/null || echo fail)
echo "STATUS=local_http PORT=$PORT CODE=$code"
if [[ -d "$NEW_DIR" ]]; then
echo "STATUS=cutover done DIR=$NEW_DIR"
elif [[ -d "$OLD_DIR" ]]; then
echo "STATUS=cutover pending DIR=$OLD_DIR NEXT=cutover-to-silverbullet.sh"
else
echo "STATUS=cutover unknown (no live dir)"
fi

23
scripts/notes/up.sh Executable file
View file

@ -0,0 +1,23 @@
#!/usr/bin/env bash
# Bring up koopa-silverbullet / SilverBullet.
set -euo pipefail
DIR="${HOME}/koopa-silverbullet"
cd "${DIR}"
set -a
# shellcheck disable=SC1091
[[ -f .env ]] && source .env
set +a
PORT="${HOST_PORT:-9028}"
podman-compose up -d
echo "== wait for :${PORT} =="
ok=0
for i in $(seq 1 40); do
code=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 5 "http://127.0.0.1:${PORT}/" || true)
echo "try $i: $code"
case "$code" in
2*|3*) ok=1; break ;;
esac
sleep 3
done
[[ "$ok" -eq 1 ]] || { echo "ERROR: no answer on ${PORT}"; podman-compose ps; exit 1; }
echo "local ok. public (after Caddy+DNS): https://silverbullet.hacktivism.ch/"