Skip to content

Releases: Partha-dev01/pocket-homeserver

v1.0.0 — first stable release

Choose a tag to compare

@Partha-dev01 Partha-dev01 released this 23 Jun 18:57

pocket-homeserver v1.0.0 — the first stable release.

A complete, opt-in personal cloud on a single unrooted Android phone: Matrix chat, a Cloudflare-tunnelled Caddy edge, and ~30 optional services — files & sync, productivity, calendar & passwords, media, a git forge, DNS-over-HTTPS, a mesh VPN, and more. Every web service is loopback-bound behind the tunnel, every embedded database lives on ext4, every module is OFF by default, and every pinned artifact is sha256-verified fail-closed.

The full feature history (v0.4.0 → v0.9.1) is in the changelog. This release closes the pre-1.0 audit's remaining coverage gaps. From here, breaking changes follow SemVer.

What landed for 1.0

  • Universal loopback backstop. Beyond each service's config/env loopback assert, a post-start ss wildcard check now refuses to leave any service listening on a non-loopback address — extended from Forgejo + AdGuard to every Go/Node/Rust web listener (Navidrome, Vikunja, Kavita, Trilium, Audiobookshelf, Pingvin, Gatus, the Syncthing GUI, Vaultwarden, Dufs). It's a shared, port-scoped helper in scripts/lib/common.sh. This closes the raw-SYS_BIND class — the reason Photoview was dropped — for the whole stack. Validated on arm64 against a real Go binary (loopback passes; a forced wildcard is detected, stopped, and its port freed).
  • Every pin re-verified. All 16 sha256-pinned artifacts were re-checked against current upstream bytes — every one matches.
  • Honest dependency accounting. Pingvin builds from smp46/pingvin-share-x because canonical upstream is archived and that fork is the maintained successor; audited at the pinned tag (no npm lifecycle hooks, stock dependencies, loopback patch intact).

Notes

  • Two upstream-imposed residuals remain documented (injection-safe, Android-mitigated): FreshRSS create-user.php and the maddy per-user-IMAP password are --password-only on the command line.
  • All optional modules ship OFF; enable what you want via setup.sh / the in-panel app catalog.

🐧 See docs/SETUP.md for the zero-to-running walkthrough.

v0.9.1 — pre-1.0 hardening

Pre-release

Choose a tag to compare

@Partha-dev01 Partha-dev01 released this 23 Jun 18:01

Pre-1.0 hardening — fixes from a multi-agent security + correctness audit of the whole tree. All changes are backward-compatible; the SQLite relocation auto-migrates (with a backup).

Security

  • No cleartext-secret leak path on the public repo: .gitignore now ignores .env.bak* / .env.tmp*, and tools/leak-scan.sh gained a JWT-shaped backstop.
  • The MCP HTTP transport binds loopback only (127.0.0.1) with a fail-closed assert.
  • Admin-panel log redaction now scrubs S3/R2/SMTP credentials (from the 0600 secrets/*.env files) and is applied to the /action + /confirm output. The SnappyMail admin password is hashed off-argv (via stdin).
  • Kavita + Audiobookshelf: the optional Matrix-SSO forward_auth block moved inside the catch-all handle {} so it can never be hoisted ahead of the OPDS / token-API exemption (caddy-validated).
  • Syncthing GUI and Vikunja API listeners gained fail-closed loopback asserts.
  • Every ext4-vs-exFAT storage guard resolves the full real path (a symlinked leaf can no longer smuggle a SQLite DB onto the exFAT SD).

Changed

  • SQLite databases for Linkding, Memos, Vikunja, and FreshRSS moved to ext4 ($HOME/.pocket/<app>) — exFAT cannot do POSIX locks / atomic rename / durable fsync, which corrupts SQLite. An existing data dir on the SD is auto-migrated once (backed up first; the original is left in place to remove after verifying). Validated end-to-end on arm64 (WAL data intact).
  • exobot pins gradio instead of --upgrade; the metrics sampler defaults OFF in setup.sh.

Fixed

  • Admin panel: Dufs / FileBrowser / Syncthing now appear in the health + restart wiring, the Tailscale restart button resolves, and the restart-button row lists the v0.6–v0.9 apps.

See CHANGELOG.md for detail.

v0.9.0 — platform leverage & networking

Choose a tag to compare

@Partha-dev01 Partha-dev01 released this 23 Jun 13:13

Platform leverage & networking. A git forge, a DNS-over-HTTPS resolver, a bring-your-own reverse-proxy, a userspace mesh VPN, an in-panel app catalog, and an optional fail2ban-style rate-jail on the honeypot — all opt-in (ENABLE_* / RATE_JAIL_MODE, off by default), loopback-bound where they front a service, keeping any database/index/state on ext4.

Added

  • Forgejo (ENABLE_FORGEJO, git.${DOMAIN}) — single-binary git forge; sha256-pinned arm64 binary; HTTP_ADDR=127.0.0.1 + config assert + post-start ss wildcard check; runs as an unprivileged user; SSH/registration/Actions off, INSTALL_LOCK; SQLite WAL + repos on ext4; first admin + secrets generated off-argv. git-HTTP/API/LFS need a CF Access service-token exemption. (docs/FORGEJO.md)
  • AdGuard Home (ENABLE_ADGUARD, dns.${DOMAIN}) — filtering DoH resolver; UI + plain-HTTP DoH (/dns-query) on 127.0.0.1:9129, resolver on 9130; config assert + a post-start ss audit scoped to its own ports. Not a LAN :53 sinkhole; /dns-query needs a CF Access path bypass. (docs/ADGUARD.md)
  • BYO reverse-proxy (ENABLE_PROXY_ROUTES, PROXY_ROUTES) — publish any loopback service on its own subdomain; fail-closed loopback-target gate, injection-guard regex, collision check, authoritative stale-route sweep, fail-closed caddy validate. (docs/PROXY_ROUTES.md)
  • Tailscale (ENABLE_TAILSCALE) — userspace mesh VPN (no TUN/root) that sidesteps CGNAT; SOCKS5 + HTTP proxy on 127.0.0.1:1055; auth key off-argv; GOMEMLIMIT cap. ⚠️ The tailnet bypasses the Cloudflare edge — the tailnet ACL is the only network gate. (docs/TAILSCALE.md)
  • App catalog / module manager (ENABLE_APP_CATALOG) — enable + install a module from the admin panel; fixed in-code allow-list (request value never reaches argv), password re-auth + CSRF, ENABLE_*-only atomic 0600 .env writer, detached installs, secret redaction at the single /logs chokepoint. (docs/ADMIN.md)
  • Honeypot rate-jail (RATE_JAIL_MODE, default off) — fail2ban-style auth-failure-burst detector; enforce reuses the existing triple-gated cf_block (degrades safely to alert-only without the blocking opt-in). (docs/HONEYPOT.md)

Validation

Verified against the real pinned arm64 binaries under qemu-aarch64: Forgejo boot + /api/healthz + admin-create flags; AdGuard boot + wizard-skip + plain-HTTP /dns-query + scoped loopback audit; Tailscale rootless userspace bring-up + up-flag validation; and caddy validate of all new vhosts. Live tailnet join, CF Access exemptions, and on-device first-run flows remain operator-owed.

Pre-release. Interfaces may still change before 1.0.

v0.8.0 — media tier (Navidrome / Kavita / Audiobookshelf)

Choose a tag to compare

@Partha-dev01 Partha-dev01 released this 23 Jun 11:05

Media tier

Three optional, self-hosted media servers — music, comics/ebooks, and audiobooks — all opt-in (ENABLE_*, off by default), loopback-bound, keeping their database/index/cache on ext4 ($HOME/.pocket/<app>) while the bulk library may live on the exFAT SD. Direct-play by default (no on-the-fly transcoding — a phone has no usable hardware transcode path; software transcode is the thermal/LMK heavy path and stays opt-in). Subsonic / OPDS / mobile API paths are reverse-proxied ahead of the optional auth gate and get a Cloudflare Access path exemption (or service token).

Added

  • Navidrome (ENABLE_NAVIDROME) → music.${DOMAIN} — a music-streaming server with its own web player and a Subsonic-compatible API. A single static Go binary (sha256-pinned). Forces ND_ADDRESS=127.0.0.1 (Navidrome defaults to 0.0.0.0) and asserts it. Subsonic /rest/* + /share/* are exempted from the gate.
  • Kavita (ENABLE_KAVITA) → books.${DOMAIN} — a manga/comic/ebook server with an OPDS feed. A self-contained .NET arm64 build (sha256-pinned, needs system libicu72). Pre-seeds appsettings.json with IpAddresses=127.0.0.1 before first start (defaults to 0.0.0.0,::) and asserts it; the JWT TokenKey is generated off-argv. OPDS (/api/opds/*) is exempted.
  • Audiobookshelf (ENABLE_AUDIOBOOKSHELF) → audiobooks.${DOMAIN} — an audiobook/podcast server with progress sync. Built from source from a pinned git tag (no arm64 release binary; first build is 15–40+ min, like Pingvin). Forces HOST=127.0.0.1 and asserts it; pins native ffmpeg + the nunicode SQLite extension (SKIP_BINARIES_CHECK=1). The mobile-app API paths are exempted.
  • docs/MEDIA.md — the three media apps with a per-app Resource & Risk section, the storage-tier and direct-play rules, the per-app Cloudflare Access exemptions, a photo-gallery roadmap note, and an honest "why Jellyfin is docs-only" note.

Roadmap (not in this release)

A photo gallery was scoped for this tier (candidate: Photoview) but is deferred to the roadmap. Its Go server hardcodes a 0.0.0.0 bind, and no userland mechanism available on this stack (proot on unrooted Android) can safely force it to loopback — Go issues bind() as a raw syscall that an LD_PRELOAD shim cannot intercept (verified: it listens on *:port with and without the shim), and ptrace / user-namespace / seccomp-notify rewriting is unavailable or unvalidatable here. Loopback-only binding is a non-negotiable security invariant in this stack, so a gallery ships only once a real loopback path exists. See docs/MEDIA.md.


Pre-release, part of the staged path to 1.0. All new apps are off by default. See the CHANGELOG.

v0.7.0 — productivity & security apps

Pre-release

Choose a tag to compare

@Partha-dev01 Partha-dev01 released this 22 Jun 17:06

Productivity & security apps. Four optional, ENABLE_*-gated apps (off by default), loopback-bound, each keeping its DB/index on ext4 ($HOME/.pocket/<app>), never on the exFAT SD. Clients that speak native/token auth (Bitwarden apps, CalDAV/CardDAV, the Wallabag API, Trilium's ETAPI/sync) use a Cloudflare Access service-token exemption, not the interactive login gate.

  • Vaultwarden (vault.) — Bitwarden-compatible password manager. Upstream ships no standalone binary, so the installer daemonlessly extracts the musl-static binary + version-locked web-vault from the official alpine image pinned by its arm64 manifest digest (each layer sha256-verified), then re-verifies the extracted binary against a self-derived sha256. ROCKET_ADDRESS=127.0.0.1 + SIGNUPS_ALLOWED=false asserted; ADMIN_TOKEN unset; ENABLE_DB_WAL=true. See docs/VAULT.md.
  • Radicale (dav.) — CalDAV/CardDAV/tasks. Python venv on ext4; bcrypt from a prebuilt aarch64 wheel only (fail-closed, never compiles); hosts forced to loopback + asserted; bcrypt htpasswd seeded off-argv; root-mounted vhost so .well-known discovery works; collection root forced to ext4. The admin panel gains a /dav QR connect-card (the QR carries only the URL + username, never the password). See docs/DAV.md.
  • Trilium (wiki.) — notes/wiki, from the official first-party arm64 server tarball (bundled Node + prebuilt better-sqlite3, no node-gyp). TRILIUM_NETWORK_HOST=127.0.0.1 forced + asserted (default is 0.0.0.0); a fail-closed GLIBCXX boot-smoke; document.db on ext4. See docs/NOTES.md.
  • Wallabag (read.) — read-later, from the official bundled tarball (vendor/ pre-installed, no composer), reusing php-fpm; SQLite on ext4; admin password fed on stdin (off-argv); upgrades back up the DB before migrations + clear/warm the prod cache. See docs/READLATER.md.

Each new doc carries a prominent Resource & Risk section.

Validated on real arm64 (qemu-aarch64 containers, real pinned artifacts): Trilium GLIBCXX boot + loopback bind, Wallabag fos:user stdin admin-seed + wallabag:install + cache:clear, Radicale bcrypt-wheel install + auth + loopback bind, Vaultwarden extract (binary sha256 exact-match) + run, and caddy validate of all four vhosts. CI gates green (leak-scan, shellcheck, py_compile, install --check).

Pre-release: interfaces may still change before 1.0.

Full changelog: CHANGELOG.md

v0.6.0 — personal cloud: files & sync

Pre-release

Choose a tag to compare

@Partha-dev01 Partha-dev01 released this 22 Jun 12:18

Personal cloud — files & sync. Serve your own files from the phone and sync them
peer-to-peer. Every module is opt-in (ENABLE_*, off by default), loopback-bound,
and keeps its secrets in 0600 files (or Syncthing's own config), never in .env.

Added

  • Dufs (ENABLE_DUFS) — a tiny stateless Rust file server (browser UI +
    WebDAV) on files.${DOMAIN} (scripts/apps/dufs.sh). Read-only by default.
    It pins the binary by sha256, forces the listener to 127.0.0.1 (dufs defaults
    to 0.0.0.0) and asserts the loopback bind fail-closed after rendering its
    config, generates a per-deploy HTTP Basic credential (the $6$ hash goes in the
    0600 config; cleartext only in ${DATA_DIR}/secrets/dufs.env, never on argv).
  • FileBrowser (ENABLE_FILEBROWSER) — the classic v2 web file manager
    (multi-user accounts + share links, no WebDAV) on files.${DOMAIN}
    (scripts/apps/filebrowser.sh). Its BoltDB is pinned to ext4 (never the
    exFAT SD), and the admin is seeded deterministically from .env
    ADMIN_USER/ADMIN_PASSWORD off-argv (a pre-hashed bcrypt import) — no
    print-a-random-password-once lockout trap.
  • Mutually exclusive on files.${DOMAIN} — Dufs and FileBrowser share the
    hostname, so enabling both dies fail-closed; ./setup.sh keeps Dufs and
    disables the other if you pick both.
  • Syncthing (ENABLE_SYNCTHING) — peer-to-peer folder sync
    (scripts/steps/89-install-syncthing.sh). It sidesteps the Cloudflare tunnel
    entirely
    (so the ~100 MB body cap is irrelevant — the large-data path); its web
    GUI stays loopback-only (no public vhost; reach it via
    ssh -L 8384:127.0.0.1:8384). The HOME (config + cert + SQLite index DB)
    is forced to ext4 with a fail-closed assert against an SD path, and a random GUI
    password is set off-argv (syncthing generate reads it from stdin, never on the
    command line).
  • docs/FILES.md — the files & sync guide, including the mandated why-not-
    Nextcloud / why-no-SMB
    rationale, the Dufs-vs-FileBrowser chooser, the
    Cloudflare Tunnel ~100 MB upload cap + workarounds, the WebDAV service-token
    recipe, the ext4-vs-exFAT storage split, the Quantum-fork note, and a Resource &
    Risk section. Cross-linked from docs/SECURITY.md (the edge body cap) and
    docs/APP_AUTH.md (non-browser clients need a service token).
  • Version pins for all three in config/versions.env (DUFS_*, FILEBROWSER_*,
    SYNCTHING_*), each sha256-verified fail-closed.

Fixed

  • config/versions.env now actually ships. The central version/checksum
    manifest (added in 0.4.0) was caught by the *.env line in .gitignore and was
    never committed, so a fresh clone had no manifest for common.sh, ops/update.sh,
    ops/doctor.sh, and docs/UPDATING.md to operate on (installs still worked via
    each step's inline ${VAR:-default} fallback). It is now un-ignored and tracked —
    public version pins + sha256s only, no secrets.

v0.5.0 — reliability & ops

Pre-release

Choose a tag to compare

@Partha-dev01 Partha-dev01 released this 22 Jun 07:26

Reliability & ops — see your phone's health over time, get told when something breaks, get backups off the device, and manage Matrix users from the panel. Every piece is opt-in (ENABLE_*, off by default) and adds no inbound surface.

Added

  • Observability (ENABLE_METRICS) — a supervised metrics sampler records CPU/mem/swap/load/disk/temp/battery + the DEGRADED count once a minute into a capped JSONL ring on ext4. The admin panel gains a /metrics page (sparklines + a 24h health strip), a DEGRADED-aware /problems view + dashboard banner, a run doctor button, and a filter + line-count on the log viewer. See docs/OBSERVABILITY.md.
  • Crash-loop alertssetup.sh wires POCKET_ALERT_CMD (none / ntfy / healthchecks / Matrix). The Matrix channel ships ops/alert-matrix.sh, reading its token from a 0600 file.
  • Off-device encrypted backup (ENABLE_OFFSITE_BACKUP) — push the age-encrypted archives to any S3-compatible bucket (R2 / B2 / S3 / Wasabi / MinIO) via a dependency-free SigV4 client (ops/offsite-s3.py + offsite-push.sh); no rclone/aws/boto3. Refuses plaintext, mirrors retention, wired into the backup daemon, panel, and pocket.sh. See docs/BACKUPS.md.
  • Matrix user management (ENABLE_USER_ADMIN) — a panel /users page + ops/user-*.sh (list/create/reset-password/suspend/unsuspend/deactivate/invite) driven through continuwuity's admin command room (lib/matrix_admin.py). Each write op needs CSRF + password re-auth + audit; deactivation needs a typed confirm. See docs/USERS.md.

Fixed

  • The admin panel launcher now exports all the ENABLE_* flags (and MCP_TRANSPORT) the panel reads — previously the cloud-bots / exobot / stickers / adminbot / email / mcp / filter health rows and the admin-bot widget never appeared even when enabled.

Operator-owed verification: the Matrix user-management and offsite-push paths talk to the live homeserver / object store and are best exercised on-device.

Full notes: CHANGELOG.md

v0.4.0 — platform foundation

Pre-release

Choose a tag to compare

@Partha-dev01 Partha-dev01 released this 22 Jun 06:08

First milestone toward 1.0: the platform/reliability foundation that the new modules will build on.

Added

  • config/versions.env — one central manifest for every pinned version + sha256 (sourced after .env; your .env still overrides).
  • scripts/ops/update.sh — dry-run-by-default updates that back up the manifest, snapshot the Matrix DB, verify the new artifact fail-closed, restart, health-check, and roll back automatically on a crash loop. Tier-aware (binary/source/app/static/schema). See docs/UPDATING.md.
  • scripts/ops/doctor.sh — read-only preflight/self-test (config, exFAT-vs-ext4 storage tiers, proot userland, Termux addons, duplicate ports, loopback reachability, DEGRADED markers); never prints secrets.
  • CI (.github/workflows/ci.yml): ShellCheck + py_compile + a blocking leak-scan gate + install --check smoke.
  • SECURITY.md, issue/PR templates, and a versioning/release policy.
  • ./pocket.sh gains Update and Doctor menu items.

Fixed

  • install.sh --check now exits 0 on success.

Full notes in CHANGELOG.md.

v0.3.3

v0.3.3 Pre-release
Pre-release

Choose a tag to compare

@Partha-dev01 Partha-dev01 released this 21 Jun 18:42

Added

  • Crash-loop resilience for every supervised service. supervise() in
    scripts/lib/common.sh now respawns with exponential backoff
    (POCKET_RESPAWN_MIN..POCKET_RESPAWN_MAX, default 5s..300s) instead of a
    fixed 5s, treats a child that stays up >= POCKET_HEALTHY_SECS (default 60s) as
    healthy (resets backoff), and after POCKET_CRASHLOOP_FAILS (default 5) rapid
    failures raises a machine-readable DEGRADED marker and fires an optional
    one-shot alert. A corrupt-DB crash loop can no longer silently hammer storage
    for hours unnoticed.
  • Crash-loop alerting hook POCKET_ALERT_CMD (optional, off by default): a
    shell command run once when any service goes DEGRADED, with
    $POCKET_ALERT_SERVICE / $POCKET_ALERT_RC / $POCKET_ALERT_FAILS in the
    environment (never on argv). Wire it to healthchecks.io, ntfy, Matrix, etc.
  • DEGRADED visibility in the admin panel + /health. Crash-looping services
    show an amber pulsing dot and a "crash-looping" badge instead of flapping green;
    the Matrix row adds a "DB may be corrupt; run scripts/ops/restore.sh" hint.
    The marker auto-clears on a healthy run or a manual restart.
  • Configurable Matrix-DB backup cadence BACKUP_DB_CADENCE
    (daily|weekly|monthly), now defaulting to daily so an unclean-kill DB
    corruption costs at most ~1 day of data (the DB tar is small; the heavy rootfs
    stays monthly).
  • docs/RESILIENCE.md — the failure modes (unclean-kill RocksDB corruption,
    silent crash loops), what the stack does automatically, alerting setup, and
    recovery via ops/restore.sh. Plus an OFF-by-default, documented
    rocksdb_recovery_mode block in config/conduwuit.toml.tmpl.

v0.3.2 — audit fixes

Pre-release

Choose a tag to compare

@Partha-dev01 Partha-dev01 released this 20 Jun 16:42

Fixed

  • First-user creation now actually works. The setup wizard wrote a
    MATRIX_REGISTRATION_TOKEN to .env that nothing consumed (registration is
    baked closed in the homeserver config), and docs/SETUP.md told you to register
    with that dead token. Removed the inert MATRIX_ALLOW_REGISTRATION /
    MATRIX_REGISTRATION_TOKEN / MATRIX_ALLOW_FEDERATION vars and rewrote the
    first-user flow around scripts/ops/rotate-registration-token.sh (which opens
    token-gated signup and prints a working token) in the wizard and SETUP.md.
  • Landing portal install no longer aborts. 84-install-landing.sh only
    substituted __LANDING_ROOT__, leaving literal ${DOMAIN}/${CADDY_PORT}/
    ${CADDY_BIND} in the rendered vhost (the heredoc can't re-expand them) →
    caddy validate failed. The renderer now substitutes all of them, and the
    auth-gateway port is templated (__AUTHGW_PORT__) instead of hardcoded.
  • Operator admin bot regains its env-dependent commands. Its launcher sourced
    only the secrets file, so DATA_DIR/POCKET_LOG_DIR/MATRIX_SERVER_NAME were
    empty and !invite-token/!private-list plus the audit log silently failed.
    The launcher now exports them (matching the exobot launcher).
  • Honeypot SQLite no longer lands on the exFAT SD card (where its own code
    warns WAL/locking misbehaves). The watcher now points HP_DB at an internal
    ext4 path under $HOME/.pocket (overridable via POCKET_HONEYPOT_DB).
  • Email install no longer 404s on the Maddy download — the arch string is now
    aarch64 (upstream's name for arm64), not arm64.
  • Setup wizard completeness: it now prompts for the honeypot and the
    scheduled-backup daemon (previously enableable only by hand-editing .env),
    warns that SearXNG / IT-Tools / Gatus have no built-in login and must sit behind
    Cloudflare Access, and writes the full MCP_ALLOWED_LOGS list (fixes a drift
    introduced in 0.3.1).
  • No-auth backends are pinned to loopback. FreshRSS and SnappyMail php-fpm
    pools (and their Caddy upstreams/probes) now bind 127.0.0.1 explicitly instead
    of following CADDY_BIND, so they cannot be exposed on the LAN if a user sets
    CADDY_BIND=0.0.0.0.
  • exobot UI is no longer force-supervised on every bring-up (it is managed
    on-demand by the waker), restoring its lazy-start / idle-stop behaviour.

Changed

  • Docs: docs/SETUP.md now walks through creating one Cloudflare Tunnel
    public hostname per exposed service and protecting them with Cloudflare Access,
    and includes the literal pkg install git / git clone first steps;
    docs/SECURITY.md reflects the shipped (optional) honeypot and email backend;
    docs/ARCHITECTURE.md corrects the Matrix hostname to chat.${DOMAIN}; the
    README docs index and scripts/README.md are refreshed. Added
    ADMINWEB_SECURE_COOKIE to .env.example.