Adds the act-runner service alongside Forgejo. It connects to the
Podman socket proxy so CI jobs can build and run containers on the Pi.
Also enables FORGEJO__actions__ENABLED on the Forgejo service.
FORGEJO_RUNNER_TOKEN must be set in .env — obtain it from:
Forgejo → Site Administration → Actions → Runners → Create new runner
https://claude.ai/code/session_01FKCW3FDjNFj6jve4niMFXH
backup.sh now covers all data:
- SQLite via podman exec into server container (fallback to host path)
- Postgres via pg_dumpall inside postgres container
- Forgejo data volume via podman volume export
- Caddy TLS certificates via podman volume export
- .env file (plaintext secrets — store archive securely)
restore.sh reverses each step: imports volumes, restores Postgres,
restores SQLite, optionally restores .env (--force to overwrite).
Both scripts find containers dynamically via compose service labels
so they work regardless of the container name podman-compose assigns.
.env.example documents HIY_BACKUP_DIR, HIY_BACKUP_REMOTE,
HIY_BACKUP_RETAIN_DAYS.
https://claude.ai/code/session_01FKCW3FDjNFj6jve4niMFXH
- docker-compose.yml: Forgejo service on hiy-net, configured via env vars
- postgres-init/01-forgejo.sql: creates forgejo user + database on first Postgres init
- .env.example: document FORGEJO_DB_PASSWORD and FORGEJO_DOMAIN
Routing: add FORGEJO_DOMAIN as an app in HIY pointing to forgejo:3000,
or add a Caddyfile block manually.
https://claude.ai/code/session_01FKCW3FDjNFj6jve4niMFXH
One Postgres 16 instance runs in the infra stack (docker-compose).
Each app can be given its own isolated schema with a dedicated,
scoped Postgres user via the new Database card on the app detail page.
What was added:
infra/
docker-compose.yml — postgres:16-alpine service + hiy-pg-data
volume; POSTGRES_URL injected into server
.env.example — POSTGRES_PASSWORD entry
server/
Cargo.toml — sqlx postgres feature
src/db.rs — databases table (SQLite) migration
src/models.rs — Database model
src/main.rs — PgPool (lazy) added to AppState;
/api/apps/:id/database routes registered
src/routes/mod.rs — databases module
src/routes/databases.rs — GET / POST / DELETE handlers:
provision — creates schema + scoped PG user, sets search_path,
injects DATABASE_URL env var
deprovision — DROP OWNED BY + DROP ROLE + DROP SCHEMA CASCADE,
removes SQLite record
src/routes/ui.rs — app_detail queries databases table, renders
db_card based on provisioning state
templates/app_detail.html — {{db_card}} placeholder +
provisionDb / deprovisionDb JS
Apps connect via:
postgres://hiy-<app>:<pw>@postgres:5432/hiy
search_path is set on the role so no URL option is needed.
https://claude.ai/code/session_01FKCW3FDjNFj6jve4niMFXH
- New HIY_ADMIN_USER / HIY_ADMIN_PASS env vars control access
- Login page at /login with redirect-after-login support
- Cookie-based sessions (HttpOnly, SameSite=Strict); cleared on restart
- Auth middleware applied to all routes except /webhook/:app_id (HMAC) and /login
- Auth is skipped when credentials are not configured (dev mode, warns at startup)
- Logout link in both dashboard nav bars
- Caddy admin port 2019 no longer published to the host in docker-compose
https://claude.ai/code/session_01FKCW3FDjNFj6jve4niMFXH
Caddy's email directive requires a non-empty argument. Since ACME_EMAIL
wasn't set, Caddy failed to parse the config. Email is optional for
Let's Encrypt — remove the directive entirely and document it as a
manual opt-in comment.
Caddy's built-in ACME support handles TLS automatically — no CF_API_TOKEN,
no Cloudflare account, no DNS plugin needed. Requires ports 80+443 forwarded
to the Pi and ACME_EMAIL set in infra/.env.
start.sh now generates proxy/caddy.json at launch time with Let's Encrypt
automatic HTTPS (HTTP-01 or TLS-ALPN-01 challenge — no Cloudflare needed).
Reads DOMAIN_SUFFIX and ACME_EMAIL from infra/.env before starting.
Added infra/.env.example to document required vars.