← Harden & defendlock down redis and database ports before shodan finds them

lock down redis and database ports before shodan finds them

$ss -tlnp

why shodan always wins if you leave the door open

shodan is just a search engine that scans the entire internet and indexes what answers back. it's not hacking anything, it's just knocking on every port on every ip address and writing down who says "hello." if your redis, mongo, postgres, mysql, or elasticsearch instance is sitting on a public ip with no password, shodan already knows about it. probably before you finished setting it up. this isn't a hypothetical, it's a daily occurrence. bots scan for these exact ports around the clock, find an open database, and start wiping or ransoming it in minutes. no skilled attacker required, just a script running on a loop.

step one: check what's actually listening

before you fix anything, you need to see what's exposed. that's what ss -tlnp is for.

ss -tlnp

breaking that down:

ss is the modern replacement for netstat, it talks directly to the kernel instead of parsing /proc the slow way.
-t shows tcp sockets only.
-l shows listening sockets, meaning things actually waiting for connections, not established ones.
-n shows numeric ports instead of resolving service names, so you see "6379" instead of it guessing a name.
-p shows the process name and pid attached to that socket, so you know exactly what's listening.

run it and look at the local address column. if you see something like 0.0.0.0:6379 or :::27017, that service is listening on every network interface, including the public one. if it says 127.0.0.1:5432, it's only reachable from the machine itself, which is what you want.

the ports to specifically hunt for:

6379 is redis. 27017 is mongodb. 5432 is postgres. 3306 is mysql/mariadb. 9200 is elasticsearch. these five account for a huge chunk of the "we got wiped overnight" posts you see in sysadmin forums.

step two: bind to localhost, not the world

the actual fix lives in the service's config file, not in iptables. each of these databases has a "bind" directive that controls which interfaces it listens on.

for redis, open redis.conf and set:

bind 127.0.0.1
protected-mode yes

bind limits it to localhost only. protected-mode is redis's built-in safety net that refuses external connections if no password is set, but don't rely on it alone, it's a backstop, not a strategy. mongo, postgres, and mysql all have equivalent bind-address or listen_addresses settings. set them to 127.0.0.1 unless you have a specific, firewalled reason to do otherwise.

if you genuinely need remote access, like an app server on another box talking to your db, bind to the specific private ip of your internal network, not 0.0.0.0. never the whole internet.

step three: passwords and acls aren't optional

binding to localhost helps, but plenty of setups still need network access between servers, and "it's on my private network" isn't a password. set a long, random requirepass in redis:

requirepass use_a_real_random_string_here_not_your_dogs_name

for anything newer, use acls instead of one shared password. acls let you create specific users with specific permissions, so your monitoring tool doesn't need full write access just to check uptime. same logic applies to postgres roles and mongo users, least privilege beats one admin password shared across every service that touches the db.

step four: the firewall is your backup, not your plan a

config mistakes happen, typos happen, someone copies a docker-compose file from a tutorial that exposes ports by default. that's why the firewall matters even after you've locked down the bind address.

sudo ufw deny 6379/tcp
sudo ufw deny 27017/tcp
sudo ufw deny 5432/tcp
sudo ufw deny 3306/tcp
sudo ufw deny 9200/tcp

or if you're on iptables directly, drop inbound traffic to those ports from anything other than your known internal ranges. the point is defense in depth, if the bind config ever slips, the firewall still stops the connection cold.

the takeaway

run ss -tlnp right now on every box you own. if you see 6379, 27017, 5432, 3306, or 9200 bound to 0.0.0.0, you have an exposed database and it's only a matter of time. bind to localhost, set real auth, use acls where you can, and firewall the ports anyway as a safety net. do this on every box you're responsible for, and send this to whoever set up the database at your job, because "it's probably fine" is exactly what every wiped database owner said the day before it wasn't.

watch the reel ↗
the weekly drop

one command a week that makes you harder to hack.

a single tool, explained in plain english, every week. straight to your inbox.

no spam. one email a week. unsubscribe anytime.