v0.2.0 on PyPIdetection onlyone Python fileMIT

Know when someone gets into your server.

sshsentry watches your SSH auth log, /etc/passwd and authorized_keys, and tells you in plain English when something matters. Built for small businesses and homelabs, not enterprise fleets.

$pip install sshsentry
sshsentry banner
00 see it run

Real output, no setup

This is sshsentry replaying the sample log that ships in the repo. Every alert says what happened, who, from where, and what to check next. Replay never sends anything anywhere.

try itsha256:e2bf380cb122
pip install sshsentrycurl -sO https://raw.githubusercontent.com/sshsentry/sshsentry/main/sample-auth.logsshsentry --db /tmp/sshsentry-try.db --replay sample-auth.log --digest-now   # prints alerts, sends nothing

The animation shows real tool output; the install lines in it are simulated.

Terminal recording of sshsentry replaying a sample auth log and printing alerts
01 detect

What it notices

Seven rules, all on by default, all tunable in sshsentry.yaml. Repeats are muted for cooldown_minutes (60).

Brute force MEDIUM

5+ failed logins from one IP within a sliding 10 minutes. Invalid usernames count too, so key-only servers are covered.

rule:brute_force

Login after failures HIGH

A successful login from an IP that failed 5+ times in the last 60 minutes. This is the one you really want to hear about.

rule:login_after_failures

Escalation CRITICAL

With alerting turned on, an IP already alerted for brute force that later logs in gets one CRITICAL alert to every destination. It replaces the login-after-failures alert for that login.

rule:escalation

New country HIGH

A successful login from a country never seen for that user. Needs the optional geoip2 library and a free MaxMind GeoLite2-Country database; skipped with a one-line note if missing.

rule:new_country

New IP LOW

A successful login from an IP never seen for that user. Approve your own addresses with --approve IP.

rule:new_ip

New user HIGH

A new account appears in /etc/passwd. Existing accounts are recorded silently on the first run.

rule:new_user

New SSH key HIGH

A new line in any watched authorized_keys file (root and /home/* by default, globs allowed). Existing keys are the silent baseline.

rule:new_ssh_key

Every rule with sample alerts →

02 how it works

Three steps

step_01

Install one script

pip install sshsentry, or copy sshsentry.py to the server. Python 3.9+ and PyYAML. No agent fleet, no database server, no dashboard.

step_02

It learns what is normal

The first run is quiet. Existing users and keys become the baseline, and the existing log teaches it which IPs each user normally uses.

step_03

You get plain-English alerts

On stdout (journald under systemd), and optionally by email, Slack or a webhook, plus an optional daily digest.

03 fits your stack

Pairs with fail2ban

sshsentry does not block anything. It reads logs and files and tells you what it saw. fail2ban (or your firewall) does the blocking. Together: fail2ban slows the guessing, sshsentry tells you when a guess worked, or when a new user or key appears that fail2ban was never designed to notice.

How they fit together →

Does it change my server?
No. It reads the auth log, /etc/passwd and authorized_keys, and writes only its own SQLite state file (and optional digest text files). Nothing leaves the machine unless you turn on alerts or opt-in sharing.