A two-target distribution for provisioning and operating a fleet of SPV landing-page host VMs. The customer self-hosts the entire stack inside their own network — there is no SaaS component, no vendor cloud, and no customer data leaves the customer's infrastructure.
- admin/ — Next.js control plane. Owns users, host registry, domain map, deploy log, nightly backups. Talks to each host over an SSH local port-forward. Phase 1 runs on a single Ubuntu VM.
- vms/ — host-VM runtime.
bootstrap.shprovisions a fresh Ubuntu host, then installs the Fastify host-api service + renderer CLI + nginx site templates + certbot. - shared/ — the canonical block schema (
shared/blocks.ts). Imported by both admin and vms; there is exactly one copy.
Each site's content lives on the host VM only. Admin stores zero site content.
v0.0.64 — see RELEASE_TAG and RELEASE_COMMIT in this repo, and the
v0.0.64 release page
for the install tarball.
This dist repo carries only the latest stable snapshot. Historical releases and snapshot branches have been retired. If you need an older build for forensic comparison, contact the vendor.
Use of this software is governed by LICENSE — a 7-day evaluation
licence. After the trial window expires you must either remove the software
or sign a commercial agreement with the vendor. See LICENSE for full terms.
| Role | Machine | Entry point | Port |
|---|---|---|---|
| Admin | one Ubuntu VM | admin/install.sh |
80 / 443 |
| Host (×N) | per-site Ubuntu | vms/bootstrap.sh (via admin) |
3001 (local-only) |
The admin installer clones this monorepo to /opt/ff-admin and runs the app
from /opt/ff-admin/admin/. The host installer clones it to
/opt/ff-host-src and runs the service from /opt/ff-host-src/vms/host-api/.
Full step-by-step instructions live in INSTALL.md. Short form:
GH_TOKEN=<your-pat> \
curl -fsSL https://raw.githubusercontent.com/antonorlov888/orox_siteconstuctor_admin-dist/v0.0.64/admin/install.sh \
| sudo -E bash -s -- --domain admin.example.comRe-running is safe — every step is idempotent.
Nightly pg_dump + tar of host content lands in /var/backups/spv/ owned
by ffadmin:ffadmin with directory mode 0700 and file mode 0600.
Back MASTER_SECRET up SEPARATELY from the pg_dump. The admin DB stores
per-host SSH keys encrypted with MASTER_SECRET (AES-256-GCM). A restore
from pg_dump alone is useless without the key — and a backup of both
together re-creates the single point of failure we encrypted against. Store
MASTER_SECRET in your password manager / vault / HSM, never alongside the
DB dump.
Every site carries a theme object on its SiteConfig that the renderer
turns into CSS custom properties (--color-primary, --font-heading, …) on
the rendered page. Schema is at v2 (SUPPORTED_SCHEMA_VERSIONS = [1, 2]) —
older v1 configs still render and are back-filled with the "Classic
Corporate" preset on read.
Presets (see shared/theme-presets.ts):
- Classic Corporate — blue primary, gold accent, serif headings / sans body.
- Modern Minimal — near-black primary, blue accent, all-Inter, rounded.
- Legal Document — stone palette, all-Merriweather serif, zero radius.
- Financial Gold — navy + gold, Playfair Display headings, Lato body.
- Dark Professional — dark canvas, light blue primary, Space Grotesk + Inter.
- Freedom Holding — green primary (
#035332), blue secondary (#007fb1), bright-green accent (#40BF80), Inter body, neutral container.
Use the admin's "Design" tab on a site (next to "Content") to pick a preset or tweak colours, fonts, heading style, radius, and container width. A sandboxed iframe preview loads the real Google Fonts so you can see the final look before deploying.
All commands assume SSH as a sudoer on the admin VM with the monorepo at
/opt/ff-admin/ (the default install layout).
sudo -u ffadmin bash -lc '
cd /opt/ff-admin/admin && set -a; . ./.env; set +a; \
node scripts/dist/scripts/add-admin.js ops@firm.local
'
The helper prints {"email":"...","password":"...","created":true} on new
accounts. Copy the password immediately — it is not stored or printable
again. Re-running with an existing email rotates the password instead.
# On the host VM:
sudo rm -f /etc/ff-host/bearer
# On the admin VM:
sudo -u postgres psql ff_admin -c "
UPDATE \"HostVM\" SET encrypted_api_token=NULL, api_token_hash=NULL
WHERE ip='<host-ip>';
"
Then click Resume bootstrap on the host's detail page. Admin generates a
fresh 32-byte bearer, drops it on the host, and re-runs bootstrap (which
writes /etc/ff-host/bearer fresh).
sudo -u ffadmin bash -lc '
cd /opt/ff-admin/admin && set -a; . ./.env; set +a; \
node_modules/.bin/prisma migrate deploy
'
Re-run update-admin.sh --no-pull afterwards so the running Next server
picks up any new Prisma client code.
Each successful deploy renames the previous render to <slug>.prev/. To
swap back:
# On the host VM:
cd /var/www
sudo mv <slug> <slug>.failed
sudo mv <slug>.prev <slug>
sudo systemctl reload nginx
The host writes one JSON line per step to /var/log/ff-bootstrap.json:
ssh root@<host-ip> 'cat /var/log/ff-bootstrap.json'
Fields are {ts, step, status, detail}. status: failed identifies the
broken step. For build errors: journalctl -u ff-host-api -n 100.
To re-run bootstrap directly on a host (bypassing admin):
ssh root@<host-ip> 'sudo API_TOKEN=<existing-bearer> bash /opt/ff-host-src/vms/bootstrap.sh'
INSTALL.md— full install walkthrough.LICENSE— 7-day trial terms.SECURITY.md— invariants and threat model.admin/.env.example— every env var the admin app reads.admin/install.sh— authoritative admin install sequence.vms/bootstrap.sh— authoritative host bootstrap sequence.