Repository navigation
calabi 2.0.0
The edge's config file changed. A server that has been running since 1.14.0
will not start on the new edge until its config catches up, so take this part
before you pull.
If you run the server bundle (deploy/server), take the new
docker-compose.yml along with the new image. That file writes the edge's
config, and the version of it shipped before this release is one the new edge
refuses: it had no public: block, which is now required of a node that serves
tunnels. Your .env needs nothing new — the value comes from
CALABI_PUBLIC_HOST, which you already set.
If you wrote your own edge config, two things can stop it: public.host is
now required on a node that serves tunnels, and a handful of settings that had
quietly done nothing for some time are now refused instead of ignored. Both are
spelled out under "Your server" below, and the edge names the exact line on
startup rather than coming up half-working.
Everything that merely moved still loads from where it was, so the rest of your
file is fine as it stands. A machine that only relays mesh traffic does not need
public.host at all. The client's own config file is renamed in this release
too, but it migrates itself and needs nothing from you — also below.
Updates
- Fixed — A client in a container was told to reinstall itself as a system
service. Running thecalabinet/calabiimage, the local console and
calabi updatesaid the daemon was not a privileged system service and to
reinstall it withcalabi daemon install --system— a command the same binary
refuses inside a container, because a container supervises its own process and
has no OS service to install. A container is now recognised before anything
else is decided, and gets the answer that works: pull the new image and
recreate the container. It still checks, so the console still says a newer
version exists. A container running as root was also a case where the daemon
believed it could install: it downloaded and verified an installer on every
cycle and only then found there was no service manager to restart. It no
longer starts.
Local console
- Fixed — The console gave a container four more pieces of advice it
could not follow. Settings listedcalabi daemon install / start / status / stop / uninstallwith copy buttons — every one of which this binary refuses
in a container — and the pinned-identity notes said to reinstall or uninstall
the service to change the key or take the machine offline. The daemon now
tells the console it runs in a container, and those four places say what
works there instead: recreate the container with a different
CALABI_API_KEY, stop or remove it, manage it with your container runtime.
The same correction reaches the log a container operator actually reads: a
rejected API key no longer answers withcalabi daemon install --api-key.
Clients installed on a machine are unchanged, wording included.
On calabi.net
-
Fixed — A payment that settled slowly could leave your order
unpaid. Paying in USD goes through Paddle, and its local payment methods
(WeChat Pay, Alipay and similar) confirm the money some minutes after you are
finished — long enough, occasionally, to miss the 30-minute window an order
stayed open for. The order was marked expired, the payment then arrived with
nothing left to apply it to, and the money had been taken. USD orders now stay
open for two hours, and a payment that still arrives after that completes the
order instead of being dropped. Orders you canceled yourself are not affected:
a payment on one is reported for a human to look at, never turned into a
subscription behind you. -
Fixed — A payment link sent by Paddle said it was invalid. The payment
page read the transaction id from?txn=, but links Paddle generates itself —
the one behind "copy payment link", and the reminder it emails about an
unfinished payment — carry it as?_ptxn=. Every one of those landed on
"this payment link is invalid or has expired" with the id sitting in the
address bar under a different name. Both spellings work now. Opening such a
link fills the page in; it does not start a checkout on its own, so the
agreements still have to be ticked.
Your server
-
Changed — The edge config is grouped by service, and the node has one
address. Two things were wrong with the old file at once.Nothing in it said which half of the program would read a given setting:
control:,http:,relay:and the rest all sat at the top level, so a
relay-only config looked exactly like an edge's. And four of those blocks
named an address —control: { addr: ":7443" }— whose host half was always
empty, because every one of those listeners has to be reachable from outside
the machine. They named ports while looking like addresses, sitting among the
settings that really are addresses. The port was then written twice: once on
the listener, once insidepublic.addr, with nothing comparing them — move
the listener, forget the other line, and every client goes on dialing a port
nothing is listening on.The layout now follows the two services.
tunnel:holds what only tunnels
read,mesh:(formerlyrelay:) what only the mesh relay reads, and the top
level what both use. Where this node can be reached is one setting, and each
service names only the port it wants:node_label: my-server role: both mode: standalone coord_pubkey_file: ./coord.pub state: { dir: ./state } public: host: server.example.com tunnel: base_domain: tunnels.example.com control_port: 7443 http_port: 80 https_port: 443 mesh: derp_port: 3340 stun_port: 3478
A node running
role: meshcan now delete its wholetunnel:block, and one
runningrole: tunnelits wholemesh:block.public.hostis required on a node that serves tunnels. It is what
clients dial and the name its certificate is issued for. It used to be
optional, falling back to the listener's bind address — a usable dial string
only on the one machine that is also the client. A node that only relays mesh
traffic still does not need it; it is named in your coordinator's relay map.
From the environment:CALABI_EDGE_PUBLIC_HOST.Apart from that line, an existing file keeps working. Every setting that
moved still loads from where it was:control: { addr: ":7443" }as
tunnel.control_port: 7443,https: { self_signed: true }as
tunnel.https_self_signed: true,relay:asmesh:, andpublic.addras
public.host— the last provided the port written into it matches the
listener's. A file that spells one setting both ways, or whose two ports
disagree, is refused rather than guessed at, naming the one to keep.One thing this shape cannot express: an external port different from the one
bound. If you reach your edge through a mapping like that, bind the external
port directly. A bind address that names a host —control.addr: "10.0.0.5:7443"— is refused rather than quietly widened to every interface.Some settings are now refused rather than ignored. They had not done
anything for some time, and a file that still carries one describes a node
that does not exist. Theidentity:,quota:,config_svc:andnats:
blocks andtunnel.addr/cert.addrwent when the edge stopped reaching the
control plane directly.presence.interval_secondsandcert.refresh_seconds
go now: both had a working default, and in the whole history of this
repository no deployed config ever set either one.edge_classandorg_id
go for a different reason — which paying plans are routed to a node, and which
organization it belongs to, are not decisions a node should be making from a
file on its own disk. On calabi.net both come from the certificate that node
authenticates with, and a server you run yourself never used either. Delete
them from your file.Refusing rather than ignoring is the point. Removing the settings alone would
have been enough to stop them working — a key the edge does not know is
skipped — and that is the outcome worth avoiding: you would set a cadence, get
the default, and never be told.One more rename, for anyone running several edges in one region: the edge
config'smesh:block used to mean edge-to-edge forwarding of tunnel
traffic, which has nothing to do with the mesh. It is now
tunnel.peer_forward:. This is the one old spelling that is not migrated
silently —mesh:means the relay now, and quietly reading a peer-forward
block as relay settings would take a node out of its region's forwarding pool
without saying so. A file that still has it is refused, and the error says
what to rename it to. -
Changed — A replaced control certificate is picked up without a
restart. The edge readcontrol_cert_pem/control_key_pemonce at start.
Renewing those files, or swapping a self-signed certificate for a real one,
changed nothing until the next restart — the edge went on presenting the copy
it had read, and kept presenting it after it expired. It now re-reads them
when they change. A rotation caught half-done (the certificate written, the
key not yet) keeps serving the pair that still works and tries again on the
next connection, rather than turning a moment into a refused device. -
Changed — The daemon's config file is now
calabi.yaml, and the
coordinator moved to aserver:block. The file stopped being about
tunnels a while ago: a machine that only joins your server has a complete,
working config in whichtunnels:is empty. And the coordinator — which
server the device belongs to, and how it proves itself there — was nested
undermesh:, which read as though a device that never turns the mesh on
did not need it. It does:calabi http 8080reaches its edge by asking that
same coordinator. Socoord,trust,pins,ca_file,auth_keyand
namenow sit in a top-levelserver:block, andmesh:keeps only the
overlay's own settings.server: coord: server.example.com:7012 trust: pin pins: ["sha256:…"] auth_key: ck_… mesh: enabled: true # optional — tunnels work without it tunnels: []
You do not have to do anything. A file in the old shape still loads, and
is rewritten into the new one the next time anything saves it. The file the
console manages in your data directory is renamed fromtunnels.yamlto
calabi.yamlthe first time this version runs; if that rename cannot be
performed, it keeps using the old name. A file you pass with--configor
CALABI_DAEMON_CONFIGis yours and is never renamed — call it whatever you
like.One thing to know if you go back: an older client looks for
tunnels.yaml
and does not understandserver:, so after downgrading it will believe the
machine has not joined. Renaming the file back restores it; nothing is lost. -
Changed — The edge's two roles are now called
tunnelandmesh.
role: edgesaid nothing useful inside a program calledcalabi-edge, and
since the relay merged into that program the setting has not been asking
which binary you are running — it asks which of the two services this machine
provides. Those services are called tunnels and mesh everywhere else, so the
roles are nowtunnel,meshandboth.Nothing to change.
edgeandrelayare still accepted and will stay
accepted — includingCALABI_EDGE_ROLE=relay, which is the line this guide
has always given for running a relay on its own. An existing machine keeps
working across the upgrade untouched.
These are the same files published at https://download.calabi.net — same
version, same bytes. This release is not a separate CI build; it is that build,
uploaded here as well.
Verify them yourself
gh release download v2.0.0 --pattern build-manifest.json
bash scripts/verify-reproducible-build.sh build-manifest.jsonThat clones this repository at d337a2dacfadb13f11d9146d88fbc4c8e93b84f6 — the commit these binaries were
built from — rebuilds all 21 Go artifacts and compares hashes. The
verify-release workflow runs exactly that on GitHub's runners for this
release, so you can also just read its result.
SHA256SUMS (client + desktop), SHA256SUMS.edge and SHA256SUMS.coord
answer a different question: whether your download arrived intact. Archives
themselves are not reproducible (tar/zip record mtimes) — the manifest compares
the binary inside.
Not covered by the manifest
The installers. The two desktop ones are Tauri/Rust builds with their own
toolchains and are not reproducible yet; every installer is listed in
SHA256SUMS, so its integrity is checkable.
calabi-desktop-windows-x64-setup.exe — the calabi daemon it carries is a
different matter: since v1.7.1 that is the released calabi-windows-amd64
binary itself, byte for byte, so the program you actually run is covered by the
manifest even though the installer around it is not.
calabi-desktop-macos-universal.pkg — here the daemon is NOT covered either.
It is a universal (arm64 + x86_64) binary produced by lipo, so it is not byte
identical to either released macOS archive. It is also neither code-signed nor
notarized yet: macOS will stop it on first open, and the download page says how
to proceed. If you would rather not trust a build you did not make, the client
is in this repository — build it.
calabi-android.apk — built from apps/client-android and apps/client/mobile
in this repository, but not reproducibly yet: the Go core records the absolute
directory it was built in, so the same commit built elsewhere differs. It is
signed with the release key; check the signer before installing:
apksigner verify --print-certs calabi-android.apk
# certificate SHA-256 digest: 5800bc9938dd507b1a4fb7cc497f9b3ce50e3c20655fdcb5383aac4049f97d23Components
calabi— the client (tunnels + mesh + the local console on :7400)calabi-edge— the data plane:role: tunnelfor tunnels,role: mesh
for the mesh relay,role: bothfor the twocalabi-coord— the coordinator, every device's identity: invites, device
registry, addresses, ACLs; names the edge and signs the grants it accepts
calabi-coord and calabi-edge together are your server
(deploy/server).
Docker images (amd64 + arm64): calabinet/calabi, calabinet/calabi-edge,
calabinet/calabi-coord. The binary inside each is the released linux one,
byte for byte.