How to Install Redis on Ubuntu 24.04 — Self-Hosted In-Memory Datastore
Redis is the in-memory datastore that powers everything from session caches and rate limiters to real-time leaderboards, pub/sub message buses, and job queues. Running it on your own VPS instead of renting AWS ElastiCache or Upstash cuts monthly costs by an order of magnitude and gives you full control over persistence, replication, and module loading. This guide walks you through a production-grade Redis install on Ubuntu 24.04, from the official packages.redis.io APT repository all the way through Sentinel HA and Cluster mode.
Looking for a fast path? A 2 vCPU / 4 GB RAM Starter VPS from VPS-Server.host runs Redis comfortably for caches up to approximately 3 GB of working set, for a flat EUR 7.99 per month with no per-request billing.
Table of Contents
What is Redis?
Redis is an open-source, in-memory data structure store that doubles as a database, cache, and message broker. Unlike traditional databases that treat everything as rows in tables, Redis exposes rich data structures natively: strings, lists, hashes, sets, sorted sets, streams, bitmaps, HyperLogLogs, and geospatial indexes. Every operation runs in RAM, which is why a single modest VPS routinely sustains hundreds of thousands of operations per second with sub-millisecond latency.
Typical Redis workloads include session stores for web applications, distributed rate limiters, idempotency keys, feature flags, pub/sub fanout for real-time notifications, job queues powering frameworks like Sidekiq, BullMQ, and Celery, short-lived OTP codes, geospatial proximity searches, and leaderboards for gaming and analytics. Redis also supports Lua scripting, transactions with MULTI/EXEC, server-assisted client-side caching, and streams for append-only event logs similar to a lightweight Kafka.
Why Self-Host Redis vs. ElastiCache or Upstash?
Managed Redis is convenient, but the pricing math gets ugly fast. Here is what a 4 GB working set costs across common providers as of 2026:
| Provider | Plan | Monthly Cost | Notes |
|---|---|---|---|
| AWS ElastiCache | cache.t4g.medium (3.09 GB) | ~55 USD | Plus data transfer, plus backups |
| AWS ElastiCache Serverless | 4 GB average | ~90 USD | Pay per GB-hour and per request |
| Upstash | Pro 10K (pay-as-you-go) | 30-150 USD | Per-request billing, 10k cmd/sec ceiling |
| Redis Cloud (Redis Ltd.) | Fixed 5 GB | ~75 USD | AWS/GCP multi-AZ |
| DigitalOcean Managed Redis | 4 GB standard | 60 USD | Single-region |
| VPS-Server.host Starter | 2 vCPU / 4 GB | 6.99 EUR | Unlimited commands, full root |
- No per-request billing -- run a 10k ops/sec rate limiter without watching a meter.
- Full configuration access -- tune
maxmemory-policy, load modules likeRedisJSONorRediSearch, set custom eviction strategies. - Data residency control -- keep EU customer data on an EU-hosted VPS for GDPR simplicity.
- No noisy-neighbor throttling -- managed Redis tiers frequently cap bandwidth and CPU burst; a dedicated VPS does not.
- Latency to your app -- colocate Redis on the same private network as your application servers for sub-millisecond round trips.
Prerequisites
Before starting, make sure you have:
- A VPS running Ubuntu 24.04 LTS with root or sudo access
- SSH access to the server
- At least 2 GB of RAM for a small cache (4 GB+ recommended for production)
- At least 10 GB of free disk space for RDB snapshots and AOF files
- A basic firewall plan -- Redis should never be exposed directly to the public internet without TLS + ACLs
Recommended Plan: Starter>
For caches up to approximately 3 GB of working set, a single Redis instance, and modest persistence, we recommend the Starter VPS:>
- 2 vCPU cores
- 4 GB RAM
- 50 GB NVMe SSD
- Unmetered bandwidth
- EUR 7.99/month>
For HA Sentinel (3 nodes) or Cluster (6 nodes), provision the same Starter plan multiplied across separate VPS instances. For caches above 8 GB of hot data, step up to a larger plan.
Connect to your server via SSH:
ssh root@your-server-ipStep 1: Update System Packages
sudo apt update && sudo apt upgrade -yInstall the prerequisites needed to add the Redis APT repository:
sudo apt install -y curl gpg lsb-release ca-certificatesStep 2: Add the Official redis.io APT Repository
Ubuntu's universe repository ships an older Redis that trails upstream by several minor versions. The official packages.redis.io repository maintained by Redis Ltd. delivers the current stable release (Redis 7.4+ at the time of writing) with timely security updates.
Import the Redis signing key:
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpgAdd the repository to your sources list:
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.listRefresh APT's package index:
sudo apt updateExpected output includes a line referring to packages.redis.io/deb noble InRelease.
Step 3: Install redis-server
sudo apt install -y redisThis pulls in redis-server, redis-tools (which provides redis-cli, redis-benchmark, and redis-check-aof), and the systemd unit. The installer starts Redis immediately on 127.0.0.1:6379.
Verify the version and service state:
redis-server --version
sudo systemctl status redis-serverExpected output:
Redis server v=7.4.1 sha=00000000:0 malloc=jemalloc-5.3.0 bits=64 build=...● redis-server.service - Advanced key-value store
Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-04-16 09:00:00 UTC; 5s agoQuick smoke test:
redis-cli pingExpected output:
PONGStep 4: Tune the Host Kernel
Two kernel settings materially affect Redis stability under load. Both throw warnings in the Redis log if left at defaults.
Disable Transparent Huge Pages
Transparent Huge Pages (THP) cause latency spikes during RDB background saves and AOF rewrites because fork() forces the kernel to copy large page tables.
Disable THP at runtime:
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/defragMake the change persist across reboots via a systemd unit:
sudo tee /etc/systemd/system/disable-thp.service > /dev/null <<EOF [Unit] Description=Disable Transparent Huge Pages Before=redis-server.service[Service] Type=oneshot ExecStart=/bin/sh -c "echo never > /sys/kernel/mm/transparent_hugepage/enabled && echo never > /sys/kernel/mm/transparent_hugepage/defrag" RemainAfterExit=yes
[Install] WantedBy=multi-user.target EOF
sudo systemctl enable --now disable-thp.service
Set vm.overcommit_memory
Redis relies on fork() to produce background snapshots. On low-memory systems, the default overcommit policy can cause fork failures during BGSAVE.
echo 'vm.overcommit_memory = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -pIncrease somaxconn
For high-connection workloads, raise the backlog so Redis does not drop incoming TCP connections:
echo 'net.core.somaxconn = 1024' | sudo tee -a /etc/sysctl.conf
sudo sysctl -pRestart Redis so it picks up the clean environment:
sudo systemctl restart redis-serverStep 5: Configure redis.conf
The main config lives at /etc/redis/redis.conf. Back up the original before editing:
sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.bak
sudo nano /etc/redis/redis.confApply or adjust these directives. Each one matters for production:
# Bind only to localhost unless other hosts need access. If you need
a private network interface, list its IP explicitly. Never bind 0.0.0.0
without TLS + ACLs.
bind 127.0.0.1 -::1Protected mode is an extra guard rail that refuses remote connections
when no password is set. Keep it on.
protected-mode yesRequire authentication. Use a long random string, at least 32 chars.
requirepass ChangeMeToALongRandomSecret_x9f82Ha7wZCap memory usage. When reached, eviction kicks in. Leave roughly 25%
of system RAM free for the OS, replication buffers, and fork copy-on-write.
maxmemory 3gbEviction policy for cache workloads. allkeys-lru evicts the least
recently used keys regardless of TTL. Use volatile-lru if you mix
cache and persistent keys in the same DB.
maxmemory-policy allkeys-lruHow many keys to sample when approximating LRU. 10 is the default,
raise to 20 for more accurate eviction at a small CPU cost.
maxmemory-samples 10Enable AOF persistence for near-zero data loss. Details in Step 7.
appendonly yes
appendfsync everysecKeep RDB snapshots as well. Default save points are fine for most loads.
save 3600 1
save 300 100
save 60 10000Log to syslog via systemd journal
loglevel notice
logfile ""TCP keepalive
tcp-keepalive 300Timeout for idle clients, 0 means never disconnect
timeout 0Client output buffer limits prevent a slow consumer from eating all RAM
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60Save and restart:
sudo systemctl restart redis-serverCheck the log for any startup warnings:
sudo journalctl -u redis-server -n 50 --no-pagerStep 6: Verify with redis-cli
Authenticate using the password you set:
redis-cli -a 'ChangeMeToALongRandomSecret_x9f82Ha7wZ'The(warning) Using a password with '-a'notice in shell history is expected. In production, useredis-cli --askpassinstead.
Inside the CLI, run a quick functional test:
127.0.0.1:6379> SET hello "world"
OK
127.0.0.1:6379> GET hello
"world"
127.0.0.1:6379> EXPIRE hello 60
(integer) 1
127.0.0.1:6379> TTL hello
(integer) 58
127.0.0.1:6379> INFO memory
Memory
used_memory:1082432
used_memory_human:1.03M
maxmemory:3221225472
maxmemory_human:3.00G
maxmemory_policy:allkeys-lru
...
127.0.0.1:6379> CONFIG GET maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-lru"
127.0.0.1:6379> DBSIZE
(integer) 1
127.0.0.1:6379> QUITRun a quick benchmark to confirm throughput:
redis-benchmark -a 'ChangeMeToALongRandomSecret_x9f82Ha7wZ' -t set,get -n 100000 -qExpected output on a Starter VPS:
SET: 92506.94 requests per second
GET: 103519.66 requests per secondStep 7: Persistence (RDB + AOF)
Redis offers two complementary persistence mechanisms. Production deployments almost always enable both.
RDB Snapshots
RDB writes compact point-in-time binary snapshots of the entire dataset. They are ideal for backups and fast restarts. The save directives you configured in Step 5 trigger snapshots based on write volume:
save 3600 1-- snapshot if at least 1 key changed in the last hoursave 300 100-- snapshot if at least 100 keys changed in the last 5 minutessave 60 10000-- snapshot if at least 10,000 keys changed in the last minute
/var/lib/redis/dump.rdb. You can trigger one manually with:redis-cli -a '...' BGSAVEAOF (Append-Only File)
AOF logs every write command as it happens, producing a replay journal at /var/lib/redis/appendonly.aof. Restart recovery replays the journal to rebuild state.
You already enabled AOF in Step 5. The critical tuning knob is appendfsync:
always-- fsync after every write. Safest, slowest (approximately 1/10 the throughput).everysec-- fsync once per second. Recommended default. Worst case you lose 1 second of writes.no-- let the OS flush when it decides. Fastest, least safe.
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mbBacking Up Redis Data
A simple cron-driven backup that ships the RDB to off-box storage:
sudo tee /etc/cron.daily/redis-backup > /dev/null <<'EOF'
#!/bin/bash
TS=$(date +%Y%m%d-%H%M%S)
DEST=/var/backups/redis
mkdir -p "$DEST"
redis-cli -a "$REDIS_PASSWORD" --no-auth-warning BGSAVE
sleep 5
cp /var/lib/redis/dump.rdb "$DEST/dump-$TS.rdb"
find "$DEST" -name 'dump-*.rdb' -mtime +7 -delete
EOF
sudo chmod 750 /etc/cron.daily/redis-backupStep 8: ACL Users
Redis 6 introduced ACLs, which replace the single shared password with named users and per-command permissions. Production deployments should define at least three users: an admin, an application user, and a read-only observer.
Inside redis-cli:
127.0.0.1:6379> ACL SETUSER app on >AppPasswordLongRandom_a7f2 ~app:* +@read +@write +@fast -@dangerous
OK
127.0.0.1:6379> ACL SETUSER readonly on >ReadPasswordLongRandom_b3k9 ~* +@read -@dangerous
OK
127.0.0.1:6379> ACL LIST
1) "user default on #... ~ & +@all"
2) "user app on #... ~app:* +@read +@write +@fast -@dangerous"
3) "user readonly on #... ~* +@read -@dangerous"
127.0.0.1:6379> ACL SAVE
OKKey points:
onenables the user;offdisables without deleting.>passwordsets a password.~app:restricts key access to keys matching the patternapp:.+@read +@writeallows the read and write command categories.-@dangerousblocks commands likeFLUSHALL,CONFIG, andDEBUG.
redis.conf:aclfile /etc/redis/users.aclComment out or remove the old requirepass once ACLs are active. Connect as a specific user:
redis-cli --user app --askpassStep 9: Enable TLS
If Redis needs to accept connections over the public internet or a shared network, TLS is mandatory. Redis supports native TLS since version 6.
Generate a self-signed CA and server certificate for internal use (use Let's Encrypt certificates for public endpoints):
sudo mkdir -p /etc/redis/tls cd /etc/redis/tlssudo openssl genrsa -out ca.key 4096 sudo openssl req -x509 -new -nodes -sha256 -key ca.key -days 3650 \ -subj "/CN=Redis Internal CA" -out ca.crt
sudo openssl genrsa -out redis.key 4096 sudo openssl req -new -key redis.key -subj "/CN=redis.internal" -out redis.csr sudo openssl x509 -req -in redis.csr -CA ca.crt -CAkey ca.key -CAcreateserial \ -out redis.crt -days 365 -sha256
sudo chown -R redis:redis /etc/redis/tls sudo chmod 600 /etc/redis/tls/*.key
Update redis.conf:
# Disable the plain-text port
port 0
Enable TLS on 6379
tls-port 6379
tls-cert-file /etc/redis/tls/redis.crt
tls-key-file /etc/redis/tls/redis.key
tls-ca-cert-file /etc/redis/tls/ca.crt
tls-auth-clients yes
tls-protocols "TLSv1.2 TLSv1.3"Restart and connect over TLS:
sudo systemctl restart redis-server
redis-cli --tls --cacert /etc/redis/tls/ca.crt --user app --askpass pingStep 10: Sentinel High Availability (3 Nodes)
Sentinel monitors a primary Redis instance, promotes a replica to primary on failure, and tells clients where the current primary lives. A production Sentinel deployment uses three nodes in a quorum so failover decisions survive the loss of any single node.
Topology
| Role | Hostname | Redis port | Sentinel port |
|---|---|---|---|
| Primary | redis-a.internal | 6379 | 26379 |
| Replica 1 | redis-b.internal | 6379 | 26379 |
| Replica 2 | redis-c.internal | 6379 | 26379 |
Configure Replication
On redis-b and redis-c, add to redis.conf:
replicaof redis-a.internal 6379
masterauth ChangeMeToALongRandomSecret_x9f82Ha7wZRestart both replicas. Verify replication on the primary:
redis-cli -a '...' INFO replicationExpected output includes:
role:master
connected_slaves:2
slave0:ip=...,port=6379,state=online
slave1:ip=...,port=6379,state=onlineConfigure Sentinel on All Three Nodes
Create /etc/redis/sentinel.conf on each node:
port 26379 daemonize no dir /var/lib/redis logfile /var/log/redis/sentinel.log
sentinel monitor mymaster redis-a.internal 6379 2 sentinel auth-pass mymaster ChangeMeToALongRandomSecret_x9f82Ha7wZ sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 60000 sentinel parallel-syncs mymaster 1
The 2 in sentinel monitor is the quorum: at least 2 Sentinels must agree that the primary is down before failover begins.
Create a systemd unit:
sudo tee /etc/systemd/system/redis-sentinel.service > /dev/null <<'EOF' [Unit] Description=Redis Sentinel After=network.target[Service] Type=simple User=redis Group=redis ExecStart=/usr/bin/redis-sentinel /etc/redis/sentinel.conf Restart=on-failure
[Install] WantedBy=multi-user.target EOF
sudo systemctl daemon-reload sudo systemctl enable --now redis-sentinel
Check Sentinel state on any node:
redis-cli -p 26379 SENTINEL MASTERS
redis-cli -p 26379 SENTINEL SENTINELS mymasterApplications should use a Sentinel-aware client (ioredis, redis-py, Lettuce) that discovers the current primary by querying Sentinel rather than hard-coding an IP.
Step 11: Redis Cluster Mode (6 Nodes)
When a single primary cannot hold the working set or sustain the write rate, Redis Cluster shards keys across multiple primaries using 16,384 hash slots. The minimum production topology is 6 nodes: 3 primaries + 3 replicas.
On each of the 6 VPS instances, add to redis.conf:
port 6379
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-require-full-coverage no
appendonly yesRestart all six instances. Then from any node, bootstrap the cluster:
redis-cli -a '...' --cluster create \
10.0.0.1:6379 10.0.0.2:6379 10.0.0.3:6379 \
10.0.0.4:6379 10.0.0.5:6379 10.0.0.6:6379 \
--cluster-replicas 1Expected output:
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 10.0.0.4:6379 to 10.0.0.1:6379
Adding replica 10.0.0.5:6379 to 10.0.0.2:6379
Adding replica 10.0.0.6:6379 to 10.0.0.3:6379
>>> Nodes configuration updated
[OK] All 16384 slots covered.Check cluster state:
redis-cli -a '...' -c CLUSTER NODES
redis-cli -a '...' -c CLUSTER INFOClients must use a cluster-aware driver (all modern Redis SDKs support cluster mode) that maintains a slot map and follows MOVED/ASK redirections.
Cluster caveats worth knowing:
- Multi-key operations only work when keys share a hash tag (keys in braces like
user:{42}:profile). - Cross-slot
MULTI/EXECtransactions are not supported. - A primary failing without a surviving replica takes its slot range offline unless
cluster-require-full-coverage nois set.
FAQ
Should I use the Ubuntu universe redis-server package or the redis.io repository?
Use the packages.redis.io repository. The Ubuntu universe package lags several minor versions behind upstream, which means you miss critical security patches, ACL improvements, and performance fixes. The official repository is maintained by Redis Ltd. and delivers the current stable release within hours of upstream publication, which matters both for CVE response and for access to new features like RESP3 and the ACL selector syntax.
What is the difference between RDB and AOF persistence?
RDB writes point-in-time binary snapshots of the dataset to disk at configurable intervals, producing a compact file that is fast to load on restart but can lose the writes between snapshots. AOF (Append-Only File) logs every write command as it happens, producing a replay-able journal that provides near-zero data loss with appendfsync everysec but grows larger and requires periodic rewrites. Most production deployments enable both and rely on AOF for recovery while keeping RDB for off-box backups.
Do I need Sentinel if I only have a single Redis node?
No. Sentinel provides automatic failover between a primary and one or more replicas. If your workload tolerates a few minutes of downtime during a VPS reboot or failure, a single well-configured node with AOF persistence is sufficient. Add Sentinel when you need sub-minute recovery and have at least three VPS instances available. Running Sentinel with fewer than three nodes defeats the quorum, and running it with only one Redis node provides no benefit because there is nothing to fail over to.
When should I use Redis Cluster instead of a single instance?
Use Cluster when your dataset exceeds the RAM of a single VPS, or when write throughput saturates a single node. Cluster shards keys across multiple primaries using hash slots, enabling horizontal scale. For caches under 30 GB and workloads under 100k ops/sec, a single node with replicas and Sentinel is simpler and equally reliable. The operational cost of Cluster (hash tags, cross-slot limitations, slot rebalancing during node adds/removes) is non-trivial, so do not reach for it prematurely.
How much does self-hosting Redis save versus AWS ElastiCache or Upstash?
For a 4 GB working set, a cache.t4g.medium ElastiCache node costs approximately 55 USD per month, and Upstash pay-per-request pricing typically runs 30 to 150 USD per month for medium workloads. A 4 GB VPS from VPS-Server.host costs 6.99 EUR per month and gives you unlimited commands, full configuration control, and no per-request billing. For anything above trivial usage, self-hosting saves 80 to 95 percent annually, with the trade-off that you manage upgrades and backups yourself.
Is Redis single-threaded, and does that limit performance?
The main command execution loop is single-threaded, which is precisely why Redis is fast and deterministic: no locking, no context switching inside the hot path. Since version 6, I/O threading offloads network reads and writes to multiple threads, and background tasks like AOF fsync and RDB snapshots run on dedicated threads. In practice a single Redis instance handles 100k to 1M operations per second on a modern VPS, which covers the vast majority of workloads. If you actually saturate a single core, the answer is usually Cluster or a multi-threaded alternative, not vertical scaling.
Should I consider Dragonfly or KeyDB instead of Redis?
Redis is the right default for compatibility, ecosystem, and documentation. Dragonfly is a modern multi-threaded drop-in replacement that delivers higher throughput on multi-core VPS plans but has a smaller operator ecosystem. KeyDB is a multi-threaded Redis fork with active-active replication. For the large majority of teams, start with Redis and migrate only if you have measured a specific bottleneck that a multi-threaded engine would actually solve.
Next Steps
- Explore alternative in-memory stores -- If Redis does not fit your workload, compare with Dragonfly (multi-threaded Redis-compatible), KeyDB (Redis fork with active-active), and Memcached (simpler, strings-only, no persistence).
- Add observability -- Export metrics with
redis_exporterfor Prometheus, and build Grafana dashboards for hit rate, evictions, and replication lag. - Harden the network -- Put Redis on a private VLAN or WireGuard mesh, so port 6379 never touches the public internet even with TLS.
- Plan capacity -- Monitor
used_memory_peakandevicted_keysweekly; if evictions climb, either raisemaxmemoryor revisit your TTL strategy. - Read the official docs -- The full reference at redis.io/docs covers every command, data structure, and deployment pattern.
Ready to self-host Redis?>
Spin up a Starter VPS in under 60 seconds -- EUR 7.99 per month, 2 vCPU, 4 GB RAM, 50 GB NVMe, unmetered bandwidth. Full root access, no per-request billing, no noisy neighbors.