23 apps (MetaCore, the library/network/client tiers and 13 MetaFeeder*) move out of the general-purpose Worph/AppStore into their own store so the MetaMesh family releases on its own cadence. - asset URLs repointed to cdn.jsdelivr.net/gh/Worph/MetaAppStore@main - store scaffolding added (category/recommend/featured lists, licence, contributing, gitattributes) - psd-source/meta-icons-v2 icon generator follows the apps MetaMCP stays in Worph/AppStore: it is third-party metatool-ai software, not part of MetaMesh.
3.3 KiB
3.3 KiB
MetaWatch — Rationale
What deviation / exception is being requested
metawatch-core,metawatch-searchandmetawatch-sharerunuser: 0:0, andmetawatch-corerunsprivileged: true.- The stack publishes two host ports:
4003/tcpand4004/tcp(libp2p). - The app exposes three public hostnames —
metawatch-,metawatchshare-andmetawatchsearch-— each with its own AppShield sidecar, so two sidecarcontainer_names differ from the compose top-levelname:.
Why it is necessary
metawatch-coreis a bundled MetaCore: rclone remote mounts need a mount namespace (SYS_ADMIN+/dev/fuse+ an unconfined AppArmor profile), plus nginx and Redis.metawatch-searchandmetawatch-sharewrite service registrations into the root-owned/meta-core/services/.- libp2p is not HTTP — Caddy cannot proxy it, and remote peers resolve this node's
public multiaddr from the kad-DHT and dial it directly. Without inbound reachability the
node never serves bytes to the swarm. The app therefore carries the reserved
needs-public-iptag. - Each hostname is a distinct UI, and
auth-registrarderives an app's OIDCclient_idfrom the sidecar's container name via PTR lookup, so three routes need three stable, distinct names.x-casaos.mainpoints atmetawatch, the sidecar carrying the primary route.
Security mitigations in place
- Every publicly-routed hostname terminates at its own AppShield sidecar
(
ghcr.io/yundera/appshield:2.0.9) behind the PCS's Authelia SSO. Each sidecar setshostname:equal to itscontainer_namesoauth-registrarcan attest it via PTR and accept its redirect URIs; the names are app-prefixed, so they cannot collide with another app's services in the sharedpcsDNS namespace. - The backends carry no Caddy labels and publish no HTTP port to the host. The only published ports are raw libp2p TCP.
- libp2p transport is authenticated and encrypted (Noise) and peer identity is a public key, so an unauthenticated dial cannot read anything the node has not chosen to publish to the swarm.
- No user directories are mounted — no
/DATA/Documents,/DATA/Downloads,/DATA/Mediaor/DATA/Gallery. cpu_shareson every service; memory-heavy services carry a hardmem_limitwithmemswap_limitequal to it. All image tags pinned.
Alternatives considered and rejected
- Proxy libp2p through Caddy. Not possible; the DHT advertises a raw TCP multiaddr.
- One sidecar with path-based routing. The three backends generate absolute URLs and set cookies on their own hostnames; path-mounting them breaks both.
- Drop
privilegedfrommetawatch-corefor acap_addlist. Same container as MetaCore; the reduced form was tried and still failed to bring up the supervised daemons. - Use the shared-backend variant instead. That is
MetaWatchShared, for a box that already runs MetaCore and MetaShare. This app is the self-contained one.
Data protection
All state lives under /DATA/AppData/metawatch/, declared in x-compose-app.folders and
archived by Maison on uninstall, so an uninstall/reinstall with "keep user data" returns My
List and Continue Watching intact. No user media directory is mounted into any service;
bytes are served through the app's own transport peer.