DOCS · ADMIN · UPGRADE

Roll it forward.

An upgrade is four moves: git pull, cargo build --release on the VM, systemctl restart qnt-server, and the smoke. Migrations ride along on restart, and the restart drains in-flight connections cleanly. If a release goes bad, the rollback is the same shape in reverse — check out the last-known-good SHA and rebuild.

1 The upgrade sequence

The repo is checked out at /opt/ngrok-qt-quic on the VM, the binary lives at /opt/ngrok-qt-quic/target/release/qnt-server, and it runs as the systemd unit qnt-server. Build on the VM — it's the target box.

Pull, rebuild, restart

From the repo root, pull (or check out a tag), put cargo on PATH, build the release binary, then restart the unit:

cd /opt/ngrok-qt-quic
git pull
source ~/.cargo/env
cargo build --release -p qnt-server
systemctl restart qnt-server

The build takes ~4 min on 2 vCPU. Pin to a tag or SHA for reproducible deploys rather than tracking a moving branch.

Confirm it came back up

Give it a few seconds, then check the unit is active:

sleep 5 && systemctl is-active qnt-server
active

is-active returning active means qnt-server bound its ports and stayed up. If it doesn't, jump to section 5.

The restart drains cleanly

The binary catches SIGINT to drain in-flight connections, and the unit sets KillSignal=SIGINT with TimeoutStopSec=30s — so systemctl restart lets active tunnels finish rather than cutting them.

2 Migrations run on restart

There is no manual migrate step. Any new migrations shipped in a release run automatically when qnt-server starts.

Automatic and idempotent

  • New migrations apply on the next restart — you don't run them by hand.
  • They're idempotent, so restarting again is safe; a migration that's already applied is a no-op.

The bad-migration caveat

Because migrations run at boot, a bad migration can wedge the boot — qnt-server won't come up clean. That's exactly what the rollback in section 4 is for. Take a backup before an upgrade so the restore path is short.

3 Smoke check

is-active proves the process is up; the smoke proves the product still works. Treat it as the post-condition of every upgrade.

Run the day-1 smoke

The repo ships an end-to-end smoke script. Run it after the restart:

bash scripts/agent-day1-smoke.sh

A clean run is the signal the upgrade landed. A failing smoke on a unit that's otherwise active is your cue to roll back before customers notice.

4 Roll back a bad release

Rollback is the upgrade in reverse: check out the last-known-good SHA, rebuild, restart, and re-run the smoke. Same box, same shape.

Find the last-known-good SHA

List the recent history and pick the commit you were on before the bad release:

cd /opt/ngrok-qt-quic
git log -5 --oneline

Or grab the previous commit straight into a variable:

PREVIOUS=$(git log --oneline -5 | sed -n 2p | awk '{print $1}')

Check out, rebuild, restart

Swap <sha> for the last-known-good commit, then run the same build-and-restart you'd use for an upgrade:

git checkout <sha>
source ~/.cargo/env && cargo build --release -p qnt-server
systemctl restart qnt-server

Confirm with the smoke

sleep 5 && bash scripts/agent-day1-smoke.sh

Migrations are idempotent, so rebuilding the previous binary and restarting brings the database and service back to a known-good pairing.

5 When it won't boot

If qnt-server doesn't come back after a restart, the logs tell you why — and systemd has a backstop so a crash loop surfaces instead of spinning forever.

Read the panic

Pull the last 100 lines of the unit's journal to see what it choked on:

journalctl -u qnt-server -n 100 --no-pager
  • a bad migration (wedged the boot — see section 4 to roll back)
  • a port collision
  • a missing JWT key

The restart backstop

The unit runs Restart=on-failure with StartLimitBurst=10 in 120s. After 10 rapid failures systemd stops retrying and surfaces the failure in systemctl status rather than looping indefinitely.

systemctl status qnt-server

If you've hit the limit and fixed the cause, clear the failed state with systemctl reset-failed qnt-server before restarting.

Next

Upgrades and rollback in hand. Round out the operational guides.