diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 0000000..6fdbad0 --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,96 @@ +# Prometheus — deploy + +Everything in this directory lands on a VPS the first time Prometheus is set +up on it, plus files that get swapped out on each release. + +``` +deploy/ + prometheus-service.service systemd unit — the Node service on :3700 + prometheus-x.conf angie vhost — TLS-terminated reverse proxy + prometheus-snapshot.service systemd unit — weekly snapshot job + prometheus-snapshot.timer systemd timer — Sunday 04:00 UTC + apps-silentmode-st.conf angie vhost — SEO mirror (apps.silentmode.st) + make-tls-cert.sh (re-)generate the self-signed cert, print the pin +``` + +## First-time install (VPS, root) + +```bash +# Code +useradd -r -s /usr/sbin/nologin -d /opt/prometheus prometheus +mkdir -p /opt/prometheus +rsync -av --exclude=node_modules --exclude=db.sqlite\* --exclude=uploads \ + --exclude=.keys --exclude=build \ + :Prometheus/ /opt/prometheus/ +cd /opt/prometheus && npm install --omit=dev +chown -R prometheus:prometheus /opt/prometheus +mkdir -p /opt/prometheus/{uploads,.keys,build} +chown prometheus:prometheus /opt/prometheus/{uploads,.keys,build} + +# TLS cert for prometheus.x (prints the fingerprint — save it for #6) +sudo bash /opt/prometheus/deploy/make-tls-cert.sh + +# angie +install -m644 /opt/prometheus/deploy/prometheus-x.conf /etc/angie/http.d/ +install -m644 /opt/prometheus/deploy/apps-silentmode-st.conf /etc/angie/http.d/ +angie -t && systemctl reload angie + +# systemd +install -m644 /opt/prometheus/deploy/prometheus-service.service /etc/systemd/system/ +install -m644 /opt/prometheus/deploy/prometheus-snapshot.service /etc/systemd/system/ +install -m644 /opt/prometheus/deploy/prometheus-snapshot.timer /etc/systemd/system/ + +# Instance-specific environment (NOT in the repo) +cat > /etc/default/prometheus < +# VIRUSTOTAL_API_KEY= # optional +# PAYMENT_REQUIRED=1 # enable paid wave +# PROMETHEUS_PAYMENT_ADDRESS= # required when PAYMENT_REQUIRED=1 +# PROMETHEUS_LISTING_FEE_USD=1 +EOF +chmod 600 /etc/default/prometheus + +systemctl daemon-reload +systemctl enable --now prometheus-service.service +systemctl enable --now prometheus-snapshot.timer + +# Verify +curl -k https://127.0.0.1/healthz # should return 200 and {ok:true,…} +``` + +## Register the on-chain record (workstation) + +```bash +IP=$(curl -s https://ifconfig.io) # or the VPS's public IP as you know it +TLS= + +node Argus/src/register.js prometheus.x "{\"ip\":\"$IP\",\"tls\":\"$TLS\"}" +# Prompts for the chipnet keystore password (or set DEVIANT_KEYSTORE_PASSWORD). +``` + +The current record (as of 2026-10-08) is `{"u":"https://silentmode.st/prometheus/"}`. +The register command above replaces it. Within a few minutes of the TX +confirming on chipnet, Theseus and Ariadne resolve `prometheus.x` to the live +service rather than the silentmode.st teaser. + +## Updates + +Code: rsync Prometheus/ again, `npm install --omit=dev` (safe no-op if deps +unchanged), `systemctl restart prometheus-service`. + +Snapshot: nothing to do — the timer runs itself. + +Cert rotation: re-run make-tls-cert.sh, grab the new fingerprint, re-register +the `tls` record, reload angie. Theseus and Ariadne pick up the new cert as +soon as the record TX confirms. + +## Rollback + +Code: rsync the previous checkout, restart. There is no "schema down migration" +discipline yet — the DB file is append-only in practice (new columns, new +tables); if a rollback hits a schema change you have to decide what to do with +the newer rows. + +Record: `node Argus/src/register.js prometheus.x '{"u":"https://silentmode.st/prometheus/"}'` +puts the name back to redirecting at the ICANN mirror. Takes the same few +minutes as any other record change. diff --git a/deploy/make-tls-cert.sh b/deploy/make-tls-cert.sh new file mode 100644 index 0000000..fd63978 --- /dev/null +++ b/deploy/make-tls-cert.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# Generate a self-signed cert for prometheus.x and print its DER sha256. +# +# The sha256 is what you register as the `tls` record on chain for the name. +# Theseus and Ariadne refuse any certificate whose DER sha256 does not match +# that value, which is the whole point of the pinning model. +# +# Run on the VPS. Writes to /etc/ssl/prometheus-x/, so sudo. +# +# Usage: +# sudo bash deploy/make-tls-cert.sh +# -> prints: tls fingerprint: 9671bd5f44047f74203a76439430bda7bcf7c36d913c0fbd4cc75e24e374dde3 +# +# To rotate: run again; it overwrites the files and prints the new fingerprint. +# Then: node Argus/src/register.js prometheus.x '{"ip":"","tls":""}' +# After the record TX confirms (~5 min on chipnet, longer on mainnet), the +# clients see the new cert. + +set -euo pipefail + +DIR=/etc/ssl/prometheus-x +mkdir -p "$DIR" + +# ECDSA P-256 — small and fast. 10-year expiry; the on-chain pin, not the cert +# metadata, is what expires. SAN includes both the BNS name and the "localhost" +# proxy destination so a sanity-check curl against the vhost works. +openssl req \ + -x509 -nodes \ + -newkey ec \ + -pkeyopt ec_paramgen_curve:P-256 \ + -keyout "$DIR/privkey.pem" \ + -out "$DIR/fullchain.pem" \ + -days 3650 \ + -subj "/CN=prometheus.x" \ + -addext "subjectAltName=DNS:prometheus.x,DNS:localhost" \ + 2>/dev/null + +chmod 600 "$DIR/privkey.pem" +chmod 644 "$DIR/fullchain.pem" + +FP=$(openssl x509 -in "$DIR/fullchain.pem" -outform DER | openssl dgst -sha256 | awk '{print $NF}') + +echo "cert path: $DIR/fullchain.pem" +echo "key path: $DIR/privkey.pem" +echo "tls fingerprint: $FP" +echo +echo "Register with: node Argus/src/register.js prometheus.x '{\"ip\":\"\",\"tls\":\"$FP\"}'" diff --git a/deploy/prometheus-service.service b/deploy/prometheus-service.service new file mode 100644 index 0000000..2cc3692 --- /dev/null +++ b/deploy/prometheus-service.service @@ -0,0 +1,35 @@ +[Unit] +Description=Prometheus — the service behind prometheus.x +Documentation=https://code.silentmode.st/silentmode/prometheus +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=prometheus +Group=prometheus +WorkingDirectory=/opt/prometheus +Environment=NODE_ENV=production +Environment=BIND=127.0.0.1 +Environment=PORT=3700 +Environment=BNS_NETWORK=chipnet +# ADMIN_PUBLISHER, VIRUSTOTAL_API_KEY, PAYMENT_REQUIRED, PROMETHEUS_PAYMENT_ADDRESS +# and PROMETHEUS_LISTING_FEE_USD go in the drop-in file at +# /etc/systemd/system/prometheus-service.service.d/override.conf so they are +# visible to systemd but not committed to the repo. +EnvironmentFile=-/etc/default/prometheus +ExecStart=/usr/bin/node service/server.js +Restart=on-failure +RestartSec=3s + +# Hardening +NoNewPrivileges=yes +PrivateTmp=yes +ProtectSystem=strict +ProtectHome=yes +# WritablePaths: the service writes the DB, the uploads directory, and (when +# the key does not yet exist) the service key file. +ReadWritePaths=/opt/prometheus/db.sqlite /opt/prometheus/uploads /opt/prometheus/.keys /opt/prometheus/build + +[Install] +WantedBy=multi-user.target diff --git a/deploy/prometheus-x.conf b/deploy/prometheus-x.conf new file mode 100644 index 0000000..667ccf4 --- /dev/null +++ b/deploy/prometheus-x.conf @@ -0,0 +1,47 @@ +# prometheus.x — the standalone service, served by this VPS. +# +# BCNR serves this name via its `ip`+`tls` records: Theseus and Ariadne +# resolve prometheus.x by fetching the on-chain record, which says +# "connect to , pin the TLS cert whose DER sha256 equals ". The resolver reverse-proxies to this vhost; a browser +# with Ariadne's Thread installed does the same. +# +# The cert is self-signed and pinned on chain — no CA is involved and +# none needs to be, which is a narrower claim than a CA makes and does +# not expire on anyone else's schedule. Rotating is one record update. +# +# To regenerate the cert and read out its DER sha256: +# bash /opt/prometheus/deploy/make-tls-cert.sh +# +# The vhost listens only on HTTPS; the on-chain `tls` pin means plain +# HTTP would be refused by the resolver anyway, and we do not want a +# scanner to be able to read ANYTHING here over cleartext. + +server { + listen 443 ssl; + listen [::]:443 ssl; + http2 on; + server_name prometheus.x; + + ssl_certificate /etc/ssl/prometheus-x/fullchain.pem; + ssl_certificate_key /etc/ssl/prometheus-x/privkey.pem; + + # The TLS resolver reaches us over the raw IP but passes `prometheus.x` + # as the Host header. The service's canonical URL generator looks at + # that header; preserving it keeps rel=canonical honest. + location / { + proxy_pass http://127.0.0.1:3700; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + + # Publishers upload binaries that can be hundreds of MB. 2 GiB + # matches the service's own cap in uploads.js. + client_max_body_size 2g; + proxy_request_buffering off; + + proxy_buffering off; + proxy_read_timeout 120s; + } +}