Apache Cassandra 5.0 LTS on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of Apache Cassandra 5.0 LTS on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Cassandra 5.0 is the latest long-term-support release of the wide-column NoSQL database originally developed at Facebook and now an Apache top-level project — the engine behind Netflix, Apple, Instagram, and Discord.
The image installs Cassandra 5.0 from the official debian.cassandra.apache.org/50x APT suite (which redirects to the Apache JFrog Artifactory mirror). The Cassandra daemon runs under OpenJDK 17 with PasswordAuthenticator enabled by default — no anonymous access. At first boot, cassandra-firstboot.service rotates the default cassandra/cassandra superuser password to a per-VM 32-char random password, creates a cloudimg superuser, creates the cloudimg keyspace (SimpleStrategy, RF=1), and writes both passwords to /stage/scripts/cassandra-credentials.log (mode 0600 root only).
Important — cqlsh Python compatibility on Ubuntu 24.04. The cqlsh shell that ships with Cassandra 5.0 requires Python 3.6–3.11; Ubuntu 24.04 noble ships Python 3.12. The image solves this by installing Python 3.11 from the deadsnakes PPA and creating an isolated cassandra-driver venv at /opt/cqlsh-venv. Use that Python interpreter for any cassandra-driver work — see the examples below.
What is included:
-
Apache Cassandra 5.0 LTS (latest 5.0.x at build time, 5.0.8) from the official Apache APT suite
-
OpenJDK 17 JRE headless (Cassandra 5.0 requires Java 11+; 17 recommended for performance)
-
cassandra.servicesystemd unit auto-starting on boot -
cassandra-firstboot.servicesystemd oneshot that rotates thecassandrasuperuser password, creates thecloudimgsuperuser, creates thecloudimgkeyspace, and writes credentials to/stage/scripts/cassandra-credentials.log(mode 0600 root only) -
Python 3.11 + cassandra-driver venv at
/opt/cqlsh-venvfor cqlsh-equivalent CLI work -
PasswordAuthenticatorandCassandraAuthorizerenabled;CassandraRoleManagerfor password-backed access control -
Default cluster name
cloudimg-cassandra(single-node by default; customers reconfigure for multi-node) -
CQL native protocol listener on TCP 9042
-
JMX bound to localhost:7199 only
-
Data directory
/var/lib/cassandra(NOT/mnt— Azure mounts the ephemeral resource disk at/mntand that location does not survive SIG capture) -
Ubuntu 24.04 LTS base with latest security patches applied at build time
-
Azure Linux Agent for seamless cloud integration and SSH key injection
-
24/7 cloudimg support with guaranteed 24 hour response SLA
Prerequisites
-
An active Azure subscription
-
A subscription to the Apache Cassandra 5.0 on Ubuntu 24.04 listing on Azure Marketplace
-
An SSH public key for VM authentication
-
A virtual network and subnet in the target region
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for development and small single-node deployments. Production multi-node clusters should use Standard_D4s_v5 or larger with attached Premium SSD data disks for the /var/lib/cassandra/data directory. Cassandra is heap-sensitive — give the JVM at least 4 GB and leave a similar amount for the page cache.
Step 1: Deploy from the Azure Portal
Navigate to Marketplace in the Azure Portal, search for Cassandra 5.0, select the cloudimg publisher entry, and click Create.
On the Networking tab attach a network security group that allows inbound TCP 22 from your management IP range and TCP 9042 from your application VMs. Do not expose port 9042 to the public internet — even with PasswordAuthenticator enabled, brute-force attacks against weak passwords are a real risk. For multi-node clusters, also open TCP 7000 (intra-node, unencrypted) or 7001 (TLS) and 7199 (JMX) between cluster member private IPs.
Click Review + create, wait for validation, then Create. Deployment takes around three minutes (Cassandra's first-boot service generates the keypair and waits for native transport on 9042).
Step 2: Deploy from the Azure CLI
RG="cassandra-prod"
LOCATION="eastus"
VM_NAME="cassandra-01"
ADMIN_USER="azureuser"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/cassandra-5-0-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create --resource-group "$RG" --name cass-vnet \
--address-prefix 10.97.0.0/16 --subnet-name cass-subnet --subnet-prefix 10.97.1.0/24
az network nsg create --resource-group "$RG" --name cass-nsg
az network nsg rule create --resource-group "$RG" --nsg-name cass-nsg \
--name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" \
--destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create --resource-group "$RG" --nsg-name cass-nsg \
--name allow-cql --priority 110 \
--source-address-prefixes 10.97.0.0/16 \
--destination-port-ranges 9042 --access Allow --protocol Tcp
az vm create \
--resource-group "$RG" --name "$VM_NAME" \
--image "$GALLERY_IMAGE_ID" \
--size Standard_B2s --storage-sku StandardSSD_LRS \
--admin-username "$ADMIN_USER" --ssh-key-values "$SSH_KEY" \
--vnet-name cass-vnet --subnet cass-subnet --nsg cass-nsg \
--public-ip-sku Standard
Step 3: Connect via SSH
ssh azureuser@<vm-ip>
cassandra.service will already be running and cassandra-firstboot.service will already have rotated the superuser password and created the cloudimg keyspace.
Step 4: Verify the Cassandra Service
sudo systemctl status cassandra.service --no-pager
Expected: active (running). Confirm the firstboot sentinel:
sudo test -f /var/lib/cloudimg/cassandra-firstboot.done && echo FIRSTBOOT_DONE
Confirm the CQL listener is bound on port 9042:
sudo ss -tln | grep 9042

Step 5: Retrieve the cassandra and cloudimg Passwords
The cassandra superuser password and the cloudimg user password have been rotated on this specific virtual machine and written to a root-only file. Read them with:
sudo cat /stage/scripts/cassandra-credentials.log
You will see lines similar to:
CASSANDRA_USER=cassandra
CASSANDRA_PASSWORD=<CASSANDRA_PASSWORD>
CLOUDIMG_USER=cloudimg
CLOUDIMG_PASSWORD=<CLOUDIMG_PASSWORD>
CLOUDIMG_KEYSPACE=cloudimg
LISTEN_PORT=9042
CLUSTER_NAME=cloudimg-cassandra
Store these in your secret store and rotate as needed via ALTER USER cassandra WITH PASSWORD '<new-password>';.

Step 6: Connect from the VM with cassandra-driver
cqlsh ships with Cassandra but requires Python 3.6–3.11; Ubuntu 24.04 noble has Python 3.12. The image installs Python 3.11 from the deadsnakes PPA and creates an isolated venv at /opt/cqlsh-venv with the cassandra-driver Python library — use that for all cluster work from the VM.
CASS_PASS=$(sudo grep '^CASSANDRA_PASSWORD=' /stage/scripts/cassandra-credentials.log | cut -d= -f2-)
/opt/cqlsh-venv/bin/python << PY
from cassandra.cluster import Cluster
from cassandra.auth import PlainTextAuthProvider
ap = PlainTextAuthProvider(username='cassandra', password='${CASS_PASS}')
session = Cluster(['127.0.0.1'], port=9042, auth_provider=ap).connect()
for row in session.execute('SELECT release_version, cluster_name FROM system.local'):
print(row.release_version, row.cluster_name)
PY
Expected output: 5.0.8 cloudimg-cassandra.
Step 7: Round-trip Test as cloudimg
The cloudimg superuser and the cloudimg keyspace are ready to use from first boot. Run a CREATE / INSERT / SELECT round-trip as the cloudimg user:
CLOUD_PASS=$(sudo grep '^CLOUDIMG_PASSWORD=' /stage/scripts/cassandra-credentials.log | cut -d= -f2-)
/opt/cqlsh-venv/bin/python << PY
from cassandra.cluster import Cluster
from cassandra.auth import PlainTextAuthProvider
ap = PlainTextAuthProvider(username='cloudimg', password='${CLOUD_PASS}')
session = Cluster(['127.0.0.1'], port=9042, auth_provider=ap).connect()
session.execute("CREATE TABLE IF NOT EXISTS cloudimg.users (id int PRIMARY KEY, name text)")
session.execute("INSERT INTO cloudimg.users (id, name) VALUES (1, 'alice')")
row = session.execute("SELECT name FROM cloudimg.users WHERE id = 1").one()
print(row.name)
session.execute("DROP TABLE cloudimg.users")
PY
Expected output: alice. The cloudimg user has full access to the cloudimg keyspace and can create / drop tables, insert / select / update / delete rows.

Step 8: Connect from a Remote Application
From any host inside the same virtual network with cassandra-driver installed (Python, Java, Go, Node.js, .NET, Rust, etc.), connect on port 9042 with the cassandra or cloudimg credentials. Example Python:
pip install cassandra-driver
from cassandra.cluster import Cluster
from cassandra.auth import PlainTextAuthProvider
ap = PlainTextAuthProvider(username='cloudimg', password='<CLOUDIMG_PASSWORD>')
cluster = Cluster(['<vm-private-ip>'], port=9042, auth_provider=ap)
session = cluster.connect('cloudimg')
session.execute("INSERT INTO orders (id, sku, qty) VALUES (uuid(), 'WIDGET-1', 4)")
Do not open port 9042 to the public internet without TLS termination at a reverse proxy or VPN. Cassandra's native protocol does not encrypt by default; for production, configure client-to-node SSL via client_encryption_options in cassandra.yaml.
Step 9: Server Components
| Component | Path |
|---|---|
| Cassandra binary | /usr/sbin/cassandra |
cqlsh (Python ≤3.11 only) |
/usr/bin/cqlsh |
| cassandra-driver Python venv | /opt/cqlsh-venv/bin/python |
| Configuration | /etc/cassandra/cassandra.yaml |
| JVM options | /etc/cassandra/jvm-server.options, /etc/cassandra/jvm17-server.options |
| Logback config | /etc/cassandra/logback.xml |
| Data directory | /var/lib/cassandra/data |
| Commit log | /var/lib/cassandra/commitlog |
| Saved caches | /var/lib/cassandra/saved_caches |
| Hints | /var/lib/cassandra/hints |
| Logs | /var/log/cassandra/system.log |
| Systemd unit | /lib/systemd/system/cassandra.service |
| Firstboot script | /usr/local/sbin/cassandra-firstboot.sh |
| Firstboot service | /etc/systemd/system/cassandra-firstboot.service |
| Credentials file | /stage/scripts/cassandra-credentials.log (mode 0600) |
| Firstboot sentinel | /var/lib/cloudimg/cassandra-firstboot.done |
Inspect the running version:
/usr/sbin/cassandra -v
Step 10: Managing the Cassandra Service
Status:
sudo systemctl status cassandra.service --no-pager
Stop / Start / Restart:
sudo systemctl stop cassandra.service
sudo systemctl start cassandra.service
sudo systemctl restart cassandra.service
View the system log:
sudo tail -f /var/log/cassandra/system.log
Inspect the node status (single-node by default, multi-node if you've added peers):
sudo nodetool status
Run a flush + compaction:
sudo nodetool flush
sudo nodetool compact
Repair (essential for multi-node clusters; safe single-node no-op):
sudo nodetool repair

Step 11: Scale to a Multi-Node Cluster
The image ships configured as a single-node cluster (cluster_name: 'cloudimg-cassandra', listening on 127.0.0.1). To convert into a real cluster:
- Stop Cassandra on every prospective node:
sudo systemctl stop cassandra - On each node, edit
/etc/cassandra/cassandra.yaml: listen_address: <node-private-ip>(or comment out and uselisten_interface)rpc_address: <node-private-ip>or0.0.0.0to listen on allseed_provider.parameters.seeds: "<node1-private-ip>,<node2-private-ip>"endpoint_snitch: GossipingPropertyFileSnitch(default isSimpleSnitch— fine for single AZ)- Wipe
/var/lib/cassandra/data/system/peers*so nodes don't carry stale peer info:sudo rm -rf /var/lib/cassandra/data/system/peers* - Start the seed node first, then the rest one-by-one with 30s gap between starts
- Verify cluster:
sudo nodetool status— all nodes should appearUN(Up Normal) - Update the
cloudimgkeyspace replication:ALTER KEYSPACE cloudimg WITH replication = {'class': 'NetworkTopologyStrategy', 'datacenter1': 3}; - Run a full repair:
sudo nodetool repair --full
For multi-DC or large-scale clusters, refer to the official Cassandra operations guide at cassandra.apache.org/doc/.
Step 12: Troubleshooting
cassandra.service won't start
- Check the system log:
sudo tail -100 /var/log/cassandra/system.log - Confirm the JVM has enough memory:
free -hshould show >= 2 GB free - Check for port conflicts:
sudo ss -tln | grep -E ':(9042|7000|7199)'
pyo3_runtime.PanicException when running cqlsh
- This is the Python 3.12 ABI mismatch documented in the Overview. Use
/opt/cqlsh-venv/bin/pythonwith cassandra-driver instead — see Step 6.
Authentication fails with rotated password
- Confirm the credentials file is current:
sudo cat /stage/scripts/cassandra-credentials.log - Check the auth keyspace exists:
sudo nodetool describering system_auth - If you've forgotten the password, you can disable auth temporarily in
cassandra.yaml(authenticator: AllowAllAuthenticator), restart, set a new password, and re-enable
Cassandra never bound port 9042 during firstboot
- The default Cassandra startup takes 30–90s on a Standard_B2s. If firstboot times out, check
sudo journalctl -u cassandra-firstboot.serviceandsudo tail -100 /var/log/cassandra/system.log - Larger heap (
MAX_HEAP_SIZEin/etc/cassandra/jvm-server.options) requires more startup time
Data dir filling up /var/lib/cassandra
- Cassandra's commit log + SSTables grow without bound on heavy write workloads
- Attach a Premium SSD data disk and bind-mount it to
/var/lib/cassandra/data(or changedata_file_directoriesincassandra.yaml) - Run
sudo nodetool compactto merge SSTables, but be aware compactions are I/O-heavy
Step 13: Security Recommendations
-
Rotate the cassandra superuser password immediately after deployment — see Step 5 for the auto-rotated one and use
ALTER USERto change -
Restrict NSG so port 9042 is only reachable from your application VMs and admin networks; never expose to the public internet
-
Enable client-to-node SSL in
cassandra.yaml(client_encryption_options.enabled: true) for any cross-VM connection -
Enable internode encryption (
server_encryption_options.internode_encryption: all) for multi-node clusters -
Restrict the cassandra superuser to admin operations only — application code should connect as
cloudimg(a regular superuser scoped to the cloudimg keyspace) or a least-privilege role you create -
Enable audit logging (
audit_logging_options.enabled: true) for compliance-sensitive workloads -
Back up
/var/lib/cassandra/dataregularly vianodetool snapshot+ Azure Files or Blob storage upload -
Patch the OS monthly with
sudo apt-get update && sudo apt-get upgrade && sudo rebooton each cluster node (rolling, one node at a time)
Step 14: Support and Licensing
Apache Cassandra is licensed under the Apache License 2.0. There is no per-node, per-CPU, or per-GB fee for any Cassandra component or for the upstream protocol.
cloudimg provides commercial support for this image separately from the upstream project.
-
Email: support@cloudimg.co.uk
-
Website: www.cloudimg.co.uk
-
Support hours: 24/7 with guaranteed 24 hour response SLA
Deploy on Azure
Launch Apache Cassandra 5.0 on Ubuntu 24.04 with 24/7 support from cloudimg.
View on Marketplace
Need Help?
Our support team is available 24/7.
support@cloudimg.co.uk