Merge ngit external-access PR 79ca68c1 into combined UAT candidate

Preserve current maintenance/session guards, Firewall UI and existing catalogs.
Retain scoped guest access, publishing journeys and local Blossom integration.
Normalize Blossom/router memory units to supported quadlet suffixes.

Validation: 108 dashboard tests, 10 gateway policy tests, strict source catalog
check. Integrated isolated backend qualification remains required before main.
This commit is contained in:
archipelago
2026-10-08 18:59:24 -04:00
100 changed files with 7479 additions and 111 deletions
+52
View File
@@ -0,0 +1,52 @@
# Public Web Router
Optional, manifest-first rootless app for node-terminated HTTPS through an
operator-owned frp gateway. Uses pinned frpc0.71.0 and Caddy2.11.7 binaries and a
pinned multi-architecture Python base. No host network, host port, capabilities,
privileged socket, or node signing keys are needed. FIPS connects the isolated
container to explicitly published website listeners.
Setup stores the private enrollment and derived routes in
`/var/lib/archipelago/public-web-router/config/router.json` (0600). The app mounts
that directory read-only, watches for atomic replacement, validates input, and
supervises only its own Caddy and frpc processes. Removing or invalidating config
stops both. The gateway CA is pinned; HTTPS SNI passes through to Caddy. Caddy
keeps certificate keys under the persistent `/data` bind mount. Uninstall and
Disconnect must preserve that data unless the user explicitly requests removal.
The automatic adapter accepts website IDs or guest-enabled app IDs and resolves
saved domains, FIPS addresses and listener ports on the backend. Arbitrary target
URLs/ports and management endpoints are not accepted. App routes require the
installed catalogue policy to enable guest sharing and retain authentication.
Each request carries the expected project/app identity. The app gate rechecks
its live policy before login actions or static exceptions; a stale route cannot
follow a reassigned port or a disabled gate. Existing manual proxies still work.
No Nostr signer integration is requested: routing neither signs nor broadcasts
Nostr events. Blossom/nsite publication continues to use its explicit profile
signer and exact-byte review. Enrollment files contain private credentials and
must never enter that publishing flow.
Public mode requests ACME using TLS-ALPN-01. A dedicated public443 path must reach
the node through the gateway; competing gateways/proxies must not claim it.
Explicit test mode uses a private Caddy CA and is not browser-trusted public TLS.
The process-health probe reports supervision, not external reachability or
certificate issuance. Setup's independent HTTPS exact-content check remains
required before claiming public reachability.
Framework qualification passed the signed private catalogue, normal manifest
installer, owner-RPC enrollment, exact website bytes through isolated Yaya TLS,
and app guest-cookie issue/revocation. Public ACME on port 443 remains untested;
the isolated test uses a private CA. General publication still requires the
repository release gates.
Distribution must include both `apps/public-web-router` and
`docker/public-web-router` in the runtime payload. Build-source manifests defer
to the shipped disk manifest; the catalogue alone cannot install the build
context. On nodes with `web-ui/archipelago-runtime`, update that payload too:
startup restores it into `/opt/archipelago`. Do not patch only the live copy.
The manifest requests CPU/memory limits. Framework's rootless runtime currently
reports no enforced memory cgroup limit; do not present the requested 256 MiB as
an enforced limit on that host. Read-only root, dropped capabilities, slirp and
read-only configuration mounts were verified on the normally installed app.
+49
View File
@@ -0,0 +1,49 @@
app:
id: public-web-router
name: Public Web Router
version: 0.1.0
description: Connect explicitly published websites to your own public gateway. HTTPS keys stay on this node. Configure routes through Setup.
container:
network: slirp4netns
build:
context: /opt/archipelago/docker/public-web-router
dockerfile: Dockerfile
tag: localhost/archipelago-public-web-router:0.1.0
dependencies:
- storage: 256Mi
resources:
cpu_limit: 1
memory_limit: 256m
disk_limit: 512Mi
security:
capabilities: []
readonly_root: true
no_new_privileges: true
network_policy: isolated
seccomp_profile: default
volumes:
- type: bind
source: /var/lib/archipelago/public-web-router/data
target: /data
options: [rw]
- type: bind
source: /var/lib/archipelago/public-web-router/config
target: /config
options: [ro]
- type: tmpfs
target: /tmp
options: [rw, nosuid, nodev, size=16m]
health_check:
type: exec
endpoint: python3 -c "import pathlib,time; assert time.time()-pathlib.Path('/tmp/router/heartbeat').stat().st_mtime < 30"
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
metadata:
author: Archipelago
category: networking
tier: optional
license: Apache-2.0 / MIT
icon: /assets/img/app-icons/nginx.svg
tags: [networking, websites, privacy]