Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ec67b8f31 | ||
|
|
7b88ba59b2 | ||
|
|
b12d1d3826 | ||
|
|
698e915df2 | ||
|
|
a179df66d8 | ||
|
|
771ff0d28b | ||
|
|
92111385b7 | ||
|
|
a9e52fa310 | ||
|
|
c188d9de78 | ||
|
|
37a82fd2f9 | ||
|
|
f1b5d2d267 | ||
|
|
d6b48ce095 |
@@ -52,13 +52,13 @@
|
|||||||
{
|
{
|
||||||
"id": "btcpay-server",
|
"id": "btcpay-server",
|
||||||
"title": "BTCPay Server",
|
"title": "BTCPay Server",
|
||||||
"version": "2.4.2",
|
"version": "2.4.3",
|
||||||
"description": "Self-hosted Bitcoin payment processor. Accept Bitcoin payments without intermediaries.",
|
"description": "Self-hosted Bitcoin payment processor. Accept Bitcoin payments without intermediaries.",
|
||||||
"icon": "/assets/img/app-icons/btcpay-server.png",
|
"icon": "/assets/img/app-icons/btcpay-server.png",
|
||||||
"author": "BTCPay Server Foundation",
|
"author": "BTCPay Server Foundation",
|
||||||
"category": "commerce",
|
"category": "commerce",
|
||||||
"tier": "core",
|
"tier": "core",
|
||||||
"dockerImage": "docker.io/btcpayserver/btcpayserver:2.4.2",
|
"dockerImage": "docker.io/btcpayserver/btcpayserver:2.4.3",
|
||||||
"repoUrl": "https://github.com/btcpayserver/btcpayserver",
|
"repoUrl": "https://github.com/btcpayserver/btcpayserver",
|
||||||
"requires": [
|
"requires": [
|
||||||
"bitcoin-knots"
|
"bitcoin-knots"
|
||||||
@@ -378,7 +378,7 @@
|
|||||||
"icon": "/assets/img/app-icons/pine.svg",
|
"icon": "/assets/img/app-icons/pine.svg",
|
||||||
"author": "Archipelago",
|
"author": "Archipelago",
|
||||||
"category": "home",
|
"category": "home",
|
||||||
"dockerImage": "docker.io/library/nginx:1.31.3-alpine",
|
"dockerImage": "docker.io/library/nginx:1.31.4-alpine",
|
||||||
"repoUrl": "https://github.com/rhasspy/wyoming"
|
"repoUrl": "https://github.com/rhasspy/wyoming"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -464,7 +464,7 @@
|
|||||||
"author": "NetBird",
|
"author": "NetBird",
|
||||||
"category": "networking",
|
"category": "networking",
|
||||||
"tier": "recommended",
|
"tier": "recommended",
|
||||||
"dockerImage": "docker.io/library/nginx:1.31.3-alpine",
|
"dockerImage": "docker.io/library/nginx:1.31.4-alpine",
|
||||||
"repoUrl": "https://github.com/netbirdio/netbird",
|
"repoUrl": "https://github.com/netbirdio/netbird",
|
||||||
"containerConfig": {
|
"containerConfig": {
|
||||||
"ports": [
|
"ports": [
|
||||||
@@ -571,6 +571,18 @@
|
|||||||
"tier": "optional",
|
"tier": "optional",
|
||||||
"dockerImage": "source.archipelago-foundation.org/lfg2025/phoenixd:0.9.0",
|
"dockerImage": "source.archipelago-foundation.org/lfg2025/phoenixd:0.9.0",
|
||||||
"repoUrl": "https://github.com/ACINQ/phoenixd"
|
"repoUrl": "https://github.com/ACINQ/phoenixd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cuprate",
|
||||||
|
"title": "Cuprate",
|
||||||
|
"version": "0.1.0-preview",
|
||||||
|
"description": "Alternative Monero node implementation in Rust. Independently validates Monero consensus rules, providing a layer of security and redundancy for the network.",
|
||||||
|
"icon": "/assets/img/app-icons/cuprate.svg",
|
||||||
|
"author": "Cuprate contributors",
|
||||||
|
"category": "money",
|
||||||
|
"tier": "optional",
|
||||||
|
"dockerImage": "source.archipelago-foundation.org/lfg2025/cuprate:0.1.0-preview-18-g618ff14",
|
||||||
|
"repoUrl": "https://github.com/Cuprate/cuprate"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
app:
|
app:
|
||||||
id: archy-nbxplorer
|
id: archy-nbxplorer
|
||||||
name: NBXplorer
|
name: NBXplorer
|
||||||
version: 2.6.0
|
version: 2.6.11
|
||||||
# Where this app comes from, so scripts/check-upstream-releases.py can
|
# Where this app comes from, so scripts/check-upstream-releases.py can
|
||||||
# tell us when the pin below has fallen behind. Without it nothing can:
|
# tell us when the pin below has fallen behind. Without it nothing can:
|
||||||
# container.image names our mirror, not the project it was mirrored from.
|
# container.image names our mirror, not the project it was mirrored from.
|
||||||
@@ -11,7 +11,7 @@ app:
|
|||||||
description: BTCPay blockchain indexer service.
|
description: BTCPay blockchain indexer service.
|
||||||
|
|
||||||
container:
|
container:
|
||||||
image: source.archipelago-foundation.org/lfg2025/nbxplorer:2.6.0
|
image: source.archipelago-foundation.org/lfg2025/nbxplorer:2.6.11
|
||||||
pull_policy: if-not-present
|
pull_policy: if-not-present
|
||||||
network: archy-net
|
network: archy-net
|
||||||
secret_env:
|
secret_env:
|
||||||
|
|||||||
@@ -2,6 +2,14 @@ app:
|
|||||||
id: barkd
|
id: barkd
|
||||||
name: Ark Wallet
|
name: Ark Wallet
|
||||||
version: 0.3.0
|
version: 0.3.0
|
||||||
|
# Where this app comes from, so scripts/check-upstream-releases.py can
|
||||||
|
# tell us when the pin below has fallen behind. bark ships on GitLab only
|
||||||
|
# (no GitHub mirror), so the gitlab fetcher is the one that can see it.
|
||||||
|
# NOTE: a version bump is code work, not a pin move — the REST shapes are
|
||||||
|
# coded in core/archipelago/src/wallet/ark_client.rs (see Dockerfile note).
|
||||||
|
upstream:
|
||||||
|
kind: gitlab
|
||||||
|
repo: ark-bitcoin/bark
|
||||||
description: Ark protocol wallet daemon (barkd). Lets the node hold self-custodial off-chain bitcoin via an Ark server; the wallet talks to it over a local REST API. Signet by default while Ark matures.
|
description: Ark protocol wallet daemon (barkd). Lets the node hold self-custodial off-chain bitcoin via an Ark server; the wallet talks to it over a local REST API. Signet by default while Ark matures.
|
||||||
|
|
||||||
container:
|
container:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
app:
|
app:
|
||||||
id: btcpay-server
|
id: btcpay-server
|
||||||
name: BTCPay Server
|
name: BTCPay Server
|
||||||
version: 2.4.2
|
version: 2.4.3
|
||||||
# Where this app comes from, so scripts/check-upstream-releases.py can
|
# Where this app comes from, so scripts/check-upstream-releases.py can
|
||||||
# tell us when the pin below has fallen behind. Without it nothing can:
|
# tell us when the pin below has fallen behind. Without it nothing can:
|
||||||
# container.image names our mirror, not the project it was mirrored from.
|
# container.image names our mirror, not the project it was mirrored from.
|
||||||
@@ -11,7 +11,7 @@ app:
|
|||||||
description: Self-hosted Bitcoin payment processor. Accept Bitcoin payments without intermediaries.
|
description: Self-hosted Bitcoin payment processor. Accept Bitcoin payments without intermediaries.
|
||||||
|
|
||||||
container:
|
container:
|
||||||
image: docker.io/btcpayserver/btcpayserver:2.4.2
|
image: docker.io/btcpayserver/btcpayserver:2.4.3
|
||||||
pull_policy: if-not-present
|
pull_policy: if-not-present
|
||||||
network: archy-net
|
network: archy-net
|
||||||
secret_env:
|
secret_env:
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
app:
|
||||||
|
id: cuprate
|
||||||
|
name: Cuprate
|
||||||
|
# Matches the crate's own Cargo.toml version (binaries/cuprated/Cargo.toml).
|
||||||
|
# Cuprate has no stable release yet — this is explicitly work-in-progress
|
||||||
|
# software (see upstream README). The image tag below pins the exact
|
||||||
|
# commit built, since "0.1.0-preview" alone is not reproducible.
|
||||||
|
version: 0.1.0-preview
|
||||||
|
# Where this app comes from, so scripts/check-upstream-releases.py can
|
||||||
|
# tell us when the pin below has fallen behind. Without it nothing can:
|
||||||
|
# container.image names our mirror, not the project it was mirrored from.
|
||||||
|
upstream:
|
||||||
|
kind: github
|
||||||
|
repo: Cuprate/cuprate
|
||||||
|
description: Alternative Monero node implementation in Rust. Independently validates Monero consensus rules, providing a layer of security and redundancy for the network.
|
||||||
|
category: money
|
||||||
|
|
||||||
|
metadata:
|
||||||
|
icon: /assets/img/app-icons/cuprate.svg
|
||||||
|
repo: https://github.com/Cuprate/cuprate
|
||||||
|
tier: optional
|
||||||
|
|
||||||
|
container:
|
||||||
|
# Built from the upstream Dockerfile at the tip of main, 18 commits past
|
||||||
|
# the cuprated-0.1.0-preview tag (commit 618ff14, 2026-08-19) — there is
|
||||||
|
# no newer tagged release as of this writing. Re-pin to a tagged release
|
||||||
|
# once upstream cuts one.
|
||||||
|
image: source.archipelago-foundation.org/lfg2025/cuprate:0.1.0-preview-18-g618ff14
|
||||||
|
pull_policy: if-not-present
|
||||||
|
network: archy-net
|
||||||
|
# The image's own ENTRYPOINT is ["/usr/local/bin/cuprated"]; these are
|
||||||
|
# appended as its argv, matching the project's own systemd unit
|
||||||
|
# (cuprated.service) invocation exactly.
|
||||||
|
custom_args: ["--config-file", "/home/cuprate/Cuprated.toml"]
|
||||||
|
# The image (FROM scratch) creates uid:gid 1000:1000 for the `cuprate`
|
||||||
|
# user at build time and runs as it unconditionally (USER 1000:1000,
|
||||||
|
# no shell to switch users at runtime) — same pattern as
|
||||||
|
# apps/phoenixd, apps/electrumx, apps/nostr-rs-relay, apps/portainer,
|
||||||
|
# apps/barkd. The bind-mounted data dir must be owned by that literal
|
||||||
|
# uid or cuprated dies on a permission error the first time it writes.
|
||||||
|
data_uid: "1000:1000"
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
# Monero mainnet is ~250GiB unpruned as of 2026 and growing a few GB a
|
||||||
|
# month; cuprated's pruning support is not confirmed stable yet (the
|
||||||
|
# `pruning` crate exists in the workspace but nothing in this config
|
||||||
|
# surface toggles it), so this sizes for a full unpruned chain plus
|
||||||
|
# headroom rather than assuming pruning is available.
|
||||||
|
- storage: 300Gi
|
||||||
|
|
||||||
|
resources:
|
||||||
|
cpu_limit: 0
|
||||||
|
memory_limit: 4Gi
|
||||||
|
disk_limit: 300Gi
|
||||||
|
|
||||||
|
security:
|
||||||
|
# FROM scratch, no package manager/shell, ownership fixed at build time
|
||||||
|
# — unlike bitcoin-knots this needs no runtime chown/setuid dance, so it
|
||||||
|
# can run fully read-only with an empty capability set.
|
||||||
|
capabilities: []
|
||||||
|
readonly_root: true
|
||||||
|
no_new_privileges: true
|
||||||
|
network_policy: isolated
|
||||||
|
|
||||||
|
ports:
|
||||||
|
# P2P. Cuprate's own default listen address is already 0.0.0.0
|
||||||
|
# (p2p.clear_net.listen_on), so no config override is needed — only the
|
||||||
|
# host-side port differs from Monero's canonical 18080 because that
|
||||||
|
# number is already taken on this fleet by lnd's REST port.
|
||||||
|
- host: 18183
|
||||||
|
container: 18080
|
||||||
|
protocol: tcp
|
||||||
|
auth: none
|
||||||
|
auth_rationale: >-
|
||||||
|
Monero p2p gossip. Peers are anonymous by design and speak the Monero wire protocol, not HTTP.
|
||||||
|
# Unrestricted RPC (full node control) is deliberately NOT published.
|
||||||
|
# cuprated has no RPC authentication, and for a published port to reach
|
||||||
|
# it the service would have to bind 0.0.0.0 inside the container — at
|
||||||
|
# which point every other app can reach it directly on 18081, since
|
||||||
|
# ports[].bind only restricts the HOST side and podman bridges route to
|
||||||
|
# each other (verified live 2026-08-22: a peer container on archy-net
|
||||||
|
# got an unauthenticated get_info, from a *different* network). That is
|
||||||
|
# unlike bitcoin-knots, whose 0.0.0.0 RPC still demands the rpcuser /
|
||||||
|
# rpcpassword it writes from generated secrets. So unrestricted RPC is
|
||||||
|
# left at cuprated's own default — container loopback only, reachable by
|
||||||
|
# nothing — which is also what upstream intends by refusing a non-local
|
||||||
|
# bind without an explicit i_know_what_im_doing override.
|
||||||
|
# Restricted RPC: Monero's own purpose-built safe-for-public subset —
|
||||||
|
# what wallets use when connecting to a "remote node". Disabled by
|
||||||
|
# cuprated's own default; enabled via files[] below. A dashboard login
|
||||||
|
# would break wallet clients connecting programmatically, same
|
||||||
|
# reasoning as electrumx's port. The daemon still uses its canonical
|
||||||
|
# container port 18089, but Penpot already owns host port 18089, so this
|
||||||
|
# maps the public host port to the free 18090 instead.
|
||||||
|
- host: 18090
|
||||||
|
container: 18089
|
||||||
|
protocol: tcp
|
||||||
|
auth: none
|
||||||
|
auth_rationale: >-
|
||||||
|
Monero restricted RPC — the subset upstream considers safe for public/remote-node use. Wallets (Feather, monero-wallet-rpc, GUI) connect directly over plain HTTP JSON-RPC and cannot hold a dashboard session cookie.
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- type: bind
|
||||||
|
source: /var/lib/archipelago/cuprate
|
||||||
|
target: /home/cuprate
|
||||||
|
options: [rw]
|
||||||
|
|
||||||
|
# Settings that need to differ from cuprated's own documented defaults
|
||||||
|
# (verified against `cuprated --generate-config` and `--dry-run` locally,
|
||||||
|
# 2026-08-21):
|
||||||
|
# - target_max_memory: cuprated's own default auto-detects total *host*
|
||||||
|
# RAM via sysinfo, which inside a memory-limited container would let
|
||||||
|
# it size caches far past what resources.memory_limit above actually
|
||||||
|
# grants — same class of problem bitcoin-knots' -dbcache sizing
|
||||||
|
# comment addresses. Set explicitly, comfortably under the 4Gi limit.
|
||||||
|
# - rpc.restricted.enable: cuprated ships this off by default; flip on
|
||||||
|
# so the auth:none host port above actually serves something instead
|
||||||
|
# of refusing every connection. port stays at its documented default
|
||||||
|
# (canonical 18089), and advertise stays false — this node is not
|
||||||
|
# opting in to being listed as a public remote node over the p2p
|
||||||
|
# network, just reachable if someone points a wallet at it directly.
|
||||||
|
# - rpc.unrestricted.address + the allow-public flag: cuprated's own
|
||||||
|
# default (127.0.0.1) looks like the obviously-correct choice for a
|
||||||
|
# port meant to stay loopback-only, but verified live (2026-08-21)
|
||||||
|
# that a service bound literally to 127.0.0.1 *inside* the container
|
||||||
|
# is unreachable through the host's published port — connections
|
||||||
|
# reset regardless of how long the daemon has been up. Binding
|
||||||
|
# 0.0.0.0 inside and letting ports[].bind: 127.0.0.1 below be the
|
||||||
|
# actual restriction is the same pattern apps/bitcoin-knots already
|
||||||
|
# uses for its own RPC port (-rpcbind=0.0.0.0:8332 internally, gate
|
||||||
|
# restricts it externally) — not a new risk, the same one already
|
||||||
|
# reviewed and accepted for Bitcoin's RPC.
|
||||||
|
files:
|
||||||
|
- path: /var/lib/archipelago/cuprate/Cuprated.toml
|
||||||
|
content: |
|
||||||
|
network = "Mainnet"
|
||||||
|
target_max_memory = 3000000000
|
||||||
|
|
||||||
|
[rpc.restricted]
|
||||||
|
enable = true
|
||||||
|
overwrite: false
|
||||||
|
|
||||||
|
health_check:
|
||||||
|
type: tcp
|
||||||
|
# Restricted RPC — the only RPC surface published now.
|
||||||
|
endpoint: localhost:18090
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
start_period: 5m
|
||||||
|
|
||||||
|
metadata:
|
||||||
|
icon: /assets/img/app-icons/cuprate.svg
|
||||||
|
category: money
|
||||||
|
tier: optional
|
||||||
|
author: Cuprate
|
||||||
|
repo: https://github.com/Cuprate/cuprate
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
app:
|
app:
|
||||||
id: homeassistant
|
id: homeassistant
|
||||||
name: Home Assistant
|
name: Home Assistant
|
||||||
version: 2026.7.3
|
version: 2026.8.3
|
||||||
# Where this app comes from, so scripts/check-upstream-releases.py can
|
# Where this app comes from, so scripts/check-upstream-releases.py can
|
||||||
# tell us when the pin below has fallen behind. Without it nothing can:
|
# tell us when the pin below has fallen behind. Without it nothing can:
|
||||||
# container.image names our mirror, not the project it was mirrored from.
|
# container.image names our mirror, not the project it was mirrored from.
|
||||||
@@ -11,7 +11,7 @@ app:
|
|||||||
description: Open source home automation platform. Control and monitor your smart home devices.
|
description: Open source home automation platform. Control and monitor your smart home devices.
|
||||||
|
|
||||||
container:
|
container:
|
||||||
image: source.archipelago-foundation.org/lfg2025/home-assistant:2026.8.2
|
image: source.archipelago-foundation.org/lfg2025/home-assistant:2026.8.3
|
||||||
pull_policy: if-not-present
|
pull_policy: if-not-present
|
||||||
network: pasta
|
network: pasta
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,12 @@ app:
|
|||||||
id: immich-postgres
|
id: immich-postgres
|
||||||
name: Immich Postgres
|
name: Immich Postgres
|
||||||
version: "14-vectorchord0.4.3-pgvectors0.2.0"
|
version: "14-vectorchord0.4.3-pgvectors0.2.0"
|
||||||
|
# Upstream is the Immich-built Postgres image, published only on ghcr.io
|
||||||
|
# (no GitHub release tags, no Docker Hub repo) — the ghcr fetcher in
|
||||||
|
# scripts/check-upstream-releases.py is the only one that can see it.
|
||||||
|
upstream:
|
||||||
|
kind: ghcr
|
||||||
|
repo: immich-app/postgres
|
||||||
description: Postgres (pgvecto.rs / vectorchord) backend for Immich.
|
description: Postgres (pgvecto.rs / vectorchord) backend for Immich.
|
||||||
|
|
||||||
# Container named immich_postgres (underscore) to match the runtime's existing
|
# Container named immich_postgres (underscore) to match the runtime's existing
|
||||||
|
|||||||
@@ -2,6 +2,12 @@ app:
|
|||||||
id: indeedhub-minio
|
id: indeedhub-minio
|
||||||
name: IndeedHub MinIO
|
name: IndeedHub MinIO
|
||||||
version: "RELEASE.2024-11-07T00-52-20Z"
|
version: "RELEASE.2024-11-07T00-52-20Z"
|
||||||
|
# MinIO's release tags are date-opaque (RELEASE.YYYY-MM-DD…), so the
|
||||||
|
# checker reports them as UNCOMPARABLE rather than ordering them — the
|
||||||
|
# latest tag is still shown for hand comparison, which is the point.
|
||||||
|
upstream:
|
||||||
|
kind: github
|
||||||
|
repo: minio/minio
|
||||||
description: MinIO S3-compatible object storage for IndeedHub media.
|
description: MinIO S3-compatible object storage for IndeedHub media.
|
||||||
category: community
|
category: community
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,12 @@ app:
|
|||||||
id: lightning-stack
|
id: lightning-stack
|
||||||
name: Lightning Stack
|
name: Lightning Stack
|
||||||
version: 0.12.0
|
version: 0.12.0
|
||||||
|
# No public listing exists for lightninglabs/lightning-stack (checked
|
||||||
|
# docker.io, ghcr.io and github.com) — nothing can be queried automatically,
|
||||||
|
# so this one is tracked by hand.
|
||||||
|
upstream:
|
||||||
|
kind: manual
|
||||||
|
url: no public listing for lightninglabs/lightning-stack — verify by hand
|
||||||
description: Complete Lightning Network implementation. Includes LND, CLN, and management tools.
|
description: Complete Lightning Network implementation. Includes LND, CLN, and management tools.
|
||||||
|
|
||||||
container:
|
container:
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ app:
|
|||||||
container_name: netbird
|
container_name: netbird
|
||||||
|
|
||||||
container:
|
container:
|
||||||
image: docker.io/library/nginx:1.31.3-alpine
|
image: docker.io/library/nginx:1.31.4-alpine
|
||||||
pull_policy: if-not-present
|
pull_policy: if-not-present
|
||||||
network: netbird-net
|
network: netbird-net
|
||||||
# Self-signed TLS cert materialised before create — the dashboard needs a
|
# Self-signed TLS cert materialised before create — the dashboard needs a
|
||||||
|
|||||||
@@ -6,6 +6,14 @@ app:
|
|||||||
# pick up the args change; the pre-release form "3.4.1-1" would compare
|
# pick up the args change; the pre-release form "3.4.1-1" would compare
|
||||||
# LOWER than 3.4.1 under semver and never roll out.
|
# LOWER than 3.4.1 under semver and never roll out.
|
||||||
version: "3.4.2"
|
version: "3.4.2"
|
||||||
|
# Tracks the rhasspy/wyoming-whisper image we pin (Docker Hub — the
|
||||||
|
# project's GitHub tags are not the image tags). NOTE: this manifest
|
||||||
|
# deliberately ships an args-tuned revision AHEAD of the image tag (see
|
||||||
|
# comment above) — BEHIND here means the image tag moved and the tuned
|
||||||
|
# revision needs re-basing onto it, not just a pin bump.
|
||||||
|
upstream:
|
||||||
|
kind: dockerhub
|
||||||
|
repo: rhasspy/wyoming-whisper
|
||||||
description: Wyoming-protocol faster-whisper speech-to-text engine. Internal Pine voice-assistant stack member — turns speech captured by a PineVoice satellite into text for Home Assistant Assist.
|
description: Wyoming-protocol faster-whisper speech-to-text engine. Internal Pine voice-assistant stack member — turns speech captured by a PineVoice satellite into text for Home Assistant Assist.
|
||||||
category: home
|
category: home
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ app:
|
|||||||
container_name: pine
|
container_name: pine
|
||||||
|
|
||||||
container:
|
container:
|
||||||
image: docker.io/library/nginx:1.31.3-alpine
|
image: docker.io/library/nginx:1.31.4-alpine
|
||||||
pull_policy: if-not-present
|
pull_policy: if-not-present
|
||||||
network: archy-net
|
network: archy-net
|
||||||
network_aliases: [pine]
|
network_aliases: [pine]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
app:
|
app:
|
||||||
id: strfry
|
id: strfry
|
||||||
name: Strfry Nostr Relay
|
name: Strfry Nostr Relay
|
||||||
version: 1.1.1
|
version: 1.1.2
|
||||||
# Where this app comes from, so scripts/check-upstream-releases.py can
|
# Where this app comes from, so scripts/check-upstream-releases.py can
|
||||||
# tell us when the pin below has fallen behind. Without it nothing can:
|
# tell us when the pin below has fallen behind. Without it nothing can:
|
||||||
# container.image names our mirror, not the project it was mirrored from.
|
# container.image names our mirror, not the project it was mirrored from.
|
||||||
@@ -11,7 +11,7 @@ app:
|
|||||||
description: Lightweight Nostr relay written in C++. Alternative to nostr-rs-relay with lower resource usage.
|
description: Lightweight Nostr relay written in C++. Alternative to nostr-rs-relay with lower resource usage.
|
||||||
|
|
||||||
container:
|
container:
|
||||||
image: dockurr/strfry:1.1.1
|
image: dockurr/strfry:1.1.2
|
||||||
image_signature: cosign://...
|
image_signature: cosign://...
|
||||||
pull_policy: verify-signature
|
pull_policy: verify-signature
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
app:
|
app:
|
||||||
id: vaultwarden
|
id: vaultwarden
|
||||||
name: Vaultwarden
|
name: Vaultwarden
|
||||||
version: 1.30.0
|
version: 1.37.2
|
||||||
# Where this app comes from, so scripts/check-upstream-releases.py can
|
# Where this app comes from, so scripts/check-upstream-releases.py can
|
||||||
# tell us when the pin below has fallen behind. Without it nothing can:
|
# tell us when the pin below has fallen behind. Without it nothing can:
|
||||||
# container.image names our mirror, not the project it was mirrored from.
|
# container.image names our mirror, not the project it was mirrored from.
|
||||||
@@ -11,7 +11,7 @@ app:
|
|||||||
description: Self-hosted password vault with zero-knowledge encryption.
|
description: Self-hosted password vault with zero-knowledge encryption.
|
||||||
|
|
||||||
container:
|
container:
|
||||||
image: source.archipelago-foundation.org/lfg2025/vaultwarden:1.37.1-alpine
|
image: source.archipelago-foundation.org/lfg2025/vaultwarden:1.37.2-alpine
|
||||||
pull_policy: if-not-present
|
pull_policy: if-not-present
|
||||||
network: pasta
|
network: pasta
|
||||||
|
|
||||||
|
|||||||
@@ -405,9 +405,17 @@ impl RpcHandler {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or_else(|| anyhow::anyhow!("Mesh service not running"))?;
|
.ok_or_else(|| anyhow::anyhow!("Mesh service not running"))?;
|
||||||
let device_type = svc.shared_state().status.read().await.device_type;
|
let device_type = svc.shared_state().status.read().await.device_type;
|
||||||
|
// Resource transfer is a native RNS transfer over LoRa — it needs an
|
||||||
|
// actual radio route to this contact, not just a Reticulum device on
|
||||||
|
// our end. A federation-only peer with no radio twin fits the size
|
||||||
|
// and device-type checks but has no dest_prefix to send to; without
|
||||||
|
// this check the send falls into send_content_resource and fails
|
||||||
|
// with "Peer is federation-only (no radio twin)" (picture-send,
|
||||||
|
// 2026-08-07) instead of falling back to the federation path below.
|
||||||
let use_resource_transfer = bytes.len() > INLINE_HARD_MAX
|
let use_resource_transfer = bytes.len() > INLINE_HARD_MAX
|
||||||
&& device_type == crate::mesh::types::DeviceType::Reticulum
|
&& device_type == crate::mesh::types::DeviceType::Reticulum
|
||||||
&& bytes.len() <= RETICULUM_RESOURCE_MAX;
|
&& bytes.len() <= RETICULUM_RESOURCE_MAX
|
||||||
|
&& svc.has_radio_route(contact_id).await;
|
||||||
|
|
||||||
if bytes.len() > INLINE_HARD_MAX && !use_resource_transfer {
|
if bytes.len() > INLINE_HARD_MAX && !use_resource_transfer {
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
@@ -492,15 +500,58 @@ impl RpcHandler {
|
|||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
} else {
|
} else {
|
||||||
svc.send_typed_wire(
|
// Federation-only peers have no radio twin for
|
||||||
contact_id,
|
// send_typed_wire's LoRa dest-prefix resolution — route over
|
||||||
wire,
|
// Tor federation instead, mirroring mesh.send-content's onion
|
||||||
"content_ref",
|
// lookup, or the send fails with "Peer is federation-only (no
|
||||||
&display,
|
// radio twin)" (picture-send from a federation-only contact,
|
||||||
Some(typed_json),
|
// 2026-08-07).
|
||||||
seq,
|
let federation_onion = {
|
||||||
)
|
let state = svc.shared_state();
|
||||||
.await?
|
let peers = state.peers.read().await;
|
||||||
|
peers
|
||||||
|
.get(&contact_id)
|
||||||
|
.map(|p| (p.pubkey_hex.clone(), p.did.clone()))
|
||||||
|
};
|
||||||
|
let federation_onion = match federation_onion {
|
||||||
|
Some((Some(pubkey_hex), did)) => {
|
||||||
|
let nodes = crate::federation::load_nodes(&self.config.data_dir)
|
||||||
|
.await
|
||||||
|
.unwrap_or_default();
|
||||||
|
nodes
|
||||||
|
.iter()
|
||||||
|
.find(|n| n.pubkey == pubkey_hex)
|
||||||
|
.map(|n| n.onion.clone())
|
||||||
|
.or_else(|| {
|
||||||
|
did.as_ref().and_then(|d| {
|
||||||
|
nodes.iter().find(|n| &n.did == d).map(|n| n.onion.clone())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some(onion) = federation_onion {
|
||||||
|
svc.send_typed_wire_via_federation(
|
||||||
|
contact_id,
|
||||||
|
&onion,
|
||||||
|
wire,
|
||||||
|
"content_ref",
|
||||||
|
&display,
|
||||||
|
Some(typed_json),
|
||||||
|
seq,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
} else {
|
||||||
|
svc.send_typed_wire(
|
||||||
|
contact_id,
|
||||||
|
wire,
|
||||||
|
"content_ref",
|
||||||
|
&display,
|
||||||
|
Some(typed_json),
|
||||||
|
seq,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -590,6 +641,16 @@ impl RpcHandler {
|
|||||||
let est_seconds = (size.saturating_add(lora_bytes_per_sec - 1) / lora_bytes_per_sec).max(1);
|
let est_seconds = (size.saturating_add(lora_bytes_per_sec - 1) / lora_bytes_per_sec).max(1);
|
||||||
|
|
||||||
let is_reticulum = device_type == crate::mesh::types::DeviceType::Reticulum;
|
let is_reticulum = device_type == crate::mesh::types::DeviceType::Reticulum;
|
||||||
|
// A Reticulum device on our end doesn't mean THIS peer is radio
|
||||||
|
// reachable — a federation-only contact (no radio twin) has no dest
|
||||||
|
// prefix for a resource transfer, even though it's small enough and
|
||||||
|
// our device type qualifies. Without this check the frontend was
|
||||||
|
// steered into mesh.send-content-inline's resource-transfer path,
|
||||||
|
// which fails with "Peer is federation-only (no radio twin)"
|
||||||
|
// (picture-send, 2026-08-07); the tier below now defers to the
|
||||||
|
// has_tor branches for such peers, which route via mesh.send-content
|
||||||
|
// (federation) instead.
|
||||||
|
let has_radio_route = is_reticulum && svc.has_radio_route(contact_id).await;
|
||||||
let (tier, reason) = if size <= MESH_AUTO_MAX {
|
let (tier, reason) = if size <= MESH_AUTO_MAX {
|
||||||
("auto-mesh", "Small enough to send inline over mesh")
|
("auto-mesh", "Small enough to send inline over mesh")
|
||||||
} else if size <= MESH_HARD_MAX {
|
} else if size <= MESH_HARD_MAX {
|
||||||
@@ -598,7 +659,7 @@ impl RpcHandler {
|
|||||||
} else {
|
} else {
|
||||||
("auto-mesh", "No Tor path — sending inline over mesh")
|
("auto-mesh", "No Tor path — sending inline over mesh")
|
||||||
}
|
}
|
||||||
} else if is_reticulum && size <= RETICULUM_RESOURCE_MAX {
|
} else if has_radio_route && size <= RETICULUM_RESOURCE_MAX {
|
||||||
(
|
(
|
||||||
"resource-mesh",
|
"resource-mesh",
|
||||||
"Sending directly over LoRa via a Reticulum resource transfer",
|
"Sending directly over LoRa via a Reticulum resource transfer",
|
||||||
|
|||||||
@@ -365,8 +365,18 @@ impl RpcHandler {
|
|||||||
// after uninstall. The reconciler owns a manifest map independent of
|
// after uninstall. The reconciler owns a manifest map independent of
|
||||||
// podman state, so a raw `podman rm` alone is not enough.
|
// podman state, so a raw `podman rm` alone is not enough.
|
||||||
if let Some(orchestrator) = &self.orchestrator {
|
if let Some(orchestrator) = &self.orchestrator {
|
||||||
|
let mut teardown_errors = Vec::new();
|
||||||
for app_id in orchestrator_uninstall_app_ids(package_id) {
|
for app_id in orchestrator_uninstall_app_ids(package_id) {
|
||||||
let _ = orchestrator.remove(&app_id, preserve_data).await;
|
if let Err(err) = orchestrator.remove(&app_id, preserve_data).await {
|
||||||
|
teardown_errors.push(format!("{app_id}: {err:#}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !teardown_errors.is_empty() {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"Uninstall {} aborted: failed to remove declarative app unit(s): {}",
|
||||||
|
package_id,
|
||||||
|
teardown_errors.join("; ")
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2182,6 +2192,11 @@ mod tests {
|
|||||||
assert!(!is_missing_container_error("Error: OCI runtime error"));
|
assert!(!is_missing_container_error("Error: OCI runtime error"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single_app_uninstall_targets_its_declarative_unit() {
|
||||||
|
assert_eq!(orchestrator_uninstall_app_ids("cuprate"), vec!["cuprate"]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn runtime_host_ports_are_manifest_derived_for_public_apps() {
|
fn runtime_host_ports_are_manifest_derived_for_public_apps() {
|
||||||
assert_eq!(runtime_host_ports("photoprism"), vec![2342]);
|
assert_eq!(runtime_host_ports("photoprism"), vec![2342]);
|
||||||
|
|||||||
@@ -1222,6 +1222,19 @@ impl MeshService {
|
|||||||
Ok(dest_prefix)
|
Ok(dest_prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// True if `contact_id` is reachable over the mesh radio right now — the
|
||||||
|
/// same peer/twin resolution `peer_dest_prefix` performs, exposed as a
|
||||||
|
/// cheap bool so RPC handlers can gate radio-only transports (LXMF
|
||||||
|
/// native image, Reticulum resource transfer) without duplicating the
|
||||||
|
/// twin-resolution logic. A federation-only contact_id with no matching
|
||||||
|
/// radio twin returns false here — offering "resource-mesh" or native
|
||||||
|
/// image to such a peer sends it straight into `peer_dest_prefix`'s
|
||||||
|
/// "federation-only (no radio twin)" error (picture-send from a
|
||||||
|
/// federation-only contact, 2026-08-07).
|
||||||
|
pub async fn has_radio_route(&self, contact_id: u32) -> bool {
|
||||||
|
self.peer_dest_prefix(contact_id).await.is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
/// Split an oversized wire payload into MC-framed base64 chunks and send
|
/// Split an oversized wire payload into MC-framed base64 chunks and send
|
||||||
/// each via the mesh device. Matches the receive-side reassembly in
|
/// each via the mesh device. Matches the receive-side reassembly in
|
||||||
/// `mesh/listener/decode.rs::handle_chunked_frame` (header `MCIIXXTT`,
|
/// `mesh/listener/decode.rs::handle_chunked_frame` (header `MCIIXXTT`,
|
||||||
|
|||||||
@@ -1746,6 +1746,15 @@ app:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
exempt.sort();
|
exempt.sort();
|
||||||
|
// 28 as of 2026-08-23: the 26 below plus cuprate's two exemptions —
|
||||||
|
// 18183 (Monero p2p gossip, same reasoning as bitcoin's 8333) and
|
||||||
|
// 18090 (host mapping for Monero's canonical 18089 restricted RPC,
|
||||||
|
// upstream's own safe-for-public
|
||||||
|
// subset that wallets connect to directly as a "remote node" over
|
||||||
|
// plain HTTP JSON-RPC — same reasoning as electrumx's 50001).
|
||||||
|
// cuprate's unrestricted RPC (full node control) stays loopback-only
|
||||||
|
// (auth: local), not in this set.
|
||||||
|
//
|
||||||
// 26 as of 2026-08-16: the 25 below plus phoenixd 9740, a
|
// 26 as of 2026-08-16: the 25 below plus phoenixd 9740, a
|
||||||
// loopback-only JSON API whose own generated http password
|
// loopback-only JSON API whose own generated http password
|
||||||
// authenticates every request (added with the phoenixd onboarding,
|
// authenticates every request (added with the phoenixd onboarding,
|
||||||
@@ -1762,7 +1771,7 @@ app:
|
|||||||
// stage timed out that cycle, so the count here lagged at 17.
|
// stage timed out that cycle, so the count here lagged at 17.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
exempt.len(),
|
exempt.len(),
|
||||||
26,
|
28,
|
||||||
"unauthenticated port set changed — review before updating this count: {exempt:?}"
|
"unauthenticated port set changed — review before updating this count: {exempt:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,4 +86,5 @@ file.
|
|||||||
## Roadmap & history
|
## Roadmap & history
|
||||||
|
|
||||||
- [Roadmap](ROADMAP.md) — where the project is going
|
- [Roadmap](ROADMAP.md) — where the project is going
|
||||||
|
- [TODO](TODO.md) — working backlog of unscoped forward-looking items
|
||||||
- [archive/](archive/README.md) — superseded design and status documents, kept for provenance
|
- [archive/](archive/README.md) — superseded design and status documents, kept for provenance
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# TODO
|
||||||
|
|
||||||
|
Working backlog of forward-looking items not yet scoped into a dedicated plan
|
||||||
|
doc. See [`ROADMAP.md`](ROADMAP.md) for the curated, public-facing direction.
|
||||||
|
|
||||||
|
## Dev & build process (priority)
|
||||||
|
|
||||||
|
- Formalize the contributor workflow: releases, CI, maintainers, automated
|
||||||
|
builds, PR/issue flow, branch naming, and reproducible builds.
|
||||||
|
|
||||||
|
## Federation & peering
|
||||||
|
|
||||||
|
- Peering trust model — define tiers (trusted / public / private / peered)
|
||||||
|
on top of the existing federation DID trust levels.
|
||||||
|
- Federation architecture built on the above peering model.
|
||||||
|
|
||||||
|
## Distributed git & OTA
|
||||||
|
|
||||||
|
- Nostr-hosted git for the alpha (see
|
||||||
|
[`nostr-git-source-hosting.md`](nostr-git-source-hosting.md)).
|
||||||
|
- Distributed git beyond the nostr-hosting case.
|
||||||
|
- Distributed OTA / app delivery.
|
||||||
|
|
||||||
|
## Nostr integration
|
||||||
|
|
||||||
|
- Nostr signer integration.
|
||||||
|
|
||||||
|
## Platform / OS
|
||||||
|
|
||||||
|
- Source-availability ISO — define the build/distribution story.
|
||||||
|
- HW/OS update pipeline.
|
||||||
|
- Deeper OpenWRT integration.
|
||||||
|
- GrapheneOS integration — backups, attestation, profiles.
|
||||||
|
|
||||||
|
## App ecosystem
|
||||||
|
|
||||||
|
- Full pass testing every app in the catalog; expect issues across the board.
|
||||||
|
- App update strategy — finalize the update policy referenced in
|
||||||
|
[`app-developer-guide.md`](app-developer-guide.md) (pinned vs. mutable
|
||||||
|
tags, catalog-vs-disk precedence, rollout/rollback).
|
||||||
|
- App wishlist — candidates not yet packaged: Cashu wallet, phoenixd.
|
||||||
|
(CLN is already shipped as `apps/core-lightning`.)
|
||||||
|
|
||||||
|
## Access & security
|
||||||
|
|
||||||
|
- SSH access strategy — define the access model (keys, rotation, recovery
|
||||||
|
path, remote-support access).
|
||||||
|
|
||||||
|
## Observability
|
||||||
|
|
||||||
|
- Capture error logs to troubleshoot customer issues.
|
||||||
|
- Stats & visualization for traffic, blocked attacks, VPNs, routing.
|
||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 6.2 KiB |
@@ -52,13 +52,13 @@
|
|||||||
{
|
{
|
||||||
"id": "btcpay-server",
|
"id": "btcpay-server",
|
||||||
"title": "BTCPay Server",
|
"title": "BTCPay Server",
|
||||||
"version": "2.4.2",
|
"version": "2.4.3",
|
||||||
"description": "Self-hosted Bitcoin payment processor. Accept Bitcoin payments without intermediaries.",
|
"description": "Self-hosted Bitcoin payment processor. Accept Bitcoin payments without intermediaries.",
|
||||||
"icon": "/assets/img/app-icons/btcpay-server.png",
|
"icon": "/assets/img/app-icons/btcpay-server.png",
|
||||||
"author": "BTCPay Server Foundation",
|
"author": "BTCPay Server Foundation",
|
||||||
"category": "commerce",
|
"category": "commerce",
|
||||||
"tier": "core",
|
"tier": "core",
|
||||||
"dockerImage": "docker.io/btcpayserver/btcpayserver:2.4.2",
|
"dockerImage": "docker.io/btcpayserver/btcpayserver:2.4.3",
|
||||||
"repoUrl": "https://github.com/btcpayserver/btcpayserver",
|
"repoUrl": "https://github.com/btcpayserver/btcpayserver",
|
||||||
"requires": [
|
"requires": [
|
||||||
"bitcoin-knots"
|
"bitcoin-knots"
|
||||||
@@ -378,7 +378,7 @@
|
|||||||
"icon": "/assets/img/app-icons/pine.svg",
|
"icon": "/assets/img/app-icons/pine.svg",
|
||||||
"author": "Archipelago",
|
"author": "Archipelago",
|
||||||
"category": "home",
|
"category": "home",
|
||||||
"dockerImage": "docker.io/library/nginx:1.31.3-alpine",
|
"dockerImage": "docker.io/library/nginx:1.31.4-alpine",
|
||||||
"repoUrl": "https://github.com/rhasspy/wyoming"
|
"repoUrl": "https://github.com/rhasspy/wyoming"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -464,7 +464,7 @@
|
|||||||
"author": "NetBird",
|
"author": "NetBird",
|
||||||
"category": "networking",
|
"category": "networking",
|
||||||
"tier": "recommended",
|
"tier": "recommended",
|
||||||
"dockerImage": "docker.io/library/nginx:1.31.3-alpine",
|
"dockerImage": "docker.io/library/nginx:1.31.4-alpine",
|
||||||
"repoUrl": "https://github.com/netbirdio/netbird",
|
"repoUrl": "https://github.com/netbirdio/netbird",
|
||||||
"containerConfig": {
|
"containerConfig": {
|
||||||
"ports": [
|
"ports": [
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ export const GENERATED_APP_TITLES: Record<string, string> = {
|
|||||||
"botfights": "BotFights",
|
"botfights": "BotFights",
|
||||||
"btcpay-server": "BTCPay Server",
|
"btcpay-server": "BTCPay Server",
|
||||||
"core-lightning": "Core Lightning (CLN)",
|
"core-lightning": "Core Lightning (CLN)",
|
||||||
|
"cuprate": "Cuprate",
|
||||||
"did-wallet": "Web5 DID Wallet",
|
"did-wallet": "Web5 DID Wallet",
|
||||||
"electrs-ui": "Electrs UI",
|
"electrs-ui": "Electrs UI",
|
||||||
"electrumx": "ElectrumX",
|
"electrumx": "ElectrumX",
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import urllib.error
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
import urllib.request
|
import urllib.request
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -191,7 +192,50 @@ def _highest(tags: list[str], current: str = "") -> str:
|
|||||||
return max(ranked)[1]
|
return max(ranked)[1]
|
||||||
|
|
||||||
|
|
||||||
FETCHERS = {"github": latest_github, "dockerhub": latest_dockerhub}
|
def latest_gitlab(project: str, current: str = "") -> str:
|
||||||
|
"""Newest release tag for a GitLab `group/project`.
|
||||||
|
|
||||||
|
Some projects publish releases only on GitLab with no GitHub mirror
|
||||||
|
(bark lives at ark-bitcoin/bark and nowhere else). GitLab release tags
|
||||||
|
sometimes carry the project name as a prefix (`bark-0.6.2`); strip it so
|
||||||
|
version ordering can see the number.
|
||||||
|
"""
|
||||||
|
esc = urllib.parse.quote(project, safe="")
|
||||||
|
releases = http_json(
|
||||||
|
f"https://gitlab.com/api/v4/projects/{esc}/releases?per_page=100"
|
||||||
|
)
|
||||||
|
tags = [str(r["tag_name"]) for r in releases]
|
||||||
|
prefix = project.rsplit("/", 1)[-1].lower() + "-"
|
||||||
|
tags = [t[len(prefix):] if t.lower().startswith(prefix) else t for t in tags]
|
||||||
|
return _highest(tags, current)
|
||||||
|
|
||||||
|
|
||||||
|
def latest_ghcr(repo: str, current: str = "") -> str:
|
||||||
|
"""Newest version-like tag on GitHub's container registry.
|
||||||
|
|
||||||
|
Some images exist only on ghcr.io (immich-app/postgres publishes there
|
||||||
|
and nowhere else), so neither the GitHub-release nor the Docker Hub
|
||||||
|
fetcher can see them. Anonymous pull token first, then the tag list —
|
||||||
|
the same handshake any `docker pull ghcr.io/...` performs.
|
||||||
|
"""
|
||||||
|
token = http_json(
|
||||||
|
f"https://ghcr.io/token?scope=repository:{repo}:pull&service=ghcr.io"
|
||||||
|
)["token"]
|
||||||
|
req = urllib.request.Request(
|
||||||
|
f"https://ghcr.io/v2/{repo}/tags/list",
|
||||||
|
headers={"User-Agent": USER_AGENT, "Authorization": f"Bearer {token}"},
|
||||||
|
)
|
||||||
|
with urllib.request.urlopen(req, timeout=TIMEOUT) as res: # noqa: S310
|
||||||
|
tags = [str(t) for t in json.loads(res.read().decode()).get("tags", [])]
|
||||||
|
return _highest(tags, current)
|
||||||
|
|
||||||
|
|
||||||
|
FETCHERS = {
|
||||||
|
"github": latest_github,
|
||||||
|
"dockerhub": latest_dockerhub,
|
||||||
|
"gitlab": latest_gitlab,
|
||||||
|
"ghcr": latest_ghcr,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# ── Manifest reading ───────────────────────────────────────────────────────
|
# ── Manifest reading ───────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -37,19 +37,19 @@ MEMPOOL_WEB_IMAGE="$ARCHY_REGISTRY/mempool-frontend:v3.3.1"
|
|||||||
MARIADB_IMAGE="$ARCHY_REGISTRY/mariadb:11.4.10"
|
MARIADB_IMAGE="$ARCHY_REGISTRY/mariadb:11.4.10"
|
||||||
|
|
||||||
# BTCPay
|
# BTCPay
|
||||||
BTCPAY_IMAGE="docker.io/btcpayserver/btcpayserver:2.4.2"
|
BTCPAY_IMAGE="docker.io/btcpayserver/btcpayserver:2.4.3"
|
||||||
NBXPLORER_IMAGE="$ARCHY_REGISTRY/nbxplorer:2.6.0"
|
NBXPLORER_IMAGE="$ARCHY_REGISTRY/nbxplorer:2.6.11"
|
||||||
POSTGRES_IMAGE="$ARCHY_REGISTRY/postgres:15.17"
|
POSTGRES_IMAGE="$ARCHY_REGISTRY/postgres:15.17"
|
||||||
BTCPAY_POSTGRES_IMAGE="$ARCHY_REGISTRY/postgres:15.17"
|
BTCPAY_POSTGRES_IMAGE="$ARCHY_REGISTRY/postgres:15.17"
|
||||||
|
|
||||||
# Apps
|
# Apps
|
||||||
HOMEASSISTANT_IMAGE="$ARCHY_REGISTRY/home-assistant:2026.8.2"
|
HOMEASSISTANT_IMAGE="$ARCHY_REGISTRY/home-assistant:2026.8.3"
|
||||||
GRAFANA_IMAGE="$ARCHY_REGISTRY/grafana:10.2.0"
|
GRAFANA_IMAGE="$ARCHY_REGISTRY/grafana:10.2.0"
|
||||||
UPTIME_KUMA_IMAGE="$ARCHY_REGISTRY/uptime-kuma:1"
|
UPTIME_KUMA_IMAGE="$ARCHY_REGISTRY/uptime-kuma:1"
|
||||||
JELLYFIN_IMAGE="$ARCHY_REGISTRY/jellyfin:10.11.11"
|
JELLYFIN_IMAGE="$ARCHY_REGISTRY/jellyfin:10.11.11"
|
||||||
PHOTOPRISM_IMAGE="$ARCHY_REGISTRY/photoprism:240915"
|
PHOTOPRISM_IMAGE="$ARCHY_REGISTRY/photoprism:240915"
|
||||||
OLLAMA_IMAGE="$ARCHY_REGISTRY/ollama:latest"
|
OLLAMA_IMAGE="$ARCHY_REGISTRY/ollama:latest"
|
||||||
VAULTWARDEN_IMAGE="$ARCHY_REGISTRY/vaultwarden:1.37.1-alpine"
|
VAULTWARDEN_IMAGE="$ARCHY_REGISTRY/vaultwarden:1.37.2-alpine"
|
||||||
NEXTCLOUD_IMAGE="$ARCHY_REGISTRY/nextcloud:29"
|
NEXTCLOUD_IMAGE="$ARCHY_REGISTRY/nextcloud:29"
|
||||||
SEARXNG_IMAGE="$ARCHY_REGISTRY/searxng:latest"
|
SEARXNG_IMAGE="$ARCHY_REGISTRY/searxng:latest"
|
||||||
# OnlyOffice removed — incompatible with rootless Podman (internal postgres/rabbitmq fail)
|
# OnlyOffice removed — incompatible with rootless Podman (internal postgres/rabbitmq fail)
|
||||||
|
|||||||
Reference in New Issue
Block a user