Upgrade
Move a running server to a newer release: check the new binary, stop the server, copy the data directory, install the binary, check the data with it, start it, and go back to the old version if you need to.
An upgrade replaces the binary. The data directory, the configuration and the keys stay as they are. A newer binary opens the data of an older one, and brings its catalogs up to its own schema version the first time it opens them, each in one transaction. An older binary refuses a catalog with a newer schema version than its own. So the way back from an upgrade is the copy of the data directory taken just before it.
CI runs every command on this page on each change. It installs the previous release, sets it up as getting started does, upgrades it to the server built from the change, and goes back again.
From 0.3.0 to 0.4.0
0.4.0 brings every catalog, server.sqlite and each tenant's, from schema
version 2 to schema version 4 the first time it opens it. 0.3.0 refuses a
catalog at schema version 3 or 4. So once 0.4.0 has opened a data directory,
as serve and check do, 0.3.0 cannot open that directory again: there is
no downgrade. 0.3.0's check and tenant list, for example, stop with
vcon-server: the registry cannot be opened: opening /var/lib/vcon-server/server.sqlite failed: schema version 4 is not one this build knows. The only way back to 0.3.0 is the copy of the data directory
taken before the upgrade, as in go back to the old
version; everything stored after the copy is
lost.
Before you install 0.4.0, keep:
- a copy of the data directory, taken with the server stopped, as in copy the data directory;
- the master key, apart from that copy;
- the configuration file, and the TLS certificate and its key;
- the 0.3.0 binary, to go back to.
Before you upgrade
-
Read the changelog for every version after yours. Each version lists what it adds, changes and fixes.
-
Know the version you run:
vcon-server --versionvcon-server <version> -
One shell for every step: later steps use variables that earlier steps set.
URL=https://vcon.example.com:8443
CONFIG=/etc/vcon-server/vcon-server.toml
TENANT=$(sudo -u vcon vcon-server tenant list --config $CONFIG | jq -r 'select(.name == "acme") | .id')
KEY=$(sudo -u vcon vcon-server key create --tenant "$TENANT" --scope write --scope read --label upgrade-check \
--config $CONFIG | jq -r .token)
Store a vCon to read back after the upgrade:
UUID=$(cat /proc/sys/kernel/random/uuid)
printf '{"vcon":"0.4.0","uuid":"%s","created_at":"2026-10-27T12:00:00Z","parties":[{"tel":"+15555550106"}],"dialog":[],"attachments":[],"analysis":[]}' \
"$UUID" > upgrade.vcon
curl -sS -o /dev/null -w '%{http_code}\n' --cacert /usr/local/share/vcon-server/ca.pem "$URL/vcons" \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/vcon" --data-binary @upgrade.vcon
201
Get the new binary
Download the new release and check it, as on install, but do not install it yet. The commands use their own variable names, so they do not change the ones from install:
NEW_VERSION=0.4.0
NEW_ARCHIVE=vcon-server-$NEW_VERSION-$(uname -m)-unknown-linux-gnu.tar.gz
curl -fsSLO https://github.com/NormB/vcon-server/releases/download/v$NEW_VERSION/$NEW_ARCHIVE
curl -fsSL -o SHA256SUMS-$NEW_VERSION.txt https://github.com/NormB/vcon-server/releases/download/v$NEW_VERSION/SHA256SUMS.txt
sha256sum -c SHA256SUMS-$NEW_VERSION.txt --ignore-missing
tar -xzf "$NEW_ARCHIVE"
vcon-server-<version>-<cpu>-unknown-linux-gnu.tar.gz: OK
The new binary is in the archive's directory. With a binary from
cargo install or a
source build, set NEW to its path
instead:
NEW=${NEW_ARCHIVE%.tar.gz}/vcon-server
"$NEW" --version
vcon-server <version>
Stop the server
Under systemd:
sudo systemctl stop vcon-server
Or, without systemd:
sudo kill -TERM "$(pidof vcon-server)"
while pidof vcon-server >/dev/null; do sleep 0.2; done
Copy the data directory
Copy the data directory with the server stopped. The copy holds the data
directory's two lock files, lock and lock.commands, as a command that
runs alone does, so no server or command can start while it runs. It works
with every version, including those without vcon-server backup.
/backup stands for your backup storage:
sudo install -d -m 0700 /backup
BEFORE=/backup/vcon-server-before-$NEW_VERSION.tar
sudo flock --nonblock /var/lib/vcon-server/lock flock --nonblock /var/lib/vcon-server/lock.commands \
tar -C /var/lib -cf "$BEFORE" vcon-server
sudo tar -tf "$BEFORE" | sed -n 's|^vcon-server/\([^/]*\)$|\1|p' | sort
lock
lock.commands
server.sqlite
flock exits 1, and copies nothing, if a server or a command still holds
the directory. The copy holds nothing readable without the master key. Keep
it away from the master key's copies. Keep the old binary too:
sudo cp -p /usr/local/bin/vcon-server /usr/local/bin/vcon-server.previous
Install the new binary and check the data with it
sudo install -m 0755 "$NEW" /usr/local/bin/vcon-server
vcon-server --version
vcon-server <version>
check opens every catalog and every stored version with the new binary.
A catalog of an older schema is brought up to date as it is opened.
Nothing else changes:
sudo -u vcon vcon-server check --config $CONFIG | jq -c 'select(.name == null) | {problems}'
{"problems":0}
Start it
Under systemd:
sudo systemctl start vcon-server
timeout 30 sh -c 'until curl -s -o /dev/null --cacert /usr/local/share/vcon-server/ca.pem https://vcon.example.com:8443/health; do sleep 1; done' && echo answering
answering
Or, without systemd:
sudo -u vcon vcon-server serve --config /etc/vcon-server/vcon-server.toml
<time> INFO vcon_server::serve: serving listen=0.0.0.0:8443
…
The vCon stored before the upgrade reads back the same:
curl -sS --cacert /usr/local/share/vcon-server/ca.pem "$URL/vcons/$UUID" -H "Authorization: Bearer $KEY" -o upgraded.vcon
cmp upgraded.vcon upgrade.vcon && echo "the same bytes"
the same bytes
Go back to the old version
Go back only with the copy taken before the upgrade: the new binary may have brought the catalogs to a schema the old one refuses. Everything stored since the copy is lost. Stop the server:
sudo systemctl stop vcon-server
sudo kill -TERM "$(pidof vcon-server)"
while pidof vcon-server >/dev/null; do sleep 0.2; done
Put back the data directory and the old binary, and check:
sudo mv /var/lib/vcon-server /var/lib/vcon-server.upgraded
sudo tar -C /var/lib -xpf "$BEFORE"
sudo install -m 0755 /usr/local/bin/vcon-server.previous /usr/local/bin/vcon-server
sudo -u vcon vcon-server check --config $CONFIG | jq -c 'select(.name == null) | {problems}'
{"problems":0}
tar -p, run as root, keeps the files' owner and modes. Start the server
as above. Once it runs as it should, remove /var/lib/vcon-server.upgraded.
In a container
Build an image for the new version, as in running it in a container, then replace the container. The volumes keep the data and the configuration. Copy the data volume first, with the container stopped:
docker build -q --build-arg VERSION=$NEW_VERSION -t vcon-server:$NEW_VERSION .
docker stop vcon-server
docker run --rm -v vcon-data:/var/lib/vcon-server -v vcon-backup:/backup debian:trixie-slim \
tar -C /var/lib -cf /backup/before-$NEW_VERSION.tar vcon-server
docker rm vcon-server
docker run -d --name vcon-server --restart unless-stopped --ulimit memlock=-1 -p 8443:8443 \
-v vcon-etc:/etc/vcon-server -v vcon-data:/var/lib/vcon-server -v vcon-backup:/backup \
vcon-server:$NEW_VERSION
With the objects in an S3 bucket
S3 storage is in release 0.4.0 and later (see keep vCons in an S3 bucket). For a server that keeps its objects in a bucket:
- An upgrade does not move objects. Adding a
[storage]table to a server that has stored vCons is a change of storage, not an upgrade: its stored versions stay in the data directory and answer500untilvcon-server storage move-objects, run with the server stopped, moves them (see move objects stored in the data directory). - The copy of the data directory does not hold the objects. The copy
taken before the upgrade holds the catalogs and
storage.claim; the objects stay in the bucket. Going back to that copy keeps the claim, so the old binary starts on the same prefix. Its start-up recovery then removes every object stored after the copy, since no row of the copy names it, and logs how many it removed. - Release 0.3.0 cannot go back to a bucket. It refuses the
[storage]table (see the build has no S3 support), so a server whose objects are in a bucket cannot go back to 0.3.0.
CI runs this page with the objects in the data directory only.
Clean up
Revoke the key this page made:
KEY_ID=$(sudo -u vcon vcon-server key list --tenant "$TENANT" --config $CONFIG | jq -r 'select(.label == "upgrade-check") | .id')
sudo -u vcon vcon-server key revoke "$KEY_ID" --config $CONFIG
Source of this page: website/content/docs/upgrading.md