Updating
The console tells you when a newer release exists, and installs it when you say so.
Agents keep themselves matched to the control plane — that is automatic and needs no configuration. The control plane is the one part you decide about, because updating it restarts the console and runs migrations, and that is a moment you choose rather than one that happens to you.
You do not have to be logged in to the host to choose it.
Where it lives
Settings → Version, in the console. It shows what this control plane is running, what the release channel is offering, what changed in that release, and a button.
When something newer exists, the Settings row in the sidebar carries the version as a badge. That is how you find out; there is nothing to check on a schedule. The channel is polled in the background and cached, so opening the page costs no outbound request.
Only the owner sees any of this. It belongs to the installation rather than to a team, so being an admin of every team is not the same thing.
Your databases are not involved. They run on their own machines, and neither the control plane nor its agents sit in the path of a query — nothing stops serving while the control plane restarts. Agents notice the new version when they next report in and update themselves, spread across the fleet rather than all at once.
What pressing the button actually does
Worth being precise about, because the honest answer is the reassuring one.
Updating means replacing the control plane's own container, which means talking to the Docker daemon. The control plane does not have the Docker socket, deliberately: it serves a console reachable from the internet, and that socket is the ability to stop and replace every container on the host — the databases included.
So the console does not do the work. It writes a version tag into a spool directory, and a root systemd
unit on the host runs quorumkit update — the same script you would run yourself, and the same one the
installer used. One update mechanism, not two.
The console writes the request. One version tag. Not an image, not a registry, not a command — the
registry stays whatever your .env says. The tag is checked against a version pattern on the way out and
again by the host on the way in.
systemd picks it up within milliseconds, via a path unit watching for that one file.
The host re-runs the installer with the requested version. Images are pulled and the stack is restarted. Every secret, the control-plane database and the certificate authority stay exactly where they were.
The console goes unreachable for a few seconds, because the thing serving it is what is being replaced. The page expects that and says so rather than showing an error. It comes back on the new version.
The host writes down the phase, the outcome and the installer's whole log as it goes. That is not
bookkeeping for its own sake: by the time an update finishes, the process that asked for it is gone, so that
record is the only thing that can tell you what happened. A failed update is diagnosable from the page
instead of over ssh.
It also re-checks the console's own health before calling the update done — so "updated" never appears next to a console nobody can reach.
The first time, on an existing installation
Any host installed before this existed has no systemd unit watching for requests. The console will report
the update and hand you the command instead of offering a button:
quorumkit updateThat run installs the unit. The button works from then on.
A button that left a request nobody collected would be worse than no button, so the console checks that the host half is genuinely armed before offering one.
Doing it from the host
Always available, and the answer whenever the console is not the right tool:
quorumkit updateInstalling a specific version
The console will only ever install the version the channel is offering — confirming what you were shown, rather than choosing freely. Anything else is a host-side command, where the person doing it can see what they are doing:
QK_VERSION=v0.3.1 quorumkit update # a rollback, or a pinVersions carry the leading v, because that is the git tag and therefore the image tag that exists.
The release channel
QK_CHANNEL is where an installation looks — the same variable the installer takes, and
recorded in /opt/quorumkit/.env so a host checks the same place it was installed from. It serves three
things:
<channel> the installer itself
<channel>/docker-compose.yml the stack definition
<channel>/version.json what the newest release isThe default is the public channel. Point it somewhere else to serve your own:
QK_CHANNEL=https://releases.example.com/quorumkit sudo sh install.shversion.json
{
"version": "v0.3.2",
"released": "2026-08-30",
"highlights": [
"What changed, in a sentence each",
"Rendered as text, never as markup"
],
"notes_url": "https://example.com/changelog",
"min_upgrade_from": "v0.3.0",
"breaking": false
}Only version is required, and it must be the git tag as published — v-prefixed. The rest improves what the
console can say and none of it changes what an update does:
| Field | What it does |
|---|---|
highlights | The answer to "what changes if I press this". Shown as a list. |
notes_url | A link to the full changelog. Dropped unless it is http(s). |
released | Shown beside the version. |
min_upgrade_from | Refuses a jump that cannot be made in one step, and names the version to install first. |
breaking | Advisory. Changes the wording and marks the confirmation. |
Air-gapped, or a private channel
QK_CHANNEL accepts a directory as well as a URL, for the reason a private repository cannot serve a file
to an unauthenticated curl and an air-gapped host has no URL to reach at all:
QK_CHANNEL=/srv/quorumkit-channel quorumkit updateA host that cannot read its channel simply reports that it could not check. It does not fail, and it does not nag — that is the normal state of an installation with no route out.
What this deliberately does not do
No automatic control-plane updates. Agents update themselves because an agent is a control-path process whose restart moves nothing. Updating the control plane restarts the console and runs migrations. This removes the need to be logged in for it; it does not decide for you.
No rollback from the console. The button installs what the channel is offering. Going backwards is a host-side command, above.