// Nathaniel Routson

Cybersecurity & IT Support B.S. Cybersecurity (Tiffin University, 4.0 GPA) · NOC & Help Desk experience · Findlay, OH or Remote

I keep networks online and I write it down clearly when they're not. This site covers my certifications, hands-on experience, and a few home-lab projects — scroll down, or use the buttons on the left.
AVAILABILITY: OPEN TO WORK — RESPONSE TIME < 24 HRS
ABOUT

I graduated from Tiffin University in December 2025 with a 4.0 GPA in Cybersecurity, after starting my technical foundation with a double major Associate of Science in Computer Information Systems and Systems & Networking Support from Terra State Community College — also 4.0, also Dean's List. Along the way I picked up my CEH along with a stack of Cisco, Red Hat, and other industry certifications, because I'd rather show a credential than promise one.

My hands-on time comes from a NOC Technician internship at CentraComm Communications, current remote technical/pharmacy support work for Costco's Pharmacy Division, and volunteer help desk work at Terra State — real tickets, real users, real "why is the VPN down" energy. Outside of work I run home-lab projects to keep my SOC and networking skills current between applications.

DegreeB.S. Cybersecurity — Tiffin University, 2025
Prior degreeA.S. Computer Info Systems & Systems/Networking Support — Terra State CC
GPA4.0 (both degrees), Dean's List
Based inFindlay, OH
Work styleOn-site (local) or Remote
LeadershipPresident, Phi Theta Kappa Honors Society — Terra State
CERTIFICATIONS
CEH
Certified Ethical Hacker
EC-Council · 2024
CCNA
CCNAv7: Enterprise Networking, Security & Automation
Cisco · 2023
CCNA
CCNAv7: Switching, Routing & Wireless Essentials
Cisco · 2023
CISCO
Cisco Entry to Networking
Cisco · 2023
RHEL
Red Hat System Administration I
Red Hat · 2023
FOA
Premises Cabling & Fiber Optics
FOA · 2023
FESTO
Fundamentals of Electricity, AC & DC
FESTO · 2023
PCPro
TestOut PC Pro
TestOut · 2023
B.S.
B.S. Cybersecurity
Tiffin University · Dec 2025
EXPERIENCE
Technical & Pharmacy Support AgentRetail Imaging — Costco Pharmacy Division
July 2026 — Present · Remote
  • Provide comprehensive technical, pharmacy, and customer support for Costco Pharmacy locations nationwide.
  • Troubleshoot account access, login issues, and pharmacy software systems for medical staff and pharmacy technicians.
  • Assist customers with insurance verification, prescription processing, and medication-related inquiries across multiple healthcare and retail platforms simultaneously.
  • Handle confidential patient-adjacent information in compliance with HIPAA privacy standards while delivering clear technical guidance in a fast-paced remote environment.
NOC Technician (Internship)CentraComm Communications
April 2024 — September 2024 · Findlay, OH
  • Implemented cybersecurity measures and protocols that prevented real-time cyberattacks and mitigated a major DDoS incident, maintaining 99% uptime and continuous operational integrity.
  • Resolved 95%+ of Tier 1 incidents independently, improving response time by 20% while supporting 100+ weekly client call-ins.
  • Supervised six staff members and developed automated scripts, Excel inventory tools, and streamlined patching processes to enhance team efficiency.
IT Help Desk Technician (Volunteer)Terra State Community College
August 2022 — May 2024 · Fremont, OH
  • Managed incoming support tickets through a help desk ticketing system, performing hands-on hardware troubleshooting including OS reinstallation, SSD replacement, printer configuration, and account resets.
  • Provided clear, friendly, and patient communication to clients — translating complex technical issues into easy-to-understand explanations while maintaining a calm, professional demeanor.
PROJECTS
Homelab RackIN PROGRESS
[ PHOTO COMING SOON — RACK BUILD IN PROGRESS ]

Self-built rack running my own router/firewall, switches, a services box, NAS storage, and a media server — still being expanded. This is the project — everything else here is a smaller piece of the same effort. Full breakdown is in the Homelab section below.

pfSenseProxmoxNASSelf-Hosted
LAN-Only HoneypotBUILT

Isolated container that fakes eight network services and raises a Wazuh alert the moment anything touches it or tries a login. LAN-only, with no real data inside. Read the write-up in the Blog section.

OpenCanaryWazuhProxmox LXCCustom Rules
Monitoring & Alerting StackBUILT

Uptime Kuma watches every service in the rack, ntfy is the alert channel (locked down with an admin account and a write-only account), and a Wazuh SIEM collects from agents on both Proxmox hosts, the scanner and the honeypot. Phone alerts are next, once the access point is in.

Uptime KumantfyWazuh SIEMLXC
ClamAV File ScanningBUILT

A ClamAV scanner in its own container with read-only access to the NAS drives, running scheduled scans of my stored files. It has a Wazuh agent, so it reports into the same SIEM as everything else.

ClamAVWazuh AgentRead-Only MountsScheduled Scans
Rack Status DashboardPLANNED

Grafana dashboard that pulls health and uptime data from the monitoring stack above and feeds a physical status screen mounted on top of the rack.

GrafanaPrometheusStatus Screen
Malware Testing LabPLANNED

Isolated, network-segmented VM environment for safely detonating and analyzing malware samples without risk to the rest of the rack.

Isolated VMsSandboxingMalware Analysis
Local AI Model ServerPLANNED

Self-hosted machine running local AI/LLM inference on the rack, kept fully offline from any third-party cloud service.

Self-HostedLocal Inference
Vulnerability ReportPLANNED

Ran a scan against a lab network, prioritized findings by risk, and wrote a remediation report aimed at a non-technical stakeholder.

OpenVASRisk Reporting
Backup & Disaster RecoveryPLANNED

Documented backup pipeline covering mirrored NAS storage and a dedicated backup server for container configs — with defined recovery goals, not just "there's a copy somewhere."

Proxmox Backup ServerRedundancyRPO/RTO
Network Segmentation (VLANs)PLANNED

Isolating the NAS, media server, and other rack traffic onto separate VLANs using the existing switches and firewall — defense in depth on hardware I already have.

VLANspfSenseNetwork Security
SKILLS

Networking

TCP/IPDNS DHCPVPN Cisco IOSFirewalls SolarWindsJuniper Networks Fortinet

Security

Vulnerability ScanningSIEM Incident ResponseEthical Hacking

Systems & Cloud

Windows ServerActive Directory Linux (Red Hat)Virtualization Azure

Programming & Web

C#C++Python SQLHTMLCSS JavaScript

Support & Tools

Ticketing SystemsRemote Support DocumentationPowerShell TeamViewerMicrosoft Remote Desktop

AI Tools

ChatGPTCopilotDeepSeek
HOMELAB — RACK STATUS

Everything below is a real, currently-running box in my rack — this isn't a wishlist. I use it to keep hands-on with the stuff I studied on paper: routing, virtualization, storage, and remote access.

RTR
Router / Firewall
Self-built box running pfSense, handling routing and firewall rules for the whole rack.
SW
Managed Switches
Segment traffic between the rack's servers, NAS, and home network.
SVC
Services Box
Proxmox VE host running everything as VMs/containers — this is where most of the rack's actual workload lives.
NAS
NAS / Storage
Network-attached storage for shared files and media, with redundancy on the roadmap.
MDA
Media Server
Self-hosted media server for content I've ripped myself, with a custom retro-console-themed UI I built for it.
VPN
Remote Access
Self-hosted VPN for securely reaching the rack from anywhere without opening ports to the public internet.

Currently expanding the rack with additional compute and multi-bay drive enclosures for backup redundancy.

BLOG — LAB NOTES

Write-ups of things I build, break and fix in the rack, newest first. Click a post to open it.

Booby-Trapping My Own NAS with Canarytokens · NOV 10, 2026

Summary

I planted two fake "secrets" on my NAS: a passwords file and a set of cloud access keys. Nobody has a reason to touch them, so any use at all means something is wrong. Then I attacked them myself. Both traps fired, and the alerts showed up within minutes with the time, the source, and the tool used. Total cost: $0.

What a canary token is

The name comes from the canary in a coal mine: a cheap early warning. A canary token is fake bait with a unique ID hidden inside it. When someone opens or uses the bait, that ID "phones home" and you get an alert. It's the same idea as a tracking pixel in an email, turned into a burglar alarm.

I used canarytokens.org, a free service from the security company Thinkst. No account is needed, just an email address for alerts and a note to remind you where you hid each token. It never sees your files or your network; it only learns about whoever trips the trap.

The bait

BaitWhat it looks likeWhat sets it off
passwords.txtA careless list of logins, with a "password manager" link at the topAnyone who visits that link
aws-keys.txtAmazon cloud access keysAnyone who tries to use the keys

Every login in the passwords file is invented, and the email address uses a .test domain, which is reserved and can never exist. The AWS keys are real keys, but for an account Thinkst owns, with zero permissions, so they can't do anything. I put both in a Finance folder on my NAS, and each file points at the other, the way a real messy setup would look.

Attacking myself

To test it, I did what an intruder would do with each file.

Terminal showing the fake files in the Finance folder, the contents of the fake passwords file with the trap link covered, and an AWS command run with the fake keys that returns an account identity, with identifiers covered.
The bait, then an "attacker" testing the stolen keys. Identifiers are covered.

The keys. I ran aws sts get-caller-identity with them. That command asks AWS "who am I?" and it succeeds for any valid key, even one with no permissions. That's exactly why attackers run it first on stolen keys. The fake keys answered, and that answer is what set off the alarm.

The passwords file. I opened its "password manager" link on my phone, over mobile data, so it would come from outside my network like a real intruder. The intruder just sees a harmless picture:

Phone browser showing a pixel-art planet, the decoy page shown when the trap link is opened.
What the intruder sees. The visit itself is the alarm.

What the alerts told me

Both traps fired. Every alert arrived within minutes, each timestamped to the minute I ran the test.

Canarytokens alert: AWS key token triggered, with the source address covered and the reminder note reading NAS finance folder - aws keys.
The AWS keys alert.
Alert details showing the date and time, and a user agent naming the AWS command line tool and the get-caller-identity command, with system details covered.
It even names the tool and the exact command.
Canarytokens alert: Web bug token triggered, with the source address covered and the reminder note reading NAS finance folder - passwords file.
The passwords file alert.
Alert details showing the time and a user agent claiming to be Firefox 24 on Ubuntu Linux.
The visitor's claimed browser. More on this below.
TrapFired?What the alert captured
AWS keysYes, every attemptTime, source address, rough location on a map, and the exact tool and command used
Passwords linkYesTime, source address, and the visitor's claimed browser
Token settings page reading: This Canarytoken has been triggered 3 times.
Three attempts with the keys, three alerts. Nothing slipped through.

A lesson from the passwords alert

The passwords alert said the visitor used Firefox 24 on Ubuntu Linux, a browser from 2013, while also claiming to be Chrome 80. I actually opened the link with a privacy-hardened Firefox on my phone, which deliberately reports a fake, generic identity.

That's the lesson: a "user agent" is just what the visitor claims to be, and it's trivial to fake. An analyst should lean on what can't be faked as easily: that the trap fired, when, and from where. Attackers with any skill disguise their tools the same way my browser did.

Why this is worth doing

  • Almost no false alarms. Normal activity never touches these files, so an alert is worth reading right away.
  • It catches what scanners miss. Antivirus looks for known bad files. A canary catches behavior: someone going through your stuff, whatever tool they use.
  • The keys follow the thief. If the files get copied off my NAS, the AWS keys still alert from wherever someone tries them.
  • Cheap and fast. Free, about 15 minutes to set up, nothing to install on my servers.

What this can't catch

  • Quiet reads. Someone who opens passwords.txt but never visits the link triggers nothing. The file only alarms when the bait is used.
  • Offline attackers. Both tokens have to reach the internet to report in. A machine with no internet access won't raise an alert.
  • It depends on an outside service. If canarytokens.org or my email is down, the alert is delayed or lost.
  • A careful attacker may spot it. Well-known token formats can be recognized, so canaries are one layer, not the whole defense.

Next: a tripwire that doesn't need the internet

The first gap matters most, so the next post closes it. I'll use the Linux audit system on the server that holds the NAS drives to watch these exact files, so any read at all, even fully offline, raises a high-priority alert in my Wazuh SIEM and on my phone, naming the process and user that touched them. Canarytokens catch the bait being used; the local tripwire will catch someone just looking.

Skills demonstrated

Deception technologyHoneytokensDetection testingAlert triageThreat intel from alertsKnowing your tool's limits
Tailworm: Locking Down My Tailnet Before a Patch Existed · OCT 30, 2026

Summary

On October 25, 2026, a researcher published "Tailworm": 11 flaws in Tailscale, the VPN mesh I use to reach my homelab from outside. Within a day I tightened my access policy, updated every server node, confirmed Tailscale SSH was off, and went through the logs for signs of intrusion. I found no evidence of exposure: zero Tailscale SSH activity, zero unexpected logins, and every change in the admin audit log was mine.

What Tailworm is

Researcher Erica Windisch published 11 findings against Tailscale and headscale (the open-source control server) without coordinated disclosure, so no fixes existed when it went public. The most serious one needs two things: Tailscale SSH turned on with forwarding allowed, and an attacker who already controls a device the access policy lets connect. From there, one compromised device could reach root on other servers.

That is lateral movement inside a tailnet, not an attack from the open internet. So the question for me was: who and what can reach what inside my tailnet?

My exposure

My homelab runs on two Proxmox hosts. Three containers are on my tailnet: Jellyfin (which a friend also uses), Navidrome, and a planner app. None of these services are port-forwarded to the internet, so Tailscale is the only remote way in to them.

FactorBeforeWhy it mattered
Tailscale SSHNever turned on (it is opt-in)The worst flaw needs it, so that path was already closed
Access policyClose to the default allow-allAny device on the tailnet could reach any service on any port
Shared userA friend's account with several devicesOne compromised friend device could reach everything, not just Jellyfin
Client versions1.102.x on the serversMissing a separate certificate-key fix (TS-2026-013)

The policy was the real problem. It had been far wider than it needed to be long before this disclosure.

What I changed

1. Least-privilege access policyI backed up the old policy and replaced it. I keep full access, every other member can reach only their own devices, and my friend can reach Jellyfin and nothing else. Tailscale SSH rules are explicitly empty.
2. Updated every server nodeAll three containers went from 1.102.x to 1.104.2. That fixes TS-2026-013, but not Tailworm: the researcher tested against 1.104.2.
3. Forced Tailscale SSH offI ran tailscale set --ssh=false on each container and confirmed every one reports "RunSSH": false.
4. InvestigatedChecked logs on every node and the admin audit trail, instead of assuming nothing happened.
Tailscale access rules after the change: me with access to all devices, every member limited to their own devices, and my friend limited to Jellyfin. Account names and port numbers are blacked out.
The new access rules. Account names and the port are blacked out.

The policy file, with names and addresses removed:

{
  "hosts": { "jellyfin": "<tailscale-ip>" },
  "acls": [
    {"action": "accept", "src": ["<me>"], "dst": ["*:*"]},
    {"action": "accept", "src": ["autogroup:member"], "dst": ["autogroup:self:*"]},
    {"action": "accept", "src": ["<friend>"], "dst": ["jellyfin:<port>"]}
  ],
  "ssh": []
}

Before saving, I used the policy preview to confirm exactly what my friend's account could reach.

Investigation

All three containers came back clean. On each one I ran a read-only check of three things:

  1. The Tailscale service log, searched for SSH session or connection entries.
  2. last, for successful logins.
  3. lastb, for failed logins.
ContainerSSH entriesLogs sinceLogins
Jellyfin0Aug 23Boots only, no failed logins since Oct 1
Navidrome0Aug 26Boots only, no failed logins since Oct 1
Planner0Oct 4 (created)Boots only, no failed logins
Terminal output for the Jellyfin and Navidrome containers: 0 Tailscale SSH log lines, only system boot entries, and no failed logins. Hostnames, container numbers and kernel versions are blacked out.
Jellyfin and Navidrome: 0 SSH entries, only reboots, no failed logins.
Terminal output for the planner container: 0 Tailscale SSH log lines, only system boot entries, and no failed logins. Hostname, container number and kernel version are blacked out.
The planner container: same result.

The only login records are reboots, and they line up with my own host maintenance. A Tailscale SSH session would have left lines in the Tailscale log, and there were none. Since SSH is opt-in and I never turned it on, it was almost certainly off before I forced it off.

Last, I checked the Tailscale admin console's configuration log. It shows only my own actions: logging in, saving the new policy, and removing two old devices. No unknown devices, keys, invites or policy edits. Every device left on the tailnet belongs to me or my friend.

Tailscale configuration log: a login to the admin console, two policy updates and two deleted devices, all on Oct 26. Actor and target columns are blacked out.
The admin audit log: every entry is mine. Names and devices are blacked out.

What this can't prove

These checks show no sign of compromise, but they can't prove there never was one.

  • Log retention. The service logs reach back to late August, failed logins to October 1, and Tailscale's configuration log keeps 90 days. Anything older isn't covered.
  • Logs live on the box. An attacker with root could edit them, so clean local logs are evidence, not proof.
  • Host console access isn't logged inside the container. Proxmox's console and pct exec don't create login records there; those depend on the hosts' own logs.
  • Scope. I checked the servers, not my phones or desktop, which are the likelier entry point for the "attacker already on the tailnet" scenario.

Lessons

  • Default-allow is the real risk. The biggest fix wasn't a patch, it was giving each person only what they actually use.
  • No patch doesn't mean no action. Reducing exposure is something you can do the same day.
  • Verify, don't assume. "I never turned SSH on" became "the logs show it was never used," which is a much stronger claim.
  • Say where the evidence stops. Knowing what your logs can't show matters as much as what they do show.

Next steps

  • Watch for Tailworm fixes and update as soon as they ship.
  • Bring every client up to the current release and keep it there.
  • Turn on key expiry for servers and clear out unused devices.
  • Send container logs to a separate system so they can't be edited from the box itself.
  • Review the configuration log regularly, not only after a disclosure.

Sources

Skills demonstrated

Vulnerability responseLeast-privilege access controlZero-trust networkingLog analysisAudit-trail reviewRisk assessment
ClamAV Flagged Two Files. I Checked Before I Believed It. · OCT 16, 2026

Summary

I set up ClamAV to scan my storage drives, and pointed it at a backup of an old Windows 10 laptop. It flagged two files: WinRAR's uninstaller as the Expiro virus, and a Windows security driver as the Puce worm. Instead of deleting them or panicking, I checked each one. Both files still match their makers' digital signatures, and on VirusTotal only 1 of 70 engines flagged each one: ClamAV itself. My conclusion is that both are false positives.

How the scanner is set up

1. Storage drivesThe internal media drive and two USB drives on my Proxmox media server.
2. ClamAV containerIts own Linux container. All three drives are mounted read-only, so the scanner can look but never change or delete anything.
3. Scan logAnything ClamAV flags is written to a log for me to review.
4. Wazuh agentThe container runs a Wazuh agent, shown Active in my monitoring post.

What ClamAV flagged

FileWhat it isClamAV said
Uninstall.exeWinRAR's uninstaller, from 2021Win.Virus.Expiro
mssecflt.sysA driver that is part of Windows' own security componentsWin.Worm.Puce

How I checked

  1. Digital signature. Real WinRAR and Windows files are signed by their makers. Expiro spreads by modifying program files, and changing a signed file breaks the match between the file and its signature. I used osslsigncode to compare each file against what was originally signed.
  2. VirusTotal. I looked up each file's SHA-256 fingerprint to see what about 70 other antivirus engines say about the exact same file.
  3. Fresh signatures. My ClamAV database turned out to be more than 7 days old. I updated it and scanned again, in case newer signatures had already dropped the detections.

Results

CheckUninstall.exemssecflt.sys
Signed bywin.rar GmbHMicrosoft Windows
File matches what was signedYesYes
Signature verificationOKFailed (see below)
VirusTotal1/70, ClamAV only1/70, ClamAV only
After updating ClamAVStill flaggedStill flagged

The Windows driver's signature check failed, but the file itself matches what Microsoft signed exactly. The most likely reason for the failure is that my Linux scanner doesn't have Microsoft's Windows root certificate in its list of trusted authorities, so it can't complete the chain even for a genuine Microsoft file. VirusTotal also lists it as a file distributed by Microsoft.

VirusTotal result for WinRAR Uninstall.exe: 1 of 70 vendors flagged it, only ClamAV, as Win.Virus.Expiro.
WinRAR's Uninstall.exe on VirusTotal: 1 of 70, and the one is ClamAV.
VirusTotal result for mssecflt.sys: 1 of 70 vendors flagged it, only ClamAV, as Win.Worm.Puce. Marked as a file distributed by Microsoft.
The Windows security driver on VirusTotal: 1 of 70, ClamAV only, and marked as distributed by Microsoft.

One loose end: VirusTotal tags WinRAR's uninstaller as both "signed" and "invalid-signature", while my own check said OK. I didn't resolve that difference, which is why the verdict rests on several independent checks rather than the signature alone.

Verdict

Both detections are false positives, with high confidence: each file is unchanged since its maker signed it, and 69 of 70 engines see nothing. Nothing was deleted. The backup sits on a read-only mount and is never run, so even a real infection there couldn't have spread.

Problems I hit

  1. The first full scan never finished. The container stopped partway through, so there was no final summary. I rescanned just the two flagged files to get a clean result.
  2. Stale virus database. ClamAV warned that its signatures were over a week old, meaning automatic updates weren't running. I updated it manually and will make sure updates run on their own.
  3. Folders skipped. ClamAV's default folder-depth limit is too shallow for Windows' deeply nested system folders, so the first scan skipped some of them. The next full scan uses a higher limit.

The main lesson: a single scanner's alert is a lead to investigate, not a verdict. Checking took a few minutes; deleting a system file on a live machine on one engine's say-so could have broken it.

Next steps

  • Report both files to ClamAV as false positives.
  • Finish the full scan of the backup with the higher folder-depth limit.
  • Make sure the virus database updates automatically.
  • Send ClamAV detections into Wazuh as alerts, so a flag shows up on my dashboard instead of only in a log.

Skills demonstrated

Malware triageFalse-positive analysisCode-signing verificationThreat intelligence (VirusTotal)ClamAVRead-only containment
Watching the Lab With Uptime Kuma and Wazuh · OCT 14, 2026

Summary

My homelab runs 15 monitored services across two Proxmox hosts and their containers. Uptime Kuma checks each one on a schedule and shows whether it is up. Wazuh collects security events from four agents across the lab. Right now all 15 services show Up. To make sure a failure really shows up, I took one service down on purpose and watched Uptime Kuma mark it Down.

The tools

  • Uptime Kuma: checks whether each service answers, shows the uptime history, and marks a service Down with the reason when it fails.
  • Wazuh: the SIEM. Agents on each host send logs and security events to one manager, and the honeypot's alerts end up there too.
  • ntfy: the notification service for phone alerts. It is running, but my phone is not set up yet. That waits on a wireless access point.

What Uptime Kuma watches

The 15 monitors cover the media stack (Jellyfin, Navidrome and Kavita), FileBrowser, my Planner and Job Tracker apps, Pi-hole, Nginx Proxy Manager, Homepage, ntfy, the router, the internet connection, both Proxmox hosts, and Wazuh itself.

Uptime Kuma dashboard with all 15 monitors showing Up.
All 15 monitors up.

Test: a service going down

I took Navidrome down on purpose. Uptime Kuma marked it Down, its monitor bar turned red, and the reason appeared in the event list and as an alert on screen. That is the behavior I need: a failure should be visible without me going looking for it.

Uptime Kuma showing Navidrome as Down with the failure reason. Internal IP address blacked out.
Navidrome down, on purpose. Uptime Kuma shows the Down status and the reason. Internal IP address blacked out.

Wazuh agents

Four agents report to the Wazuh manager, and all four show Active: the media server, the services box, the ClamAV scanner and the honeypot. Each one is a Debian host running Wazuh agent 4.9.2, the same version as the manager.

Wazuh agents page showing four active agents: mediaserver, servicesbox, clamav and honeypot. Internal IP addresses blacked out.
Four agents, all Active. Internal IP addresses blacked out.

What is not done yet

  • Phone alerts: ntfy is running, but I have not set up the phone app or sent a test alert to my phone. That waits on the wireless access point.
  • Wazuh to ntfy: sending the higher-level Wazuh alerts to my phone is next, after the phone setup.
  • Router outages: the router was the unreliable piece before the renumber. I'm still watching whether the outages come back, and the Router monitor is one of the ways I'll see it.

Skills demonstrated

Service monitoringUptime KumaSIEM dashboardsWazuh agentsFailure testingProxmox
Building a LAN-Only Honeypot That Alerts Into Wazuh · OCT 12, 2026

Summary

I built a LAN-only honeypot in an isolated Proxmox container that fakes eight network services and sends its alerts into my Wazuh SIEM. When I submitted a fake login to its web page from my own PC, Wazuh raised a level-12 alert about a second later, with the source address, the credentials tried and the service touched. The honeypot holds no real data and has no route from the internet.

How it works

1. Test PCAny device on the LAN that touches a fake service.
2. OpenCanary (honeypot container)Fake FTP, SSH, Telnet, HTTP, MySQL, RDP, VNC and Redis. Every touch is written to a JSON log.
3. Wazuh agent 4.9.2Runs in the same container and reads the JSON log file.
4. Wazuh managerCustom rules 110200 to 110202 match the events.
5. Alert in the dashboardLevel 12 for a login attempt, with the source, the credentials and the service.

Detection rules

Three custom Wazuh rules turn OpenCanary's JSON log lines into alerts. Anything that merely connects to a fake service is a level 8; anything that tries credentials is a level 12.

RuleLevelFires when
1102000Base rule: matches JSON events from the honeypot node, raises no alert itself.
1102018Someone connects to a fake service (web page view, SSH, Telnet, MySQL, RDP, VNC or Redis connection).
11020212Someone tries credentials on a fake service (FTP, web login, SSH, Telnet, MySQL).

Test and result

From my own PC I opened the honeypot's fake NAS login page and submitted a made-up username and password twice. OpenCanary logged each attempt as an HTTP login attempt, the Wazuh agent shipped it, and rule 110202 fired at level 12 with a fire count of 2. Wazuh showed the source address, the credentials typed, the browser user agent and the service touched.

Wazuh event detail for rule 110202, Honeypot login attempt, level 12, from agent honeypot, showing the fake username and password and the fake service touched. Internal IP addresses are blacked out.
The Wazuh alert for my own test login. Internal IP addresses are blacked out.

These were my own test attempts, not real attackers. The result proves the detection pipeline works from log line to SIEM alert; it says nothing yet about how often anything touches the honeypot in normal use.

Safety design

The honeypot is built so that being compromised costs nothing.

  • Isolated container: its own unprivileged LXC with 512 MB of memory and 4 GB of disk, no mounted drives and no real credentials anywhere in it.
  • LAN only: no port forward, no tunnel entry and no Tailscale on it, and my router sits behind another router, so nothing from the internet reaches it.
  • Admin path: the container's real SSH service is disabled so the fake SSH can use port 22; I manage it from the Proxmox host console instead.
  • Known limit: OpenCanary runs as root inside the unprivileged container. A dedicated VLAN and a low-privilege service user are on the next-steps list.

Problems I hit and how I fixed them

  1. Config step failed silently. OpenCanary's helper script calls a bare python3, which in the container was the system Python, not my virtual environment. I put the environment first on the path and regenerated the config.
  2. Port 22 already in use. The container's real SSH server, which can also start through a socket unit, held the port, so the fake SSH crashed on start. I stopped and masked both the service and the socket.
  3. Wazuh rejected my first rules. Wazuh's default regex engine does not support grouped alternation like (a|b). My deploy script tested the rules before restarting the manager, so it restored the original rules file automatically. I rewrote the match as ^a$|^b$ and it loaded.
  4. Agent and manager versions. An agent newer than its manager can fail to connect, so I pinned the agent to the manager's version (4.9.2) and put the package on hold.

The main lesson: every change went through a script that checks first and rolls back on failure, which is why the rule mistake cost nothing.

Next steps

  • Send level-10 and higher Wazuh alerts, including the honeypot, to my phone through ntfy.
  • Forward pfSense firewall logs to Wazuh and add Suricata for network intrusion detection.
  • Move the honeypot into its own VLAN and run OpenCanary as a low-privilege user.
  • Run a proper attack-and-detect test from a separate machine (port scan and a scripted login attempt) and document the alerts.

Skills demonstrated

Deception technologySIEM engineeringCustom Wazuh rulesProxmox LXCsystemdNetwork containmentChange control and rollbackLog-based troubleshooting
PICTOCHAT — OFF THE CLOCK
NATHANIEL

Yes, this whole site is styled after the DS Lite. If you get the reference, we're already off to a good start.

NATHANIEL

When I'm not chasing tickets or building lab environments, I'm probably tearing apart hardware I have no business opening, lifting, gaming, or getting outside — pretty much anything that isn't a screen with a ticket queue on it.

NATHANIEL

Favorite kind of problem to solve: the one where the fix is obvious in hindsight but took forty minutes of staring at logs to find.

Nathaniel has entered the chat.

Built with ds.css (MIT licensed) — font and border assets are embedded in this file.

CONTACT
Email is the fastest way to reach me — I'll get back to you within a day.
LinkedIn GitHub (coming soon) Resume (PDF)