feat(nostr-vpn): package paid-exit seller + web control panel as manifest apps
Phase 1 of docs/nostr-vpn-integration-plan.md's Phase 0->4 plan (seller-side
rootless feasibility already confirmed there). Two apps, one image:
- apps/nostr-vpn: the daemon. Own network namespace (container.network:
pasta), NET_ADMIN+NET_RAW scoped to that netns, /dev/net/tun, and the
net.ipv4.ip_forward sysctl via the primitive added in e42bd26. UDP 51822
(not upstream's default 51820, which collides with archipelago-wg on
fleet nodes per the Phase 0 log). Seller mode stays off until an operator
explicitly enables it (paid_exit.enabled defaults to false upstream).
- apps/nostr-vpn-web: the control panel, gated behind 127.0.0.1:38080,
talking to the daemon only through the shared /data volume (state-file
status + shelling out to the nvpn CLI) -- no network link between the
two containers, matching upstream's own umbrel/docker-compose.yml.
- docker/nostr-vpn: upstream's umbrel/Dockerfile, unchanged except for how
the pinned commit arrives (shallow git fetch of a verified SHA, since
codeload.github.com archive tarballs 404 from this environment and
GitHub won't fetch an arbitrary SHA directly). Entrypoint seeds a minimal
config.toml with the chosen listen_port on first boot only -- every
AppConfig field is `serde(default = ...)`, confirmed by reading
nostr-vpn-core directly, so this merges with nvpn's own identity/wallet
bootstrap instead of needing a generated_secrets entry or full config
template, and never touches a config that already exists.
Both volumes point at /var/lib/archipelago/nostr-vpn, adopting state from
the old root-mode install. Build and the seed-config path were verified
against the real `nvpn daemon` binary, not just read -- see the plan doc's
Phase 1 log for what that caught (a fabricated commit SHA, the codeload
404, wrong default branch name, and confirming identity/wallet persistence
actually survives container recreation).
Not done here, flagged in the plan doc instead: removing the old root-mode
path (rpc/vpn.rs, rpc/auth.rs's auto-enable-on-login) touches live
onboarding on every node, not just this app -- needs explicit sign-off.
Also missing: a stop-hook/uninstall-guard manifest primitive (doesn't
exist yet -- LifecycleHooks only has post_install/pre_start) for the
collect-due-on-stop and non-zero-wallet uninstall guard, and registry
mirroring + catalog signing (need credentials this pass doesn't have).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
app:
|
||||
id: nostr-vpn-web
|
||||
name: Nostr VPN Control Panel
|
||||
version: 1.0.0
|
||||
upstream:
|
||||
kind: github
|
||||
repo: mmalmi/nostr-vpn
|
||||
description: |
|
||||
Web control panel for the nostr-vpn paid-exit seller (apps/nostr-vpn).
|
||||
Talks to the daemon only through the shared /data volume (state-file
|
||||
status + shelling out to the nvpn CLI) -- no network link between the
|
||||
two containers, mirroring upstream's own umbrel/docker-compose.yml
|
||||
exactly (read directly, not assumed). Same image as apps/nostr-vpn,
|
||||
different entrypoint args.
|
||||
category: money
|
||||
|
||||
container:
|
||||
build:
|
||||
context: /opt/archipelago/docker/nostr-vpn
|
||||
dockerfile: Dockerfile
|
||||
tag: localhost/nostr-vpn:local
|
||||
entrypoint: ["/usr/local/bin/archy-nvpn-entrypoint.sh"]
|
||||
custom_args:
|
||||
- /usr/local/bin/nvpn-web
|
||||
- --listen
|
||||
- 0.0.0.0:38080
|
||||
- --behind-trusted-proxy
|
||||
- --config
|
||||
- /data/config/nvpn/config.toml
|
||||
|
||||
dependencies:
|
||||
- app_id: nostr-vpn
|
||||
|
||||
resources:
|
||||
memory_limit: 128Mi
|
||||
|
||||
security:
|
||||
capabilities: []
|
||||
readonly_root: false
|
||||
no_new_privileges: true
|
||||
network_policy: bridge
|
||||
|
||||
ports:
|
||||
- host: 38080
|
||||
container: 38080
|
||||
protocol: tcp
|
||||
bind: 127.0.0.1
|
||||
auth: gated
|
||||
|
||||
volumes:
|
||||
# Same volume as apps/nostr-vpn, read-write: the panel's wallet/seller
|
||||
# actions (wallet send, paid-exit run) shell out to the nvpn CLI
|
||||
# against this same config.toml and data dir, per
|
||||
# NVPN_EXTERNAL_DAEMON/NVPN_DAEMON_STATUS_MODE below.
|
||||
- type: bind
|
||||
source: /var/lib/archipelago/nostr-vpn
|
||||
target: /data
|
||||
options: [rw]
|
||||
|
||||
environment:
|
||||
- NVPN_CLI_PATH=/usr/local/bin/nvpn
|
||||
- NVPN_DAEMON_STATUS_MODE=state-file
|
||||
- NVPN_EXTERNAL_DAEMON=true
|
||||
|
||||
health_check:
|
||||
type: http
|
||||
endpoint: http://127.0.0.1:38080
|
||||
path: /
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
interfaces:
|
||||
main:
|
||||
name: Control Panel
|
||||
description: nostr-vpn paid-exit status, wallet, and seller settings
|
||||
type: ui
|
||||
port: 38080
|
||||
protocol: http
|
||||
path: /
|
||||
|
||||
metadata:
|
||||
category: money
|
||||
tier: optional
|
||||
author: mmalmi
|
||||
repo: https://github.com/mmalmi/nostr-vpn
|
||||
features:
|
||||
- Paid-exit seller status, wallet, and offer controls
|
||||
- Shares state with apps/nostr-vpn via one data volume, no RPC link
|
||||
Reference in New Issue
Block a user