By the end of this guide you'll have Redis installed, locked down with a password, and serving as a real cache for a web app or a bot. You'll see the exact config lines that matter, test everything from the command line, and wire up a small cache-aside example you can drop into your own project. This is written for anyone running their own server or VPS who wants their app to feel faster without rewriting it.
What Redis is and when a cache actually helps
Redis is an in memory data store. It keeps your data in RAM instead of on disk, which makes reads and writes extremely quick. People use it for caching, session storage, rate limiting, queues, and a lot more. For this guide we'll treat it as a cache, which is the most common starting point.
A cache helps when you have data that's expensive to produce but cheap to reuse. Think of a database query that joins five tables and takes 200 milliseconds, or an API call to an external service that you pay for per request. If the answer doesn't change every second, you can compute it once, stash it in Redis, and hand out the saved copy for the next few minutes. The slow work happens once instead of on every page load.
A cache does not help much when your data changes constantly, when every request needs a different unique answer, or when your database is already fast and barely used. Caching adds a moving part, so only add it where you can point at the slow thing it's fixing. For a Discord bot, good candidates are things like guild settings, role lookups, or results from a third party API. For a website, it's rendered pages, query results, or computed lists.
Step 1: Install Redis
These instructions are for Debian or Ubuntu, which covers most VPS setups. Update your package list and install the server package.
sudo apt update
sudo apt install redis-server -y
The package sets up a systemd service for you. Check that it's running.
sudo systemctl status redis-server
You should see something with active (running) in green. If it isn't running, start it and enable it so it comes back after a reboot.
sudo systemctl enable --now redis-server
Now confirm Redis actually answers. The redis-cli tool ships with the package.
redis-cli ping
The reply you want is a single line:
PONG
If you got PONG, Redis is alive. On RHEL, Rocky, or AlmaLinux the package is usually just redis and you'd run sudo dnf install redis then enable redis instead of redis-server. Everything after this point is the same.
Step 2: The config that matters
The main config file lives at /etc/redis/redis.conf. It's long, but only a handful of lines really matter for a cache. Open it with a text editor.
sudo nano /etc/redis/redis.conf
Here are the settings worth setting, with sensible values.
bind: who can reach Redis
By default Redis listens only on the loopback address, which means only programs on the same machine can connect. That's usually what you want. Make sure this line reads:
bind 127.0.0.1 -::1
If your app runs on the same server as Redis, leave it like this and you're safe by design. Do not change this to 0.0.0.0 unless you have a very specific reason and a firewall in front of it. We'll come back to this, because an open Redis is one of the easiest servers in the world to get hacked.
requirepass: set a password
Even on loopback, set a password. It's one line and it stops any other local user or stray process from poking at your data. Find the commented requirepass line and replace it with a real one.
requirepass S0me-L0ng-Random-String-Here
Use something long and random. You can generate one quickly:
openssl rand -base64 32
maxmemory and an eviction policy
This is the part people skip and then regret. Redis stores everything in RAM. If you never cap it, a busy cache can eat all the memory on your box and get killed by the kernel. Set a hard ceiling and tell Redis what to throw away when it hits that ceiling.
maxmemory 256mb
maxmemory-policy allkeys-lru
Pick a maxmemory value that leaves plenty of room for your other services. On a 1 GB VPS, 256mb is reasonable. The policy allkeys-lru means "when full, evict the least recently used keys." That's the right choice for a pure cache, because old unused entries get dropped to make space for fresh ones. If you store some keys you never want auto deleted, look at volatile-lru instead, which only evicts keys that have an expiry set.
Save the file (in nano that's Ctrl+O then Enter, then Ctrl+X) and restart Redis so the changes take effect.
sudo systemctl restart redis-server
Step 3: Test with redis-cli
Now that there's a password, a plain redis-cli ping will be rejected. Authenticate first. The cleanest way is to connect and then run AUTH.
redis-cli
127.0.0.1:6379> AUTH S0me-L0ng-Random-String-Here
OK
Let's prove the cache works by hand. Set a key, give it a 60 second expiry, read it back, and check how long it has left.
127.0.0.1:6379> SET greeting "hello from redis" EX 60
OK
127.0.0.1:6379> GET greeting
"hello from redis"
127.0.0.1:6379> TTL greeting
(integer) 54
The EX 60 part is the heart of caching. It tells Redis to forget this key after 60 seconds, so stale data cleans itself up. The TTL command shows the seconds remaining. Wait a minute, run GET greeting again, and you'll get (nil) because it expired. Type exit to leave the prompt.
Step 4: A cache-aside example in your app
The most common caching pattern is called cache-aside, and it's simple to reason about. The logic is always the same three steps. Check Redis for the answer. If it's there, return it. If it's not, do the slow work, save the result in Redis with an expiry, and return it.
Here's a Node.js version using the redis package and a fake slow database call. Install the client first with npm install redis.
import { createClient } from "redis";
const client = createClient({
url: "redis://127.0.0.1:6379",
password: process.env.REDIS_PASSWORD,
});
await client.connect();
async function getUserProfile(userId) {
const cacheKey = `profile:${userId}`;
// 1. Try the cache first
const cached = await client.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
// 2. Cache miss, do the slow work
const profile = await slowDatabaseLookup(userId);
// 3. Store it for 5 minutes, then return
await client.set(cacheKey, JSON.stringify(profile), { EX: 300 });
return profile;
}
If you'd rather use Python, the pattern is identical. Install the client with pip install redis.
import os
import json
import redis
r = redis.Redis(
host="127.0.0.1",
port=6379,
password=os.environ["REDIS_PASSWORD"],
decode_responses=True,
)
def get_user_profile(user_id):
cache_key = f"profile:{user_id}"
# 1. Try the cache first
cached = r.get(cache_key)
if cached:
return json.loads(cached)
# 2. Cache miss, do the slow work
profile = slow_database_lookup(user_id)
# 3. Store it for 5 minutes, then return
r.set(cache_key, json.dumps(profile), ex=300)
return profile
Notice the password comes from an environment variable, not a hardcoded string. Keep secrets out of your code. Also notice the key naming, profile:123. Using a prefix like profile: keeps your keys organized and makes it easy to find or clear a group later. One more thing worth knowing: when the underlying data changes, delete the key so the next read rebuilds it. A quick client.del("profile:123") after an update keeps the cache honest.
Step 5: Use Redis as a WordPress object cache
If you run WordPress, Redis can cache database query results so pages build faster under load. The easiest route is the Redis Object Cache plugin. Install and activate it from the WordPress admin, then add your connection details to wp-config.php above the line that says "stop editing."
define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_PASSWORD', 'S0me-L0ng-Random-String-Here' );
define( 'WP_REDIS_PREFIX', 'mysite_' );
Then go to Settings, Redis in the WordPress dashboard and click Enable Object Cache. If your site and Redis are on the same Bytte.cloud server or VPS, the loopback host above is exactly right. The prefix matters if you ever run more than one WordPress site against the same Redis instance, since it keeps their keys from colliding.
Persistence: RDB and AOF in plain terms
Redis keeps data in RAM, but it can also write to disk so your data survives a restart. There are two methods, and you can use either, both, or neither.
- RDB (snapshots): Every so often, Redis writes a full point in time dump of everything to a file. It's compact and fast to load. The downside is that if Redis crashes between snapshots, you lose whatever changed since the last one.
- AOF (append only file): Redis logs every write command as it happens. On restart it replays the log to rebuild state. You lose far less data, at the cost of a larger file and slightly more disk activity.
For a pure cache, persistence often doesn't matter at all. If Redis restarts empty, your app just refills it on the next few requests, the way it would on a cold start. So plenty of people turn persistence off for a cache to keep things lean. If your Redis also holds data you don't want to recompute, turn on AOF for the better safety. You enable it in the config like this:
appendonly yes
appendfsync everysec
The everysec setting flushes the log to disk once a second, which is a good balance of safety and speed.
Keeping it private and password protected
This deserves its own section because it's the mistake we see most often. Scanners crawl the entire internet looking for Redis servers with no password listening on a public address. If they find yours, they can read your data, wipe it, or use the box for worse. So two rules.
First, keep bind 127.0.0.1 unless you genuinely need remote access. If your app is on the same server, you never need to expose Redis at all. Second, always set requirepass. If you truly must reach Redis from another machine, do it over a private network or an SSH tunnel, and add a firewall rule so only that one machine can reach port 6379.
sudo ufw allow from 10.0.0.5 to any port 6379 proto tcp
That line allows only the host at 10.0.0.5 to connect, and blocks everyone else. Replace it with your app server's private IP. Never open 6379 to the whole world.
Troubleshooting
Connection refused
If your app or redis-cli reports "Connection refused," Redis probably isn't running, or it's listening somewhere you're not connecting to. Check the service first.
sudo systemctl status redis-server
If it's stopped, start it and read the log for the reason it died.
sudo journalctl -u redis-server -n 50 --no-pager
If the service is up but you still can't connect from another machine, that's the bind setting doing its job. Connecting from the same server with 127.0.0.1 should work.
NOAUTH Authentication required
This means you set a password, which is good, but the client didn't send it. In redis-cli, run AUTH yourpassword after connecting, or start with redis-cli -a yourpassword. In your app, make sure the password is passed in the client config and that the environment variable is actually set. A quick way to confirm the variable exists in your shell:
echo $REDIS_PASSWORD
OOM command not allowed when used memory > maxmemory
You hit your memory cap and your eviction policy won't free anything. This usually happens when the policy is noeviction, which refuses new writes when full instead of dropping old keys. For a cache, switch to allkeys-lru in the config, or raise maxmemory if your box can spare the RAM. Check current usage with:
redis-cli -a yourpassword INFO memory | grep used_memory_human
It was reachable from the internet
If you discover Redis was open to the world, treat the data as compromised. Stop the service, set bind 127.0.0.1, set a strong requirepass, restart, and add a firewall rule. Then flush and rebuild the cache, since you can't trust what's in it. An exposed cache with no password is the single most common way these get abused, so fix it before anything else.
Keys disappear sooner than expected
If cached values vanish before their TTL, you're probably hitting maxmemory and the LRU eviction is dropping keys to make room. That's working as designed, but it tells you the cache is too small for your workload. Either raise maxmemory, shorten what you store, or accept the extra misses. You can watch evictions climb with redis-cli -a yourpassword INFO stats | grep evicted_keys.
Wrapping up
You now have a Redis instance that's installed, capped at a safe memory limit, password protected, and private to your server. You tested it by hand with redis-cli, and you have a cache-aside pattern in Node or Python that you can paste into a real project today. Start small. Cache the one slow query or API call that's actually hurting you, give it a sensible TTL, and measure the difference. Add a key, remember to delete or expire it when the source data changes, and you'll get most of the benefit with very little risk.



