Liftbridge on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of Liftbridge on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Liftbridge provides lightweight, fault-tolerant message streams by implementing a durable, replicated log directly on top of NATS. It gives Kafka-style semantics — durable streams, consumer groups, at-least-once delivery, message replay, log compaction — without the operational weight of a JVM-based streaming platform, and its canonical client (go-liftbridge) is Go, not Java.
Liftbridge can run its own NATS server embedded in the same process, so a single node is a complete, self-contained streaming system with no external broker to install or operate. This image runs exactly that: one VM, one Liftbridge process, one embedded NATS server bound to loopback for Liftbridge's own internal use.
Release note. Liftbridge went quiet between 2022 and 2025. It has since been revived by new maintainers (Basekick Labs) with the v26.01.1 calendar-versioned release (January 2026) and active commits since — this image tracks that current release.
Secure by default. Liftbridge's own protocol supports exactly one authentication mechanism: mutual TLS (there is no username/password or token concept at the Liftbridge layer — this is upstream's own design, not a cloudimg limitation). On first boot, this image generates a brand-new certificate authority, a server certificate, and a client certificate, all unique to this VM and never baked into the image. A client without a certificate signed by this VM's own CA cannot complete a TLS handshake against the streaming API at all. The embedded NATS server is bound to 127.0.0.1 only, so it is never reachable from outside the VM — the mutual-TLS-protected Liftbridge API is the only externally exposed port.
What is included:
- Liftbridge 26.01.1, the official
linux_amd64release binary, run under systemd asliftbridge.service - An embedded NATS server (loopback-only), Liftbridge's own internal transport
lift-cli— a small command-line client cloudimg built on the officialgo-liftbridgelibrary, since upstream Liftbridge ships no CLI of its own (only client libraries)- A fresh per-VM certificate authority, server certificate and client certificate, generated on first boot
- Per-VM credentials written once to
/root/liftbridge-credentials.txt(0600 root:root) - Upstream's optional telemetry beacon disabled — this image makes no unexpected outbound calls
Prerequisites
- Active Azure subscription, SSH public key, VNet + subnet in target region
- Subscription to the Liftbridge listing on Azure Marketplace
- Network Security Group rules allowing TCP 22 (admin) and TCP 9292 (the Liftbridge streaming API) from whichever networks should be able to publish and consume
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM). Liftbridge is a single Go binary with an embedded NATS server — this is a genuinely light footprint, with headroom to spare.
Step 1: Deploy from the Azure Portal
- Open the Liftbridge offer on the Azure Marketplace and choose Get It Now, then Create.
- Select your subscription, resource group and region, and choose the
Standard_B2ssize. - Provide your SSH public key for the
azureuseraccount. - Allow inbound TCP 22 and TCP 9292 in the Network Security Group, then create the VM.
Step 2: Deploy from the Azure CLI
az vm create \
--resource-group my-rg \
--name liftbridge-01 \
--image <liftbridge-marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
Step 3: First boot
On the first boot of every VM, liftbridge-firstboot.service generates a unique certificate authority plus a server certificate (covering this VM's public IP, its private IP, and localhost) and a client certificate, renders the Liftbridge config with them, starts liftbridge.service, and then runs a real create-stream / publish / subscribe round trip over the freshly-minted mutual TLS connection to prove the node actually works before it finishes — a broken certificate or a broken server means first boot fails loud rather than silently reporting done. First boot completes in well under a minute; give it a moment before you connect.
Step 4: Confirm the daemon is running
SSH in as azureuser and confirm the service is active, the version, and the listening surface:
systemctl is-active liftbridge liftbridge-firstboot
liftbridge --version
ss -tln
sudo stat -c '%a %U:%G %n' /root/liftbridge-credentials.txt
You should see active for both services, version 26.01.1, a listener on :9292 (Liftbridge's mutual-TLS API, reachable from anywhere) and 127.0.0.1:4222 (the embedded NATS server, loopback-only), and the credentials file at 0600 root:root.

Step 5: Create a stream and publish a message
Liftbridge ships no CLI of its own, so this image includes lift-cli — a small wrapper cloudimg built on the official go-liftbridge client library — at /usr/local/bin/lift-cli. Every command needs the three files first boot generated:
sudo lift-cli create \
-addr 127.0.0.1:9292 \
-ca /etc/liftbridge/tls/ca-cert.pem \
-cert /etc/liftbridge/tls/client-cert.pem \
-key /etc/liftbridge/tls/client-key.pem \
-stream demo-orders -subject demo.orders
sudo lift-cli publish \
-addr 127.0.0.1:9292 \
-ca /etc/liftbridge/tls/ca-cert.pem \
-cert /etc/liftbridge/tls/client-cert.pem \
-key /etc/liftbridge/tls/client-key.pem \
-stream demo-orders -message 'order-42 placed at 2026-08-09T01:00:00Z'
create attaches a new durable stream to the NATS subject demo.orders; publish writes one message to it and reports the offset it landed at.

Step 6: Consume the message back
Read the stream from the beginning — this is the "consume it back" half of the round trip, and because Liftbridge is a durable log, not a queue, reading it again returns the same message rather than draining it:
sudo lift-cli subscribe \
-addr 127.0.0.1:9292 \
-ca /etc/liftbridge/tls/ca-cert.pem \
-cert /etc/liftbridge/tls/client-cert.pem \
-key /etc/liftbridge/tls/client-key.pem \
-stream demo-orders -start earliest -count 1

-start earliest reads from the beginning of the log; use -start latest to pick up only new messages, or -count 0 to stream continuously.
Step 7: Mutual TLS is enforced — there is no open broker
Two proofs that the streaming API is not reachable without a valid per-VM client certificate: a plaintext connection gets no data back (the server only ever speaks TLS), and a client presenting no certificate at all is rejected outright by the TLS handshake itself.
timeout 5 bash -c 'exec 3<>/dev/tcp/127.0.0.1/9292 && printf "" >&3 && head -c1 <&3' || true
sudo lift-cli metadata -addr 127.0.0.1:9292 -insecure || true
(Both commands are expected to fail — that failure is the proof. || true just keeps your shell's exit status clean; the rejection message printed above is the evidence.)

Step 8: Connect from your own machine
The certificate authority, server certificate and client certificate all live under /etc/liftbridge/tls/ on the VM, root-owned. Pull the CA certificate and the client certificate + key down to wherever you will run lift-cli or your own go-liftbridge client from — sudo cat over SSH, since scp alone can't read a root-only file as azureuser:
ssh azureuser@<vm-ip> "sudo cat /etc/liftbridge/tls/ca-cert.pem" > ca-cert.pem
ssh azureuser@<vm-ip> "sudo cat /etc/liftbridge/tls/client-cert.pem" > client-cert.pem
ssh azureuser@<vm-ip> "sudo cat /etc/liftbridge/tls/client-key.pem" > client-key.pem
Then connect to the VM's public IP on port 9292 from your own machine:
lift-cli metadata -addr <vm-ip>:9292 -ca ca-cert.pem -cert client-cert.pem -key client-key.pem
Step 9: Mint an additional client certificate (optional)
Every consumer or producer of this stream needs its own client certificate signed by the same per-VM CA — the CA's private key is kept on the VM specifically so you can issue more without redeploying:
sudo openssl genrsa -out /etc/liftbridge/tls/app2-key.pem 2048
sudo openssl req -new -key /etc/liftbridge/tls/app2-key.pem -out /tmp/app2.csr -subj "/CN=app2"
sudo openssl x509 -req -in /tmp/app2.csr \
-CA /etc/liftbridge/tls/ca-cert.pem -CAkey /etc/liftbridge/tls/ca-key.pem -CAcreateserial \
-out /etc/liftbridge/tls/app2-cert.pem -days 3650 -sha256
sudo rm -f /tmp/app2.csr
Step 10: Review your credentials
sudo cat /root/liftbridge-credentials.txt
This file records the resolved host/port and the paths to the CA, client certificate and client key generated for this VM — everything lift-cli (or your own client) needs to connect.
Step 11: Security recommendations
- Restrict TCP 9292 in the Network Security Group to the networks that genuinely need to publish or consume, if you are not intentionally exposing it broadly.
- Treat
/etc/liftbridge/tls/ca-key.pemas sensitive — anyone who can read it can mint a trusted client certificate. It is root-only (0600) by default. - Keep the OS patched. The image ships fully updated and with unattended security upgrades enabled.
- The embedded NATS server (
127.0.0.1:4222) is intentionally loopback-only and has nothing to configure — it is Liftbridge's own internal transport, never a customer-facing endpoint.
Step 12: Support and Licensing
Liftbridge is free and open source software distributed under the Apache License 2.0. This image bundles the official upstream release binary unmodified; lift-cli is cloudimg's own small addition, built on the official go-liftbridge client library (also Apache-2.0). Your use of Liftbridge is governed by its license. cloudimg is not affiliated with, endorsed by, or sponsored by the Liftbridge project, its maintainers, or Basekick Labs.
cloudimg images include 24/7 support. If you need help deploying or configuring Liftbridge on Azure, contact us.
Deploy on Azure
Find this image on the Azure Marketplace and deploy in minutes.
Need Help?
Email support@cloudimg.co.uk and our team will help you get up and running.