This session completed Approach C end-to-end on marcelle (status=COMPLETED,
mkdocs untouched, idempotent on re-run). Four fixes landed:
1. template-engine.ts: dropped nginx/conf.d/*.hbs (default, api, services)
from renderAllTemplates AND renderAllTemplatesInMemory. The new
prod-style docker-compose.yml.hbs does NOT mount conf.d/ into the
nginx container ("Note: conf.d is NOT mounted (configs are generated
at startup from templates)" — nginx confs are baked into the nginx
Docker image). Writing them was a no-op orphan that showed up as 3
"modified" lines in preview unnecessarily.
Same reason removed nginx/nginx.conf from staticFiles.
2. templates/configs/{pangolin/resources.yml,prometheus/prometheus.yml,
grafana/datasources/datasources.yml}.hbs: synced byte-identical to
canonical changemaker.lite/configs/*. These ARE mounted into pangolin
tunnel + prometheus + grafana respectively. Preview now reports
"unchanged" for them on install.sh tenants.
3. templates/docker-compose.yml.hbs: dropped the CCP-tenant header
comment, making the template now BYTE-IDENTICAL (58907 bytes) to
canonical changemaker.lite/docker-compose.prod.yml. Even a 1-byte
comment difference caused docker compose to compute new config hashes
for every service, triggering full-stack recreates (including
ccp-agent — the Phase 6 self-destruct trap from upgrade.sh).
4. upgrade.service.ts:runReleaseUpgrade — composeUp now restricted to
core app services [api, admin, media-api, nginx] (same set as
image-upgrade.sh). Unscoped composeUp would recreate ccp-agent
mid-apply and orphan the runner. Until Approach C inherits the
deferred-ccp-agent-restart pattern from upgrade.sh, this restriction
keeps the apply path safe. Limitation: brand-new services in a
release won't auto-deploy via Approach C alone — operator must
follow with Approach A (full upgrade.sh) to pick them up.
E2E verification on marcelle:
- Apply: status=COMPLETED, duration<10s.
- mkdocs.yml md5 unchanged (38810d9df8b4258ad46a6739232cf88a).
- mkdocs/docs file count unchanged (242).
- docker-compose.yml now byte-identical to canonical (58907 bytes).
- app + api public sites: 200 both.
- Re-preview: ALL 10 files show "unchanged" — true idempotency.
Phase 6 acceptance gate met. Approach C now fully operational on the
install.sh fleet.
Bunker Admin
156 lines
3.2 KiB
Handlebars
156 lines
3.2 KiB
Handlebars
# Pangolin Resource Definitions
|
|
# All resources route through Nginx (port 80) by default
|
|
# Newt tunnel → Nginx (port 80) → Backend containers (various ports)
|
|
#
|
|
# target_ip: the hostname/IP that Newt sends traffic to (default: nginx)
|
|
# target_port: the port on the target host (default: 80)
|
|
|
|
resources:
|
|
# Required services (fail if down)
|
|
- subdomain: app
|
|
name: Admin GUI
|
|
container: changemaker-v2-admin
|
|
port: 3000
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: true
|
|
|
|
- subdomain: api
|
|
name: API Server
|
|
container: changemaker-v2-api
|
|
port: 4000
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: true
|
|
|
|
- subdomain: "" # Root domain
|
|
name: Public Site
|
|
container: mkdocs-site-server-changemaker
|
|
port: 80
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: true
|
|
|
|
# Optional services (warn and skip if down)
|
|
- subdomain: db
|
|
name: NocoDB
|
|
container: changemaker-v2-nocodb
|
|
port: 8080
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
|
|
- subdomain: docs
|
|
name: Documentation
|
|
container: mkdocs-changemaker
|
|
port: 8000
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
|
|
- subdomain: code
|
|
name: Code Server
|
|
container: code-server-changemaker
|
|
port: 8080
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
|
|
- subdomain: n8n
|
|
name: Workflows
|
|
container: n8n-changemaker
|
|
port: 5678
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
|
|
- subdomain: git
|
|
name: Gitea
|
|
container: gitea-changemaker
|
|
port: 3000
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
|
|
- subdomain: home
|
|
name: Homepage
|
|
container: homepage-changemaker
|
|
port: 3000
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
|
|
- subdomain: listmonk
|
|
name: Newsletter
|
|
container: listmonk-app
|
|
port: 9000
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
|
|
- subdomain: qr
|
|
name: Mini QR
|
|
container: mini-qr
|
|
port: 8080
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
|
|
- subdomain: draw
|
|
name: Excalidraw
|
|
container: excalidraw-changemaker
|
|
port: 80
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
|
|
- subdomain: vault
|
|
name: Vaultwarden
|
|
container: vaultwarden-changemaker
|
|
port: 80
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
|
|
- subdomain: mail
|
|
name: MailHog
|
|
container: mailhog-changemaker
|
|
port: 8025
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
|
|
- subdomain: chat
|
|
name: Rocket.Chat
|
|
container: rocketchat-changemaker
|
|
port: 3000
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
|
|
- subdomain: events
|
|
name: Gancio Events
|
|
container: gancio-changemaker
|
|
port: 13120
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
|
|
- subdomain: meet
|
|
name: Jitsi Meet
|
|
container: jitsi-web-changemaker
|
|
port: 80
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
|
|
# Monitoring services (auto-detect profile)
|
|
- subdomain: grafana
|
|
name: Grafana
|
|
container: grafana-changemaker
|
|
port: 3000
|
|
target_ip: nginx
|
|
target_port: 80
|
|
required: false
|
|
profile: monitoring # Auto-detect if monitoring profile active
|