Redis Sentinel monitors a Redis primary and its replicas, and when the primary stops responding, the Sentinels agree on the failure, promote a replica and tell clients where the new primary is. In this tutorial you will build a three-server Redis setup on Ubuntu 24.04 with one primary, two replicas and a Sentinel on every server, then trigger a failover and connect an application that follows it automatically.
Prerequisites
To follow this tutorial, you need:
- Three servers running Ubuntu 24.04 LTS, for example three CubePath VPS, connected by a private network. This guide uses these addresses:
| Hostname | Private IP | Initial role |
|---|---|---|
| redis1 | 10.0.0.11 | Primary + Sentinel |
| redis2 | 10.0.0.12 | Replica + Sentinel |
| redis3 | 10.0.0.13 | Replica + Sentinel |
- A non-root user with
sudoprivileges on each server. - UFW enabled on each server, with SSH allowed.
Replace the IP addresses with your own throughout the guide.
NoteYou need at least three Sentinels on three separate machines. With two, a single failed server leaves no majority to authorize a failover.
How Sentinel decides to fail over
Each Sentinel pings the primary. When a Sentinel gets no valid reply for down-after-milliseconds, it marks the primary as subjectively down (+sdown). When the number of Sentinels that agree reaches the quorum (2 in this guide), the primary is objectively down (+odown). One Sentinel is then elected leader by a majority of all Sentinels, promotes the best replica and reconfigures the others. When the old primary comes back, Sentinel turns it into a replica of the new one.
Step 1 - Installing Redis and Sentinel
Run this step on all three servers. Ubuntu packages Redis server and Sentinel separately:
sudo apt update
sudo apt install redis-server redis-sentinel
Both services start right away with their default configuration. Confirm the versions:
redis-server --version
redis-sentinel --version
Redis server v=7.0.15 sha=00000000:0 malloc=jemalloc-5.3.0 bits=64 build=...
Redis server v=7.0.15 sha=00000000:0 malloc=jemalloc-5.3.0 bits=64 build=...
Step 2 - Opening the firewall on the private network
Redis listens on port 6379 and Sentinel on port 26379. Allow both only from the private subnet, on every server:
sudo ufw allow from 10.0.0.0/24 to any port 6379 proto tcp
sudo ufw allow from 10.0.0.0/24 to any port 26379 proto tcp
Check the rules:
sudo ufw status
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
6379/tcp ALLOW 10.0.0.0/24
26379/tcp ALLOW 10.0.0.0/24
Step 3 - Configuring the Redis primary and replicas
Every node needs the same password in two directives: requirepass protects the node itself, and masterauth lets it authenticate to the primary when it is a replica. Because any node can become primary after a failover, set both on all three servers. Generate a strong password once and reuse it everywhere:
openssl rand -base64 32
On redis1, open the configuration:
sudo nano /etc/redis/redis.conf
Find the existing bind line and add the private IP, then set the password directives (they are commented out by default). Replace your_redis_password with the generated password:
bind 127.0.0.1 -::1 10.0.0.11
requirepass your_redis_password
masterauth your_redis_password
On redis2 and redis3, make the same changes with each server's own IP in bind, and add a replicaof line pointing to the primary:
bind 127.0.0.1 -::1 10.0.0.12
requirepass your_redis_password
masterauth your_redis_password
replicaof 10.0.0.11 6379
Restart Redis on all three servers:
sudo systemctl restart redis-server
To avoid putting the password on the command line, export it in the REDISCLI_AUTH variable, which redis-cli reads automatically:
export REDISCLI_AUTH='your_redis_password'
Check replication from redis1:
redis-cli info replication
# Replication
role:master
connected_slaves:2
slave0:ip=10.0.0.12,port=6379,state=online,offset=420,lag=0
slave1:ip=10.0.0.13,port=6379,state=online,offset=420,lag=0
...
Write a key on the primary and read it on a replica to confirm data flows:
redis-cli set sentinel:test ok
redis-cli -h 10.0.0.12 get sentinel:test
"ok"
Step 4 - Configuring Sentinel
Run this step on all three servers; the Sentinel configuration is identical everywhere. Open the file installed by the package:
sudo nano /etc/redis/sentinel.conf
Find the existing sentinel monitor line and the related mymaster lines, and set them to the following values. Add sentinel auth-pass right after sentinel monitor:
sentinel monitor mymaster 10.0.0.11 6379 2
sentinel auth-pass mymaster your_redis_password
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
What each line does:
sentinel monitor mymaster 10.0.0.11 6379 2: watch the primary at that address under the namemymaster, with a quorum of 2.auth-pass: the password Sentinel uses to talk to the Redis nodes.down-after-milliseconds 5000: consider a node down after 5 seconds without a valid reply. The default is 30 seconds.failover-timeout 60000: time limit for a failover attempt, and the wait before retrying one.parallel-syncs 1: resynchronize replicas with the new primary one at a time, so the others keep serving reads.
Sentinel rewrites this file at runtime to store the discovered replicas, the other Sentinels and the current primary, so the file must stay writable by the redis user. The package already sets the right ownership.
Restart Sentinel on all three servers:
sudo systemctl restart redis-sentinel
Step 5 - Verifying the Sentinel setup
Ask any Sentinel which node is the current primary:
redis-cli -p 26379 sentinel get-master-addr-by-name mymaster
1) "10.0.0.11"
2) "6379"
Check that the Sentinels found each other and can reach the quorum:
redis-cli -p 26379 sentinel ckquorum mymaster
OK 3 usable Sentinels. Quorum and failover authorization can be reached
You can also list what each Sentinel knows with sentinel replicas mymaster and sentinel sentinels mymaster. The Sentinel log confirms the discovery:
sudo tail -n 20 /var/log/redis/redis-sentinel.log
+monitor master mymaster 10.0.0.11 6379 quorum 2
+slave slave 10.0.0.12:6379 10.0.0.12 6379 @ mymaster 10.0.0.11 6379
+slave slave 10.0.0.13:6379 10.0.0.13 6379 @ mymaster 10.0.0.11 6379
+sentinel sentinel 3f1c... 10.0.0.12 26379 @ mymaster 10.0.0.11 6379
+sentinel sentinel 9a7e... 10.0.0.13 26379 @ mymaster 10.0.0.11 6379
Step 6 - Testing automatic failover
Simulate a crash of the primary. On redis1, stop Redis (leave Sentinel running):
sudo systemctl stop redis-server
On redis2, follow the Sentinel log:
sudo tail -f /var/log/redis/redis-sentinel.log
After about five seconds you see the failure detected, agreed and resolved:
+sdown master mymaster 10.0.0.11 6379
+odown master mymaster 10.0.0.11 6379 #quorum 3/2
+try-failover master mymaster 10.0.0.11 6379
+elected-leader master mymaster 10.0.0.11 6379
+selected-slave slave 10.0.0.12:6379 10.0.0.12 6379 @ mymaster 10.0.0.11 6379
+promoted-slave slave 10.0.0.12:6379 10.0.0.12 6379 @ mymaster 10.0.0.11 6379
+switch-master mymaster 10.0.0.11 6379 10.0.0.12 6379
Press Ctrl+C to stop following the log, then confirm the new primary:
redis-cli -p 26379 sentinel get-master-addr-by-name mymaster
1) "10.0.0.12"
2) "6379"
Now bring the old primary back on redis1:
sudo systemctl start redis-server
Within a few seconds Sentinel logs +convert-to-slave and redis1 starts replicating from redis2:
redis-cli info replication | grep -E 'role|master_host|master_link_status'
role:slave
master_host:10.0.0.12
master_link_status:up
For planned maintenance you do not need to stop anything: redis-cli -p 26379 sentinel failover mymaster promotes a replica in a controlled way.
Step 7 - Connecting a client through Sentinel
Applications must not hardcode the primary address. Instead, they ask the Sentinels for it and reconnect after a failover. Most Redis client libraries support this. Here is an example with the Python library on any machine in the private network:
sudo apt install python3-redis
nano sentinel_test.py
from redis.sentinel import Sentinel
PASSWORD = "your_redis_password"
sentinel = Sentinel(
[("10.0.0.11", 26379), ("10.0.0.12", 26379), ("10.0.0.13", 26379)],
socket_timeout=0.5,
)
primary = sentinel.master_for("mymaster", socket_timeout=0.5, password=PASSWORD)
replica = sentinel.slave_for("mymaster", socket_timeout=0.5, password=PASSWORD)
print("Primary:", sentinel.discover_master("mymaster"))
primary.set("app:counter", 1)
print("Read from replica:", replica.get("app:counter"))
Run it:
python3 sentinel_test.py
Primary: ('10.0.0.12', 6379)
Read from replica: b'1'
Writes always go to whichever node the Sentinels report as primary, so the application keeps working after the next failover without a configuration change.
Troubleshooting
- Replicas show
master_link_status:down: usually a missing or wrongmasterauth, or the primary'sbinddoes not include its private IP. Checksudo tail /var/log/redis/redis-server.logon the replica. sentinel ckquorumreports fewer than 3 Sentinels: port26379is blocked between servers, or the Sentinels were started before the primary was reachable. Check UFW, then restartredis-sentinel.- Failover never starts (
+sdownbut no+odown): the other Sentinels still reach the primary, so there is no agreement. This is expected when only one Sentinel has a network problem. - Sentinel does not start after editing the file: run
sudo journalctl -u redis-sentinel -n 50. A common cause is thatsentinel.confis no longer writable by theredisuser; fix it withsudo chown redis:redis /etc/redis/sentinel.conf.
Conclusion
You now have a Redis primary with two replicas and three Sentinels that detect a failed primary, promote a replica in a few seconds and return the old primary to service as a replica. Next, enable persistence (appendonly yes) according to how much data you can afford to lose, point your application's Redis client to the Sentinels instead of a single host, and add monitoring for the +switch-master event so you know when a failover happened. If you need more memory or write throughput than a single primary provides, look at Redis Cluster, which shards data across several primaries.
