Exposed Redis
Redis is built for trusted clients on a trusted network. It has no login by default, and every connection can run every command. If port 6379 answers the internet, anyone can read it, wipe it, or use it to get further into your server.
Published . Redis 6 and later (ACL users need 6.0; subcommand rules like -config|set need 7.0), from distro packages or the official Docker image.
- Why an open Redis is a takeover path
- Check from outside
- Bind to loopback
- Protected mode is a safety net, not a lock
- Require a password, or better, ACL users
- Disable risky commands with ACL, not rename-command
- Docker publishes 6379 with no password
- Remote admin and the final check
Why an open Redis is a takeover path
Out of the box, every connection is logged in as the default user, with no password and permission to run every command on every key. That is fine on loopback. On a public port it means:
- Your data is gone in one command.
FLUSHALLdeletes the whole data set. - The server itself is at risk. The
CONFIGcommand can change Redis's working directory and the name of its dump file, so a client can write files to other paths on disk. The Redis docs say this can lead to compromising the system and running code as the user Redis runs as.
That second point is why Redis should run as its own unprivileged redis user, never as root. Check with ps -o user=,args= -C redis-server.
Check from outside
From a machine that is not the server:
nmap -Pn -p 6379 your.server.example
redis-cli -h your.server.example ping
If ping answers PONG, your Redis is open to anyone. An error about protected mode or authentication is better, but still means the port is reachable. filtered in nmap, or a timeout, is what you want. On the server, sudo ss -tlnp | grep 6379 shows which addresses it listens on.
Bind to loopback
The redis.conf that ships with Redis has this line active:
bind 127.0.0.1 -::1
That listens on IPv4 and IPv6 loopback only. The - means Redis still starts if IPv6 isn't available. Problems start when someone comments the line out or changes it to 0.0.0.0 so another host can connect. Find the config file your Redis started with (it's on the command line in ps -o args= -C redis-server), put the line back, and restart Redis. If another server really needs access, add its private interface address to the bind line, never a public one, and firewall the port.
Protected mode is a safety net, not a lock
Since Redis 3.2, protected mode kicks in when Redis listens on all interfaces and has no password. It then only answers clients on loopback, and sends everyone else an error explaining how to configure it. The default is:
protected-mode yes
Leave it on, but don't rely on it. It only applies while there is no password and no explicit bind line, so it does nothing once someone binds Redis to a public address. Forum answers often say to turn it off to "fix" a connection error. Treat that error as a warning, not a bug.
Require a password, or better, ACL users
The simplest step is a password for the default user. Generate a long random one with redis-cli ACL GENPASS and add it to redis.conf:
requirepass CHANGE_ME
Since Redis 6, requirepass just sets the password of the default user. ACL users go further: named users, each with their own password and only the commands they need. In redis.conf:
user default off
user app on >CHANGE_ME ~* &* +@all -@dangerous
user admin on >CHANGE_ME_TOO ~* &* +@all
Rules apply left to right. app gets every command except the @dangerous category, which includes FLUSHALL, CONFIG, DEBUG and KEYS. That category also includes INFO, CLIENT and SORT, which some client libraries and job queues use. If your app breaks, add back just what it needs, for example -@dangerous +info. ACL CAT dangerous lists the full category on your version.
Turning off the default user cuts off every client that only sends a password. With user default off, new connections start unauthenticated and must log in with a user name, as in AUTH app CHANGE_ME. Update your app's Redis URL to include the user name before you restart, or start with requirepass and move to ACL users later.
You can keep users in redis.conf or in a separate file set with aclfile /etc/redis/users.acl, but not both at once. With an ACL file, ACL LOAD reloads it and ACL SAVE writes changes back. Check the result with ACL LIST.
Disable risky commands with ACL, not rename-command
Old guides tell you to hide commands with rename-command CONFIG "". Redis now marks this as deprecated and may remove it. Use ACL rules instead. To block single commands for a user:
user app on >CHANGE_ME ~* &* +@all -flushall -flushdb -swapdb -config
From Redis 7.0 you can also block just a subcommand, such as -config|set, and leave CONFIG GET working. Key patterns like ~app:* do not stop FLUSHALL, because that command names no keys. Only removing the command does.
Docker publishes 6379 with no password
The official Redis image turns protected mode off by default and starts with no password. The image's own docs warn that if you publish the port outside the host, for example with -p 6379:6379, it is open without a password to anyone. Docker's firewall rules also skip UFW, so ufw deny 6379 doesn't help. See Docker bypasses UFW.
If only other containers use Redis, remove the ports: entry. If something on the host needs it, publish on loopback only:
ports:
- "127.0.0.1:6379:6379"
Either way, give it a password through a config file: mount a directory with your redis.conf and start the container with redis-server /usr/local/etc/redis/redis.conf. Recreate the container afterwards.
Remote admin and the final check
To use redis-cli or a GUI from your laptop, forward a local port over SSH instead of opening 6379:
ssh -N -L 6380:127.0.0.1:6379 [email protected]
redis-cli -p 6380
Then run AUTH admin CHANGE_ME_TOO inside redis-cli. When you're done, repeat the redis-cli -h your.server.example ping test from outside. It should time out or be refused.
Stenvakt checks this on every server. Its Review is a read-only check of each server, and the database guard finds a Redis that answers from outside or has no password, with Back up now before you change anything. You see a Preview of every fix before it runs, and fixes run in safe mode: a snapshot first, a rollback timer and a fresh-connection test. It's a Mac app and isn't out yet: get early access.
Sources
- Redis docs: Redis security
- Redis docs: ACL
- Redis source: the default redis.conf (bind, protected-mode, rename-command)
- Docker Hub: redis official image (protected mode, config file)