Deploy automation (idempotent, runs on every deploy): - .github/workflows/deploy.yml: push to main/master (or dispatch) SSHes to the droplet and re-runs setup.sh; deploys the pushed branch; smoke-tests :22. - scripts/self-update.sh + agentbbs-update.timer: autonomous backstop that redeploys only when origin advances. - setup.sh hardened: flock, fetch+reset (survives force-push), fixed the always-skipped arcade asset fetch path. Membership model: - Free, email-verified members get their own Docker pod (pod@ paywall removed) and a /~name homepage (seeded at join@). - join@ is now interactive: email -> emailed 6-digit code -> enter code. - Premium ($10 one-time, lifetime via CoinPay) grants a personal <name>@host email (new internal/forwardemail; forwardemail.net aliases) and custom domains (domain@ gated to Premium). - ensurePremium() silently verifies/grants/provisions on hub login, join@, and domain@. New-signup details emailed to AGENTBBS_SIGNUP_NOTIFY (subject "bbs"). Store: User.Premium + premium/premium_ref cols, ConfirmEmailCode, GrantPremium. Tests: store_premium_test.go, forwardemail_test.go. Build/vet/gofmt/test green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2.9 KiB
Autonomous deploy
AgentBBS deploys to a single Ubuntu droplet (bbs.profullstack.com). The whole
provisioner — setup.sh — is idempotent: it pulls the tracked branch,
rebuilds the Go binaries, rewrites the systemd unit / Caddyfile / env, and
restarts the service that answers ssh join@bbs.profullstack.com. Re-running it
is always safe, so "deploy" just means "run setup.sh again."
Two mechanisms keep the box current, and they cooperate (both go through the
same flock in setup.sh, so they never race):
1. Push-triggered — GitHub Actions (.github/workflows/deploy.yml)
On every push to main (and via Run workflow), CI SSHes to the droplet's
admin port and runs setup.sh. This is the "runs on every deploy" path.
Configure these repo secrets — Settings → Secrets and variables → Actions:
| Secret | Required | Default | Notes |
|---|---|---|---|
DEPLOY_SSH_KEY |
yes | — | private key; its public half is in the droplet admin user's ~/.ssh/authorized_keys |
DEPLOY_HOST |
yes | — | bbs.profullstack.com or the droplet IP |
DEPLOY_USER |
no | root |
admin SSH user (needs passwordless sudo if not root) |
DEPLOY_PORT |
no | 2202 |
admin OpenSSH port (setup.sh moves it off :22) |
The job bootstraps a bare box (clones /opt/agentbbs if missing), hard-resets to
origin/main so it always runs the latest setup.sh, then execs it, and finally
smoke-tests that something serves SSH on :22.
2. Pull-triggered — self-update timer (autonomous backstop)
setup.sh also installs agentbbs-update.timer, which runs
scripts/self-update.sh every SELF_UPDATE_INTERVAL (default 15 min). That
script git fetches origin and, only if the branch advanced or the service is
down, re-runs setup.sh. When nothing changed it costs one fetch and exits, so
the box self-heals and stays current even if CI is unavailable.
Disable it with SELF_UPDATE=0 ./setup.sh; change the cadence with
SELF_UPDATE_INTERVAL=5min ./setup.sh.
First-time bootstrap
The droplet is already provisioned. To bring up a fresh box manually:
git clone https://github.com/profullstack/agentbbs /opt/agentbbs
sudo /opt/agentbbs/setup.sh # DOMAIN/ADMIN_SSH_PORT/etc. overridable via env
After that, pushes to main deploy automatically.
Operations
journalctl -u agentbbs -f # live BBS logs
systemctl status agentbbs # service health
systemctl list-timers agentbbs-update.timer # next self-update
sudo /opt/agentbbs/scripts/self-update.sh --force # force a redeploy now
Note on the logicsrc connector
@logicsrc/plugin-agentbbs (in the logicsrc monorepo) is a registry
connector that talks to this running server over SSH — it is not installed on
the droplet and is not needed for ssh join@bbs.profullstack.com to work. The Go
server provisioned here is what serves all SSH routes.