# Upgrading

## Recommended path

```
tar xzf ANetBBS-vX.Y.Z.tar.gz
cd ANetBBS-vX.Y.Z
sudo bash update.sh
```

The update script (8 steps):

1. Detects your install directory from the running `anetbbs-web`
   service's `WorkingDirectory=` (falls back to `/opt/anetbbs` if no
   service is installed yet).
2. Backs up `.env`, the SQLite database(s) (via `sqlite3 .backup`, a
   consistent snapshot even with the service still running), the
   systemd unit files, and the nginx site config to a timestamped
   directory under `data/backups/anetbbs-backup-YYYYMMDDHHMMSS/`
   (inside your install dir — moved off `/tmp` after a real incident
   where a Pi's `/tmp` turned out to be a small RAM-backed tmpfs and
   the backup didn't survive). This backup
   does **not** include `data/` or `logs/` — those are never touched
   by the update in the first place (see "What's safe to skip" below),
   so there's nothing to restore for them.
3. Stops `anetbbs-web`, `anetbbs` (the unified telnet/SSH/rlogin
   process), and any of `anetbbs-mrc-bridge`/`anetbbs-finger`/
   `anetbbs-binkp` that are currently running. Also removes the
   legacy split `anetbbs-telnet`/`anetbbs-ssh` units if a very old
   install still has them (replaced by the unified `anetbbs.service`
   back in v1.0a2.10).
4. Rsync's the new code over your install dir — excludes `data/`,
   `.env`, `venv/`, `logs/`, `doors/`, `gallery-config.json`, and the
   MRC bridge's own config/data/logs, so none of those are ever
   overwritten by an update.
5. Runs `pip install -e .` to pick up new/changed dependencies
   (includes an automatic Python 3.13 eventlet-on-ARM compatibility
   check/rebuild — see docs/INSTALL-PI.md).
6. Merges any new keys into your existing `.env` (never overwrites
   values you've already set) and auto-generates a real `SECRET_KEY`
   if yours is still a known insecure default.
7. Updates the database schema — adds missing columns/tables directly
   via a minimal script (deliberately avoids the normal app startup
   path, which would crash on an old schema missing new columns).
8. Restarts services (only restarts the optional ones —
   mrc-bridge/finger/binkp — if they were already running before the
   update) and probes `/healthz` for up to 30 seconds.

If the web service fails to start after restart, the script
**automatically rolls back** — no prompt — restoring `.env`, the DB
file, and the systemd units from the Step 2 backup, then restarting.
One exception: if the failure looks like the known Python 3.13
eventlet/ARM wheel issue, it tries rebuilding eventlet from source and
retrying instead of rolling back (rolling back application files
wouldn't fix a broken Python package anyway).

## Auto-update (Admin UI)

You can also trigger upgrades from **Admin → Upgrades** in the web
interface. The BBS checks for new releases against the configured
registry and offers a one-click install that runs `update.sh` in the
background. Progress is streamed to the browser log viewer.

## Manual rollback

If you need to undo a bad upgrade yourself, the backup directory path
is printed during the update — it looks like
`/opt/anetbbs/data/backups/anetbbs-backup-YYYYMMDDHHMMSS/` (inside
your install dir, so it survives a reboot). Find it with
`ls -dt /opt/anetbbs/data/backups/anetbbs-backup-* | head -1` if you
didn't note it down. Restore with:

```
sudo systemctl stop anetbbs-web anetbbs anetbbs-mrc-bridge anetbbs-finger anetbbs-binkp
sudo cp /opt/anetbbs/data/backups/anetbbs-backup-YYYYMMDDHHMMSS/.env.bak /opt/anetbbs/.env
sudo cp /opt/anetbbs/data/backups/anetbbs-backup-YYYYMMDDHHMMSS/anetbbs.db.bak /opt/anetbbs/data/anetbbs.db
sudo systemctl start anetbbs-web anetbbs anetbbs-mrc-bridge anetbbs-finger anetbbs-binkp
```

Only start the optional services (mrc-bridge/finger/binkp) if you were
actually running them before.

## What's safe to skip

- `data/` — uploads, avatars, echomail, personal pages, galleries.
  Excluded from the update's rsync entirely; never touched.
- `.env` — your config and secrets. Existing values are never
  overwritten; only new keys get merged in.
- `venv/` — kept; only `pip install -e .` runs to pick up new/changed
  dependencies.
- `logs/` — excluded from rsync; never touched.
- `doors/` — vendor door-game trees; excluded from rsync so any local
  changes/saves survive.
- The SQLite database(s) — kept; schema is migrated forward only
  (new columns/tables added, nothing dropped).

## Upgrade frequency

Versions ship roughly weekly. Every release adds either:

- A bug fix (always safe to deploy)
- A new feature (additive, no migration of data)
- A schema change (handled automatically in Step 7)

Read the release notes if anything mentions a destructive migration
(rare).
