Same companion shape as bitcoin-ui/electrs-ui: host-networked nginx bound to 127.0.0.1:18091 (auth: gated + session_passthrough), serving a dark glass status page that polls the node's restricted RPC via a session-gated /cuprate-rpc/ proxy — sync height/target with progress bar, peers, mempool, chain size and free disk (from get_info), plus a wallet 'remote node' endpoint. The offline state explains the disk gate so a refused node says why. No secret rendering: the restricted RPC is Monero's safe-for-public subset, so nginx.conf is baked into the image (no pre_start hook, no bind mount). companion.rs auto-provisions archy-cuprate-ui alongside cuprate and reaps it when cuprate goes. Catalog regenerated (cuprate-ui entry + manifest embed, 18091 into the mesh launch-port list). NOTE: releases/app-catalog.json is UNSIGNED as committed — run scripts/sign-catalog.sh before publishing.
57 lines
2.6 KiB
Nginx Configuration File
57 lines
2.6 KiB
Nginx Configuration File
server {
|
|
# Loopback ONLY — same rule as docker/bitcoin-ui and docker/electrs-ui.
|
|
# This container is host-networked, so nginx binds the HOST's address
|
|
# directly; a bare `listen` would expose the page on LAN, Tailscale and
|
|
# the mesh with the app gate nowhere in front of it. Binding loopback lets
|
|
# the daemon claim the external addresses and authenticate them;
|
|
# see appgate::listener and apps/cuprate-ui/manifest.yml (auth: gated).
|
|
listen 127.0.0.1:18091;
|
|
server_name _;
|
|
|
|
root /usr/share/nginx/html;
|
|
index index.html;
|
|
|
|
# Session gate for the RPC proxy below. Internal: reachable only by
|
|
# nginx's own auth_request subrequest, never by a client.
|
|
location = /_session_check {
|
|
internal;
|
|
proxy_pass http://127.0.0.1:5678/auth/session-check;
|
|
proxy_pass_request_body off;
|
|
proxy_set_header Content-Length "";
|
|
proxy_set_header Host $host;
|
|
proxy_set_header Cookie $http_cookie;
|
|
proxy_set_header X-CSRF-Token $http_x_csrf_token;
|
|
}
|
|
|
|
# Cuprate's restricted RPC (host-published on 127.0.0.1:18090, auth: open
|
|
# — Monero's own safe-for-public subset, what remote-node wallets use).
|
|
# It injects no credentials the caller lacks, but it is still session-
|
|
# gated here so the whole companion behaves as one authenticated surface
|
|
# (same defence-in-depth bitcoin-ui applies to its credential-injecting
|
|
# proxy: loopback reaches it without the gate's challenge).
|
|
location /cuprate-rpc/ {
|
|
# Preflight carries no cookies by design — answer it before the gate,
|
|
# otherwise the browser reports an opaque CORS failure instead of a 401.
|
|
if ($request_method = OPTIONS) { return 204; }
|
|
auth_request /_session_check;
|
|
proxy_pass http://127.0.0.1:18090/;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
add_header Access-Control-Allow-Origin $scheme://$http_host always;
|
|
add_header Access-Control-Allow-Credentials "true" always;
|
|
add_header Vary "Origin" always;
|
|
add_header Access-Control-Allow-Methods "POST, GET, OPTIONS" always;
|
|
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
|
|
}
|
|
|
|
# no-cache (revalidate), not no-store — same reasoning as docker/bitcoin-ui:
|
|
# a rebuilt companion image must actually be seen by the browser, while the
|
|
# ETag still saves the transfer when nothing changed.
|
|
location / {
|
|
add_header Cache-Control "no-cache";
|
|
try_files $uri $uri/ /index.html;
|
|
}
|
|
}
|