Honeypot Live Stats — 15846 connections today from 41 unique IPs (125502 total, 1534 unique IPs all-time)
Miles Huynh

Every command

Reading time: 3 minutes

A reference dump of every command from the honeypot, domain/HTTPS, and SSH-hardening posts — no narrative, just the commands, grouped by post.

From: Building my first honeypot on AWS

sudo apt install -y git python3-venv python3-dev libssl-dev libffi-dev build-essential
sudo adduser --disabled-password --gecos "" cowrie

(Cowrie itself was cloned and installed inside a sudo su - cowrie session, so those exact clone/pip steps didn't survive in the ubuntu user's history — but the systemd unit that runs it did:)

sudo tee /etc/systemd/system/cowrie.service << 'EOF'
[Unit]
Description=Cowrie SSH/telnet Honeypot
After=network.target

[Service] Type=forking User=cowrie Group=cowrie WorkingDirectory=/home/cowrie/cowrie Environment="PATH=/home/cowrie/cowrie/cowrie-env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ExecStart=/home/cowrie/cowrie/cowrie-env/bin/cowrie start ExecStop=/home/cowrie/cowrie/cowrie-env/bin/cowrie stop PIDFile=/home/cowrie/cowrie/var/run/cowrie.pid Restart=on-failure

[Install] WantedBy=multi-user.target EOF sudo systemctl enable cowrie sudo systemctl start cowrie sudo systemctl status cowrie.service

Quick log analysis, straight from the honeypot's own log file:

grep -c "New connection" var/log/cowrie/cowrie.log
grep -oP '(?<=,)[0-9]{1,3}(?:\.[0-9]{1,3}){3}(?=\])' var/log/cowrie/cowrie.log | sort | uniq -c | sort -rn | head -10

From: Getting a real domain and real HTTPS

sudo ss -tlnp | grep -E ':80|:443|:8080'
ps aux | grep -E 'nginx|apache2|php' | grep -v grep

Edited /etc/nginx/sites-enabled/default, changed server_name _; to the real domain, then:

sudo nginx -t
sudo systemctl reload nginx
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d mileshuynh.duckdns.org

From: My real SSH port was just as exposed as my fake one

sudo ss -tlnp | grep -E ':22|:2222'
sudo grep -i "^Port" /etc/ssh/sshd_config
sudo grep -iE "PasswordAuthentication|PermitRootLogin|PubkeyAuthentication" /etc/ssh/sshd_config
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd admin
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl status fail2ban
sudo fail2ban-client status

Plus one change made entirely in the AWS console: the EC2 security group's port 22 rule, source changed from 0.0.0.0/0 to my own IP.

My real SSH port was just as exposed as my fake one

Reading time: 2 minutes

Went looking for the next thing to fix and found something dumber than expected: the box hosting my honeypot had a second, unintentional honeypot right next to it — my real SSH.

The discovery

I'd assumed only Cowrie (port 2222) was exposed. A quick check said otherwise — port 22, the real sshd, was also open to 0.0.0.0/0. Any scanner had just as much access to my real login as to the fake one.

Closing the real door

Fixed it in the security group, not on the box — changed the port 22 source to "My IP." No risk of locking myself out, since editing a security group doesn't need SSH access. Password auth was already disabled, key-only login — the fix was about cutting attack surface, not plugging an active hole.

Locking /admin behind a second door

Added HTTP Basic Auth in front of Bludit's login at the Nginx level.

Almost made it worse

Nearly pointed fail2ban at the honeypot port too, out of a vague "more banning is safer" instinct — which would have defeated the entire point of Cowrie. Checked what fail2ban was actually watching: one jail, sshd, correctly scoped to the real port only.

What I actually learned

Every port a security-group wizard opens is equally open to everyone, lure or not. Restricting a rule to "my IP" is safer than it sounds — fixing it wrong just means editing it again from a browser.

Next up: what's landed in the Cowrie logs.

Getting a real domain and real HTTPS

Reading time: 2 minutes

Next goal: stop serving this site off a bare IP and get it behind a real domain with real HTTPS.

Free domain

Used DuckDNS for a free subdomain, mileshuynh.duckdns.org. Gotcha: it auto-fills "current ip" with whatever machine is viewing the page, not the server — had to overwrite it manually.

Nginx + Certbot

Changed Nginx's catch-all server_name to the real domain, then ran Certbot with "redirect HTTP to HTTPS." Cert issued, deployed, auto-renewal scheduled — a surprisingly small amount of work.

The mixed-content trap

Switched to https:// and the page lost all styling. Bludit had the site's base URL cached as the old http://ip, so every asset request got blocked. Fixed by updating the URL setting.

A brief AWS billing scare

Watched the cost tick from $0.16 to $0.21 in a day, briefly panicked. Turned out I'm on AWS's credit-based free plan — everything draws from a $100 credit that comfortably outlasts the plan's window.

What I actually learned

"Free" domain and HTTPS are each about 10 minutes once you know the gotchas. Mixed content errors are unusually self-explanatory. AWS billing looks scarier than it is.

Next up: back to the honeypot, see what's landed in the logs.

Building my first honeypot on AWS

Building my first honeypot on AWS

Reading time: 2 minutes

I've spent most of my time in IT support handling tickets, MFA resets, and onboarding — not touching cloud infrastructure directly. Today's goal: launch a real AWS server, put something live, and see what actually happens to it.

Launching the instance

Picked the simplest starting point — a t3.micro running Ubuntu, free-tier eligible, connecting straight from the browser through EC2 Instance Connect. No key pair, no prior setup.

Putting something live

Nginx first, to prove I could serve something. Then a hand-written personal page, deployed by pasting into nano over SSH — small, but the first server I've ever owned end to end.

Then I got curious who else was watching. Any public IP gets scanned constantly. Instead of ignoring it, I set up Cowrie — a fake SSH server on port 2222 that logs every command an attacker tries. Opened the port to the world, and within a few hours the first scanner found it: connected, grabbed the banner, disconnected in 34 milliseconds. No login attempt, no commands. Just reconnaissance — the internet doing what it always does.

What I actually learned

Launching a real EC2 instance is a lot less scary than it sounds. A public IP gets attention within hours, not days. Logging is the whole point of a honeypot — the fake shell is just bait, the log file is the actual value.

Next up: a real domain and HTTPS, then writing up whatever the honeypot picks up.