- apps/web: redesigned landing (Hero/Scanner/HowItWorks/Features/Footer), honest live-vs-coming-soon badges, same-origin /api/scan, ember theme. - ecosystem.config.cjs: runnable — pyre-api/worker via `node --import tsx`, pyre-web via `next start`, fork mode, env wired. pm2 web+api verified online (api /health 200, scan 200, web 200). - infra/nginx/feedthepyre.com.conf: app at / (proxy :3000), API at /api (proxy :4000, prefix preserved), dev tracker at /status (static). - scripts/deploy-web.sh: sudo cutover (install vhost, nginx -t, reload, certbot --nginx --keep-until-expiring). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PYRE — scripts/
Operational scripts for the PYRE VPS (Ubuntu 24.04). These cover Phase 0
(server + repo setup) per docs/PYRE_MVP_DESIGN.md §12, §18, §19.
| Script | Purpose | Who runs it |
|---|---|---|
phase0-provision.sh |
Idempotent root provisioning: nginx, PostgreSQL, Redis, certbot/TLS, UFW, systemd pm2 unit, logrotate, status page. | root (sudo) |
gen-status.mjs |
Generates the public status.json for the status page. (Authored by another agent — see that file's header for usage.) |
pyre user |
backup.sh |
Database / config backup routine. (Authored by another agent — see that file's header for usage.) | pyre user / cron |
phase0-provision.sh
Provisions all system-level services PYRE depends on. It is idempotent and safe to re-run — every step checks current state before changing anything.
What it does NOT do
- Does not install Node.js 22, pnpm, the repo, or app
.envfiles (those are handled separately / by thepyreuser). - Does not run a Solana validator/RPC node or any local LLM/image model (explicitly out of scope per design §11/§12).
- Does not change Postgres
listen_addressesor expose Redis — both stay localhost-only. - Does not store any wallet private key. PYRE never holds keys; there is intentionally no key/mnemonic variable anywhere.
Steps
apt-get update+ installnginx postgresql postgresql-contrib redis-server certbot python3-certbot-nginx ufw.- Enable + start
postgresqlandredis-server. - Create Postgres role
pyre(LOGIN, NOCREATEDB) and databasepyreowned by it — only if absent. MatchesDATABASE_URL=postgresql://pyre:pyre@localhost:5432/pyrefrom.env.example. - Harden Redis:
bind 127.0.0.1 ::1andmaxmemory-policy noeviction, then restart. - UFW: allow
22,2222,80,443before enabling the firewall. - Install the nginx vhost, remove the default site, validate, reload.
- Create the status-page webroot and copy in
index.html/status.json. - Obtain/renew the TLS certificate via certbot (nginx plugin), with redirect.
- Install the
pm2-pyresystemd unit (enable, don't start) and the logrotate config. - Print versions, service statuses, a checklist, and a reminder to set real secrets.
Prerequisites
- Ubuntu 24.04 with the base setup already done (
pyreuser, SSH key auth, root login disabled, Fail2ban) — per design §12. - The repo present at
/home/pyre/pyre, owned bypyre. - The
infra/config sources present (authored by other agents):infra/nginx/feedthepyre.com.confinfra/status/index.html,infra/status/status.jsoninfra/systemd/pm2-pyre.serviceinfra/logrotate/pyre- If any are missing the script warns and continues rather than failing, so you can re-run it once the sources exist.
- DNS must already point
feedthepyre.comandwww.feedthepyre.comat this box before the TLS step can succeed. If DNS isn't live yet, certbot is skipped gracefully — just re-run the script later.
How to run
# Default (dev) — uses DB password "pyre" and the built-in certbot email:
sudo bash scripts/phase0-provision.sh
It must run as root. If you forget sudo, it re-execs itself under sudo
(or errors with instructions if sudo is unavailable).
Overridable environment variables
| Variable | Default | Notes |
|---|---|---|
PYRE_DB_PASSWORD |
pyre |
Postgres password for role pyre. The default is dev-only; the script prints a loud warning when it's used. Set a real one for production. Only applied when the role is first created — re-runs do not change an existing role's password. |
CERTBOT_EMAIL |
a31s15.roguewave@gmail.com |
Let's Encrypt registration / expiry-notice email. |
Pass overrides via sudo -E so the environment is preserved:
PYRE_DB_PASSWORD='a-strong-secret' \
CERTBOT_EMAIL='ops@feedthepyre.com' \
sudo -E bash scripts/phase0-provision.sh
If you set a non-default PYRE_DB_PASSWORD, update DATABASE_URL in the
per-app .env files to match.
⚠️ UFW / SSH warning
This script runs over SSH and enables the firewall. It deliberately allows the SSH ports before enabling UFW:
22/tcp(system SSH) and2222/tcp(Gitea git-SSH) MUST stay open. If you remove these allow rules, you will permanently lose remote access to the box. The script never removes existing allow rules; if you edit UFW by hand, keep 22 and 2222 open.
After provisioning
Set real secrets in the per-app .env files (copy from .env.example):
DATABASE_URL, ANTHROPIC_API_KEY / OPENAI_API_KEY / IMAGE_GEN_API_KEY,
ADMIN_API_TOKEN, SOLANA_RPC_URL, etc. Never commit a real .env.