Ceph is a distributed storage system that spreads data across many servers and disks, replicates it, and recovers automatically when a disk or node fails. A single Ceph cluster can provide block devices (RBD), a shared POSIX file system (CephFS) and S3-compatible object storage (RGW). In this tutorial you will deploy a three-node cluster on Ubuntu 24.04 with cephadm, the official deployment tool, add disks as OSDs, and try each of the three storage interfaces.
Prerequisites
To follow this guide you need three servers running Ubuntu 24.04 LTS, for example CubePath VPS or dedicated servers, each with:
- At least 4 vCPU and 8 GB of RAM. Each OSD daemon aims to use about 4 GB of memory by default, and the monitor and manager daemons need memory too.
- At least one additional, completely empty disk (no partitions, no file system, no LVM) for Ceph. Ceph will not use the system disk.
- A private network between the nodes. This guide uses
10.0.0.11,10.0.0.12and10.0.0.13for the hostsceph1,ceph2andceph3. - Root access over SSH from
ceph1to the other two nodes, because cephadm manages the hosts asrootover SSH.
Replace the host names and addresses with your own throughout.
How the cluster is laid out
cephadm runs every Ceph daemon in a container managed by systemd. The main daemon types are:
| Daemon | Role | In this cluster |
|---|---|---|
| MON (monitor) | Holds the cluster map and forms a quorum | 3, one per node |
| MGR (manager) | Orchestration, dashboard, metrics | 2, one active and one standby |
| OSD | Stores data on one disk each | One per empty disk |
| MDS | Metadata for CephFS | 2, created in Step 7 |
| RGW | S3 and Swift gateway | 1, created in Step 8 |
With three nodes, pools keep three copies of each object (one per host) and stay writable if one node goes down.
Step 1 - Preparing all three nodes
Run the commands in this step on every node. First, make the host names resolve on each node by adding them to /etc/hosts:
sudo nano /etc/hosts
10.0.0.11 ceph1
10.0.0.12 ceph2
10.0.0.13 ceph3
Set each node's short host name to match, for example on the first node:
sudo hostnamectl set-hostname ceph1
cephadm needs a container runtime, LVM for the OSDs and synchronized clocks, because monitors refuse to form a quorum when clocks drift. Install them:
sudo apt update
sudo apt install podman lvm2 chrony
Check that the clock is synchronized:
timedatectl | grep synchronized
System clock synchronized: yes
Allow all traffic between the nodes on the private network. Ceph uses ports 3300 and 6789 for monitors and the range 6800 to 7300 for OSDs and other daemons, so allowing the whole subnet is simpler and keeps the public interface closed:
sudo ufw allow from 10.0.0.0/24
Finally, identify the empty disk that Ceph will use:
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
vda 253:0 0 40G 0 disk
├─vda1 253:1 0 39G 0 part /
...
vdb 253:16 0 100G 0 disk
Here vdb has no partitions or mount points, so it is available. Your disk name may differ.
Step 2 - Installing cephadm and bootstrapping the first node
On ceph1 only, install cephadm and the Ceph command-line tools from the Ubuntu repositories. On Ubuntu 24.04 these are Ceph 19 (Squid), and cephadm will deploy the matching container images:
sudo apt install cephadm ceph-common
Bootstrap the cluster. This creates the first monitor and manager on ceph1, generates the cluster SSH key and the admin keyring, and starts the dashboard:
sudo cephadm bootstrap --mon-ip 10.0.0.11
The command takes a few minutes while it pulls the container image. It ends with the dashboard credentials:
Ceph Dashboard is now available at:
URL: https://ceph1:8443/
User: admin
Password: 5xk0q2l7ab
Enabling client.admin keyring and conf on hosts with "admin" label
...
Bootstrap complete.
Save the password; you will be asked to change it on first login. Check the cluster from the host:
sudo ceph -s
cluster:
id: 2c6b7e7a-9a1f-11f1-8f4e-525400a1b2c3
health: HEALTH_WARN
OSD count 0 < osd_pool_default_size 3
services:
mon: 1 daemons, quorum ceph1 (age 2m)
mgr: ceph1.kxqvbz(active, since 1m)
osd: 0 osds: 0 up, 0 in
The warning is expected: there are no OSDs yet.
Step 3 - Adding the other hosts
cephadm connects to the other nodes as root using the public key it generated in /etc/ceph/ceph.pub. Copy it to ceph2 and ceph3:
sudo ssh-copy-id -f -i /etc/ceph/ceph.pub root@ceph2
sudo ssh-copy-id -f -i /etc/ceph/ceph.pub root@ceph3
If password login for root is disabled, append the contents of /etc/ceph/ceph.pub to /root/.ssh/authorized_keys on each node instead.
Add the hosts to the cluster, with the _admin label so they also receive the configuration and admin keyring:
sudo ceph orch host add ceph2 10.0.0.12 --labels _admin
sudo ceph orch host add ceph3 10.0.0.13 --labels _admin
sudo ceph orch host ls
HOST ADDR LABELS STATUS
ceph1 10.0.0.11 _admin
ceph2 10.0.0.12 _admin
ceph3 10.0.0.13 _admin
3 hosts in cluster
cephadm automatically deploys additional monitors and a standby manager on the new hosts. After a minute or two, confirm there are three monitors in quorum:
sudo ceph mon stat
e3: 3 mons at {ceph1=[v2:10.0.0.11:3300/0,v1:10.0.0.11:6789/0],ceph2=[...],ceph3=[...]} ... quorum 0,1,2 ceph1,ceph2,ceph3
Step 4 - Creating OSDs
List the disks that cephadm sees on all hosts. Only disks with AVAILABLE set to Yes can become OSDs:
sudo ceph orch device ls
HOST PATH TYPE DEVICE ID SIZE AVAILABLE REFRESHED REJECT REASONS
ceph1 /dev/vdb hdd 100G Yes 2m ago
ceph2 /dev/vdb hdd 100G Yes 1m ago
ceph3 /dev/vdb hdd 100G Yes 1m ago
Tell the orchestrator to turn every available disk into an OSD. This also applies to disks you add later:
sudo ceph orch apply osd --all-available-devices
If you prefer to choose disks explicitly, add them one at a time instead with sudo ceph orch daemon add osd ceph1:/dev/vdb.
After a few minutes the OSDs are up. Check the tree and the cluster health:
sudo ceph osd tree
sudo ceph -s
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 0.29306 root default
-3 0.09769 host ceph1
0 hdd 0.09769 osd.0 up 1.00000 1.00000
-5 0.09769 host ceph2
1 hdd 0.09769 osd.1 up 1.00000 1.00000
-7 0.09769 host ceph3
2 hdd 0.09769 osd.2 up 1.00000 1.00000
cluster:
health: HEALTH_OK
A disk that shows Insufficient space or Has partitions as the reject reason still contains old data. After double-checking that it is the right disk, wipe it with sudo ceph orch device zap ceph2 /dev/vdb --force.
Step 5 - Accessing the dashboard
The dashboard listens on port 8443 of the active manager. Rather than opening it to the internet, reach it through an SSH tunnel from your workstation:
ssh -L 8443:10.0.0.11:8443 your_user@ceph1_public_ip
Then open https://localhost:8443 in your browser, accept the self-signed certificate and log in as admin with the password from Step 2. If the manager fails over to another node, sudo ceph mgr services shows the current dashboard URL.
Step 6 - Using block storage with RBD
RBD provides virtual disks stored in Ceph, used by Proxmox, OpenStack, Kubernetes and plain Linux hosts. Create a pool for them and initialize it. The placement group autoscaler is on by default, so you do not need to choose a PG count:
sudo ceph osd pool create rbd
sudo rbd pool init rbd
Create a 10 GB image and map it as a block device on ceph1:
sudo rbd create --size 10G rbd/test-disk
sudo rbd map rbd/test-disk
/dev/rbd0
Format and mount it like any other disk:
sudo mkfs.ext4 /dev/rbd0
sudo mkdir -p /mnt/rbd
sudo mount /dev/rbd0 /mnt/rbd
df -h /mnt/rbd
Filesystem Size Used Avail Use% Mounted on
/dev/rbd0 9.8G 24K 9.3G 1% /mnt/rbd
When you are done testing, unmount and unmap it with sudo umount /mnt/rbd && sudo rbd unmap /dev/rbd0.
Step 7 - Creating a CephFS file system
CephFS is a shared file system that many clients can mount at the same time. The ceph fs volume create command creates the data and metadata pools and asks the orchestrator to deploy MDS daemons:
sudo ceph fs volume create cephfs
sudo ceph fs status cephfs
cephfs - 0 clients
======
RANK STATE MDS ACTIVITY DNS INOS DIRS CAPS
0 active cephfs.ceph2.hqzvkt Reqs: 0 /s 10 13 12 0
POOL TYPE USED AVAIL
cephfs.cephfs.meta metadata 96.0k 94.9G
cephfs.cephfs.data data 0 94.9G
STANDBY MDS
cephfs.ceph3.jmwpfa
Create a client key that can only access this file system, instead of using the admin key:
sudo ceph fs authorize cephfs client.fsuser / rw | sudo tee /etc/ceph/ceph.client.fsuser.keyring
sudo chmod 600 /etc/ceph/ceph.client.fsuser.keyring
Mount it with the kernel client. The [email protected]=/ syntax means user fsuser, the cluster in /etc/ceph/ceph.conf, file system cephfs, path /:
sudo mkdir -p /mnt/cephfs
sudo mount -t ceph [email protected]=/ /mnt/cephfs
df -h /mnt/cephfs
Filesystem Size Used Avail Use% Mounted on
10.0.0.11:6789,...:/ 95G 0 95G 0% /mnt/cephfs
To mount it on another machine, install ceph-common there and copy /etc/ceph/ceph.conf and the fsuser keyring to its /etc/ceph directory.
Step 8 - Providing S3 object storage with RGW
The RADOS Gateway exposes Ceph through the S3 API. Deploy one gateway on ceph1 listening on port 8080:
sudo ceph orch apply rgw s3 --placement="ceph1" --port=8080
sudo ceph orch ps --daemon-type rgw
NAME HOST PORTS STATUS REFRESHED AGE
rgw.s3.ceph1.xbmwqd ceph1 *:8080 running (30s) 20s ago 31s
Create an S3 user. radosgw-admin runs inside the Ceph container, which cephadm shell opens for you:
sudo cephadm shell -- radosgw-admin user create --uid=appuser --display-name="App user"
The JSON output contains the credentials:
"keys": [
{
"user": "appuser",
"access_key": "Q3V7J5N0H2X8KZ1LAB4C",
"secret_key": "b7c2...your_secret_key"
}
],
Test the endpoint with the AWS CLI or any S3 client. For example, with s3cmd from the Ubuntu repositories:
sudo apt install s3cmd
s3cmd --access_key=your_access_key --secret_key=your_secret_key \
--host=10.0.0.11:8080 --host-bucket=10.0.0.11:8080 --no-ssl mb s3://test-bucket
Bucket 's3://test-bucket/' created
For production use, put the gateway behind a reverse proxy or load balancer with TLS rather than exposing plain HTTP.
Troubleshooting
ceph -s shows clock skew detected. A node's clock drifted. Check chronyc tracking on each node and make sure chrony is running and can reach its time servers.
A host shows as Offline in ceph orch host ls. cephadm cannot SSH to it. Run sudo ceph cephadm check-host ceph2 to see the exact error, usually a missing key in /root/.ssh/authorized_keys or a firewall rule.
HEALTH_WARN with pools have too many placement groups or pool has no application enabled. The first is informational while the autoscaler adjusts. For the second, enable the application with sudo ceph osd pool application enable <pool> rbd (or cephfs, rgw).
An OSD is down. Find the host with sudo ceph osd tree and check the daemon state with sudo ceph orch ps --daemon-type osd. Then, on that host, read its log with sudo cephadm logs --name osd.1.
Conclusion
You now have a three-node Ceph cluster managed by cephadm, with three-way replication across hosts and working block, file and object interfaces. Next steps are adding more disks or nodes (the OSD service picks up new empty disks automatically), moving replication traffic to a dedicated network (the cluster_network option, easiest to set with --cluster-network at bootstrap), and wiring the rbd pool into Proxmox or Kubernetes through Ceph CSI.
