How to Install Apache Cassandra on Rocky Linux 10
Apache Cassandra is a distributed wide-column NoSQL database built for massive write throughput, linear horizontal scaling and no single point of failure. It powers workloads such as messaging, IoT telemetry, user activity feeds and recommendation stores. This guide installs Apache Cassandra 5.0 on Rocky Linux 10 using the official Apache RPM repository, tunes the operating system, secures the node, opens the right firewall ports, handles SELinux, and then shows how to grow the node into a 3-node cluster.
Table of Contents
- Cassandra in 60 Seconds
- Choosing a Cassandra Version
- Lab Architecture
- Prerequisites
- Step 1: Update the System and Set the Hostname
- Step 2: Install Java
- Step 3: Tune Linux for Cassandra
- Step 4: Add the Apache Cassandra Repository
- Step 5: Install Cassandra
- Step 6: Configure cassandra.yaml
- Step 7: Start Cassandra and Verify
- Step 8: Firewall and SELinux
- Step 9: Enable Authentication
- Step 10: First Keyspace, Table and Query
- Expanding to a 3-Node Cluster
- Backup and Maintenance
- Useful Files and Commands
- Troubleshooting
- FAQ
- Conclusion
1. Cassandra in 60 Seconds
Cassandra has no primary node. Every node is equal, data is spread across the cluster by a hash of the partition key, and each row is stored on several nodes according to the replication factor. You choose, per query, how many replicas must respond (the consistency level), which lets you trade consistency against latency and availability.
| SQL concept | Cassandra equivalent | Note |
|---|---|---|
| Database / schema | Keyspace | Holds replication settings |
| Table | Table | Designed around your queries, not around entities |
| Primary key | Partition key + clustering columns | Partition key decides where data lives; clustering columns decide sort order within it |
| JOIN | Not supported | Denormalize data instead |
| Transactions | Limited (lightweight transactions) | Not a general ACID engine |
| Scaling | Add nodes | Roughly linear, no downtime |
Cassandra rewards query-first data modelling. If your workload needs joins, ad-hoc analytics and strong multi-row transactions, a relational database is a better fit.
2. Choosing a Cassandra Version
| Aspect | Cassandra 4.1 | Cassandra 5.0 |
|---|---|---|
| Java support | 8 and 11 | 11 and 17 |
| Key new features | Improved configuration and guardrails | Storage-Attached Indexes (SAI), vector data type and vector search, Unified Compaction Strategy, trie-based memtables and SSTables, new CQL functions |
| RPM repository path | 41x | 50x |
| Recommended for | Existing clusters that are not yet upgrading | New installations |
This guide uses the 5.0 line with OpenJDK 17. If Apache has released a newer stable line by the time you read this, check the download page and adjust the repository path and Java version accordingly.
3. Lab Architecture
Rocky Linux 10 host(s)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Client / App โโโบ :9042 (CQL native transport) โ
โ โ โ
โ โโโโโโโโโโโโผโโโโโโโโโโโโ โ
โ โ Apache Cassandra 5.0โ JVM: OpenJDK 17 โ
โ โ โโ commitlog โ /var/lib/cassandra/commitlog
โ โ โโ data (SSTables) โ /var/lib/cassandra/data โ
โ โ โโ gossip :7000 โโโโโบ other nodes (:7000) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโ โ
โ JMX :7199 (localhost only) โโโ nodetool โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
3-node target: node1 (seed) โโโโบ node2 (seed) โโโโบ node3
same cluster_name, same datacenter, RF = 3
4. Prerequisites
| Requirement | Recommendation |
|---|---|
| OS | Rocky Linux 10 (fresh install) |
| CPU | 4 vCPU minimum for a lab; 8 or more for production. Rocky Linux 10 expects a modern x86-64 CPU baseline (x86-64-v3), so very old CPUs and some VM CPU models may not be supported |
| RAM | 8 GB minimum for a lab; 16 to 32 GB or more for production nodes |
| Disk | SSD or NVMe on XFS; put the commit log on a separate device in production |
| Network | Static IP, working DNS or /etc/hosts entries, and NTP time sync |
| Access | A user with sudo privileges |
5. Step 1: Update the System and Set the Hostname
sudo dnf -y update
sudo dnf -y install chrony curl wget vim tar
sudo hostnamectl set-hostname cass01.example.local
sudo systemctl enable --now chronyd
chronyc tracking
Cassandra depends on synchronized clocks because it uses timestamps to resolve conflicting writes. Confirm chrony reports a small offset before continuing.
6. Step 2: Install Java
sudo dnf -y install java-17-openjdk-headless
java -version
If several Java versions are installed, select the right one:
sudo alternatives --config java
7. Step 3: Tune Linux for Cassandra
These settings avoid the most common production problems.
Disable swap
sudo swapoff -a
sudo sed -i '/\sswap\s/ s/^/#/' /etc/fstab
free -h
Kernel parameters
sudo tee /etc/sysctl.d/99-cassandra.conf > /dev/null <<'EOF'
vm.max_map_count = 1048575
vm.swappiness = 1
net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl = 10
EOF
sudo sysctl --system
Resource limits
The Cassandra RPM normally installs /etc/security/limits.d/cassandra.conf. Check it after installation (Step 5) and make sure it contains at least:
cassandra - memlock unlimited
cassandra - nofile 100000
cassandra - nproc 32768
cassandra - as unlimited
Transparent Huge Pages
Set THP to a non-aggressive mode to avoid latency spikes:
echo madvise | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/defrag
These runtime changes do not survive a reboot. Make them persistent with a small systemd unit, a tuned profile or the transparent_hugepage=madvise kernel argument.
8. Step 4: Add the Apache Cassandra Repository
sudo tee /etc/yum.repos.d/cassandra.repo > /dev/null <<'EOF'
[cassandra]
name=Apache Cassandra baseurl=https://redhat.cassandra.apache.org/50x/ gpgcheck=1 repo_gpgcheck=1 gpgkey=https://downloads.apache.org/cassandra/KEYS EOF sudo dnf clean all sudo dnf makecache
50x is the 5.0 release line. Use 41x for 4.1.
Rocky Linux 10 note: RHEL 10 family systems apply a stricter system-wide cryptographic policy that rejects SHA-1 signatures by default. If
dnf makecachefails while importing the Cassandra signing key, see the first two rows of the troubleshooting table before changing any policy.
9. Step 5: Install Cassandra
sudo dnf -y install cassandra
Review what the package created:
rpm -ql cassandra | head -30
cat /etc/security/limits.d/cassandra.conf
id cassandra
Reload systemd so it picks up the service definition:
sudo systemctl daemon-reload
Do not start Cassandra yet. Settings such as cluster_name should be set before the first start, because changing it later on a node that already has data requires extra steps.
10. Step 6: Configure cassandra.yaml
Back up the default file, then edit it:
sudo cp /etc/cassandra/conf/cassandra.yaml /etc/cassandra/conf/cassandra.yaml.orig
sudo vim /etc/cassandra/conf/cassandra.yaml
Set or verify these keys for a single-node lab (replace 10.10.10.11 with the node’s own IP):
cluster_name: 'BCK Cassandra Cluster'
num_tokens: 16
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "10.10.10.11:7000"
listen_address: 10.10.10.11 # internode communication
rpc_address: 10.10.10.11 # client (CQL) connections
# broadcast_rpc_address: only needed with NAT or when rpc_address is 0.0.0.0
endpoint_snitch: GossipingPropertyFileSnitch
native_transport_port: 9042
storage_port: 7000
Key points:
| Setting | Why it matters |
|---|---|
| cluster_name | Must be identical on all nodes; hard to change after first start |
| seeds | Contact points for gossip discovery; not a “master” |
| listen_address / rpc_address | Use a real IP. Never leave localhost on a node that other machines must reach |
| endpoint_snitch | GossipingPropertyFileSnitch is the recommended production choice and reads the datacenter and rack from a properties file |
| num_tokens | Leave the default for the release unless you have a reason to change it |
Set the datacenter and rack names:
sudo tee /etc/cassandra/conf/cassandra-rackdc.properties > /dev/null <<'EOF'
dc=dc1
rack=rack1
EOF
Choose these names carefully. Changing a datacenter name after data exists is disruptive.
Heap size
By default Cassandra sizes its heap automatically, which is acceptable for a lab. For production, set it explicitly in /etc/cassandra/conf/jvm-server.options (for example -Xms8G and -Xmx8G, with both values equal) and follow the current sizing guidance for your release. Leave the rest of the machine’s memory for the operating system page cache.
11. Step 7: Start Cassandra and Verify
sudo systemctl enable --now cassandra
sudo systemctl status cassandra --no-pager
The first start can take a minute or two. Watch the log until you see that the node is listening for CQL clients:
sudo tail -f /var/log/cassandra/system.log
Then check the cluster state:
nodetool status
Expected output shows one node with status UN (Up / Normal):
Datacenter: dc1
===============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns Host ID Rack
UN 10.10.10.11 110 KiB 16 100.0% xxxxxxxx... rack1
Confirm the CQL shell connects:
cqlsh 10.10.10.11 9042
If cqlsh fails with a Python error on Rocky Linux 10, jump to the troubleshooting table.
12. Step 8: Firewall and SELinux
Ports
| Port | Purpose | Expose to |
|---|---|---|
| 9042 | CQL native transport (clients) | Application servers only |
| 7000 | Internode communication | Other Cassandra nodes only |
| 7001 | Internode with TLS | Other Cassandra nodes only |
| 7199 | JMX (nodetool) | Localhost only; do not open |
# Client access from the application subnet
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.10.20.0/24" port protocol="tcp" port="9042" accept'
# Internode traffic from the Cassandra subnet
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.10.10.0/24" port protocol="tcp" port="7000" accept'
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.10.10.0/24" port protocol="tcp" port="7001" accept'
sudo firewall-cmd --reload
sudo firewall-cmd --list-rich-rules
SELinux
Keep SELinux in enforcing mode. With the default RPM paths (/var/lib/cassandra, /var/log/cassandra), nothing extra is normally required.
getenforce
sudo ausearch -m avc -ts recent # look for denials after start-up
If you place data on a separate mount such as /data/cassandra, give it the correct ownership and let SELinux relabel it:
sudo mkdir -p /data/cassandra/{data,commitlog,saved_caches,hints}
sudo chown -R cassandra:cassandra /data/cassandra
sudo restorecon -Rv /data/cassandra
Then point data_file_directories, commitlog_directory, saved_caches_directory and hints_directory in cassandra.yaml to the new paths. If you still see AVC denials, review them with ausearch and create a targeted policy rather than disabling SELinux. See Docker on Rocky Linux 10 with SELinux for the same troubleshooting mindset.
13. Step 9: Enable Authentication
A default Cassandra install accepts anyone. Turn on password authentication and authorization.
Edit /etc/cassandra/conf/cassandra.yaml:
authenticator: PasswordAuthenticator
authorizer: CassandraAuthorizer
Restart the node:
sudo systemctl restart cassandra
Log in with the built-in superuser, which starts as cassandra / cassandra:
cqlsh -u cassandra -p cassandra 10.10.10.11
Immediately create your own superuser, then remove the default account’s privileges:
CREATE ROLE bckadmin WITH PASSWORD = 'ChangeMe_UseALongPassword!'
AND LOGIN = true AND SUPERUSER = true;
-- reconnect as bckadmin, then neutralize the default account
ALTER ROLE cassandra WITH PASSWORD = 'A_Long_Random_Unused_Password'
AND SUPERUSER = false AND LOGIN = false;
Create a least-privilege role for an application:
CREATE ROLE appuser WITH PASSWORD = 'AppStrongPassword!' AND LOGIN = true;
GRANT SELECT ON KEYSPACE shop TO appuser;
GRANT MODIFY ON KEYSPACE shop TO appuser;
Set the replication of the system_auth keyspace to match your cluster. On a single node this is already fine; in a multi-node cluster raise it so logins survive a node failure:
ALTER KEYSPACE system_auth WITH replication =
{'class': 'NetworkTopologyStrategy', 'dc1': 3};
Then run nodetool repair system_auth on each node.
For production, also enable TLS for client-to-node and node-to-node traffic (
client_encryption_optionsandserver_encryption_optionsincassandra.yaml) using certificates from your CA.
14. Step 10: First Keyspace, Table and Query
CREATE KEYSPACE IF NOT EXISTS shop
WITH replication = {'class': 'NetworkTopologyStrategy', 'dc1': 1}
AND durable_writes = true;
USE shop;
CREATE TABLE IF NOT EXISTS orders_by_customer (
customer_id uuid,
order_time timestamp,
order_id uuid,
total decimal,
status text,
PRIMARY KEY ((customer_id), order_time, order_id)
) WITH CLUSTERING ORDER BY (order_time DESC, order_id ASC);
INSERT INTO orders_by_customer (customer_id, order_time, order_id, total, status)
VALUES (11111111-1111-1111-1111-111111111111, toTimestamp(now()), uuid(), 250000, 'PAID');
SELECT * FROM orders_by_customer
WHERE customer_id = 11111111-1111-1111-1111-111111111111
LIMIT 10;
Notice the design: the table is shaped around one query (“latest orders for a customer”). The partition key customer_id keeps each customer’s orders together, and the clustering columns sort them newest first.
| Rule of thumb | Reason |
|---|---|
| Design one table per query pattern | No joins, so denormalize |
| Keep partitions reasonably sized | Huge partitions hurt latency and repairs |
Avoid ALLOW FILTERING in production | It forces expensive scans |
Use NetworkTopologyStrategy even for a single datacenter | Makes future expansion easier |
| Use replication factor 3 in production clusters | Survives a node failure with quorum reads and writes |
15. Expanding to a 3-Node Cluster
Prepare three Rocky Linux 10 hosts with identical OS tuning, Java and Cassandra installation (Steps 1 to 5). Example addresses: 10.10.10.11, 10.10.10.12, 10.10.10.13.
On every node, set:
cluster_name: 'BCK Cassandra Cluster' # identical everywhere
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "10.10.10.11:7000,10.10.10.12:7000"
listen_address: <this node's own IP>
rpc_address: <this node's own IP>
endpoint_snitch: GossipingPropertyFileSnitch
And set dc=dc1 with rack=rack1, rack2 and rack3 in cassandra-rackdc.properties on each node respectively. Open ports 7000 and 7001 between all three nodes.
Start the nodes one at a time, waiting for each to show UN before starting the next:
# node1 first, then node2, then node3
sudo systemctl enable --now cassandra
nodetool status
If a node was started earlier with different settings and holds test data, stop it and clear
/var/lib/cassandra/data,commitlog,saved_cachesandhintsbefore joining it to the cluster.
After all nodes join, raise the replication of your keyspaces to 3:
ALTER KEYSPACE shop WITH replication = {'class': 'NetworkTopologyStrategy', 'dc1': 3};
nodetool repair shop # run on each node after changing replication
| Check | Command | Healthy result |
|---|---|---|
| Cluster membership | nodetool status | All nodes UN |
| Schema agreement | nodetool describecluster | One schema version |
| Gossip state | nodetool gossipinfo | All peers NORMAL |
| Pending work | nodetool tpstats | No growing pending or blocked queues |
16. Backup and Maintenance
Snapshots
A snapshot is a fast, hard-link based copy of SSTables:
nodetool snapshot -t before_change shop
nodetool listsnapshots
nodetool clearsnapshot -t before_change
Snapshots live inside the data directory on the same disk, so copy them to remote storage for real protection. A restore means placing the snapshot files back into the table directory (or using sstableloader) and refreshing, and it should be rehearsed on a spare cluster.
Routine care
| Task | Command | Frequency |
|---|---|---|
| Repair (anti-entropy) | nodetool repair -pr | Regularly, within the gc_grace_seconds window |
| Node health | nodetool status, nodetool info | Daily or via monitoring |
| Table statistics | nodetool tablestats shop | When tuning |
| Compaction activity | nodetool compactionstats | When disk or latency looks odd |
| Log review | /var/log/cassandra/system.log and debug.log | Continuously via log shipping |
Repairs are essential in Cassandra because they reconcile replicas that missed writes. Schedule them, or use a repair scheduler tool.
Upgrade and node removal
sudo dnf upgrade cassandra # read release notes first; upgrade one node at a time
nodetool drain # before stopping a node for maintenance
nodetool decommission # gracefully remove a live node from the cluster
17. Useful Files and Commands
| Item | Location or command |
|---|---|
| Main config | /etc/cassandra/conf/cassandra.yaml |
| JVM options | /etc/cassandra/conf/jvm-server.options (and jvm17-server.options) |
| Datacenter and rack | /etc/cassandra/conf/cassandra-rackdc.properties |
| Data directory | /var/lib/cassandra/data |
| Commit log | /var/lib/cassandra/commitlog |
| Main log | /var/log/cassandra/system.log |
| Service control | `sudo systemctl status |
| CQL shell | cqlsh <ip> 9042 -u <user> |
| Version | cassandra -v or nodetool version |
| Cluster state | nodetool status |
| Flush memtables | nodetool flush |
18. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
dnf makecache or install fails importing the Cassandra GPG key | RHEL 10 family crypto policy rejects SHA-1 signatures used by the key | Verify the key fingerprint against Apache’s published KEYS file. Prefer installing from the tarball or a manually verified RPM. As a last resort and temporarily, relax the policy (update-crypto-policies --set DEFAULT:SHA1), install, then revert with update-crypto-policies --set DEFAULT |
Repository metadata signature check (repo_gpgcheck) fails | Same policy issue on the repository metadata | Same as above, or set repo_gpgcheck=0 only after verifying downloaded packages by checksum and signature |
cqlsh fails with No module named 'asyncore' or a driver import error | Rocky Linux 10 ships Python 3.12, and older bundled drivers depend on modules removed from Python | Update to a Cassandra release whose bundled cqlsh supports Python 3.12, or point cqlsh to another supported Python (for example through the CQLSH_PYTHON variable), or run cqlsh from a container |
Unsupported major.minor or Java startup error | Wrong Java version for the Cassandra release | Install java-17-openjdk-headless for 5.0 and select it with alternatives --config java |
Service shows active but cqlsh says connection refused | Cassandra still starting, or rpc_address bound to another IP | Wait and watch system.log; confirm rpc_address and use that IP with cqlsh |
Cannot start node if snitch's data center (X) differs from previous data center (Y) | Datacenter name changed after first start | Restore the original name in cassandra-rackdc.properties, or clear data on a fresh node |
Saved cluster name Test Cluster != configured name | cluster_name changed after the first start | Revert the name, or wipe the node’s data directories if it holds no data you need |
Node stays DN (down) in nodetool status | Gossip port blocked, wrong seed or clock problem | Check firewalld on port 7000, verify seeds, and check chronyc tracking |
| Nodes cannot see each other | listen_address set to localhost or wrong IP | Use each node’s real private IP and restart |
| Permission denied errors in the log | Wrong ownership or SELinux label after moving directories | chown -R cassandra:cassandra, then restorecon -Rv; inspect with ausearch -m avc |
JVM cannot lock memory or too many open files | Limits not applied | Check /etc/security/limits.d/cassandra.conf, then restart via systemd |
| Heavy GC pauses and timeouts | Heap too large or too small, swap active | Set equal -Xms/-Xmx, disable swap, review gc.log |
| Read timeouts under load | Large partitions, tombstones, or ALLOW FILTERING queries | Review the data model; use nodetool tablestats and tablehistograms |
| Disk fills unexpectedly | Old snapshots, compaction backlog | nodetool listsnapshots and clearsnapshot; check compactionstats |
| Login fails after enabling authentication | Wrong role or system_auth replicated to too few nodes | Use the default superuser to recover; raise system_auth replication and repair |
19. FAQ
Is Apache Cassandra free?
Yes. It is open source under the Apache 2.0 licence. Commercial distributions and managed services exist if you want support.
Can I run Cassandra on a single node?
Yes, for development and learning. Production deployments normally use at least three nodes with a replication factor of 3.
Which Java version does Cassandra 5.0 use?
Java 11 or 17. This guide uses OpenJDK 17, which is available in the Rocky Linux 10 repositories.
Cassandra or MongoDB?
Cassandra excels at very high write volume, multi-node availability and predictable scaling for query-designed tables. MongoDB offers a more flexible document model with richer ad-hoc querying. See Install MongoDB on Rocky Linux 10.2 for the alternative.
Does Cassandra support vector search?
Version 5.0 introduced a vector data type and vector search using Storage-Attached Indexes, which makes it usable for some similarity search workloads. For a comparison with dedicated engines, read Vector Databases Explained.
Can Cassandra store time series data?
Yes, and it is widely used for it, though you must design partitions carefully (for example bucketing by time). For a comparison with dedicated time series databases, see InfluxDB vs Prometheus vs TimescaleDB.
Why do I have to run repairs?
Cassandra favours availability, so a replica can miss a write while it is down. Repairs reconcile differences between replicas and must run regularly to keep data consistent and to prevent deleted data from reappearing.
20. Conclusion
You now have Apache Cassandra 5.0 running on Rocky Linux 10 with a tuned operating system, a configured cassandra.yaml, authentication, firewalld and SELinux handled correctly, a first data model and a path to a 3-node cluster. Before going to production, add TLS, set an explicit heap size, schedule repairs and backups, set up monitoring for nodetool metrics and GC, and rehearse a node replacement.





