Generated-secrets system: apps declare `generated_secrets` in their manifest (kinds hex16/hex32/bcrypt); `container::secrets::ensure_generated_secrets` materialises them 0600/rootless in resolve_dynamic_env — idempotent and self-healing (recovers wrongly root-owned secrets with no privilege). Replaces per-app Rust (deletes ensure_fmcd_password). fedimint-clientd/gateway manifests now declare fmcd-password / fedimint-gateway-hash. companion.rs: rebuild the auto-built :latest image when its build context changes (staleness check) so baked-in fixes (e.g. guardian-UI CSS) actually reach nodes. quadlet.rs: skip PublishPort under Network=host (podman rejects the combo, exit 125) + regression tests. UI: "Fedimint Guardian" rename, fedimint-clientd/nostr-rs-relay/meshtastic tagged as Services (headless backends), gateway icon fallback. Deployed + verified on .228 (generated-secrets fixed fedimint-gateway start; grafana/strfry orphan crash-loop units removed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
96 lines
4.5 KiB
YAML
96 lines
4.5 KiB
YAML
app:
|
|
id: fedimint-clientd
|
|
name: Fedimint Client
|
|
version: 0.8.0
|
|
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.
|
|
|
|
container:
|
|
# fmcd built from source (github.com/minmoto/fmcd v0.8.0, fedimint-client
|
|
# 0.8.2 — iroh-capable). No usable upstream image exists, so we build + push
|
|
# this to the node registry. Pin the tag to match the REST shapes coded in
|
|
# core/archipelago/src/wallet/fedimint_client.rs (validated against 0.8.2).
|
|
image: 146.59.87.168:3000/lfg2025/fmcd:0.8.0
|
|
pull_policy: if-not-present
|
|
network: archy-net
|
|
# No entrypoint override: the image's resilient `fmcd-run` launcher loops
|
|
# fmcd and retries on join failure (fmcd needs >=1 federation to boot), so an
|
|
# unreachable default never crash-loops. All config comes from FMCD_* env
|
|
# below. Nodes can join more federations via wallet.fedimint-join.
|
|
# Auto-generated on first install (random hex, 0600, rootless-owned) so the
|
|
# app needs no host provisioning. The wallet bridge reads the same file.
|
|
generated_secrets:
|
|
- name: fmcd-password
|
|
kind: hex16
|
|
secret_env:
|
|
- key: FMCD_PASSWORD
|
|
secret_file: fmcd-password
|
|
data_uid: "1000:1000"
|
|
|
|
# NOTE: this is a CLIENT, not the guardian — it does not require the local
|
|
# `fedimint` app. It joins external federations (default below), so it can be
|
|
# bundled standalone on every node.
|
|
dependencies:
|
|
- storage: 2Gi
|
|
|
|
resources:
|
|
cpu_limit: 1
|
|
memory_limit: 1Gi
|
|
disk_limit: 2Gi
|
|
|
|
security:
|
|
# fmcd's `fmcd-run` launcher chowns its /data (existing federation DB) on
|
|
# every start. With the default `cap_drop: ALL` and no caps added back, that
|
|
# chown fails and fmcd dies "Operation not permitted (os error 1)" — but ONLY
|
|
# once /data holds a joined federation (a fresh/empty dir needs no chown, so
|
|
# it appeared to work). Restore the standard container capability set so the
|
|
# startup chown succeeds (#7). Verified by bisection on .116: these caps make
|
|
# fmcd boot + serve /v2/*; DAC_OVERRIDE or SETUID/SETGID alone do NOT.
|
|
capabilities: ["CHOWN", "DAC_OVERRIDE", "FOWNER", "SETUID", "SETGID"]
|
|
readonly_root: true
|
|
# NOT isolated: fmcd needs outbound UDP + Mainline DHT (port 6881) + iroh
|
|
# relays to reach iroh-transport federations. `bridge` gives NAT'd outbound
|
|
# (UDP/DHT/iroh hole-punch all work) plus the published 8178→8080 port the
|
|
# wallet bridge targets. ("open" is not a valid policy — it made the loader
|
|
# skip this whole manifest, so fmcd never ran and federations never joined.)
|
|
# Lock down once the default federation's reachability model is finalized.
|
|
network_policy: bridge
|
|
|
|
ports:
|
|
# fmcd REST bound to 8080 in-container; 8080 collides with LND REST on the
|
|
# host, so map to 8178. The Rust bridge targets http://127.0.0.1:8178.
|
|
- host: 8178
|
|
container: 8080
|
|
protocol: tcp
|
|
|
|
volumes:
|
|
# Same dir the first-boot bundled path uses + where the wallet bridge reads
|
|
# the password (/var/lib/archipelago/fmcd/password) — keep install paths aligned.
|
|
- type: bind
|
|
source: /var/lib/archipelago/fmcd
|
|
target: /data
|
|
options: [rw]
|
|
|
|
environment:
|
|
- FMCD_ADDR=0.0.0.0:8080
|
|
- FMCD_MODE=rest
|
|
- FMCD_DATA_DIR=/data
|
|
# Default federation joined out-of-the-box (guardian on .116, iroh
|
|
# transport; validated to join with fmcd 0.8.2). iroh does NAT traversal so
|
|
# it's reachable fleet-wide. Keep in sync with DEFAULT_FEDERATION_INVITE in
|
|
# core/.../wallet/fedimint_client.rs. CAVEAT: iroh is experimental — validate
|
|
# join reliability from a real second node before relying on auto-bundle.
|
|
- FMCD_INVITE_CODE=fed11qgqyj3mfwfhksw309uuxywtxxfjrjc35xuexverpxdsnxcnrxucxvenzveskgc3kvvun2c34xp3k2ep38yunzdpexcekxe3hvd3rvvmx8pnrvdenx5mnzvtzqqqjqt0t6pc3s5z0ynqjw9s4njf6svwgu59kweawc0vvrddcjeemw6yyn4pcdp
|
|
|
|
# fmcd serves only authenticated /v2/* routes — there is no unauthenticated
|
|
# /health endpoint, so an http probe to /health 404s forever and pins the
|
|
# container in "(starting)". fmcd's own image also ships neither curl nor wget.
|
|
# Use a TCP probe: the Quadlet renderer skips it (no HealthCmd emitted) and the
|
|
# host-side lifecycle layer verifies reachability, so the container reports
|
|
# "running" instead of a perpetual false-negative "(starting)".
|
|
health_check:
|
|
type: tcp
|
|
endpoint: localhost:8080
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|