Redis is fast partly because it does very little by default: out of the box there is no password and it happily runs any command it is given. That is fine on your laptop. On a server it is a problem. To secure Redis you need only a handful of settings, and one rule you must never break.
The golden rule: never expose Redis to the internet
Say this out loud: Redis should never be reachable from the public internet. Port
6379 open to the world is one of the most-scanned, most-exploited mistakes in all of
web hosting. Bots sweep the entire IPv4 space looking for open Redis ports. When they
find one with no password, they connect, run FLUSHALL, and leave a single key behind
demanding a ransom to get your data back. It is automated, it is constant, and it has
hit thousands of servers.
Your Redis should only be reachable by your own application - nothing else. Everything below is about enforcing that.
Set a password with requirepass
The first line of defense is a password. Add this to your redis.conf:
requirepass a-long-random-password-not-this-one
Now every client must authenticate before it can run commands. In redis-cli you pass
the password with -a:
redis-cli -a a-long-random-password-not-this-one
Or authenticate after connecting:
redis-cli
AUTH a-long-random-password-not-this-one
OK
Without the password, commands are refused with a NOAUTH Authentication required
error. Use a long, random string - this password is often the only thing between an
attacker and your data. In Laravel you set the same value with REDIS_PASSWORD in
.env, which you saw in
connecting Redis to Laravel.
Redis 6+ ACLs: users with limited powers
requirepass gives everyone the same all-powerful login. Redis 6 and later (so
redis:7, which this course uses) add ACLs: named users, each with their own
password and their own list of allowed commands and keys.
ACL SETUSER app on >app-password ~cache:* +get +set +del +expire
That creates a user app that can only touch keys starting with cache: and can only
run GET, SET, DEL, and EXPIRE. If those credentials leak, the damage is limited -
no FLUSHALL, no reading other keys. For a small app requirepass is usually enough,
but ACLs are there when you want to lock things down further.
If ACLs feel like too much, there is a lighter trick from the same toolbox: rename or
disable a dangerous command outright. Putting rename-command FLUSHALL "" in redis.conf
makes FLUSHALL stop existing, so even an authenticated client cannot wipe the keyspace by
accident or on a leaked password. It is a blunt instrument, but a useful one for the handful
of commands you never want an app to run.
Bind to localhost or a private interface
A password stops unauthorized commands. bind stops the connection from even being
accepted. It tells Redis which network interfaces to listen on:
bind 127.0.0.1
This makes Redis listen only on localhost, so nothing outside the machine can reach it
at all. If your app runs on the same server, this alone closes the door to the internet.
When Redis and your app are on different machines in a private network, bind to the
private interface instead (for example bind 127.0.0.1 10.0.0.5) - never to a public IP.
protected-mode: the safety net
protected-mode yes
protected-mode is on by default. When Redis has no password and is not bound to a
specific interface, protected mode refuses connections from other machines. It is a
safety net for the exact "I forgot to configure anything" case that gets servers
ransomed. Do not turn it off to "make things work" - if a remote client cannot connect,
fix the bind and requirepass settings instead.
Use a private Docker network
If you run Redis with Docker (as in run Redis with Docker), Docker gives you isolation for free. When your app and Redis are on the same Docker network, they reach each other by service name and you do not publish the Redis port to the host at all. Compare these two commands:
# Bad on a server: 6379 is now open on the host's public interface
docker run -p 6379:6379 redis:7
# Good: no -p, Redis is only reachable inside the Docker network
docker run --network app-net --name redis redis:7
Without -p 6379:6379, the port is never exposed outside Docker. Your app container,
attached to the same network, still connects to redis:6379 by name. You will see this
put together in the full Docker stack
lesson.
A minimal secure redis.conf
Putting the pieces together, a safe baseline looks like this:
bind 127.0.0.1
protected-mode yes
requirepass a-long-random-password-not-this-one
Localhost only, protected mode on, password required. Layer a private network and ACLs on top as your setup grows.
Common mistake
Publishing the Redis port "just to test something" and forgetting to close it. A server
with -p 6379:6379 and no password can be found and wiped within minutes of coming
online. If you must reach Redis remotely for debugging, do it over an SSH tunnel, never
by opening the port. Treat an exposed, password-less Redis as already compromised.
FAQ
Do I still need a password if I bind to localhost?
Yes. Set both. bind 127.0.0.1 stops outside connections, but a password protects you if
another process on the same machine (or a misconfigured container) can reach Redis. Layers
are the point - do not rely on a single setting.
Where does the password go in Laravel?
In .env as REDIS_PASSWORD, which Laravel passes to Redis on connect. See
connecting Redis to Laravel.
If it is missing or wrong, you get a NOAUTH error - covered in the
troubleshooting lesson.
Is there any harm in leaving protected-mode on?
No. Leave it on. It only ever refuses connections that were already unsafe (no password and no explicit bind). If it blocks a legitimate client, that client was reaching an unprotected Redis, which is exactly what you want to prevent.