252 lines
11 KiB
YAML
252 lines
11 KiB
YAML
name: metacore
|
|
|
|
services:
|
|
# Backend service. Reachable on the pcs network as `metacore-app`.
|
|
# Public ingress goes through the `metacore` hash-lock proxy below — this
|
|
# service has no public Caddy labels and no exposed host ports.
|
|
metacore-app:
|
|
image: ipcr-watch.nsl.sh/ipns/metadec.eth/metadec.eth/meta-core:1.2.0
|
|
container_name: metacore-app
|
|
# Hard RAM cap, swap disabled (memswap_limit == mem_limit) → OOM
|
|
# instead of swap. Both values must move together or swap comes back.
|
|
#
|
|
# Lowered to 1g (2026-10-19, meta-core 1.2.0). The store is an embedded
|
|
# SQLite file now (no Redis, no in-memory search copy): on watch.nsl.sh,
|
|
# 169k records, meta-core idles at ~70-160 MB and peaked at 568 MB during
|
|
# a full counter rebuild (POST /api/schema/rescan) — the heaviest operation
|
|
# it has. Page cache for the database file is charged here too but is
|
|
# reclaimable. History: 768m → 1536m (Redis working set) → 6g → 8g (the
|
|
# Redis-era in-memory index, ~30 KB/record, OOM-killed repeatedly).
|
|
mem_limit: 1g
|
|
memswap_limit: 1g
|
|
hostname: metacore-app
|
|
restart: unless-stopped
|
|
privileged: true
|
|
cpu_shares: 50
|
|
|
|
expose:
|
|
- 80
|
|
|
|
volumes:
|
|
# Shared infrastructure state: the metadata store (db/meta-core.db, SQLite),
|
|
# the leader lock, identity and mounts.
|
|
# Lives inside /DATA/AppData/metacore/ so CasaOS archives it on uninstall.
|
|
- ${DATA_ROOT:-/DATA}/AppData/metacore/meta-core:/meta-core:rw
|
|
|
|
# User's media directories — bind-mounted directly (no parent named volume,
|
|
# so `docker volume rm` cannot recurse into these and wipe host data).
|
|
- ${DATA_ROOT:-/DATA}/Downloads:/files/watch/downloads:ro
|
|
- ${DATA_ROOT:-/DATA}/Media:/files/watch/media:ro
|
|
|
|
# Application cache storage
|
|
- ${DATA_ROOT:-/DATA}/AppData/metacore/cache:/data/cache
|
|
|
|
# Plugin output — gateway/feeder-published artwork (posters, backdrops)
|
|
# lands here via meta-core's WebDAV endpoint, and every record's
|
|
# `filePath` points into it. This MUST be a bind mount: without it the
|
|
# directory is the container's writable layer, so any `docker compose
|
|
# up -d` that recreates metacore-app silently deletes every poster while
|
|
# the records keep pointing at them. That is exactly what happened on
|
|
# watch.nsl.sh on 2026-08-03 (270 files → 0), and it is the reason a
|
|
# fraction of poster CIDs 404 with a healthy-looking record behind them.
|
|
# metacore-app is the only service that mounts /files; the gateway and
|
|
# feeders write here over HTTP, so this one mount covers all of them.
|
|
- ${DATA_ROOT:-/DATA}/AppData/metacore/plugin:/files/plugin:rw
|
|
|
|
# MetaShare's download cache, read-only. Content fetched over the swarm
|
|
# lands there; meta-core indexes it (as a watcher POSTed at runtime, not
|
|
# an env var) so cached items become ordinary local records with a real
|
|
# filePath. Harmless when MetaShare isn't installed: the dir is empty.
|
|
- ${DATA_ROOT:-/DATA}/AppData/metashare/data/meta-share/cache:/files/cache:ro
|
|
|
|
environment:
|
|
- BASE_URL=https://metacore-$APP_DOMAIN
|
|
- TZ=$TZ
|
|
|
|
# Runs as root for nginx and rclone mounts
|
|
user: 0:0
|
|
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-sf", "http://localhost/health"]
|
|
interval: 5s
|
|
timeout: 3s
|
|
retries: 30
|
|
start_period: 30s
|
|
networks:
|
|
- pcs
|
|
|
|
# OIDC perimeter for the MetaCore dashboard. Self-registers as an OIDC client
|
|
# with the platform's auth-registrar on first login (no secrets to manage).
|
|
#
|
|
# Naming convention (per appshield + auth-registrar): the proxy's
|
|
# container_name MUST equal the URL-prefix of the public hostname, because the
|
|
# registrar's redirect-URI allowlist is "<container_name>" or "<container_name>-*".
|
|
# Our public URL is `metacore-${APP_DOMAIN}`, so the proxy container is named
|
|
# `metacore` and the backend takes the `-app` suffix.
|
|
metacore:
|
|
image: ghcr.io/yundera/appshield:2.0.9
|
|
cpu_shares: 80
|
|
container_name: metacore
|
|
hostname: metacore
|
|
restart: unless-stopped
|
|
user: "0:0"
|
|
|
|
expose:
|
|
- 80
|
|
|
|
environment:
|
|
OIDC_REGISTRAR_URL: "http://auth-registrar:9092"
|
|
BACKEND_HOST: "metacore-app"
|
|
BACKEND_PORT: "80"
|
|
LISTEN_PORT: "80"
|
|
REDIRECT_HOST_SUFFIXES: "${APP_DOMAIN},${APP_PUBLIC_IP_DASH}.nip.io,${APP_PUBLIC_IP_DASH}.sslip.io"
|
|
|
|
depends_on:
|
|
- metacore-app
|
|
|
|
labels:
|
|
# Only /health bypasses hash-lock — inter-service traffic (/meta/*,
|
|
# /webdav/*, /file/cid) flows over the pcs network from sibling apps
|
|
# (metasort-app, metafuse-app, metastremio) directly to metacore-app
|
|
# and never traverses the public proxy.
|
|
|
|
# ---- metacore-${APP_DOMAIN} (gateway TLS) ----
|
|
caddy_0: metacore-${APP_DOMAIN}
|
|
caddy_0.import: gateway_tls
|
|
caddy_0.0_handle: "/health"
|
|
caddy_0.0_handle.reverse_proxy: "metacore-app:80"
|
|
caddy_0.1_handle: ""
|
|
caddy_0.1_handle.reverse_proxy: "{{upstreams 80}}"
|
|
|
|
# ---- metacore-IP.nip.io (gateway TLS) ----
|
|
caddy_1: metacore-${APP_PUBLIC_IP_DASH}.nip.io
|
|
caddy_1.import: gateway_tls
|
|
caddy_1.0_handle: "/health"
|
|
caddy_1.0_handle.reverse_proxy: "metacore-app:80"
|
|
caddy_1.1_handle: ""
|
|
caddy_1.1_handle.reverse_proxy: "{{upstreams 80}}"
|
|
|
|
# ---- metacore-IP.sslip.io (Let's Encrypt) ----
|
|
caddy_2: metacore-${APP_PUBLIC_IP_DASH}.sslip.io
|
|
caddy_2.0_handle: "/health"
|
|
caddy_2.0_handle.reverse_proxy: "metacore-app:80"
|
|
caddy_2.1_handle: ""
|
|
caddy_2.1_handle.reverse_proxy: "{{upstreams 80}}"
|
|
|
|
networks:
|
|
- pcs
|
|
|
|
networks:
|
|
pcs:
|
|
name: ${APP_NET:-pcs}
|
|
external: true
|
|
|
|
x-casaos:
|
|
architectures:
|
|
- amd64
|
|
- arm64
|
|
author: Worph Team
|
|
category: Media
|
|
developer: Aptero Team
|
|
|
|
description:
|
|
en_us: |
|
|
**The infrastructure foundation for the MetaMesh media management ecosystem.**
|
|
|
|
MetaCore provides the shared services that power all MetaMesh applications: distributed leader election, Redis database, WebDAV file serving, remote mount management, and service discovery.
|
|
|
|
**Key Features:**
|
|
- **Leader Election** - Automatic flock-based leader election with failover support
|
|
- **Redis Database** - Centralized metadata storage for all MetaMesh services
|
|
- **WebDAV File Serving** - Cached file access for all services via HTTP
|
|
- **Mount Management** - Add NFS, SMB, and rclone remote mounts from the dashboard
|
|
- **File Watcher** - Monitors folders and notifies services of new files
|
|
- **Metadata Editor** - Browse and edit file metadata stored in Redis
|
|
- **Service Discovery** - Automatic registration and discovery of MetaMesh services
|
|
- **OIDC Single Sign-On** - Dashboard protected by Yundera's built-in Authelia (auto-registered, no secrets to configure)
|
|
|
|
**Install this FIRST** before MetaSort, MetaFuse, or MetaStremio.
|
|
|
|
**Dashboard Features:** Service health, file watchers, mount management, metadata editor, KV browser
|
|
|
|
fr_fr: |
|
|
**La fondation d'infrastructure pour l'ecosysteme de gestion de medias MetaMesh.**
|
|
|
|
MetaCore fournit les services partages qui alimentent toutes les applications MetaMesh : election de leader distribuee, base de donnees Redis, service de fichiers WebDAV, gestion de montages distants et decouverte de services.
|
|
|
|
**Fonctionnalites Cles:**
|
|
- **Election de Leader** - Election automatique basee sur flock avec support de basculement
|
|
- **Base de Donnees Redis** - Stockage centralise des metadonnees pour tous les services
|
|
- **Service de Fichiers WebDAV** - Acces aux fichiers en cache via HTTP
|
|
- **Gestion des Montages** - Ajout de montages NFS, SMB et rclone depuis le tableau de bord
|
|
- **Surveillance de Fichiers** - Surveille les dossiers et notifie les services des nouveaux fichiers
|
|
- **Editeur de Metadonnees** - Parcourir et editer les metadonnees stockees dans Redis
|
|
- **Decouverte de Services** - Enregistrement et decouverte automatiques des services
|
|
- **SSO OIDC** - Tableau de bord protege par l'Authelia integre de Yundera (auto-enregistre, aucun secret a configurer)
|
|
|
|
**Installez ceci EN PREMIER** avant MetaSort, MetaFuse ou MetaStremio.
|
|
|
|
tagline:
|
|
en_us: MetaMesh infrastructure - Leader election, Redis, WebDAV, and service discovery
|
|
fr_fr: Infrastructure MetaMesh - Election de leader, Redis, WebDAV et decouverte de services
|
|
|
|
title:
|
|
en_us: MetaCore
|
|
|
|
icon: https://gitea-watch.nsl.sh/metastar/MetaAppStore/raw/branch/main/Apps/MetaCore/icon.png
|
|
screenshot_link:
|
|
- https://gitea-watch.nsl.sh/metastar/MetaAppStore/raw/branch/main/Apps/MetaCore/screenshot-1.png
|
|
- https://gitea-watch.nsl.sh/metastar/MetaAppStore/raw/branch/main/Apps/MetaCore/screenshot-2.png
|
|
- https://gitea-watch.nsl.sh/metastar/MetaAppStore/raw/branch/main/Apps/MetaCore/screenshot-3.png
|
|
thumbnail: https://gitea-watch.nsl.sh/metastar/MetaAppStore/raw/branch/main/Apps/MetaCore/thumbnail.png
|
|
|
|
index: /
|
|
store_app_id: metacore
|
|
main: metacore
|
|
is_uncontrolled: false
|
|
|
|
tips:
|
|
before_install:
|
|
en_us: |
|
|
**MetaCore is the foundation for the MetaMesh ecosystem.**
|
|
|
|
Install this FIRST before MetaSort, MetaFuse, or MetaStremio.
|
|
|
|
**What MetaCore can see:** it mounts your **`/DATA/Downloads`** and **`/DATA/Media`**
|
|
folders **read-only** so it can watch them for new files and index what it finds.
|
|
It cannot modify, rename or delete anything in them. Everything it writes stays in
|
|
`/DATA/AppData/metacore/`. See `rationale.md` for the full breakdown.
|
|
|
|
**Authentication:** The dashboard is protected by Yundera's built-in Authelia via OIDC.
|
|
Sign in with your existing Yundera account when you open the dashboard for the first time.
|
|
|
|
**After installation:**
|
|
1. Open the dashboard at `https://metacore-$APP_DOMAIN/`
|
|
2. Sign in via the Authelia portal that appears
|
|
3. Install MetaSort, MetaFuse, or MetaStremio as needed
|
|
|
|
# Maison (Yundera dashboard) configuration. Read in preference to x-casaos.
|
|
# schema_version 2 is required for `folders`: an older Maison refuses the app
|
|
# outright rather than starting it without its directories.
|
|
x-compose-app:
|
|
schema_version: 2
|
|
# Created and chowned by Maison before any image is pulled, before any hook
|
|
# runs and before the containers start — on the first boot and every one after.
|
|
# Compose would otherwise create a missing bind source as a root-owned dir.
|
|
folders:
|
|
- path: /DATA/AppData/metacore/meta-core
|
|
user: $PUID
|
|
group: $PGID
|
|
- path: /DATA/AppData/metacore/cache
|
|
user: $PUID
|
|
group: $PGID
|
|
- path: /DATA/AppData/metacore/plugin
|
|
user: $PUID
|
|
group: $PGID
|
|
- path: /DATA/AppData/metacore/plugin/share
|
|
user: $PUID
|
|
group: $PGID
|
|
# Same string as the caddy_0 label, so the tile link and the route agree.
|
|
webui-host: metacore-${domain}
|
|
webui-path: "/"
|