diff --git a/deploy/apps-silentmode-st.conf b/deploy/apps-silentmode-st.conf new file mode 100644 index 0000000..2732a6c --- /dev/null +++ b/deploy/apps-silentmode-st.conf @@ -0,0 +1,62 @@ +# apps.silentmode.st — SEO-friendly read-only mirror of prometheus.x. +# +# Prometheus's real home is the BCNR name `prometheus.x`, served from this +# VPS via the name's `ip`+`tls` records. Search engines can't resolve `.x`, +# so this subdomain exists specifically to be crawled: it reverse-proxies to +# the same service and the response's `rel=canonical` already names +# `prometheus.x` as the authoritative URL — Googlebot indexes the content +# but attributes it to the real address. +# +# This is the same practice theseus.x and ariadne.x use via their +# conventional-DNS mirrors; see [[silentmode-site-url-scheme]] for the +# family's URL convention. +# +# POST endpoints (publish, admin, login) are proxied too — operator admin +# over https works via this hostname as a backup. For the typical sign-in +# flow we still prefer prometheus.x directly from Theseus. + +server { + listen 443 ssl; + listen [::]:443 ssl; + http2 on; + server_name apps.silentmode.st; + + # Reuse the main silentmode.st certificate (it covers *.silentmode.st when + # that SAN is set up). If it isn't, request one and reload angie. + ssl_certificate /etc/letsencrypt/live/silentmode.st/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/silentmode.st/privkey.pem; + + # No agent, no cookies lost in transit — we want the proxy to be a thin + # pipe so what the live service sends is what the crawler reads. + 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; + proxy_set_header X-Forwarded-Host apps.silentmode.st; + + # Large publisher uploads need a generous ceiling — matches the service's + # own 2 GiB cap. Reads are small; this governs POST /api/upload. + client_max_body_size 2g; + proxy_request_buffering off; + + # The service's own long-cache headers decide for static assets; this + # proxy does not add any additional caching layer. + proxy_buffering off; + proxy_read_timeout 120s; + } + + # Deny the admin via the mirror — the operator always goes direct to + # prometheus.x. Removes one scanner's worth of noise against /admin. + location ^~ /admin { + return 404; + } +} + +server { + listen 80; + listen [::]:80; + server_name apps.silentmode.st; + return 301 https://$host$request_uri; +} diff --git a/service/layout.js b/service/layout.js index ba43f99..e0b8ba7 100644 --- a/service/layout.js +++ b/service/layout.js @@ -26,7 +26,12 @@ const NAV = [ * @returns {string} the HTML document, ready to send. */ export function layout(page) { - const { title, description, body, here = '' } = page; + const { + title, description, body, here = '', + ogType = 'website', + ogImage = 'https://prometheus.x/static/favicon.svg', + headExtra = '', + } = page; // The canonical URL is always on prometheus.x — never the IP+port the server // actually listens on, and never the SEO mirror at apps.silentmode.st, even @@ -48,14 +53,16 @@ export function layout(page) {