archy/releases/app-catalog.json

4245 lines
129 KiB
JSON
Raw Normal View History

{
"apps": {
"adguardhome": {
"image": "146.59.87.168:3000/lfg2025/adguardhome:v0.107.55",
"version": "v0.107.55"
},
"aiui": {
"manifest": {
"app": {
"container": {
"image": "localhost/archipelago-aiui:latest",
"pull_policy": "always"
},
"description": "Conversational AI interface for Archipelago. Quarantined — communicates only via context broker.",
"health_check": {
"endpoint": "http://localhost:80",
"interval": "60s",
"path": "/",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "aiui",
"internal": true,
"name": "AI Assistant",
"ports": [
{
"bind": "127.0.0.1",
"container": 80,
"host": 5180,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 1,
"disk_limit": "1Gi",
"memory_limit": "512Mi"
},
"security": {
"apparmor_profile": "aiui",
"capabilities": [],
"network_policy": "isolated",
"no_new_privileges": true,
"readonly_root": true,
"seccomp_profile": "default",
"user": 1000
},
"version": "0.1.0"
}
},
"version": "0.1.0"
},
"archy-btcpay-db": {
"manifest": {
"app": {
"bitcoin_integration": {
"rpc_access": "none",
"sync_required": false
},
"container": {
"data_uid": "100998:100998",
"image": "git.tx1138.com/lfg2025/postgres:15.17",
"network": "archy-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "POSTGRES_PASSWORD",
"secret_file": "btcpay-db-password"
}
]
},
"dependencies": [
{
"storage": "20Gi"
}
],
"description": "Postgres backend for BTCPay and NBXplorer.",
"environment": [
"POSTGRES_DB=btcpay",
"POSTGRES_USER=btcpay"
],
"health_check": {
"endpoint": "localhost:5432",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "archy-btcpay-db",
"name": "BTCPay Postgres",
"ports": [],
"resources": {
"disk_limit": "20Gi",
"memory_limit": "1Gi"
},
"security": {
"capabilities": [
"CHOWN",
"FOWNER",
"SETUID",
"SETGID",
"DAC_OVERRIDE"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "15.17",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/postgres-btcpay",
"target": "/var/lib/postgresql/data",
"type": "bind"
}
]
}
},
"version": "15.17"
},
"archy-mempool-db": {
"manifest": {
"app": {
"bitcoin_integration": {
"rpc_access": "none",
"sync_required": false
},
"container": {
"data_uid": "100998:100998",
"image": "git.tx1138.com/lfg2025/mariadb:11.4.10",
"network": "archy-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "MYSQL_PASSWORD",
"secret_file": "mempool-db-password"
},
{
"key": "MYSQL_ROOT_PASSWORD",
"secret_file": "mysql-root-db-password"
}
]
},
"dependencies": [
{
"storage": "20Gi"
}
],
"description": "MariaDB backend for the mempool explorer stack.",
"environment": [
"MYSQL_DATABASE=mempool",
"MYSQL_USER=mempool"
],
"health_check": {
"endpoint": "localhost:3306",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "archy-mempool-db",
"name": "Mempool MariaDB",
"ports": [],
"resources": {
"disk_limit": "20Gi",
"memory_limit": "512Mi"
},
"security": {
"capabilities": [
"CHOWN",
"FOWNER",
"SETUID",
"SETGID",
"DAC_OVERRIDE"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "11.4.10",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/mysql-mempool",
"target": "/var/lib/mysql",
"type": "bind"
}
]
}
},
"version": "11.4.10"
},
"archy-mempool-web": {
"manifest": {
"app": {
"bitcoin_integration": {
"rpc_access": "none",
"sync_required": false
},
"container": {
"image": "146.59.87.168:3000/lfg2025/mempool-frontend:v3.0.1",
"network": "archy-net",
"pull_policy": "if-not-present"
},
"container_name": "mempool",
"dependencies": [
{
"app_id": "mempool-api",
"version": ">=3.0.0"
}
],
"description": "Frontend web UI for mempool explorer.",
"environment": [
"FRONTEND_HTTP_PORT=8080",
"BACKEND_MAINNET_HTTP_HOST=mempool-api"
],
"health_check": {
"endpoint": "http://127.0.0.1:8080",
"interval": "30s",
"path": "/",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "archy-mempool-web",
"name": "Mempool Web",
"ports": [
{
"container": 8080,
"host": 4080,
"protocol": "tcp"
}
],
"resources": {
"memory_limit": "512Mi"
},
"security": {
"capabilities": [],
"network_policy": "isolated",
"readonly_root": false
},
"version": "3.0.1"
}
},
"version": "3.0.1"
},
"archy-nbxplorer": {
"manifest": {
"app": {
"bitcoin_integration": {
"rpc_access": "read-only",
"sync_required": true
},
"container": {
"image": "git.tx1138.com/lfg2025/nbxplorer:2.6.0",
"network": "archy-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "NBXPLORER_BTCRPCPASSWORD",
"secret_file": "bitcoin-rpc-password"
},
{
"key": "BTCPAY_DB_PASS",
"secret_file": "btcpay-db-password"
}
]
},
"dependencies": [
{
"app_id": "bitcoin-core",
"version": ">=26.0"
},
{
"app_id": "archy-btcpay-db",
"version": ">=15.17"
}
],
"description": "BTCPay blockchain indexer service.",
"environment": [
"NBXPLORER_DATADIR=/data",
"NBXPLORER_NETWORK=mainnet",
"NBXPLORER_CHAINS=btc",
"NBXPLORER_BIND=0.0.0.0:32838",
"NBXPLORER_BTCRPCURL=http://bitcoin-knots:8332",
"NBXPLORER_BTCRPCUSER=archipelago",
"NBXPLORER_BTCNODEENDPOINT=bitcoin-knots:8333",
"NBXPLORER_NOAUTH=1",
"NBXPLORER_POSTGRES=Username=btcpay;Password=${BTCPAY_DB_PASS};Host=archy-btcpay-db;Port=5432;Database=nbxplorer"
],
"health_check": {
"endpoint": "http://localhost:32838",
"interval": "30s",
"path": "/",
"retries": 5,
"timeout": "30s",
"type": "http"
},
"id": "archy-nbxplorer",
"name": "NBXplorer",
"ports": [
{
"container": 32838,
"host": 32838,
"protocol": "tcp"
}
],
"resources": {
"disk_limit": "20Gi",
"memory_limit": "2Gi"
},
"security": {
"capabilities": [],
"network_policy": "isolated",
"readonly_root": false
},
"version": "2.6.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/nbxplorer",
"target": "/data",
"type": "bind"
}
]
}
},
"version": "2.6.0"
},
"bitcoin-core": {
"manifest": {
"app": {
"bitcoin_integration": {
"pruning_support": true,
"rpc_access": "admin",
"sync_required": true,
"testnet_support": false
},
"container": {
"custom_args": [
"BITCOIND=\"$(command -v bitcoind || true)\"; if [ -z \"$BITCOIND\" ]; then\n BITCOIND=\"$(find /opt -path '*/bin/bitcoind' -type f 2>/dev/null | sort | tail -n 1)\";\nfi; if [ -z \"$BITCOIND\" ]; then\n echo \"bitcoind not found in image\" >&2;\n exit 127;\nfi; RPC_USER=\"$(printenv BITCOIN_RPC_USER)\"; RPC_PASS=\"$(printenv BITCOIN_RPC_PASS)\"; RPC_TXRELAY_AUTH=\"$(printenv BITCOIN_RPC_TXRELAY_RPCAUTH || true)\"; DISK_GB_VALUE=\"$(printenv DISK_GB || true)\"; RPC_HEADROOM=\"-rpcthreads=16 -rpcworkqueue=256\"; RPC_TXRELAY_FLAGS=\"-rpcwhitelistdefault=0\"; if [ -n \"$RPC_TXRELAY_AUTH\" ]; then\n RPC_TXRELAY_FLAGS=\"$RPC_TXRELAY_FLAGS -rpcauth=$RPC_TXRELAY_AUTH -rpcwhitelist=txrelay:sendrawtransaction,submitpackage,testmempoolaccept,getmempoolinfo,getrawmempool,getmempoolentry,getnetworkinfo,getblockchaininfo,getblockcount,getblockhash,getblock,getblockheader,getrawtransaction,gettxout,gettxspendingprevout,decoderawtransaction,decodescript,estimatesmartfee,uptime,ping,getconnectioncount,getpeerinfo,getindexinfo,getdeploymentinfo,getchaintips\";\nfi; if [ \"${DISK_GB_VALUE:-0}\" -lt 1000 ]; then\n exec \"$BITCOIND\" -datadir=/home/bitcoin/.bitcoin -noconf -server=1 -prune=550 -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 -listen=1 -bind=0.0.0.0:8333 -dbcache=1024 -par=0 -maxconnections=125 $RPC_HEADROOM $RPC_TXRELAY_FLAGS -rpcuser=\"$RPC_USER\" -rpcpassword=\"$RPC_PASS\";\nelse\n exec \"$BITCOIND\" -datadir=/home/bitcoin/.bitcoin -noconf -server=1 -txindex=1 -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 -listen=1 -bind=0.0.0.0:8333 -dbcache=4096 -par=0 -maxconnections=125 $RPC_HEADROOM $RPC_TXRELAY_FLAGS -rpcuser=\"$RPC_USER\" -rpcpassword=\"$RPC_PASS\";\nfi"
],
"data_uid": "100101:100101",
"derived_env": [
{
"key": "DISK_GB",
"template": "{{DISK_GB}}"
}
],
"entrypoint": [
"sh",
"-lc"
],
"image": "146.59.87.168:3000/lfg2025/bitcoin:28.4",
"network": "archy-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "BITCOIN_RPC_PASS",
"secret_file": "bitcoin-rpc-password"
},
{
"key": "BITCOIN_RPC_TXRELAY_RPCAUTH",
"secret_file": "bitcoin-rpc-txrelay-rpcauth"
}
]
},
"container_name": "bitcoin-core",
"dependencies": [
{
"storage": "500Gi"
}
],
"description": "Reference Bitcoin Core node with dynamic prune/full-mode startup based on host disk.",
"environment": [
"BITCOIN_RPC_USER=archipelago"
],
"health_check": {
"endpoint": "localhost:8332",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "bitcoin-core",
"name": "Bitcoin Core",
"ports": [
{
"container": 8332,
"host": 8332,
"protocol": "tcp"
},
{
"container": 8333,
"host": 8333,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 0,
"disk_limit": "500Gi",
"memory_limit": "4Gi"
},
"security": {
"capabilities": [
"CHOWN",
"FOWNER",
"SETUID",
"SETGID",
"DAC_OVERRIDE"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "28.4.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/bitcoin",
"target": "/home/bitcoin/.bitcoin",
"type": "bind"
}
]
}
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
},
"version": "latest",
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
"versions": [
fix(bitcoin): bulletproof multi-version switching (Knots & Core) Three stacked bugs made "switch version" silently fail / crash-loop, and the data-access mismatch corrupted a node's index during recovery attempts. Backend renderer: - sync_quadlet_unit ignored the per-app pinned version and re-rendered the quadlet with the manifest's :latest every reconcile tick, reverting any switch. Factor the install-time catalog/pin resolution into a shared resolve_catalog_image() and call it in BOTH install_fresh and sync_quadlet_unit. - The renderer folded manifest `entrypoint: ["sh","-lc"]` into Exec=, which only worked when the image entrypoint was a passthrough shell wrapper. The versioned images use ENTRYPOINT ["bitcoind"], so Exec=sh -lc ... became `bitcoind sh -lc ...` and crash-looped. Emit a real Entrypoint= override; exec_changed now also compares Entrypoint=. Images: - Build all bitcoin images (Core + Knots, every version) as container-root (USER removed) like the legacy :latest image. Chain data is owned by the data_uid (container uid 102); root reads it via CAP_DAC_OVERRIDE (granted in the manifest). A non-root USER (the previous uid 1000) can't read existing chain data → "Error initializing block database". Still fully rootless: container-root maps to the unprivileged host service user. Catalog: - bitcoin-knots versions[]: 29.3.knots20260508/20260507/20260210 + 29.2.knots20251110, "latest" tracking newest. - bitcoin-core versions[]: add 29.2 + a "latest" entry. All images rebuilt root and published to the mirror. Frontend: - AppSidebar version dropdown: rename the latest option to "Always use the latest version" (no v prefix), fix right padding, and guarantee the current selection matches a real option (was rendering blank). - New InstallVersionModal: full-screen version chooser shown from the App Store / Discover install button for multi-version apps (Bitcoin Knots/Core), app icon + "Install <name>", latest pre-selected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 05:46:04 -04:00
{
"default": true,
fix(bitcoin): bulletproof multi-version switching (Knots & Core) Three stacked bugs made "switch version" silently fail / crash-loop, and the data-access mismatch corrupted a node's index during recovery attempts. Backend renderer: - sync_quadlet_unit ignored the per-app pinned version and re-rendered the quadlet with the manifest's :latest every reconcile tick, reverting any switch. Factor the install-time catalog/pin resolution into a shared resolve_catalog_image() and call it in BOTH install_fresh and sync_quadlet_unit. - The renderer folded manifest `entrypoint: ["sh","-lc"]` into Exec=, which only worked when the image entrypoint was a passthrough shell wrapper. The versioned images use ENTRYPOINT ["bitcoind"], so Exec=sh -lc ... became `bitcoind sh -lc ...` and crash-looped. Emit a real Entrypoint= override; exec_changed now also compares Entrypoint=. Images: - Build all bitcoin images (Core + Knots, every version) as container-root (USER removed) like the legacy :latest image. Chain data is owned by the data_uid (container uid 102); root reads it via CAP_DAC_OVERRIDE (granted in the manifest). A non-root USER (the previous uid 1000) can't read existing chain data → "Error initializing block database". Still fully rootless: container-root maps to the unprivileged host service user. Catalog: - bitcoin-knots versions[]: 29.3.knots20260508/20260507/20260210 + 29.2.knots20251110, "latest" tracking newest. - bitcoin-core versions[]: add 29.2 + a "latest" entry. All images rebuilt root and published to the mirror. Frontend: - AppSidebar version dropdown: rename the latest option to "Always use the latest version" (no v prefix), fix right padding, and guarantee the current selection matches a real option (was rendering blank). - New InstallVersionModal: full-screen version chooser shown from the App Store / Discover install button for multi-version apps (Bitcoin Knots/Core), app icon + "Install <name>", latest pre-selected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 05:46:04 -04:00
"image": "146.59.87.168:3000/lfg2025/bitcoin:latest",
"version": "latest"
fix(bitcoin): bulletproof multi-version switching (Knots & Core) Three stacked bugs made "switch version" silently fail / crash-loop, and the data-access mismatch corrupted a node's index during recovery attempts. Backend renderer: - sync_quadlet_unit ignored the per-app pinned version and re-rendered the quadlet with the manifest's :latest every reconcile tick, reverting any switch. Factor the install-time catalog/pin resolution into a shared resolve_catalog_image() and call it in BOTH install_fresh and sync_quadlet_unit. - The renderer folded manifest `entrypoint: ["sh","-lc"]` into Exec=, which only worked when the image entrypoint was a passthrough shell wrapper. The versioned images use ENTRYPOINT ["bitcoind"], so Exec=sh -lc ... became `bitcoind sh -lc ...` and crash-looped. Emit a real Entrypoint= override; exec_changed now also compares Entrypoint=. Images: - Build all bitcoin images (Core + Knots, every version) as container-root (USER removed) like the legacy :latest image. Chain data is owned by the data_uid (container uid 102); root reads it via CAP_DAC_OVERRIDE (granted in the manifest). A non-root USER (the previous uid 1000) can't read existing chain data → "Error initializing block database". Still fully rootless: container-root maps to the unprivileged host service user. Catalog: - bitcoin-knots versions[]: 29.3.knots20260508/20260507/20260210 + 29.2.knots20251110, "latest" tracking newest. - bitcoin-core versions[]: add 29.2 + a "latest" entry. All images rebuilt root and published to the mirror. Frontend: - AppSidebar version dropdown: rename the latest option to "Always use the latest version" (no v prefix), fix right padding, and guarantee the current selection matches a real option (was rendering blank). - New InstallVersionModal: full-screen version chooser shown from the App Store / Discover install button for multi-version apps (Bitcoin Knots/Core), app icon + "Install <name>", latest pre-selected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 05:46:04 -04:00
},
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
{
"image": "146.59.87.168:3000/lfg2025/bitcoin:31.0",
"version": "31.0"
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
},
{
"image": "146.59.87.168:3000/lfg2025/bitcoin:30.2",
"version": "30.2"
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
},
{
"image": "146.59.87.168:3000/lfg2025/bitcoin:29.3",
"version": "29.3"
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
},
fix(bitcoin): bulletproof multi-version switching (Knots & Core) Three stacked bugs made "switch version" silently fail / crash-loop, and the data-access mismatch corrupted a node's index during recovery attempts. Backend renderer: - sync_quadlet_unit ignored the per-app pinned version and re-rendered the quadlet with the manifest's :latest every reconcile tick, reverting any switch. Factor the install-time catalog/pin resolution into a shared resolve_catalog_image() and call it in BOTH install_fresh and sync_quadlet_unit. - The renderer folded manifest `entrypoint: ["sh","-lc"]` into Exec=, which only worked when the image entrypoint was a passthrough shell wrapper. The versioned images use ENTRYPOINT ["bitcoind"], so Exec=sh -lc ... became `bitcoind sh -lc ...` and crash-looped. Emit a real Entrypoint= override; exec_changed now also compares Entrypoint=. Images: - Build all bitcoin images (Core + Knots, every version) as container-root (USER removed) like the legacy :latest image. Chain data is owned by the data_uid (container uid 102); root reads it via CAP_DAC_OVERRIDE (granted in the manifest). A non-root USER (the previous uid 1000) can't read existing chain data → "Error initializing block database". Still fully rootless: container-root maps to the unprivileged host service user. Catalog: - bitcoin-knots versions[]: 29.3.knots20260508/20260507/20260210 + 29.2.knots20251110, "latest" tracking newest. - bitcoin-core versions[]: add 29.2 + a "latest" entry. All images rebuilt root and published to the mirror. Frontend: - AppSidebar version dropdown: rename the latest option to "Always use the latest version" (no v prefix), fix right padding, and guarantee the current selection matches a real option (was rendering blank). - New InstallVersionModal: full-screen version chooser shown from the App Store / Discover install button for multi-version apps (Bitcoin Knots/Core), app icon + "Install <name>", latest pre-selected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 05:46:04 -04:00
{
"image": "146.59.87.168:3000/lfg2025/bitcoin:29.2",
"version": "29.2"
fix(bitcoin): bulletproof multi-version switching (Knots & Core) Three stacked bugs made "switch version" silently fail / crash-loop, and the data-access mismatch corrupted a node's index during recovery attempts. Backend renderer: - sync_quadlet_unit ignored the per-app pinned version and re-rendered the quadlet with the manifest's :latest every reconcile tick, reverting any switch. Factor the install-time catalog/pin resolution into a shared resolve_catalog_image() and call it in BOTH install_fresh and sync_quadlet_unit. - The renderer folded manifest `entrypoint: ["sh","-lc"]` into Exec=, which only worked when the image entrypoint was a passthrough shell wrapper. The versioned images use ENTRYPOINT ["bitcoind"], so Exec=sh -lc ... became `bitcoind sh -lc ...` and crash-looped. Emit a real Entrypoint= override; exec_changed now also compares Entrypoint=. Images: - Build all bitcoin images (Core + Knots, every version) as container-root (USER removed) like the legacy :latest image. Chain data is owned by the data_uid (container uid 102); root reads it via CAP_DAC_OVERRIDE (granted in the manifest). A non-root USER (the previous uid 1000) can't read existing chain data → "Error initializing block database". Still fully rootless: container-root maps to the unprivileged host service user. Catalog: - bitcoin-knots versions[]: 29.3.knots20260508/20260507/20260210 + 29.2.knots20251110, "latest" tracking newest. - bitcoin-core versions[]: add 29.2 + a "latest" entry. All images rebuilt root and published to the mirror. Frontend: - AppSidebar version dropdown: rename the latest option to "Always use the latest version" (no v prefix), fix right padding, and guarantee the current selection matches a real option (was rendering blank). - New InstallVersionModal: full-screen version chooser shown from the App Store / Discover install button for multi-version apps (Bitcoin Knots/Core), app icon + "Install <name>", latest pre-selected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 05:46:04 -04:00
},
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
{
"image": "146.59.87.168:3000/lfg2025/bitcoin:28.4",
"version": "28.4.0"
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
},
{
"image": "146.59.87.168:3000/lfg2025/bitcoin:27.2",
"version": "27.2"
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
},
{
"deprecated": true,
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
"image": "146.59.87.168:3000/lfg2025/bitcoin:26.2",
"version": "26.2"
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
},
{
"deprecated": true,
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
"image": "146.59.87.168:3000/lfg2025/bitcoin:25.2",
"version": "25.2"
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
}
]
},
"bitcoin-knots": {
"image": "146.59.87.168:3000/lfg2025/bitcoin-knots:latest",
"manifest": {
"app": {
"bitcoin_integration": {
"pruning_support": true,
"rpc_access": "admin",
"sync_required": true,
"testnet_support": false
},
"container": {
"custom_args": [
"BITCOIND=\"$(command -v bitcoind || true)\"; if [ -z \"$BITCOIND\" ]; then\n BITCOIND=\"$(find /opt -path '*/bin/bitcoind' -type f 2>/dev/null | sort | tail -n 1)\";\nfi; if [ -z \"$BITCOIND\" ]; then\n echo \"bitcoind not found in image\" >&2;\n exit 127;\nfi; RPC_USER=\"$(printenv BITCOIN_RPC_USER)\"; RPC_PASS=\"$(printenv BITCOIN_RPC_PASS)\"; RPC_TXRELAY_AUTH=\"$(printenv BITCOIN_RPC_TXRELAY_RPCAUTH || true)\"; DISK_GB_VALUE=\"$(printenv DISK_GB || true)\"; RPC_HEADROOM=\"-rpcthreads=16 -rpcworkqueue=256\"; RPC_TXRELAY_FLAGS=\"-rpcwhitelistdefault=0\"; if [ -n \"$RPC_TXRELAY_AUTH\" ]; then\n RPC_TXRELAY_FLAGS=\"$RPC_TXRELAY_FLAGS -rpcauth=$RPC_TXRELAY_AUTH -rpcwhitelist=txrelay:sendrawtransaction,submitpackage,testmempoolaccept,getmempoolinfo,getrawmempool,getmempoolentry,getnetworkinfo,getblockchaininfo,getblockcount,getblockhash,getblock,getblockheader,getrawtransaction,gettxout,gettxspendingprevout,decoderawtransaction,decodescript,estimatesmartfee,uptime,ping,getconnectioncount,getpeerinfo,getindexinfo,getdeploymentinfo,getchaintips\";\nfi; if [ \"${DISK_GB_VALUE:-0}\" -lt 1000 ]; then\n exec \"$BITCOIND\" -datadir=/home/bitcoin/.bitcoin -noconf -server=1 -prune=550 -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 -listen=1 -bind=0.0.0.0:8333 -dbcache=2048 -par=0 -maxconnections=125 $RPC_HEADROOM $RPC_TXRELAY_FLAGS -rpcuser=\"$RPC_USER\" -rpcpassword=\"$RPC_PASS\";\nelse\n exec \"$BITCOIND\" -datadir=/home/bitcoin/.bitcoin -noconf -server=1 -txindex=1 -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 -listen=1 -bind=0.0.0.0:8333 -dbcache=4096 -par=0 -maxconnections=125 $RPC_HEADROOM $RPC_TXRELAY_FLAGS -rpcuser=\"$RPC_USER\" -rpcpassword=\"$RPC_PASS\";\nfi"
],
"data_uid": "100101:100101",
"derived_env": [
{
"key": "DISK_GB",
"template": "{{DISK_GB}}"
}
],
"entrypoint": [
"sh",
"-lc"
],
"image": "146.59.87.168:3000/lfg2025/bitcoin-knots:latest",
"network": "archy-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "BITCOIN_RPC_PASS",
"secret_file": "bitcoin-rpc-password"
},
{
"key": "BITCOIN_RPC_TXRELAY_RPCAUTH",
"secret_file": "bitcoin-rpc-txrelay-rpcauth"
}
]
},
"container_name": "bitcoin-knots",
"dependencies": [
{
"storage": "500Gi"
}
],
"description": "Full Bitcoin Knots node with dynamic prune/full-mode startup based on host disk.",
"environment": [
"BITCOIN_RPC_USER=archipelago"
],
"health_check": {
"endpoint": "localhost:8332",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "bitcoin-knots",
"name": "Bitcoin Knots",
"ports": [
{
"container": 8332,
"host": 8332,
"protocol": "tcp"
},
{
"container": 8333,
"host": 8333,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 0,
"disk_limit": "500Gi",
"memory_limit": "8Gi"
},
"security": {
"capabilities": [
"CHOWN",
"FOWNER",
"SETUID",
"SETGID",
"DAC_OVERRIDE"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "28.1.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/bitcoin",
"target": "/home/bitcoin/.bitcoin",
"type": "bind"
}
]
}
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
},
"version": "latest",
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
"versions": [
{
"default": true,
fix(bitcoin): bulletproof multi-version switching (Knots & Core) Three stacked bugs made "switch version" silently fail / crash-loop, and the data-access mismatch corrupted a node's index during recovery attempts. Backend renderer: - sync_quadlet_unit ignored the per-app pinned version and re-rendered the quadlet with the manifest's :latest every reconcile tick, reverting any switch. Factor the install-time catalog/pin resolution into a shared resolve_catalog_image() and call it in BOTH install_fresh and sync_quadlet_unit. - The renderer folded manifest `entrypoint: ["sh","-lc"]` into Exec=, which only worked when the image entrypoint was a passthrough shell wrapper. The versioned images use ENTRYPOINT ["bitcoind"], so Exec=sh -lc ... became `bitcoind sh -lc ...` and crash-looped. Emit a real Entrypoint= override; exec_changed now also compares Entrypoint=. Images: - Build all bitcoin images (Core + Knots, every version) as container-root (USER removed) like the legacy :latest image. Chain data is owned by the data_uid (container uid 102); root reads it via CAP_DAC_OVERRIDE (granted in the manifest). A non-root USER (the previous uid 1000) can't read existing chain data → "Error initializing block database". Still fully rootless: container-root maps to the unprivileged host service user. Catalog: - bitcoin-knots versions[]: 29.3.knots20260508/20260507/20260210 + 29.2.knots20251110, "latest" tracking newest. - bitcoin-core versions[]: add 29.2 + a "latest" entry. All images rebuilt root and published to the mirror. Frontend: - AppSidebar version dropdown: rename the latest option to "Always use the latest version" (no v prefix), fix right padding, and guarantee the current selection matches a real option (was rendering blank). - New InstallVersionModal: full-screen version chooser shown from the App Store / Discover install button for multi-version apps (Bitcoin Knots/Core), app icon + "Install <name>", latest pre-selected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 05:46:04 -04:00
"image": "146.59.87.168:3000/lfg2025/bitcoin-knots:29.3.knots20260508",
"version": "latest"
},
{
"image": "146.59.87.168:3000/lfg2025/bitcoin-knots:29.3.knots20260508",
"version": "29.3.knots20260508"
fix(bitcoin): bulletproof multi-version switching (Knots & Core) Three stacked bugs made "switch version" silently fail / crash-loop, and the data-access mismatch corrupted a node's index during recovery attempts. Backend renderer: - sync_quadlet_unit ignored the per-app pinned version and re-rendered the quadlet with the manifest's :latest every reconcile tick, reverting any switch. Factor the install-time catalog/pin resolution into a shared resolve_catalog_image() and call it in BOTH install_fresh and sync_quadlet_unit. - The renderer folded manifest `entrypoint: ["sh","-lc"]` into Exec=, which only worked when the image entrypoint was a passthrough shell wrapper. The versioned images use ENTRYPOINT ["bitcoind"], so Exec=sh -lc ... became `bitcoind sh -lc ...` and crash-looped. Emit a real Entrypoint= override; exec_changed now also compares Entrypoint=. Images: - Build all bitcoin images (Core + Knots, every version) as container-root (USER removed) like the legacy :latest image. Chain data is owned by the data_uid (container uid 102); root reads it via CAP_DAC_OVERRIDE (granted in the manifest). A non-root USER (the previous uid 1000) can't read existing chain data → "Error initializing block database". Still fully rootless: container-root maps to the unprivileged host service user. Catalog: - bitcoin-knots versions[]: 29.3.knots20260508/20260507/20260210 + 29.2.knots20251110, "latest" tracking newest. - bitcoin-core versions[]: add 29.2 + a "latest" entry. All images rebuilt root and published to the mirror. Frontend: - AppSidebar version dropdown: rename the latest option to "Always use the latest version" (no v prefix), fix right padding, and guarantee the current selection matches a real option (was rendering blank). - New InstallVersionModal: full-screen version chooser shown from the App Store / Discover install button for multi-version apps (Bitcoin Knots/Core), app icon + "Install <name>", latest pre-selected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 05:46:04 -04:00
},
{
"image": "146.59.87.168:3000/lfg2025/bitcoin-knots:29.3.knots20260507",
"version": "29.3.knots20260507"
fix(bitcoin): bulletproof multi-version switching (Knots & Core) Three stacked bugs made "switch version" silently fail / crash-loop, and the data-access mismatch corrupted a node's index during recovery attempts. Backend renderer: - sync_quadlet_unit ignored the per-app pinned version and re-rendered the quadlet with the manifest's :latest every reconcile tick, reverting any switch. Factor the install-time catalog/pin resolution into a shared resolve_catalog_image() and call it in BOTH install_fresh and sync_quadlet_unit. - The renderer folded manifest `entrypoint: ["sh","-lc"]` into Exec=, which only worked when the image entrypoint was a passthrough shell wrapper. The versioned images use ENTRYPOINT ["bitcoind"], so Exec=sh -lc ... became `bitcoind sh -lc ...` and crash-looped. Emit a real Entrypoint= override; exec_changed now also compares Entrypoint=. Images: - Build all bitcoin images (Core + Knots, every version) as container-root (USER removed) like the legacy :latest image. Chain data is owned by the data_uid (container uid 102); root reads it via CAP_DAC_OVERRIDE (granted in the manifest). A non-root USER (the previous uid 1000) can't read existing chain data → "Error initializing block database". Still fully rootless: container-root maps to the unprivileged host service user. Catalog: - bitcoin-knots versions[]: 29.3.knots20260508/20260507/20260210 + 29.2.knots20251110, "latest" tracking newest. - bitcoin-core versions[]: add 29.2 + a "latest" entry. All images rebuilt root and published to the mirror. Frontend: - AppSidebar version dropdown: rename the latest option to "Always use the latest version" (no v prefix), fix right padding, and guarantee the current selection matches a real option (was rendering blank). - New InstallVersionModal: full-screen version chooser shown from the App Store / Discover install button for multi-version apps (Bitcoin Knots/Core), app icon + "Install <name>", latest pre-selected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 05:46:04 -04:00
},
{
"image": "146.59.87.168:3000/lfg2025/bitcoin-knots:29.3.knots20260210",
"version": "29.3.knots20260210"
fix(bitcoin): bulletproof multi-version switching (Knots & Core) Three stacked bugs made "switch version" silently fail / crash-loop, and the data-access mismatch corrupted a node's index during recovery attempts. Backend renderer: - sync_quadlet_unit ignored the per-app pinned version and re-rendered the quadlet with the manifest's :latest every reconcile tick, reverting any switch. Factor the install-time catalog/pin resolution into a shared resolve_catalog_image() and call it in BOTH install_fresh and sync_quadlet_unit. - The renderer folded manifest `entrypoint: ["sh","-lc"]` into Exec=, which only worked when the image entrypoint was a passthrough shell wrapper. The versioned images use ENTRYPOINT ["bitcoind"], so Exec=sh -lc ... became `bitcoind sh -lc ...` and crash-looped. Emit a real Entrypoint= override; exec_changed now also compares Entrypoint=. Images: - Build all bitcoin images (Core + Knots, every version) as container-root (USER removed) like the legacy :latest image. Chain data is owned by the data_uid (container uid 102); root reads it via CAP_DAC_OVERRIDE (granted in the manifest). A non-root USER (the previous uid 1000) can't read existing chain data → "Error initializing block database". Still fully rootless: container-root maps to the unprivileged host service user. Catalog: - bitcoin-knots versions[]: 29.3.knots20260508/20260507/20260210 + 29.2.knots20251110, "latest" tracking newest. - bitcoin-core versions[]: add 29.2 + a "latest" entry. All images rebuilt root and published to the mirror. Frontend: - AppSidebar version dropdown: rename the latest option to "Always use the latest version" (no v prefix), fix right padding, and guarantee the current selection matches a real option (was rendering blank). - New InstallVersionModal: full-screen version chooser shown from the App Store / Discover install button for multi-version apps (Bitcoin Knots/Core), app icon + "Install <name>", latest pre-selected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 05:46:04 -04:00
},
{
"image": "146.59.87.168:3000/lfg2025/bitcoin-knots:29.2.knots20251110",
"version": "29.2.knots20251110"
feat(bitcoin): multi-version support for Core & Knots (install/switch/pin/auto-update) Lets a node runner choose which Bitcoin Core / Knots version to install (latest pre-selected), then switch, pin, or opt into auto-update from the app's interface — all manifest/catalog-driven, rootless, signed-registry, zero-data-loss. Motivated by upcoming BIP-110 signalling: runners need a real choice of software version. Backend: - version_config.rs: per-app pin + auto-update persistence (atomic, merge- preserving), downgrade detection, auto-update enumeration (+ unit tests). - app_catalog.rs: CatalogVersion / versions[] schema, catalog_versions(), catalog_image_for_version() (same-repo guard); a pin suppresses the update badge. - prod_orchestrator.rs: pinned version wins over the catalog default on every install/recreate. - install.rs: install-time `version` param persisted (default = unpinned). - set_config.rs: package.versions (read) + package.set-config (write) RPCs; downgrade is gated behind explicit confirm (warn + confirm + allow). - update.rs/main.rs: hourly per-app auto-update tick via the orchestrator (opt-in, pin-respecting); fix handle_package_update to be non-fatal for orchestrator-managed apps lacking a catalog primary image (bitcoin-core). UI: - MarketplaceAppDetails.vue: install-time version selector (shown when an app offers >=2 versions). - appDetails/AppSidebar.vue: "Version & Updates" card (switch / pin / auto- update toggle / downgrade warning), per app. - rpc-client.ts + en.json: RPC methods, types, strings. Phase 0 image pipeline: - scripts/build-bitcoin-image.sh: download official tarball + SHA256SUMS(.asc), verify SHA-256 + pinned-maintainer OpenPGP signature (fail-closed), build a minimal rootless image, smoke-test, tag + push. - apps/bitcoin-core/Dockerfile rewritten (drops stale community base); apps/bitcoin-knots/Dockerfile added. - generate-app-catalog.sh: emit curated versions[]; published + catalog now offers Core 25.2/26.2/27.2/28.4/29.3/30.2/31.0 + Knots 29.3.knots20260508. docs/bitcoin-multi-version-design.md: live progress tracker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:46:17 -04:00
}
]
},
"bitcoin-ui": {
"image": "146.59.87.168:3000/lfg2025/bitcoin-ui:1.7.84-alpha",
"manifest": {
"app": {
"container": {
"build": {
"context": "/opt/archipelago/docker/bitcoin-ui",
"dockerfile": "Dockerfile",
"tag": "localhost/bitcoin-ui:local"
}
},
"dependencies": [
{
"app_id": "bitcoin-core"
}
],
"description": "Archipelago-native HTTP proxy + static site for interacting with the\nBitcoin Core / Bitcoin Knots JSON-RPC. Runs nginx inside a container\nand reverse-proxies /bitcoin-rpc/ to 127.0.0.1:8332 on the host. The\nupstream Authorization header is substituted from\n/var/lib/archipelago/secrets/bitcoin-rpc-password by the prod\norchestrator's pre-start hook, rendered into an nginx.conf that is\nbind-mounted read-only at container start.\n",
"environment": [],
"health_check": {
"endpoint": "http://127.0.0.1:8334",
"interval": "30s",
"path": "/",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "bitcoin-ui",
"name": "Bitcoin UI",
"ports": [],
"resources": {
"memory_limit": "128Mi"
},
"security": {
"network_policy": "host",
"readonly_root": false
},
"version": "1.0.0",
"volumes": [
{
"options": [
"ro"
],
"source": "/var/lib/archipelago/bitcoin-ui/nginx.conf",
"target": "/etc/nginx/conf.d/default.conf",
"type": "bind"
}
]
}
},
"version": "1.7.84-alpha"
},
"botfights": {
"manifest": {
"app": {
"category": "community",
"container": {
"image": "146.59.87.168:3000/lfg2025/botfights:1.1.0",
"pull_policy": "always"
},
"dependencies": [
{
"storage": "500Mi"
}
],
"description": "Bot competition arena with 2-player arcade fighting mode. AI bots battle in trivia challenges while humans duke it out with controllers. Built for Bitcoiners.",
"environment": [
"NODE_ENV=production"
],
"health_check": {
"endpoint": "http://localhost:9100",
"interval": "30s",
"path": "/api/health",
"retries": 3,
"start_period": "30s",
"timeout": "10s",
"type": "http"
},
"id": "botfights",
"interfaces": {
"main": {
"description": "Bot arena and arcade fighter with controller support",
"name": "Web UI",
"path": "/",
"port": 9100,
"protocol": "http",
"type": "ui"
}
},
"metadata": {
"author": "Dorian",
"icon": "/assets/img/app-icons/botfights.svg",
"license": "MIT",
"repo": "https://botfights.net",
"tags": [
"bitcoin",
"gaming",
"arcade",
"fighter",
"bots",
"competition",
"controller"
]
},
"name": "BotFights",
"ports": [
{
"container": 9100,
"host": 9100,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 2,
"disk_limit": "500Mi",
"memory_limit": "512Mi"
},
"security": {
"apparmor_profile": "default",
"capabilities": [],
"network_policy": "bridge",
"no_new_privileges": true,
"readonly_root": true,
"seccomp_profile": "default",
"user": 1001
},
"version": "1.1.0",
"volumes": [
{
"source": "botfights-data",
"target": "/app/server/data",
"type": "bind"
},
{
"options": [
"rw",
"noexec",
"nosuid",
"size=64m"
],
"target": "/tmp",
"type": "tmpfs"
}
]
}
},
"version": "1.1.0"
},
"btcpay": {
"image": "docker.io/btcpayserver/btcpayserver:2.3.9",
"images": {
"archy-btcpay-db": "146.59.87.168:3000/lfg2025/postgres:15.17",
"archy-nbxplorer": "146.59.87.168:3000/lfg2025/nbxplorer:2.6.0",
"btcpay-server": "docker.io/btcpayserver/btcpayserver:2.3.9"
},
"version": "2.3.9"
},
"btcpay-server": {
"manifest": {
"app": {
"bitcoin_integration": {
"rpc_access": "read-only",
"sync_required": true
},
"container": {
"derived_env": [
{
"key": "BTCPAY_HOST",
"template": "{{HOST_IP}}:23000"
}
],
"image": "docker.io/btcpayserver/btcpayserver:2.3.9",
"network": "archy-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "BTCPAY_BTCRPCPASSWORD",
"secret_file": "bitcoin-rpc-password"
},
{
"key": "BTCPAY_DB_PASS",
"secret_file": "btcpay-db-password"
}
]
},
"dependencies": [
{
"app_id": "bitcoin-core",
"version": ">=26.0"
},
{
"app_id": "archy-btcpay-db",
"version": ">=15.17"
},
{
"app_id": "archy-nbxplorer",
"version": ">=2.6.0"
}
],
"description": "Self-hosted Bitcoin payment processor. Accept Bitcoin payments without intermediaries.",
"environment": [
"ASPNETCORE_URLS=http://0.0.0.0:49392",
"BTCPAY_PROTOCOL=http",
"BTCPAY_CHAINS=btc",
"BTCPAY_BTCEXPLORERURL=http://archy-nbxplorer:32838",
"BTCPAY_BTCRPCURL=http://bitcoin-knots:8332",
"BTCPAY_BTCRPCUSER=archipelago",
"BTCPAY_POSTGRES=Username=btcpay;Password=${BTCPAY_DB_PASS};Host=archy-btcpay-db;Port=5432;Database=btcpay"
],
"health_check": {
"endpoint": "http://localhost:49392",
"interval": "30s",
"path": "/",
"retries": 5,
"timeout": "30s",
"type": "http"
},
"id": "btcpay-server",
"interfaces": {
"main": {
"description": "BTCPay Server dashboard",
"name": "Web UI",
"path": "/",
"port": 23000,
"protocol": "http",
"type": "ui"
}
},
"lightning_integration": {
"invoice_management": true,
"payment_processing": false
},
"metadata": {
"launch": {
"open_in_new_tab": true
}
},
"name": "BTCPay Server",
"ports": [
{
"container": 49392,
"host": 23000,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 2,
"disk_limit": "20Gi",
"memory_limit": "2Gi"
},
"security": {
"capabilities": [],
"network_policy": "isolated",
"readonly_root": false
},
"version": "2.3.9",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/btcpay",
"target": "/datadir",
"type": "bind"
}
]
}
},
"version": "2.3.9"
},
"core-lightning": {
"manifest": {
"app": {
"bitcoin_integration": {
"rpc_access": "admin",
"sync_required": true
},
"container": {
"image": "elementsproject/lightningd:v23.08.2",
"image_signature": "cosign://...",
"pull_policy": "verify-signature"
},
"dependencies": [
{
"app_id": "bitcoin-core",
"version": ">=26.0"
}
],
"description": "Lightning Network implementation in C. Lightweight alternative to LND.",
"environment": [
"BITCOIND_RPCURL=http://bitcoin-core:8332",
"BITCOIND_RPCUSER=${BITCOIN_RPC_USER}",
"BITCOIND_RPCPASS=${BITCOIN_RPC_PASSWORD}",
"NETWORK=bitcoin"
],
"health_check": {
"endpoint": "lightning-cli getinfo",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "exec"
},
"id": "core-lightning",
"lightning_integration": {
"channel_management": true,
"payment_routing": true
},
"name": "Core Lightning (CLN)",
"ports": [
{
"container": 9735,
"host": 9736,
"protocol": "tcp"
},
{
"container": 9835,
"host": 9835,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 1,
"disk_limit": "5Gi",
"memory_limit": "512Mi"
},
"security": {
"apparmor_profile": "core-lightning",
"capabilities": [
"NET_BIND_SERVICE"
],
"network_policy": "isolated",
"no_new_privileges": true,
"readonly_root": true,
"seccomp_profile": "default",
"user": 1000
},
"version": "23.08.2",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/core-lightning",
"target": "/home/clightning/.lightning",
"type": "bind"
}
]
}
},
"version": "23.08.2"
},
"cryptpad": {
"image": "146.59.87.168:3000/lfg2025/cryptpad:2024.12.0",
"version": "2024.12.0"
},
"did-wallet": {
"manifest": {
"app": {
"container": {
"image": "archipelago/did-wallet:1.0.0",
"image_signature": "cosign://...",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"storage": "2Gi"
}
],
"description": "Web5 wallet with Decentralized Identifier (DID) support. Manage your digital identity and Web5 assets.",
"environment": [
"WALLET_STORAGE=/app/wallet"
],
"health_check": {
"endpoint": "http://localhost:8083",
"interval": "30s",
"path": "/health",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "did-wallet",
"name": "Web5 DID Wallet",
"ports": [
{
"container": 8080,
"host": 8083,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 1,
"disk_limit": "2Gi",
"memory_limit": "512Mi"
},
"security": {
"apparmor_profile": "did-wallet",
"capabilities": [],
"network_policy": "isolated",
"no_new_privileges": true,
"readonly_root": true,
"seccomp_profile": "default",
"user": 1000
},
"version": "1.0.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/did-wallet",
"target": "/app/wallet",
"type": "bind"
}
],
"web5_integration": {
"bitcoin_integration": true,
"did_support": true,
"wallet_functionality": true
}
}
},
"version": "1.0.0"
},
"electrs-ui": {
"image": "146.59.87.168:3000/lfg2025/electrs-ui:latest",
"manifest": {
"app": {
"container": {
"build": {
"context": "/opt/archipelago/docker/electrs-ui",
"dockerfile": "Dockerfile",
"tag": "localhost/electrs-ui:local"
}
},
"dependencies": [],
"description": "Archipelago-native HTTP frontend for electrs/electrumx status. Runs\nnginx inside a container, serves static assets, and proxies\n/electrs-status to the archipelago backend on 127.0.0.1:5678.\n",
"environment": [],
"health_check": {
"endpoint": "http://127.0.0.1:50002",
"interval": "30s",
"path": "/",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "electrs-ui",
"name": "Electrs UI",
"ports": [],
"resources": {
"memory_limit": "64Mi"
},
"security": {
"network_policy": "host",
"readonly_root": false
},
"version": "1.0.0",
"volumes": []
}
},
"version": "latest"
},
"electrumx": {
"image": "146.59.87.168:3000/lfg2025/electrumx:v1.18.0",
"manifest": {
"app": {
"bitcoin_integration": {
"pruning_support": false,
"rpc_access": "read-only",
"sync_required": true
},
"container": {
"custom_args": [
"export DAEMON_URL=\"http://archipelago:$(printenv BITCOIN_RPC_PASS)@bitcoin-knots:8332/\"; exec electrumx_server"
],
"data_uid": "1000:1000",
"entrypoint": [
"sh",
"-lc"
],
"image": "146.59.87.168:3000/lfg2025/electrumx:v1.18.0",
"network": "archy-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "BITCOIN_RPC_PASS",
"secret_file": "bitcoin-rpc-password"
}
]
},
"dependencies": [
{
"app_id": "bitcoin-knots",
"version": ">=26.0"
},
{
"storage": "50Gi"
}
],
"description": "Electrum server indexing Bitcoin chain data for lightweight wallet queries.",
"environment": [
"COIN=Bitcoin",
"DB_DIRECTORY=/data",
"SERVICES=tcp://:50001,rpc://0.0.0.0:8000",
"CACHE_MB=1024",
"MAX_SEND=10000000"
],
"health_check": {
"endpoint": "localhost:50001",
"interval": "30s",
"retries": 3,
"start_period": "10m",
"timeout": "5s",
"type": "tcp"
},
"id": "electrumx",
"interfaces": {
"main": {
"description": "ElectrumX server status and connection details",
"name": "Web UI",
"port": 50002,
"protocol": "http",
"type": "ui"
}
},
"name": "ElectrumX",
"ports": [
{
"container": 50001,
"host": 50001,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 0,
"disk_limit": "50Gi",
"memory_limit": "6Gi"
},
"security": {
"capabilities": [
"DAC_OVERRIDE"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "1.18.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/electrumx",
"target": "/data",
"type": "bind"
}
]
}
},
"version": "v1.18.0"
},
"fedimint": {
"image": "146.59.87.168:3000/lfg2025/fedimintd:v0.10.0",
"manifest": {
"app": {
"bitcoin_integration": {
"rpc_access": "admin",
"sync_required": true
},
"container": {
"custom_args": [
"until state=\"$(curl -sS --connect-timeout 5 -m 45 -u \"$FM_BITCOIND_USERNAME:$FM_BITCOIND_PASSWORD\" -H \"Content-Type: application/json\" --data-binary '{\"jsonrpc\":\"1.0\",\"id\":\"fedimint-wait\",\"method\":\"getblockchaininfo\",\"params\":[]}' \"$FM_BITCOIND_URL/\")\" && echo \"$state\" | grep -q '\"initialblockdownload\":false'; do\n echo \"Waiting for Bitcoin RPC sync at $FM_BITCOIND_URL...\";\n sleep 30;\ndone;\nexec fedimintd"
],
"data_uid": "1000:1000",
"derived_env": [
{
"key": "FM_P2P_URL",
"template": "fedimint://{{HOST_MDNS}}:8173"
},
{
"key": "FM_API_URL",
"template": "ws://{{HOST_MDNS}}:8174"
}
],
"entrypoint": [
"sh",
"-lc"
],
"image": "146.59.87.168:3000/lfg2025/fedimintd:v0.10.0",
"network": "archy-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "FM_BITCOIND_PASSWORD",
"secret_file": "bitcoin-rpc-password"
}
]
},
"dependencies": [
{
"app_id": "bitcoin-core",
"version": ">=26.0"
},
{
"storage": "20Gi"
}
],
"description": "Federated Bitcoin minting service with built-in Guardian UI. Privacy-preserving Bitcoin custody.",
"environment": [
"FM_DATA_DIR=/data",
"FM_BITCOIND_URL=http://bitcoin-knots:8332",
"FM_BITCOIND_USERNAME=archipelago",
"FM_BITCOIN_NETWORK=bitcoin",
"FM_BIND_P2P=0.0.0.0:8173",
"FM_BIND_API=0.0.0.0:8174",
"FM_BIND_UI=0.0.0.0:8175"
],
"health_check": {
"endpoint": "http://localhost:8175",
"interval": "30s",
"path": "/",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "fedimint",
"interfaces": {
"main": {
"description": "Fedimint Guardian wait/proxy UI",
"name": "Guardian UI",
"path": "/",
"port": 8175,
"protocol": "http",
"type": "ui"
}
},
"name": "Fedimint Guardian",
"ports": [
{
"container": 8173,
"host": 8173,
"protocol": "tcp"
},
{
"container": 8174,
"host": 8174,
"protocol": "tcp"
},
{
"container": 8175,
"host": 8177,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 4,
"disk_limit": "20Gi",
"memory_limit": "4Gi"
},
"security": {
"capabilities": [],
"network_policy": "isolated",
"readonly_root": true
},
"version": "0.10.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/fedimint",
"target": "/data",
"type": "bind"
}
]
}
},
"version": "v0.10.0"
},
"fedimint-clientd": {
"manifest": {
"app": {
"container": {
"data_uid": "1000:1000",
"generated_secrets": [
{
"kind": "hex16",
"name": "fmcd-password"
}
],
"image": "146.59.87.168:3000/lfg2025/fmcd:0.8.1",
"network": "archy-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "FMCD_PASSWORD",
"secret_file": "fmcd-password"
}
]
},
"dependencies": [
{
"storage": "2Gi"
}
],
"description": "Fedimint ecash client daemon (fmcd). Lets the node hold Fedimint ecash and join federations; the wallet talks to it over a local REST API.",
"environment": [
"FMCD_ADDR=0.0.0.0:8080",
"FMCD_MODE=rest",
"FMCD_DATA_DIR=/data",
"FMCD_INVITE_CODE=fed11qgqyj3mfwfhksw309uuxywtxxfjrjc35xuexverpxdsnxcnrxucxvenzveskgc3kvvun2c34xp3k2ep38yunzdpexcekxe3hvd3rvvmx8pnrvdenx5mnzvtzqqqjqt0t6pc3s5z0ynqjw9s4njf6svwgu59kweawc0vvrddcjeemw6yyn4pcdp"
],
"health_check": {
"endpoint": "localhost:8080",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "fedimint-clientd",
"name": "Fedimint Client",
"ports": [
{
"container": 8080,
"host": 8178,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 1,
"disk_limit": "2Gi",
"memory_limit": "1Gi"
},
"security": {
"capabilities": [
"CHOWN",
"DAC_OVERRIDE",
"FOWNER",
"SETUID",
"SETGID"
],
"network_policy": "bridge",
"readonly_root": true
},
"version": "0.8.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/fmcd",
"target": "/data",
"type": "bind"
}
]
}
},
"version": "0.8.0"
},
"fedimint-gateway": {
"image": "146.59.87.168:3000/lfg2025/gatewayd:v0.10.0",
"manifest": {
"app": {
"bitcoin_integration": {
"rpc_access": "admin",
"sync_required": true
},
"container": {
"custom_args": [
"if [ -f /lnd/tls.cert ] && [ -f /lnd/data/chain/bitcoin/mainnet/admin.macaroon ]; then\n exec gatewayd --data-dir /data --listen 0.0.0.0:8176 --bcrypt-password-hash \"$FEDI_HASH\" --network bitcoin --bitcoind-url http://host.archipelago:8332 --bitcoind-username \"$FM_BITCOIND_USERNAME\" --bitcoind-password \"$FM_BITCOIND_PASSWORD\" lnd --lnd-rpc-host lnd:10009 --lnd-tls-cert /lnd/tls.cert --lnd-macaroon /lnd/data/chain/bitcoin/mainnet/admin.macaroon;\nelse\n exec gatewayd --data-dir /data --listen 0.0.0.0:8176 --bcrypt-password-hash \"$FEDI_HASH\" --network bitcoin --bitcoind-url http://host.archipelago:8332 --bitcoind-username \"$FM_BITCOIND_USERNAME\" --bitcoind-password \"$FM_BITCOIND_PASSWORD\" ldk --ldk-lightning-port 9737 --ldk-alias archipelago-gateway;\nfi"
],
"data_uid": "1000:1000",
"entrypoint": [
"sh",
"-lc"
],
"generated_secrets": [
{
"kind": "bcrypt",
"name": "fedimint-gateway-hash"
}
],
"image": "git.tx1138.com/lfg2025/gatewayd:v0.10.0",
"network": "archy-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "FM_BITCOIND_PASSWORD",
"secret_file": "bitcoin-rpc-password"
},
{
"key": "FEDI_HASH",
"secret_file": "fedimint-gateway-hash"
}
]
},
"dependencies": [
{
"app_id": "bitcoin-core",
"version": ">=26.0"
},
{
"app_id": "fedimint",
"version": ">=0.10.0"
}
],
"description": "Fedimint gateway service with automatic LND-or-LDK backend selection.",
"environment": [
"FM_BITCOIND_USERNAME=archipelago"
],
"health_check": {
"endpoint": "http://localhost:8176",
"interval": "30s",
"path": "/",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "fedimint-gateway",
"name": "Fedimint Gateway",
"ports": [
{
"container": 8176,
"host": 8176,
"protocol": "tcp"
},
{
"container": 9737,
"host": 9737,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 2,
"disk_limit": "10Gi",
"memory_limit": "2Gi"
},
"security": {
"capabilities": [],
"network_policy": "isolated",
"readonly_root": true
},
"version": "0.10.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/fedimint-gateway",
"target": "/data",
"type": "bind"
},
{
"options": [
"ro"
],
"source": "/var/lib/archipelago/lnd",
"target": "/lnd",
"type": "bind"
}
]
}
},
"version": "v0.10.0"
},
"filebrowser": {
"image": "146.59.87.168:3000/lfg2025/filebrowser:v2.27.0",
"manifest": {
"app": {
"bitcoin_integration": {
"rpc_access": "none",
"sync_required": false
},
"container": {
"custom_args": [
"--config",
"/data/.filebrowser.json"
],
"data_uid": "100000:100000",
"image": "git.tx1138.com/lfg2025/filebrowser:v2.27.0",
"network": "archy-net",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"storage": "10Gi"
}
],
"description": "Baseline Archipelago file manager service.",
"environment": [],
"health_check": {
"endpoint": "http://localhost:80",
"interval": "30s",
"path": "/health",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "filebrowser",
"name": "File Browser",
"ports": [
{
"container": 80,
"host": 8083,
"protocol": "tcp"
}
],
"resources": {
"disk_limit": "10Gi",
"memory_limit": "256Mi"
},
"security": {
"capabilities": [
"CHOWN",
"FOWNER",
"SETUID",
"SETGID",
"DAC_OVERRIDE",
"NET_BIND_SERVICE"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "2.27.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/filebrowser",
"target": "/srv",
"type": "bind"
},
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/filebrowser-data",
"target": "/data",
"type": "bind"
}
]
}
},
"version": "v2.27.0"
},
"fips": {
"image": "146.59.87.168:3000/lfg2025/fips:v0.1.0",
"version": "v0.1.0"
},
"fips-ui": {
"manifest": {
"app": {
"container": {
"build": {
"context": "/opt/archipelago/docker/fips-ui",
"dockerfile": "Dockerfile",
"tag": "localhost/fips-ui:local"
}
},
"description": "Archipelago-native dashboard for the FIPS mesh transport. Runs nginx\ninside a container with host networking, serves a static dashboard on\n:8336, and reverse-proxies /rpc/v1 to the archipelago backend on\n127.0.0.1:5678. All FIPS controls (status, seed anchors, reconnect,\nrestart, and stable-channel daemon updates) go through the existing\nfips.* RPC methods, authenticated by the browser's own archipelago\nsession — there is no separate secret to manage.\n",
"environment": [],
"health_check": {
"endpoint": "http://127.0.0.1:8336",
"interval": "30s",
"path": "/",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "fips-ui",
"name": "FIPS Mesh",
"ports": [],
"resources": {
"memory_limit": "128Mi"
},
"security": {
"network_policy": "host",
"readonly_root": false
},
"version": "1.0.0",
"volumes": []
}
},
"version": "1.0.0"
},
"gitea": {
"manifest": {
"app": {
"category": "development",
"container": {
"image": "docker.io/gitea/gitea:1.23",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"storage": "500Mi"
}
],
"description": "Self-hosted Git service with built-in container registry, CI/CD, and package hosting.",
"environment": [
"GITEA__database__DB_TYPE=sqlite3",
"GITEA__server__SSH_PORT=2222",
"GITEA__server__SSH_LISTEN_PORT=22",
"GITEA__server__LFS_START_SERVER=true",
"GITEA__packages__ENABLED=true",
"GITEA__repository__ENABLE_PUSH_CREATE_USER=true",
"GITEA__repository__ENABLE_PUSH_CREATE_ORG=true"
],
"health_check": {
"endpoint": "http://localhost:3000",
"interval": "120s",
"path": "/",
"retries": 5,
"timeout": "30s",
"type": "http"
},
"id": "gitea",
"interfaces": {
"main": {
"description": "Gitea web interface",
"name": "Web UI",
"path": "/",
"port": 3001,
"protocol": "http",
"type": "ui"
}
},
"metadata": {
"features": [
"Git repositories with web UI",
"Built-in container/package registry",
"Issue tracking and pull requests",
"CI/CD via Gitea Actions",
"Lightweight SQLite deployment"
],
"icon": "/assets/img/app-icons/gitea.svg",
"launch": {
"open_in_new_tab": true
},
"repo": "https://gitea.com",
"tier": "optional"
},
"name": "Gitea",
"nginx_proxy": {
"extra_headers": [
"proxy_hide_header X-Frame-Options",
"proxy_hide_header Content-Security-Policy"
],
"listen": 3000,
"proxy_pass": "http://127.0.0.1:3001"
},
"ports": [
{
"container": 3000,
"host": 3001,
"protocol": "tcp"
},
{
"container": 22,
"host": 2222,
"protocol": "tcp"
}
],
"resources": {
"disk_limit": "500Mi",
"memory_limit": "256Mi"
},
"security": {
"capabilities": [
"CHOWN",
"FOWNER",
"SETUID",
"SETGID",
"DAC_OVERRIDE",
"NET_BIND_SERVICE"
],
"network_policy": "bridge",
"no_new_privileges": false,
"readonly_root": false
},
"version": "1.23",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/gitea/data",
"target": "/data",
"type": "bind"
},
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/gitea/config",
"target": "/etc/gitea",
"type": "bind"
}
]
}
},
"version": "1.23"
},
"grafana": {
"image": "146.59.87.168:3000/lfg2025/grafana:10.2.0",
"manifest": {
"app": {
"container": {
"data_uid": "472:472",
"image": "grafana/grafana:10.2.0",
"image_signature": "cosign://...",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"storage": "5Gi"
}
],
"description": "Analytics and monitoring platform. Visualize metrics and create dashboards.",
"environment": [
"GF_SECURITY_ADMIN_USER=admin",
"GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}",
"GF_SERVER_ROOT_URL=http://localhost:3000",
"GF_INSTALL_PLUGINS="
],
"health_check": {
"endpoint": "http://localhost:3000",
"interval": "30s",
"path": "/api/health",
"retries": 5,
"timeout": "30s",
"type": "http"
},
"id": "grafana",
"metadata": {
"launch": {
"open_in_new_tab": true
}
},
"name": "Grafana",
"ports": [
{
"container": 3000,
"host": 3000,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 2,
"disk_limit": "5Gi",
"memory_limit": "1Gi"
},
"security": {
"apparmor_profile": "grafana",
"capabilities": [],
"network_policy": "isolated",
"no_new_privileges": true,
"readonly_root": true,
"seccomp_profile": "default",
"user": 1000
},
"version": "10.2.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/grafana",
"target": "/var/lib/grafana",
"type": "bind"
}
]
}
},
"version": "10.2.0"
},
"homeassistant": {
"image": "146.59.87.168:3000/lfg2025/home-assistant:2024.1",
"manifest": {
"app": {
"container": {
"image": "146.59.87.168:3000/lfg2025/home-assistant:2024.1",
"network": "pasta",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"storage": "10Gi"
}
],
"description": "Open source home automation platform. Control and monitor your smart home devices.",
"devices": [],
"environment": [
"TZ=UTC"
],
"health_check": {
"endpoint": "localhost:8123",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "homeassistant",
"interfaces": {
"main": {
"description": "Home Assistant dashboard",
"name": "Web UI",
"path": "/",
"port": 8123,
"protocol": "http",
"type": "ui"
}
},
"metadata": {
"author": "Home Assistant",
"category": "home",
"icon": "/assets/img/app-icons/homeassistant.png",
"launch": {
"open_in_new_tab": true
},
"repo": "https://github.com/home-assistant/core"
},
"name": "Home Assistant",
"ports": [
{
"container": 8123,
"host": 8123,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 2,
"disk_limit": "10Gi",
"memory_limit": "512Mi"
},
"security": {
"apparmor_profile": "home-assistant",
"capabilities": [
"CHOWN",
"FOWNER",
"SETUID",
"SETGID",
"DAC_OVERRIDE",
"NET_BIND_SERVICE",
"NET_RAW"
],
"network_policy": "isolated",
"no_new_privileges": true,
"readonly_root": false,
"seccomp_profile": "default",
"user": 1000
},
"version": "2024.1.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/home-assistant",
"target": "/config",
"type": "bind"
}
]
}
},
"version": "2024.1"
},
"immich": {
"image": "146.59.87.168:3000/lfg2025/immich-server:release",
"images": {
"immich_postgres": "146.59.87.168:3000/lfg2025/immich-postgres:14-vectorchord0.4.3-pgvectors0.2.0",
"immich_redis": "146.59.87.168:3000/lfg2025/redis:7.4.8",
"immich_server": "146.59.87.168:3000/lfg2025/immich-server:release"
},
"manifest": {
"app": {
"container": {
"image": "146.59.87.168:3000/lfg2025/immich-server:release",
"network": "archy-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "DB_PASSWORD",
"secret_file": "immich-db-password"
}
]
},
"container_name": "immich_server",
"dependencies": [
{
"app_id": "immich-postgres"
},
{
"app_id": "immich-redis"
},
{
"storage": "200Gi"
}
],
"description": "Self-hosted photo and video backup with mobile apps and search.",
"environment": [
"DB_HOSTNAME=immich_postgres",
"DB_USERNAME=postgres",
"DB_DATABASE_NAME=immich",
"REDIS_HOSTNAME=immich_redis",
"UPLOAD_LOCATION=/usr/src/app/upload"
],
"health_check": {
"endpoint": "http://localhost:2283",
"interval": "30s",
"path": "/api/server/ping",
"retries": 20,
"timeout": "5s",
"type": "http"
},
"id": "immich",
"interfaces": {
"main": {
"description": "Immich photo library",
"name": "Web UI",
"path": "/",
"port": 2283,
"protocol": "http",
"type": "ui"
}
},
"metadata": {
"launch": {
"open_in_new_tab": true
}
},
"name": "Immich",
"ports": [
{
"container": 2283,
"host": 2283,
"protocol": "tcp"
}
],
"resources": {
"disk_limit": "200Gi",
"memory_limit": "2Gi"
},
"security": {
"capabilities": [],
"network_policy": "isolated",
"readonly_root": false
},
"version": "2.7.4",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/immich",
"target": "/usr/src/app/upload",
"type": "bind"
}
]
}
},
"version": "release"
},
"immich-postgres": {
"manifest": {
"app": {
"container": {
"data_uid": "100998:100998",
"generated_secrets": [
{
"kind": "hex32",
"name": "immich-db-password"
}
],
"image": "146.59.87.168:3000/lfg2025/immich-postgres:14-vectorchord0.4.3-pgvectors0.2.0",
"network": "archy-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "POSTGRES_PASSWORD",
"secret_file": "immich-db-password"
}
]
},
"container_name": "immich_postgres",
"dependencies": [
{
"storage": "40Gi"
}
],
"description": "Postgres (pgvecto.rs / vectorchord) backend for Immich.",
"environment": [
"POSTGRES_USER=postgres",
"POSTGRES_DB=immich"
],
"health_check": {
"endpoint": "localhost:5432",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "immich-postgres",
"name": "Immich Postgres",
"ports": [],
"resources": {
"disk_limit": "40Gi",
"memory_limit": "2Gi"
},
"security": {
"capabilities": [
"CHOWN",
"DAC_OVERRIDE",
"FOWNER",
"SETGID",
"SETUID"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "14-vectorchord0.4.3-pgvectors0.2.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/immich-db",
"target": "/var/lib/postgresql/data",
"type": "bind"
}
]
}
},
"version": "14-vectorchord0.4.3-pgvectors0.2.0"
},
"immich-redis": {
"manifest": {
"app": {
"container": {
"image": "146.59.87.168:3000/lfg2025/valkey:7-alpine",
"network": "archy-net",
"pull_policy": "if-not-present"
},
"container_name": "immich_redis",
"dependencies": [],
"description": "Valkey (Redis-compatible) cache for Immich.",
"environment": [],
"health_check": {
"endpoint": "localhost:6379",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "immich-redis",
"name": "Immich Redis",
"ports": [],
"resources": {
"memory_limit": "128Mi"
},
"security": {
"capabilities": [
"SETGID",
"SETUID"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "7-alpine",
"volumes": []
}
},
"version": "7-alpine"
},
"indeedhub": {
"image": "146.59.87.168:3000/lfg2025/indeedhub:1.0.0",
"images": {
"indeedhub": "146.59.87.168:3000/lfg2025/indeedhub:1.0.0",
"indeedhub-api": "146.59.87.168:3000/lfg2025/indeedhub-api:1.0.0",
"indeedhub-ffmpeg": "146.59.87.168:3000/lfg2025/indeedhub-ffmpeg:1.0.0"
},
"manifest": {
"app": {
"category": "community",
"container": {
"image": "146.59.87.168:3000/lfg2025/indeedhub:1.0.0",
"network": "indeedhub-net",
"pull_policy": "if-not-present"
},
"container_name": "indeedhub",
"dependencies": [
{
"app_id": "indeedhub-api"
},
{
"storage": "1Gi"
}
],
"description": "Bitcoin documentary streaming platform featuring God Bless Bitcoin and other educational content about Bitcoin, sovereignty, and decentralized technology. Sign in with your Nostr identity.",
"environment": [],
"health_check": {
"endpoint": "localhost:7777",
"interval": "30s",
"retries": 5,
"start_period": "30s",
"timeout": "5s",
"type": "tcp"
},
"hooks": {
"post_install": [
{
"exec": [
"sed",
"-i",
"/X-Frame-Options/d",
"/etc/nginx/conf.d/default.conf"
]
},
{
"copy_from_host": {
"dest": "/usr/share/nginx/html/nostr-provider.js",
"src": "web-ui/nostr-provider.js"
}
},
{
"exec": [
"sh",
"-c",
"grep -q nostr-provider /etc/nginx/conf.d/default.conf || sed -i 's#</head>#<script src=\"/nostr-provider.js\"></script></head>#' /etc/nginx/conf.d/default.conf"
]
},
{
"exec": [
"nginx",
"-s",
"reload"
]
}
]
},
"id": "indeedhub",
"interfaces": {
"main": {
"description": "Stream Bitcoin documentaries with Nostr identity",
"name": "Web UI",
"path": "/",
"port": 7778,
"protocol": "http",
"type": "ui"
}
},
"metadata": {
"author": "Indeehub Team",
"icon": "/assets/img/app-icons/indeedhub.png",
"license": "MIT",
"repo": "https://github.com/indeedhub/indeedhub",
"tags": [
"bitcoin",
"documentary",
"streaming",
"media",
"education",
"nostr"
],
"website": "https://indeedhub.com"
},
"name": "IndeeHub",
"ports": [
{
"container": 7777,
"host": 7778,
"protocol": "tcp"
}
],
"resources": {
"disk_limit": "1Gi",
"memory_limit": "512Mi"
},
"security": {
"capabilities": [
"CHOWN",
"DAC_OVERRIDE",
"SETGID",
"SETUID"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "1.0.0",
"volumes": [
{
"options": [
"rw",
"nosuid",
"nodev",
"size=16m"
],
"target": "/run",
"type": "tmpfs"
},
{
"options": [
"rw",
"nosuid",
"nodev",
"size=32m"
],
"target": "/var/cache/nginx",
"type": "tmpfs"
}
]
}
},
"version": "1.0.0"
},
"indeedhub-api": {
"manifest": {
"app": {
"category": "community",
"container": {
"generated_secrets": [
{
"kind": "hex32",
"name": "indeedhub-jwt"
}
],
"image": "146.59.87.168:3000/lfg2025/indeedhub-api:1.0.0",
"network": "indeedhub-net",
"network_aliases": [
"api"
],
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "DATABASE_PASSWORD",
"secret_file": "indeedhub-db-password"
},
{
"key": "AWS_SECRET_KEY",
"secret_file": "indeedhub-minio-password"
},
{
"key": "NOSTR_JWT_SECRET",
"secret_file": "indeedhub-jwt"
}
]
},
"container_name": "indeedhub-api",
"dependencies": [
{
"app_id": "indeedhub-postgres"
},
{
"app_id": "indeedhub-redis"
},
{
"app_id": "indeedhub-minio"
}
],
"description": "IndeedHub backend API (Nostr auth, media, payments).",
"environment": [
"PORT=4000",
"DATABASE_HOST=postgres",
"DATABASE_PORT=5432",
"DATABASE_USER=indeedhub",
"DATABASE_NAME=indeedhub",
"QUEUE_HOST=redis",
"QUEUE_PORT=6379",
"S3_ENDPOINT=http://minio:9000",
"AWS_REGION=us-east-1",
"AWS_ACCESS_KEY=indeeadmin",
"S3_PUBLIC_BUCKET_NAME=indeedhub-public",
"S3_PRIVATE_BUCKET_NAME=indeedhub-private",
"S3_PUBLIC_BUCKET_URL=/storage",
"NOSTR_JWT_EXPIRES_IN=7d",
"AES_MASTER_SECRET=0123456789abcdef0123456789abcdef",
"ENVIRONMENT=production"
],
"health_check": {
"endpoint": "localhost:4000",
"interval": "30s",
"retries": 10,
"timeout": "5s",
"type": "tcp"
},
"id": "indeedhub-api",
"name": "IndeedHub API",
"ports": [],
"resources": {
"memory_limit": "2Gi"
},
"security": {
"capabilities": [],
"network_policy": "isolated",
"readonly_root": false
},
"version": "1.0.0",
"volumes": []
}
},
"version": "1.0.0"
},
"indeedhub-ffmpeg": {
"manifest": {
"app": {
"category": "community",
"container": {
"image": "146.59.87.168:3000/lfg2025/indeedhub-ffmpeg:1.0.0",
"network": "indeedhub-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "DATABASE_PASSWORD",
"secret_file": "indeedhub-db-password"
},
{
"key": "AWS_SECRET_KEY",
"secret_file": "indeedhub-minio-password"
}
]
},
"container_name": "indeedhub-ffmpeg",
"dependencies": [
{
"app_id": "indeedhub-api"
}
],
"description": "IndeedHub background media transcoding worker.",
"environment": [
"DATABASE_HOST=postgres",
"DATABASE_PORT=5432",
"DATABASE_USER=indeedhub",
"DATABASE_NAME=indeedhub",
"QUEUE_HOST=redis",
"QUEUE_PORT=6379",
"S3_ENDPOINT=http://minio:9000",
"AWS_REGION=us-east-1",
"AWS_ACCESS_KEY=indeeadmin",
"S3_PUBLIC_BUCKET_NAME=indeedhub-public",
"S3_PRIVATE_BUCKET_NAME=indeedhub-private",
"ENVIRONMENT=production",
"AES_MASTER_SECRET=0123456789abcdef0123456789abcdef"
],
"id": "indeedhub-ffmpeg",
"name": "IndeedHub FFmpeg Worker",
"ports": [],
"resources": {
"memory_limit": "4Gi"
},
"security": {
"capabilities": [],
"network_policy": "isolated",
"readonly_root": false
},
"version": "1.0.0",
"volumes": []
}
},
"version": "1.0.0"
},
"indeedhub-minio": {
"manifest": {
"app": {
"category": "community",
"container": {
"custom_args": [
"server",
"/data"
],
"generated_secrets": [
{
"kind": "hex32",
"name": "indeedhub-minio-password"
}
],
"image": "146.59.87.168:3000/lfg2025/minio:RELEASE.2024-11-07T00-52-20Z",
"network": "indeedhub-net",
"network_aliases": [
"minio"
],
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "MINIO_ROOT_PASSWORD",
"secret_file": "indeedhub-minio-password"
}
]
},
"container_name": "indeedhub-minio",
"dependencies": [
{
"storage": "50Gi"
}
],
"description": "MinIO S3-compatible object storage for IndeedHub media.",
"environment": [
"MINIO_ROOT_USER=indeeadmin"
],
"health_check": {
"endpoint": "http://localhost:9000",
"interval": "30s",
"path": "/minio/health/live",
"retries": 5,
"timeout": "5s",
"type": "http"
},
"id": "indeedhub-minio",
"name": "IndeedHub MinIO",
"ports": [],
"resources": {
"disk_limit": "50Gi",
"memory_limit": "1Gi"
},
"security": {
"capabilities": [],
"network_policy": "isolated",
"readonly_root": false
},
"version": "RELEASE.2024-11-07T00-52-20Z",
"volumes": [
{
"options": [
"rw"
],
"source": "indeedhub-minio-data",
"target": "/data",
"type": "volume"
}
]
}
},
"version": "RELEASE.2024-11-07T00-52-20Z"
},
"indeedhub-postgres": {
"manifest": {
"app": {
"category": "community",
"container": {
"generated_secrets": [
{
"kind": "hex32",
"name": "indeedhub-db-password"
}
],
"image": "146.59.87.168:3000/lfg2025/postgres:16.13-alpine",
"network": "indeedhub-net",
"network_aliases": [
"postgres"
],
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "POSTGRES_PASSWORD",
"secret_file": "indeedhub-db-password"
}
]
},
"container_name": "indeedhub-postgres",
"dependencies": [
{
"storage": "10Gi"
}
],
"description": "Postgres database backend for IndeedHub.",
"environment": [
"POSTGRES_USER=indeedhub",
"POSTGRES_DB=indeedhub"
],
"health_check": {
"endpoint": "localhost:5432",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "indeedhub-postgres",
"name": "IndeedHub Postgres",
"ports": [],
"resources": {
"disk_limit": "10Gi",
"memory_limit": "1Gi"
},
"security": {
"capabilities": [
"CHOWN",
"DAC_OVERRIDE",
"FOWNER",
"SETGID",
"SETUID"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "16.13-alpine",
"volumes": [
{
"options": [
"rw"
],
"source": "indeedhub-postgres-data",
"target": "/var/lib/postgresql/data",
"type": "volume"
}
]
}
},
"version": "16.13-alpine"
},
"indeedhub-redis": {
"manifest": {
"app": {
"category": "community",
"container": {
"image": "146.59.87.168:3000/lfg2025/redis:7.4.8-alpine",
"network": "indeedhub-net",
"network_aliases": [
"redis"
],
"pull_policy": "if-not-present"
},
"container_name": "indeedhub-redis",
"dependencies": [
{
"storage": "1Gi"
}
],
"description": "Redis queue/cache backend for IndeedHub.",
"environment": [],
"health_check": {
"endpoint": "localhost:6379",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "indeedhub-redis",
"name": "IndeedHub Redis",
"ports": [],
"resources": {
"memory_limit": "256Mi"
},
"security": {
"capabilities": [
"SETGID",
"SETUID"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "7.4.8-alpine",
"volumes": [
{
"options": [
"rw"
],
"source": "indeedhub-redis-data",
"target": "/data",
"type": "volume"
}
]
}
},
"version": "7.4.8-alpine"
},
"indeedhub-relay": {
"manifest": {
"app": {
"category": "community",
"container": {
"image": "146.59.87.168:3000/lfg2025/nostr-rs-relay:0.9.0",
"network": "indeedhub-net",
"network_aliases": [
"relay"
],
"pull_policy": "if-not-present"
},
"container_name": "indeedhub-relay",
"dependencies": [
{
"storage": "2Gi"
}
],
"description": "nostr-rs-relay backing IndeedHub's Nostr identity + comments.",
"environment": [],
"health_check": {
"endpoint": "localhost:8080",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "indeedhub-relay",
"name": "IndeedHub Nostr Relay",
"ports": [],
"resources": {
"disk_limit": "2Gi",
"memory_limit": "256Mi"
},
"security": {
"capabilities": [],
"network_policy": "isolated",
"readonly_root": false
},
"version": "0.9.0",
"volumes": [
{
"options": [
"rw"
],
"source": "indeedhub-relay-data",
"target": "/usr/src/app/db",
"type": "volume"
}
]
}
},
"version": "0.9.0"
},
"jellyfin": {
"image": "146.59.87.168:3000/lfg2025/jellyfin:10.8.13",
"manifest": {
"app": {
"container": {
"image": "146.59.87.168:3000/lfg2025/jellyfin:10.8.13",
"network": "pasta",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"storage": "10Gi"
}
],
"description": "Free media server. Stream movies, music, and photos.",
"environment": [],
"health_check": {
"endpoint": "localhost:8096",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "jellyfin",
"interfaces": {
"main": {
"description": "Jellyfin media dashboard",
"name": "Web UI",
"path": "/",
"port": 8096,
"protocol": "http",
"type": "ui"
}
},
"metadata": {
"author": "Jellyfin",
"category": "data",
"icon": "/assets/img/app-icons/jellyfin.webp",
"repo": "https://github.com/jellyfin/jellyfin"
},
"name": "Jellyfin",
"ports": [
{
"container": 8096,
"host": 8096,
"protocol": "tcp"
}
],
"resources": {
"disk_limit": "10Gi",
"memory_limit": "1Gi"
},
"security": {
"capabilities": [
"CHOWN",
"FOWNER",
"SETUID",
"SETGID",
"DAC_OVERRIDE"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "10.8.13",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/jellyfin/config",
"target": "/config",
"type": "bind"
},
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/jellyfin/cache",
"target": "/cache",
"type": "bind"
}
]
}
},
"version": "10.8.13"
},
"lightning-stack": {
"manifest": {
"app": {
"bitcoin_integration": {
"rpc_access": "admin",
"sync_required": true
},
"container": {
"image": "lightninglabs/lightning-stack:v0.12.0",
"image_signature": "cosign://...",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"app_id": "bitcoin-core",
"version": ">=24.0"
},
{
"storage": "50Gi"
}
],
"description": "Complete Lightning Network implementation. Includes LND, CLN, and management tools.",
"environment": [
"BITCOIND_HOST=bitcoin-core",
"BITCOIND_RPCUSER=${BITCOIN_RPC_USER}",
"BITCOIND_RPCPASS=${BITCOIN_RPC_PASSWORD}",
"NETWORK=mainnet"
],
"health_check": {
"endpoint": "http://localhost:8087",
"interval": "30s",
"path": "/v1/getinfo",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "lightning-stack",
"lightning_integration": {
"channel_management": true,
"payment_routing": true
},
"name": "Lightning Stack",
"ports": [
{
"container": 9735,
"host": 9737,
"protocol": "tcp"
},
{
"container": 10009,
"host": 10010,
"protocol": "tcp"
},
{
"container": 8080,
"host": 8087,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 4,
"disk_limit": "50Gi",
"memory_limit": "4Gi"
},
"security": {
"apparmor_profile": "lightning-stack",
"capabilities": [
"NET_BIND_SERVICE"
],
"network_policy": "isolated",
"no_new_privileges": true,
"readonly_root": true,
"seccomp_profile": "default",
"user": 1000
},
"version": "0.12.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/lightning-stack",
"target": "/root/.lightning",
"type": "bind"
}
]
}
},
"version": "0.12.0"
},
"lnd": {
"image": "146.59.87.168:3000/lfg2025/lnd:v0.18.4-beta",
"manifest": {
"app": {
"bitcoin_integration": {
"rpc_access": "admin",
"sync_required": true
},
"container": {
"data_uid": "100000:100000",
"image": "146.59.87.168:3000/lfg2025/lnd:v0.18.4-beta",
"network": "archy-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "BITCOIND_RPCPASS",
"secret_file": "bitcoin-rpc-password"
}
]
},
"dependencies": [
{
"app_id": "bitcoin-core",
"version": ">=26.0"
}
],
"description": "Lightning Network implementation by Lightning Labs. Enables instant, low-cost Bitcoin payments.",
"environment": [
"BITCOIND_HOST=bitcoin-knots",
"BITCOIND_RPCUSER=archipelago",
"NETWORK=mainnet"
],
"health_check": {
"endpoint": "localhost:10009",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "lnd",
"lightning_integration": {
"channel_management": true,
"payment_routing": true
},
"name": "LND",
"ports": [
{
"container": 9735,
"host": 9735,
"protocol": "tcp"
},
{
"container": 10009,
"host": 10009,
"protocol": "tcp"
},
{
"container": 8080,
"host": 18080,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 2,
"disk_limit": "10Gi",
"memory_limit": "1Gi"
},
"security": {
"capabilities": [
"CHOWN",
"FOWNER",
"SETUID",
"SETGID",
"DAC_OVERRIDE",
"NET_RAW"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "0.18.4",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/lnd",
"target": "/root/.lnd",
"type": "bind"
}
]
}
},
"version": "v0.18.4-beta"
},
"lnd-ui": {
"image": "146.59.87.168:3000/lfg2025/lnd-ui:latest",
"manifest": {
"app": {
"container": {
"build": {
"context": "/opt/archipelago/docker/lnd-ui",
"dockerfile": "Dockerfile",
"tag": "localhost/lnd-ui:local"
}
},
"dependencies": [
{
"app_id": "lnd"
}
],
"description": "Archipelago-native HTTP frontend for LND. Runs nginx inside a\ncontainer and serves static assets. LND connection info is fetched\nvia an absolute URL that the host nginx routes to the archipelago\nbackend on 127.0.0.1:5678, so no upstream auth is baked in.\n",
"environment": [],
"health_check": {
"endpoint": "http://127.0.0.1:18083",
"interval": "30s",
"path": "/",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "lnd-ui",
"name": "LND UI",
"ports": [
{
"container": 80,
"host": 18083,
"protocol": "tcp"
}
],
"resources": {
"memory_limit": "64Mi"
},
"security": {
"network_policy": "bridge",
"readonly_root": false
},
"version": "1.0.0",
"volumes": []
}
},
"version": "latest"
},
"mempool": {
"image": "146.59.87.168:3000/lfg2025/mempool-frontend:v3.0.1",
"images": {
"archy-mempool-db": "146.59.87.168:3000/lfg2025/mariadb:11.4.10",
"archy-mempool-web": "146.59.87.168:3000/lfg2025/mempool-frontend:v3.0.1",
"mempool-api": "146.59.87.168:3000/lfg2025/mempool-backend:v3.0.0"
},
"manifest": {
"app": {
"bitcoin_integration": {
"rpc_access": "read-only",
"sync_required": true
},
"container": {
"image": "146.59.87.168:3000/lfg2025/mempool-frontend:v3.0.1",
"image_signature": "cosign://...",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"app_id": "bitcoin-core",
"version": ">=24.0"
},
{
"storage": "20Gi"
}
],
"description": "Bitcoin mempool and blockchain explorer. Real-time transaction and block visualization.",
"environment": [
"MEMPOOL_BACKEND=electrum",
"MEMPOOL_BITCOIN_HOST=bitcoin-core",
"MEMPOOL_BITCOIN_PORT=8332",
"MEMPOOL_BITCOIN_USER=${BITCOIN_RPC_USER}",
"MEMPOOL_BITCOIN_PASSWORD=${BITCOIN_RPC_PASSWORD}"
],
"health_check": {
"endpoint": "http://localhost:4080",
"interval": "30s",
"path": "/api/health",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "mempool",
"name": "Mempool Explorer",
"ports": [
{
"container": 8080,
"host": 4080,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 2,
"disk_limit": "20Gi",
"memory_limit": "2Gi"
},
"security": {
"apparmor_profile": "mempool",
"capabilities": [],
"network_policy": "isolated",
"no_new_privileges": true,
"readonly_root": true,
"seccomp_profile": "default",
"user": 1000
},
"version": "3.0.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/mempool",
"target": "/data",
"type": "bind"
}
]
}
},
"version": "v3.0.1"
},
"mempool-api": {
"manifest": {
"app": {
"bitcoin_integration": {
"pruning_support": false,
"rpc_access": "read-only",
"sync_required": true
},
"container": {
"derived_env": [
{
"key": "CORE_RPC_HOST",
"template": "{{BITCOIN_HOST}}"
}
],
"image": "git.tx1138.com/lfg2025/mempool-backend:v3.0.0",
"network": "archy-net",
"pull_policy": "if-not-present",
"secret_env": [
{
"key": "CORE_RPC_PASSWORD",
"secret_file": "bitcoin-rpc-password"
},
{
"key": "DATABASE_PASSWORD",
"secret_file": "mempool-db-password"
}
]
},
"dependencies": [
{
"app_id": "bitcoin-knots",
"version": ">=26.0"
},
{
"app_id": "electrumx",
"version": ">=1.18.0"
},
{
"app_id": "archy-mempool-db",
"version": ">=11.4.10"
}
],
"description": "Backend API for mempool explorer.",
"environment": [
"MEMPOOL_BACKEND=electrum",
"ELECTRUM_HOST=electrumx",
"ELECTRUM_PORT=50001",
"ELECTRUM_TLS_ENABLED=false",
"CORE_RPC_PORT=8332",
"CORE_RPC_USERNAME=archipelago",
"DATABASE_ENABLED=true",
"DATABASE_HOST=archy-mempool-db",
"DATABASE_DATABASE=mempool",
"DATABASE_USERNAME=mempool"
],
"health_check": {
"endpoint": "http://localhost:8999",
"interval": "30s",
"path": "/api/v1/backend-info",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "mempool-api",
"name": "Mempool API",
"ports": [
{
"container": 8999,
"host": 8999,
"protocol": "tcp"
}
],
"resources": {
"disk_limit": "20Gi",
"memory_limit": "2Gi"
},
"security": {
"capabilities": [],
"network_policy": "isolated",
"readonly_root": false
},
"version": "3.0.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/mempool",
"target": "/data",
"type": "bind"
}
]
}
},
"version": "3.0.0"
},
"morphos-server": {
"manifest": {
"app": {
"container": {
"image": "archipelago/morphos-server:1.0.0",
"image_signature": "cosign://...",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"storage": "5Gi"
}
],
"description": "MorphOS server platform. Decentralized application server.",
"environment": [
"MORPHOS_ENV=production",
"MORPHOS_DATA_DIR=/app/data"
],
"health_check": {
"endpoint": "http://localhost:8086",
"interval": "30s",
"path": "/health",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "morphos-server",
"name": "MorphOS Server",
"ports": [
{
"container": 8080,
"host": 8086,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 2,
"disk_limit": "5Gi",
"memory_limit": "2Gi"
},
"security": {
"apparmor_profile": "morphos-server",
"capabilities": [],
"network_policy": "isolated",
"no_new_privileges": true,
"readonly_root": true,
"seccomp_profile": "default",
"user": 1000
},
"version": "1.0.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/morphos-server",
"target": "/app/data",
"type": "bind"
}
]
}
},
"version": "1.0.0"
},
"netbird": {
"manifest": {
"app": {
"category": "networking",
"container": {
"generated_certs": [
{
"crt": "/var/lib/archipelago/netbird/tls.crt",
"key": "/var/lib/archipelago/netbird/tls.key"
}
],
"image": "docker.io/library/nginx:1.27-alpine",
"network": "netbird-net",
"pull_policy": "if-not-present"
},
"container_name": "netbird",
"dependencies": [
{
"app_id": "netbird-server"
},
{
"app_id": "netbird-dashboard"
},
{
"storage": "1Gi"
}
],
"description": "Self-hosted WireGuard mesh VPN control plane with dashboard, embedded identity provider, management API, signal, relay, and STUN. The user-facing entry point — a TLS proxy in front of the dashboard + server.",
"environment": [],
"files": [
{
"content": "server {\n listen 443 ssl;\n server_name _;\n\n # netbird's dashboard needs a secure context (window.crypto.subtle for\n # OIDC PKCE), so the proxy terminates TLS with a self-signed cert (#15).\n ssl_certificate /etc/nginx/tls.crt;\n ssl_certificate_key /etc/nginx/tls.key;\n\n # Rootless Podman can hand a container a new IP across restarts/reboots.\n # nginx resolves a literal upstream name ONCE at startup and caches it,\n # so after the IP moves every request 502s with \"host unreachable\"\n # (issue #15, observed live on .198: nginx pinned to a dead\n # netbird-dashboard IP). Fix: point `resolver` at the netbird-net\n # gateway (Podman's aardvark DNS) and use VARIABLE upstreams, which\n # forces nginx to re-resolve the container names at request time.\n resolver {{NETWORK_GATEWAY}} valid=10s ipv6=off;\n\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto $scheme;\n proxy_http_version 1.1;\n\n location ~ ^/(relay|ws-proxy/) {\n set $nb_server netbird-server;\n proxy_pass http://$nb_server:80;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection \"upgrade\";\n proxy_read_timeout 1d;\n }\n\n location ~ ^/(api|oauth2)(/|$) {\n # The dashboard is a SPA whose API/OIDC base URL is baked at build\n # time to one host:port. A single box is reached via several\n # addresses, so those fetches are cross-origin and the browser\n # blocks them with no Access-Control-Allow-Origin (#15, live on\n # .198). Reflect the caller's Origin and answer the CORS preflight.\n if ($request_method = OPTIONS) {\n add_header Access-Control-Allow-Origin $http_origin always;\n add_header Access-Control-Allow-Credentials true always;\n add_header Access-Control-Allow-Methods \"GET, POST, PUT, PATCH, DELETE, OPTIONS\" always;\n add_header Access-Control-Allow-Headers \"Authorization, Content-Type, Accept\" always;\n add_header Access-Control-Max-Age 86400 always;\n add_header Content-Length 0;\n return 204;\n }\n add_header Access-Control-Allow-Origin $http_origin always;\n add_header Access-Control-Allow-Credentials true always;\n add_header Access-Control-Allow-Methods \"GET, POST, PUT, PATCH, DELETE, OPTIONS\" always;\n add_header Access-Control-Allow-Headers \"Authorization, Content-Type, Accept\" always;\n set $nb_server netbird-server;\n proxy_pass http://$nb_server:80;\n }\n\n location ~ ^/(signalexchange\\.SignalExchange|management\\.ManagementService|management\\.ProxyService)/ {\n set $nb_server netbird-server;\n grpc_pass grpc://$nb_server:80;\n grpc_read_timeout 1d;\n grpc_send_timeout 1d;\n }\n\n # OIDC callback routes are client-side SPA routes with NO prebuilt page\n # in the dashboard bundle, so proxying them straight through 404s —\n # which crashes the dashboard's auth init and shows \"Unauthenticated\"\n # with dead buttons (#15, live on .198: /nb-auth + /nb-silent-auth\n # returned 404). Serve index.html at these paths (URL unchanged) so\n # react-oidc boots and completes the login / silent-SSO.\n location ~ ^/(nb-auth|nb-silent-auth) {\n set $nb_dashboard netbird-dashboard;\n rewrite ^.*$ /index.html break;\n proxy_pass http://$nb_dashboard:80;\n }\n\n location / {\n set $nb_dashboard netbird-dashboard;\n proxy_pass http://$nb_dashboard:80;\n }\n}\n",
"overwrite": true,
"path": "/var/lib/archipelago/netbird/nginx.conf"
}
],
"health_check": {
"endpoint": "localhost:443",
"interval": "30s",
"retries": 5,
"start_period": "20s",
"timeout": "5s",
"type": "tcp"
},
"id": "netbird",
"interfaces": {
"main": {
"description": "Manage your self-hosted NetBird mesh VPN",
"name": "Dashboard",
"path": "/",
"port": 8087,
"protocol": "https",
"type": "ui"
}
},
"metadata": {
"author": "NetBird",
"icon": "/assets/img/app-icons/netbird.svg",
"license": "BSD-3-Clause",
"repo": "https://github.com/netbirdio/netbird",
"tags": [
"networking",
"vpn",
"wireguard",
"mesh"
],
"website": "https://netbird.io"
},
"name": "NetBird",
"ports": [
{
"container": 443,
"host": 8087,
"protocol": "tcp"
}
],
"resources": {
"memory_limit": "256Mi"
},
"security": {
"capabilities": [
"CHOWN",
"DAC_OVERRIDE",
"SETGID",
"SETUID",
"NET_BIND_SERVICE"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "2.38.0",
"volumes": [
{
"options": [
"ro"
],
"source": "/var/lib/archipelago/netbird/nginx.conf",
"target": "/etc/nginx/conf.d/default.conf",
"type": "bind"
},
{
"options": [
"ro"
],
"source": "/var/lib/archipelago/netbird/tls.crt",
"target": "/etc/nginx/tls.crt",
"type": "bind"
},
{
"options": [
"ro"
],
"source": "/var/lib/archipelago/netbird/tls.key",
"target": "/etc/nginx/tls.key",
"type": "bind"
}
]
}
},
"version": "2.38.0"
},
"netbird-dashboard": {
"manifest": {
"app": {
"category": "networking",
"container": {
"derived_env": [
{
"key": "NETBIRD_MGMT_API_ENDPOINT",
"template": "https://{{HOST_IP}}:8087"
},
{
"key": "NETBIRD_MGMT_GRPC_API_ENDPOINT",
"template": "https://{{HOST_IP}}:8087"
},
{
"key": "AUTH_AUTHORITY",
"template": "https://{{HOST_IP}}:8087/oauth2"
}
],
"image": "docker.io/netbirdio/dashboard:v2.38.0",
"network": "netbird-net",
"network_aliases": [
"netbird-dashboard"
],
"pull_policy": "if-not-present"
},
"container_name": "netbird-dashboard",
"dependencies": [
{
"app_id": "netbird-server"
}
],
"description": "NetBird management dashboard (SPA). Internal stack member served through the netbird proxy.",
"environment": [
"AUTH_AUDIENCE=netbird-dashboard",
"AUTH_CLIENT_ID=netbird-dashboard",
"AUTH_CLIENT_SECRET=",
"USE_AUTH0=false",
"AUTH_SUPPORTED_SCOPES=openid profile email groups",
"AUTH_REDIRECT_URI=/nb-auth",
"AUTH_SILENT_REDIRECT_URI=/nb-silent-auth",
"NETBIRD_TOKEN_SOURCE=idToken",
"NGINX_SSL_PORT=443",
"LETSENCRYPT_DOMAIN=none"
],
"health_check": {
"endpoint": "localhost:80",
"interval": "30s",
"retries": 5,
"start_period": "20s",
"timeout": "5s",
"type": "tcp"
},
"id": "netbird-dashboard",
"metadata": {
"author": "NetBird",
"icon": "/assets/img/app-icons/netbird.svg",
"license": "BSD-3-Clause",
"repo": "https://github.com/netbirdio/dashboard",
"tags": [
"networking",
"vpn",
"dashboard"
],
"website": "https://netbird.io"
},
"name": "NetBird Dashboard",
"ports": [],
"resources": {
"memory_limit": "256Mi"
},
"security": {
"capabilities": [
"CHOWN",
"DAC_OVERRIDE",
"SETGID",
"SETUID",
"NET_BIND_SERVICE"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "2.38.0",
"volumes": []
}
},
"version": "2.38.0"
},
"netbird-server": {
"manifest": {
"app": {
"category": "networking",
"container": {
"custom_args": [
"--config",
"/etc/netbird/config.yaml"
],
"generated_secrets": [
{
"kind": "base64",
"name": "netbird-relay-auth-secret"
},
{
"kind": "base64",
"name": "netbird-store-encryption-key"
}
],
"image": "docker.io/netbirdio/netbird-server:0.71.2",
"network": "netbird-net",
"network_aliases": [
"netbird-server"
],
"pull_policy": "if-not-present"
},
"container_name": "netbird-server",
"dependencies": [
{
"storage": "1Gi"
}
],
"description": "NetBird combined management / signal / relay server with an embedded identity provider and STUN. Backend for the self-hosted NetBird mesh VPN.",
"environment": [],
"files": [
{
"content": "server:\n listenAddress: \":80\"\n exposedAddress: \"https://{{HOST_IP}}:8087\"\n stunPorts:\n - 3478\n metricsPort: 9090\n healthcheckAddress: \":9000\"\n logLevel: \"info\"\n logFile: \"console\"\n authSecret: \"{{secret:netbird-relay-auth-secret}}\"\n dataDir: \"/var/lib/netbird\"\n auth:\n issuer: \"https://{{HOST_IP}}:8087/oauth2\"\n localAuthDisabled: false\n signKeyRefreshEnabled: false\n dashboardRedirectURIs:\n - \"https://{{HOST_IP}}:8087/nb-auth\"\n - \"https://{{HOST_IP}}:8087/nb-silent-auth\"\n dashboardPostLogoutRedirectURIs:\n - \"https://{{HOST_IP}}:8087/\"\n cliRedirectURIs:\n - \"http://localhost:53000/\"\n store:\n engine: \"sqlite\"\n encryptionKey: \"{{secret:netbird-store-encryption-key}}\"\n",
"overwrite": true,
"path": "/var/lib/archipelago/netbird/config.yaml"
}
],
"health_check": {
"endpoint": "localhost:80",
"interval": "30s",
"retries": 10,
"start_period": "30s",
"timeout": "5s",
"type": "tcp"
},
"id": "netbird-server",
"metadata": {
"author": "NetBird",
"icon": "/assets/img/app-icons/netbird.svg",
"license": "BSD-3-Clause",
"repo": "https://github.com/netbirdio/netbird",
"tags": [
"networking",
"vpn",
"wireguard",
"mesh"
],
"website": "https://netbird.io"
},
"name": "NetBird Server",
"ports": [
{
"container": 80,
"host": 8086,
"protocol": "tcp"
},
{
"container": 3478,
"host": 3478,
"protocol": "udp"
}
],
"resources": {
"memory_limit": "1Gi"
},
"security": {
"capabilities": [
"NET_BIND_SERVICE"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "0.71.2",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/netbird/data",
"target": "/var/lib/netbird",
"type": "bind"
},
{
"options": [
"ro"
],
"source": "/var/lib/archipelago/netbird/config.yaml",
"target": "/etc/netbird/config.yaml",
"type": "bind"
}
]
}
},
"version": "0.71.2"
},
"nextcloud": {
"image": "146.59.87.168:3000/lfg2025/nextcloud:29",
"manifest": {
"app": {
"container": {
"image": "146.59.87.168:3000/lfg2025/nextcloud:29",
"network": "pasta",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"storage": "10Gi"
}
],
"description": "Your own private cloud. File sync, calendars, contacts.",
"environment": [],
"health_check": {
"endpoint": "localhost:80",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "nextcloud",
"interfaces": {
"main": {
"description": "Nextcloud file and collaboration dashboard",
"name": "Web UI",
"path": "/",
"port": 8085,
"protocol": "http",
"type": "ui"
}
},
"metadata": {
"author": "Nextcloud",
"category": "data",
"icon": "/assets/img/app-icons/nextcloud.webp",
"launch": {
"open_in_new_tab": true
},
"repo": "https://github.com/nextcloud/server"
},
"name": "Nextcloud",
"ports": [
{
"container": 80,
"host": 8085,
"protocol": "tcp"
}
],
"resources": {
"disk_limit": "10Gi",
"memory_limit": "1Gi"
},
"security": {
"capabilities": [
"CHOWN",
"SETUID",
"SETGID",
"DAC_OVERRIDE",
"NET_BIND_SERVICE"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "29",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/nextcloud",
"target": "/var/www/html",
"type": "bind"
}
]
}
},
"version": "29"
},
"nginx-proxy-manager": {
"image": "146.59.87.168:3000/lfg2025/nginx-proxy-manager:latest",
"version": "latest"
},
"nostr-rs-relay": {
"image": "146.59.87.168:3000/lfg2025/nostr-rs-relay:0.9.0",
"manifest": {
"app": {
"container": {
"data_uid": "1000:1000",
"image": "scsibug/nostr-rs-relay:0.8.9",
"image_signature": "cosign://...",
"pull_policy": "verify-signature"
},
"dependencies": [
{
"storage": "10Gi"
}
],
"description": "High-performance Nostr relay written in Rust. Host your own decentralized social media relay and earn networking profits.",
"environment": [
"RELAY_NAME=Archipelago Nostr Relay",
"RELAY_DESCRIPTION=Self-hosted Nostr relay on Archipelago",
"MAX_EVENTS=1000000",
"MAX_SUBSCRIPTIONS=100"
],
"health_check": {
"endpoint": "http://localhost:8080",
"interval": "30s",
"path": "/",
"retries": 5,
"timeout": "30s",
"type": "http"
},
"id": "nostr-rs-relay",
"name": "Nostr Relay (Rust)",
"nostr_integration": {
"event_storage": "sqlite",
"monetization_enabled": true,
"relay_type": "public"
},
"ports": [
{
"container": 8080,
"host": 18081,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 2,
"disk_limit": "10Gi",
"memory_limit": "1Gi"
},
"security": {
"apparmor_profile": "nostr-relay",
"capabilities": [],
"network_policy": "isolated",
"no_new_privileges": true,
"readonly_root": true,
"seccomp_profile": "default",
"user": 1000
},
"version": "0.8.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/nostr-relay",
"target": "/usr/src/app/db",
"type": "bind"
}
]
}
},
"version": "0.9.0"
},
"nostr-vpn": {
"image": "146.59.87.168:3000/lfg2025/nostr-vpn:v0.3.7",
"version": "v0.3.7"
},
"ollama": {
"image": "146.59.87.168:3000/lfg2025/ollama:latest",
"version": "latest"
},
"penpot": {
"image": "146.59.87.168:3000/lfg2025/penpot-frontend:2.4",
"images": {
"penpot-backend": "146.59.87.168:3000/lfg2025/penpot-backend:2.4",
"penpot-exporter": "146.59.87.168:3000/lfg2025/penpot-exporter:2.4",
"penpot-frontend": "146.59.87.168:3000/lfg2025/penpot-frontend:2.4",
"penpot-postgres": "146.59.87.168:3000/lfg2025/postgres:15",
"penpot-valkey": "146.59.87.168:3000/lfg2025/valkey:8.1"
},
"version": "2.4"
},
"photoprism": {
"image": "146.59.87.168:3000/lfg2025/photoprism:240915",
"manifest": {
"app": {
"container": {
"image": "146.59.87.168:3000/lfg2025/photoprism:240915",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"storage": "10Gi"
}
],
"description": "AI-powered photo management with facial recognition.",
"environment": [
"PHOTOPRISM_ADMIN_PASSWORD=archipelago",
"PHOTOPRISM_DEFAULT_LOCALE=en"
],
"health_check": {
"endpoint": "localhost:2342",
"interval": "60s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "photoprism",
"interfaces": {
"main": {
"description": "PhotoPrism photo library",
"name": "Web UI",
"path": "/",
"port": 2342,
"protocol": "http",
"type": "ui"
}
},
"metadata": {
"author": "PhotoPrism",
"category": "data",
"icon": "/assets/img/app-icons/photoprism.svg",
"launch": {
"open_in_new_tab": true
},
"repo": "https://github.com/photoprism/photoprism"
},
"name": "PhotoPrism",
"ports": [
{
"container": 2342,
"host": 2342,
"protocol": "tcp"
}
],
"resources": {
"disk_limit": "10Gi",
"memory_limit": "1Gi"
},
"security": {
"capabilities": [
"CHOWN",
"SETUID",
"SETGID"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "240915",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/photoprism",
"target": "/photoprism/storage",
"type": "bind"
}
]
}
},
"version": "240915"
},
"portainer": {
"image": "146.59.87.168:3000/lfg2025/portainer:2.19.4",
"manifest": {
"app": {
"category": "development",
"container": {
"data_uid": "1000:1000",
"image": "146.59.87.168:3000/lfg2025/portainer:2.19.4",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"storage": "1Gi"
}
],
"description": "Container management web UI for the local Podman socket.",
"environment": [],
"id": "portainer",
"interfaces": {
"main": {
"description": "Portainer web interface",
"name": "Web UI",
"path": "/",
"port": 9000,
"protocol": "http",
"type": "ui"
}
},
"metadata": {
"features": [
"Container management dashboard",
"Local Podman socket access",
"Compose stack storage"
],
"icon": "/assets/img/app-icons/portainer.webp",
"launch": {
"open_in_new_tab": true
},
"tier": "optional"
},
"name": "Portainer",
"ports": [
{
"container": 9000,
"host": 9000,
"protocol": "tcp"
}
],
"resources": {
"disk_limit": "1Gi",
"memory_limit": "256Mi"
},
"security": {
"capabilities": [
"CHOWN",
"SETUID",
"SETGID",
"DAC_OVERRIDE"
],
"network_policy": "isolated",
"no_new_privileges": true,
"readonly_root": false
},
"version": "2.19.4",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/portainer",
"target": "/data",
"type": "bind"
},
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/portainer/compose",
"target": "/data/compose",
"type": "bind"
},
{
"options": [
"rw"
],
"source": "/run/user/1000/podman/podman.sock",
"target": "/var/run/docker.sock",
"type": "bind"
}
]
}
},
"version": "2.19.4"
},
"router": {
"manifest": {
"app": {
"container": {
"image": "archipelago/router:1.0.0",
"image_signature": "cosign://...",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"storage": "500Mi"
}
],
"description": "Mesh routing and local network management. Provides device discovery, routing, and network topology visualization.",
"environment": [
"NETWORK_INTERFACE=eth0",
"MESH_ENABLED=true",
"DEVICE_DISCOVERY=true"
],
"health_check": {
"endpoint": "http://localhost:8084",
"interval": "30s",
"path": "/health",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "router",
"name": "Mesh Router",
"networking": {
"device_discovery": true,
"local_network_access": true,
"mesh_enabled": true,
"routing_protocols": [
"olsr",
"babel"
]
},
"ports": [
{
"container": 8080,
"host": 8084,
"protocol": "tcp"
},
{
"container": 5353,
"host": 5353,
"protocol": "udp"
},
{
"container": 1900,
"host": 1900,
"protocol": "udp"
}
],
"resources": {
"cpu_limit": 2,
"disk_limit": "500Mi",
"memory_limit": "512Mi"
},
"security": {
"apparmor_profile": "router",
"capabilities": [
"NET_ADMIN",
"NET_RAW"
],
"network_policy": "host",
"no_new_privileges": true,
"readonly_root": true,
"seccomp_profile": "default",
"user": 1000
},
"version": "1.0.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/router",
"target": "/app/data",
"type": "bind"
},
{
"options": [
"ro"
],
"source": "/var/run/dbus",
"target": "/var/run/dbus",
"type": "bind"
}
]
}
},
"version": "1.0.0"
},
"routstr": {
"image": "146.59.87.168:3000/lfg2025/routstr:v0.4.3",
"version": "v0.4.3"
},
"searxng": {
"image": "146.59.87.168:3000/lfg2025/searxng:latest",
"manifest": {
"app": {
"container": {
"image": "146.59.87.168:3000/lfg2025/searxng:latest",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"storage": "2Gi"
}
],
"description": "Privacy-respecting metasearch engine. Search the web without tracking.",
"environment": [
"SEARXNG_HOSTNAME=localhost",
"SEARXNG_BIND_ADDRESS=0.0.0.0:8080"
],
"health_check": {
"endpoint": "http://localhost:8080",
"interval": "30s",
"path": "/",
"retries": 5,
"timeout": "30s",
"type": "http"
},
"id": "searxng",
"name": "SearXNG",
"ports": [
{
"container": 8080,
"host": 8888,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 2,
"disk_limit": "2Gi",
"memory_limit": "1Gi"
},
"security": {
"apparmor_profile": "searxng",
"capabilities": [],
"network_policy": "isolated",
"no_new_privileges": true,
"readonly_root": true,
"seccomp_profile": "default",
"user": 1000
},
"version": "1.0.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/searxng",
"target": "/etc/searxng",
"type": "bind"
}
]
}
},
"version": "latest"
},
"strfry": {
"manifest": {
"app": {
"container": {
"image": "dockurr/strfry:1.0.4",
"image_signature": "cosign://...",
"pull_policy": "verify-signature"
},
"dependencies": [
{
"storage": "5Gi"
}
],
"description": "Lightweight Nostr relay written in C++. Alternative to nostr-rs-relay with lower resource usage.",
"environment": [
"RELAY_NAME=Archipelago Strfry Relay"
],
"health_check": {
"endpoint": "http://localhost:8082",
"interval": "30s",
"path": "/health",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "strfry",
"name": "Strfry Nostr Relay",
"nostr_integration": {
"monetization_enabled": true,
"relay_type": "public"
},
"ports": [
{
"container": 8080,
"host": 8082,
"protocol": "tcp"
}
],
"resources": {
"cpu_limit": 1,
"disk_limit": "5Gi",
"memory_limit": "512Mi"
},
"security": {
"apparmor_profile": "nostr-relay",
"capabilities": [],
"network_policy": "isolated",
"no_new_privileges": true,
"readonly_root": true,
"seccomp_profile": "default",
"user": 1000
},
"version": "0.9.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/strfry",
"target": "/strfry",
"type": "bind"
}
]
}
},
"version": "0.9.0"
},
"tailscale": {
"image": "146.59.87.168:3000/lfg2025/tailscale:stable",
"version": "stable"
},
"uptime-kuma": {
"image": "146.59.87.168:3000/lfg2025/uptime-kuma:1",
"manifest": {
"app": {
"container": {
"custom_args": [
"--",
"node",
"server/server.js"
],
"image": "146.59.87.168:3000/lfg2025/uptime-kuma:1",
"network": "pasta",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"storage": "1Gi"
}
],
"description": "Self-hosted uptime monitoring.",
"environment": [
"TZ=UTC"
],
"health_check": {
"endpoint": "localhost:3001",
"interval": "30s",
"path": "/",
"retries": 3,
"timeout": "5s",
"type": "http"
},
"id": "uptime-kuma",
"metadata": {
"author": "Uptime Kuma",
"category": "data",
"icon": "/assets/img/app-icons/uptime-kuma.webp",
"launch": {
"open_in_new_tab": true
},
"repo": "https://github.com/louislam/uptime-kuma",
"tier": "recommended"
},
"name": "Uptime Kuma",
"ports": [
{
"container": 3001,
"host": 3002,
"protocol": "tcp"
}
],
"resources": {
"disk_limit": "1Gi",
"memory_limit": "256Mi"
},
"security": {
"capabilities": [
"CHOWN",
"FOWNER",
"SETUID",
"SETGID"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "1.23.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/uptime-kuma",
"target": "/app/data",
"type": "bind"
}
]
}
},
"version": "1"
},
"vaultwarden": {
"image": "146.59.87.168:3000/lfg2025/vaultwarden:1.30.0-alpine",
"manifest": {
"app": {
"container": {
"image": "146.59.87.168:3000/lfg2025/vaultwarden:1.30.0-alpine",
"network": "pasta",
"pull_policy": "if-not-present"
},
"dependencies": [
{
"storage": "1Gi"
}
],
"description": "Self-hosted password vault with zero-knowledge encryption.",
"environment": [],
"health_check": {
"endpoint": "localhost:80",
"interval": "30s",
"retries": 3,
"timeout": "5s",
"type": "tcp"
},
"id": "vaultwarden",
"interfaces": {
"main": {
"description": "Vaultwarden web vault",
"name": "Web UI",
"path": "/",
"port": 8082,
"protocol": "http",
"type": "ui"
}
},
"metadata": {
"author": "Vaultwarden",
"category": "data",
"icon": "/assets/img/app-icons/vaultwarden.webp",
"launch": {
"open_in_new_tab": true
},
"repo": "https://github.com/dani-garcia/vaultwarden",
"tier": "recommended"
},
"name": "Vaultwarden",
"ports": [
{
"container": 80,
"host": 8082,
"protocol": "tcp"
}
],
"resources": {
"disk_limit": "1Gi",
"memory_limit": "256Mi"
},
"security": {
"capabilities": [
"CHOWN",
"SETUID",
"SETGID",
"NET_BIND_SERVICE"
],
"network_policy": "isolated",
"readonly_root": false
},
"version": "1.30.0",
"volumes": [
{
"options": [
"rw"
],
"source": "/var/lib/archipelago/vaultwarden",
"target": "/data",
"type": "bind"
}
]
}
},
"version": "1.30.0-alpine"
}
},
"schema": 1,
"signature": "0e8bd98743c5ac56ef350964e99f72358fd05d051c002dcd92a7d3e089bd7fddad4ae2870b39ae35e6b2fc386780f8bca53f6eb10dfefd295977e17ec239ac0a",
"signed_by": "did:key:z6MkkidEnEpo6qHMCNSZoNKWtvQvxq3whnaME9wGgEFhq7ur",
"updated": "2026-06-29"
}