Converting Nginx Proxy Manager to a platform manifest (fc68c5b6) dropped
two things its image hard-requires, and the result was an endless
start/die loop — shorty-s watched it restart 3,176 times:
1. /etc/letsencrypt mount: NPM's s6 'prepare' service refuses to boot
without it ('ERROR: /etc/letsencrypt is not mounted!'). Mounted from
the same persistent app directory as before
(/var/lib/archipelago/nginx-proxy-manager/letsencrypt), so existing
certificates are preserved — no data moves, no migration.
2. NET_BIND_SERVICE: NPM's internal nginx listens on 80, 443 AND 81,
and the orchestrator runs --cap-drop=ALL. The legacy podman-run path
defaulted to the full capability set (and the legacy repair path in
package/config.rs always listed it), which is why this only broke
once the manifest became the source of truth.
The signed catalog embeds manifests with origin-wins semantics, so the
catalog carries the fix for every catalog-covered node — regenerate it
here (plus the generated store/launcher-port artifacts, which also pick
up drift from bf6ef964's retired apps). Catalog re-signing follows the
usual ceremony.
89 lines
2.7 KiB
YAML
89 lines
2.7 KiB
YAML
app:
|
|
id: nginx-proxy-manager
|
|
name: Nginx Proxy Manager
|
|
version: 2.12.1
|
|
upstream:
|
|
kind: github
|
|
repo: NginxProxyManager/nginx-proxy-manager
|
|
description: >-
|
|
Reverse proxy with SSL. Beautiful web interface for managing proxies.
|
|
On a node, this manages its admin UI and upstream configuration — the
|
|
proxy's own :80/:443 listeners are not published (the node's web server
|
|
owns those ports).
|
|
|
|
container:
|
|
image: source.archipelago-foundation.org/lfg2025/nginx-proxy-manager:latest
|
|
pull_policy: if-not-present
|
|
network: pasta
|
|
|
|
dependencies:
|
|
- storage: 1Gi
|
|
|
|
resources:
|
|
memory_limit: 512Mi
|
|
disk_limit: 1Gi
|
|
|
|
security:
|
|
# NET_BIND_SERVICE is load-bearing, not decoration: NPM's internal nginx
|
|
# listens on 80, 443 AND 81, and the orchestrator runs --cap-drop=ALL —
|
|
# without this cap every start dies with "bind() to 0.0.0.0:80 failed
|
|
# (13: Permission denied)" and s6 restart-loops forever (shorty-s,
|
|
# 2026-09-01, restart counter 3176 within hours of the manifest
|
|
# conversion). The legacy podman-run path defaulted to the full cap set,
|
|
# which is why it never showed there.
|
|
capabilities: [CHOWN, SETUID, SETGID, DAC_OVERRIDE, NET_BIND_SERVICE]
|
|
readonly_root: false
|
|
no_new_privileges: true
|
|
network_policy: isolated
|
|
|
|
ports:
|
|
- host: 8081
|
|
container: 81
|
|
protocol: tcp
|
|
bind: 127.0.0.1
|
|
# open, not gated: NPM carries a complete admin login of its own. The
|
|
# gate still fronts the port (TLS on the same port, header fixes, retry
|
|
# page, Tor) without putting a cookie challenge in front of it.
|
|
auth: open
|
|
auth_rationale: >-
|
|
Nginx Proxy Manager enforces its own admin account on every page;
|
|
the initial setup wizard also has to answer before any account exists.
|
|
|
|
volumes:
|
|
- type: bind
|
|
source: /var/lib/archipelago/nginx-proxy-manager
|
|
target: /data
|
|
options: [rw]
|
|
# Current NPM images refuse to start unless /etc/letsencrypt is a mount in
|
|
# its own right. Keeping the files below the same persistent app directory
|
|
# preserves existing certificates while satisfying that startup contract.
|
|
- type: bind
|
|
source: /var/lib/archipelago/nginx-proxy-manager/letsencrypt
|
|
target: /etc/letsencrypt
|
|
options: [rw]
|
|
|
|
environment: []
|
|
|
|
health_check:
|
|
type: tcp
|
|
endpoint: localhost:81
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
|
|
interfaces:
|
|
main:
|
|
name: Admin UI
|
|
description: Nginx Proxy Manager admin interface
|
|
type: ui
|
|
port: 8081
|
|
protocol: http
|
|
path: /
|
|
|
|
metadata:
|
|
author: Nginx Proxy Manager
|
|
category: networking
|
|
icon: /assets/img/app-icons/nginx.svg
|
|
repo: https://github.com/NginxProxyManager/nginx-proxy-manager
|
|
tier: optional
|