Streaming & Messaging Azure

Liftbridge on Ubuntu 24.04 on Azure User Guide

| Product: Liftbridge 26.01.1 on Ubuntu 24.04 LTS on Azure

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_amd64 release binary, run under systemd as liftbridge.service
  • An embedded NATS server (loopback-only), Liftbridge's own internal transport
  • lift-cli — a small command-line client cloudimg built on the official go-liftbridge library, 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

  1. Open the Liftbridge offer on the Azure Marketplace and choose Get It Now, then Create.
  2. Select your subscription, resource group and region, and choose the Standard_B2s size.
  3. Provide your SSH public key for the azureuser account.
  4. 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.

systemctl reports liftbridge and liftbridge-firstboot both active, liftbridge --version reports 26.01.1, ss shows a listener on 0.0.0.0:9292 and one on 127.0.0.1:4222 only, and the credentials file is 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.

lift-cli create reports OK created stream demo-orders, and lift-cli publish reports OK published to demo-orders at offset 0

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

lift-cli subscribe reads back offset 0 with the exact message published in the previous step, twice in a row, proving the log is durable rather than a drain-once queue

-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.)

a plaintext connection to port 9292 returns nothing at all, and lift-cli with -insecure (no client certificate) is rejected with a TLS handshake error, while the real per-VM client certificate connects successfully

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.pem as 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.