Skip to content

Upgrading

Schema migrations run automatically on startup, in order, and are recorded in SQLite's user_version. There is no separate migrate command to remember.

Before you start

Back up the data directory. The database runs in WAL mode, so copy all three files together, or stop the service first:

sudo systemctl stop longbox          # or: docker compose stop
cp -a /var/lib/longbox /var/lib/longbox.backup-$(date +%F)

Check where you are starting from. A minimal Debian install has no sqlite3 command, so either works:

sqlite3 /var/lib/longbox/longbox.db 'PRAGMA user_version;'
python3 -c "import sqlite3;print(sqlite3.connect('/var/lib/longbox/longbox.db').execute('PRAGMA user_version').fetchone()[0])"
Version Shipped
1 Single-user catalogue
2 Multi-user accounts, OAuth identity model
3 Password reset, admin audit log
4 Full ComicInfo coverage, portable ids, integrity hashes
5 A second metadata source — Metron ids alongside the Comic Vine ones
6 Skins, with Newsprint and Midnight seeded as real rows

Docker

cd longbox
git pull
docker compose up -d --build
docker compose logs -f longbox        # watch it come up

systemd

Re-run the installer. It replaces the application and the unit file, refreshes dependencies, and leaves your data and configuration alone:

cd longbox
git pull
sudo ./deploy/install.sh
journalctl -u longbox -f

/var/lib/longbox is never touched, and /etc/longbox.env keeps every value you have set — which is why host-specific settings belong in the env file and not in the unit, since anything you put in the unit is overwritten on the next upgrade. The installer will append a setting the file is missing entirely, so that longbox-cli reads the same paths the service does, and tells you when it does.

Upgrading onto the /var/cache layout. Extracted pages used to live in /var/lib/longbox/pages and now use /var/cache/longbox, so a backup of the library no longer sweeps them up. They rebuild themselves on demand, so there is nothing to migrate — the installer points out the old directory and you can remove it whenever it suits you.

What each upgrade does to your data

1 → 2 (single-user to multi-user). comic, library_folder and setting are rebuilt, because they need constraints SQLite cannot add to an existing table. Your library is parked on an inactive placeholder account, and the first account you create adopts all of it — comics, reading state, favourites, watched folders and your Comic Vine key. So after this upgrade, open the web UI and register before anyone else does; whoever registers first becomes the administrator and inherits the library.

2 → 3 (password reset and audit log). Purely additive: two new tables and one column. Nothing moves, nobody needs to re-register.

3 → 4 (metadata coverage and identity). Seventeen nullable columns, then a backfill that gives every existing comic a portable id. Nothing is re-read from disk, so the new ComicInfo fields stay empty on comics already imported until you re-read them — python -m app.cli verify will not do it, but "Re-read file" on a comic, or a rescan with Re-read files already imported, will.

4 → 5 (a second metadata source). Nullable columns only. Metron ids sit alongside the Comic Vine ones rather than replacing them, so a book tagged from either source carries both and stays cross-referenced.

5 → 6 (skins). A new table and its two seed rows, both created by the schema script that runs after every migration. Nothing existing is altered, and the active skin is a setting rather than a row — selecting "Default" clears it.

Afterwards

Confirm the service actually restarted, before anything else. Copying files over a running process does not change what it serves, and every other check on this page can pass while the previous release keeps answering.

systemctl show longbox -p ActiveEnterTimestamp

That timestamp should be from the upgrade, not from whenever the service last came up. install.sh now runs systemctl restart rather than relying on enable --now, which starts a stopped unit and does nothing at all to a running one — so on any release before that fix, re-running the installer left the old process in place. It looked like a successful upgrade in every respect the log could show.

Then:

  • GET /healthz reports the version and the number of accounts.
  • Check PRAGMA user_version again to confirm it advanced.
  • Open the library and confirm your comics are there. Covers are cached in data/covers/ and are not touched by migrations.
  • If something looks wrong, stop the service and restore the backup. Migrations are one-way — a newer database will not run on an older release, so rolling back means restoring the copy you took.

If you are locked out after upgrading

The account recovery CLI needs no web UI and no third-party packages:

sudo longbox-cli list-users
sudo longbox-cli reset-password <username>

Use the wrapper rather than calling the interpreter yourself. Invoking /opt/longbox/.venv/bin/python -m app.cli by hand picks up neither /etc/longbox.env — systemd loads it only for the units it starts — nor the working directory the package needs, so it would look for a database in the wrong place entirely.