Skip to content

antonorlov888/f_webpage_constuctor_vms

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ff-host — SPV website constructor Host VM runtime

Lightweight per-VM runtime for the SPV website constructor. Runs on a fresh Ubuntu 22.04 VM and:

  • accepts site configs + asset/document uploads from the admin orchestrator over an SSH tunnel
  • renders 11 types of content blocks to static HTML via a React server-side renderer CLI
  • serves the rendered sites via nginx
  • provisions per-site Let's Encrypt certs via certbot

This repo is what bootstrap.sh configures. The admin orchestrator lives in a separate repo and reaches this VM's host-api over an SSH tunnel — host-api never binds to a public interface.

Components

  • shared/blocks.ts — canonical block schema shared byte-identically with the admin repo.
  • host-api/ — Fastify 4 service bound to 127.0.0.1:3001. Bearer-authenticated (token at /etc/ff-host/bearer).
  • renderer/ — Node CLI that reads /var/sites/<slug>/config.json and writes static HTML to /var/www/<slug>.new/.
  • nginx/ — base nginx.conf + per-site template with /pdf-stream proxy and CSP isolation for the PDF.js viewer.
  • systemd/ff-host-api.service — hardened unit file for the host-api.
  • bootstrap.sh — idempotent setup for a fresh VM.

Disk layout at runtime

/opt/ff-host/                # this repo cloned here
/etc/ff-host/bearer          # 0400, admin-injected token
/etc/ff-host/env             # 0400, admin email + paths
/var/sites/<slug>/
    config.json
    assets/                  # images
    documents/               # PDFs only
/var/sites/_shared/pdf-viewer/   # pdfjs-dist viewer, symlinked into each site's _pdf/
/var/www/<slug>/             # rendered static output (served by nginx)
/var/www/<slug>.new/         # transient during deploy
/var/www/<slug>.prev/        # last-known-good, for rollback
/var/log/ff-bootstrap.json   # per-step bootstrap status (JSONL)
/var/log/ff-host-audit.jsonl # append-only audit log

Installation

On a fresh Ubuntu 22.04 VM:

# Admin supplies API_TOKEN via SSH env. Bearer is never generated by bootstrap.
sudo API_TOKEN=<long-random-token> ADMIN_EMAIL=ops@example.com bash bootstrap.sh

Re-running is safe — every step is check-then-act and emits a JSON status line to /var/log/ff-bootstrap.json. The bearer file is written once under a [ -f … ] || guard.

host-api endpoints

All require Authorization: Bearer <token> except /healthz and /pdf-stream (which uses its own signed-token gate).

Method Path Purpose
GET /healthz Liveness. {ok:true}. Unauthenticated.
GET /capabilities {renderer_version, supported_schema_versions:[1]}.
GET /sites List slugs.
GET /sites/:slug Return current SiteConfig.
PUT /sites/:slug Validate schema, write atomically, render, swap into /var/www.
DELETE /sites/:slug Remove site data and rendered output.
PUT /sites/:slug/assets/:name Upload image (`image/png
PUT /sites/:slug/documents/:id Upload a PDF. Rejects anything whose first 5 bytes aren't %PDF- or whose Content-Type isn't application/pdf.
DELETE /sites/:slug/documents/:id Remove a PDF.
GET /sites/:slug/documents/:id/token?sid=<sessionId> Mint a 60-second HS256 stream token bound to {slug, id, sid}.
GET /pdf-stream?t=…&id=…&slug=… Stream a PDF. Gated by signed token + Referer check. Single-use nonce.
POST /sites/:slug/domains Body {domain}. Writes nginx conf, reloads, runs certbot --nginx.
DELETE /sites/:slug/domains Remove the site's nginx conf and reload.
POST /self-update git pull && npm ci && npm run build && systemctl restart ff-host-api.

Hard architectural constraints

  1. host-api binds only to 127.0.0.1:3001 — admin reaches it via SSH tunnel.
  2. Bootstrap is strictly idempotent; per-step JSONL status in /var/log/ff-bootstrap.json.
  3. The bearer token is injected by admin via SSH env var (API_TOKEN), not generated by bootstrap. Written to /etc/ff-host/bearer (0400) under a [ -f … ] || guard.
  4. Atomic on-disk deploys: render to <slug>.new/, rename(2) over <slug>/, keep previous as <slug>.prev/.
  5. SiteConfig.schema_version must equal SCHEMA_VERSION; mismatched PUTs return 400.
  6. Documents are PDF-only — enforced via magic bytes and Content-Type. No overrides.
  7. /pdf-stream sets Content-Disposition: inline, Cache-Control: private, no-store, max-age=0, Pragma: no-cache, X-Content-Type-Options: nosniff. nginx sets proxy_no_cache 1; proxy_cache_bypass 1;.
  8. Stream tokens are HS256, 60 s TTL, bound to {slug, documentId, sessionId} with a single-use in-memory nonce. Referer must match one of the site's configured server_name values.
  9. POST /self-update is bearer-protected and restarts the service after the response flushes.
  10. Append-only audit log at /var/log/ff-host-audit.jsonl: {ts, route, slug?, actor_ip, status}. No tokens, no bodies, no file bytes.
  11. systemd-timesyncd enabled by bootstrap.
  12. certbot --nginx -d <domain> --non-interactive --agree-tos -m <email> — admin is responsible for DNS preflight.

Out of scope for Phase 1

  • HTTPS on host-api (SSH tunnel handles transport).
  • Admin-side anything (separate repo).
  • Rich-text sanitization (renderer uses dangerouslySetInnerHTML with // TODO Phase 2: DOMPurify markers).
  • i18n, backups, fleet-update UI.

Development

cd host-api  && npm install && npm run build
cd ../renderer && npm install && npm run build

To exercise the service locally, point it at scratch dirs:

export API_TOKEN=devtoken
export FF_BEARER_FILE=/tmp/ff-bearer; echo -n devtoken > $FF_BEARER_FILE
export FF_SITES_DIR=/tmp/ff-sites
export FF_WWW_DIR=/tmp/ff-www
export FF_AUDIT_FILE=/tmp/ff-audit.jsonl
export FF_NGINX_SITES=/tmp/ff-nginx
export FF_NGINX_TEMPLATE=$(pwd)/../nginx/site.conf.template
export FF_REPO_DIR=$(pwd)/..
export ADMIN_EMAIL=dev@example.com
node dist/index.js

Then from another terminal: curl -H "Authorization: Bearer devtoken" http://127.0.0.1:3001/capabilities.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors