Build on git.eeqj.de/sneak/baseimage:2026-11-05 with the docker CLI copied from docker:cli. A runit service sleeps INTERVAL seconds (default 1200), then runs the reporter with --since INTERVAL --submit; DOCKER_CONTAINER_NAME and IPABUSEDB_API_KEY come from the container environment. Add .dockerignore, make image, and README section; fix the binary name in .gitignore.
ipabusedb-docker-ssh
Reads the logs of a dockerised sshd with docker logs -t, extracts
brute-force / invalid-user login attempts, and emits a CSV in the format
expected by the AbuseIPDB bulk-report
endpoint. Optionally submits it.
What gets reported:
Invalid user X from IP port NUser X from IP not allowed because not listed in AllowUsersFailed password for invalid user X from IP port NConnection closed by invalid user X IP port NandDisconnected from invalid user X IP port N
Attempts with the username git are excluded (so people poking a git
host with git@ are not reported). Private, loopback and link-local
source addresses are skipped. Each IP appears once in the CSV, dated with
its most recent attempt and annotated with the number of matching lines.
Categories are 18,22 (Brute-Force, SSH).
Configuration
A .env file in the working directory is loaded at startup (see
.env.example; .env is gitignored). Variables already set in the
shell take precedence over the file.
| Variable | Purpose |
|---|---|
DOCKER_CONTAINER_NAME |
container whose logs are read (required) |
IPABUSEDB_API_KEY |
AbuseIPDB API key (required only with --submit) |
DOCKER_HOST |
passed through to the docker CLI to target a remote daemon |
Because the program shells out to the docker CLI with its own
environment, DOCKER_HOST (and DOCKER_CONTEXT, DOCKER_TLS_VERIFY,
DOCKER_CERT_PATH) work exactly as they do for docker itself. Set
DOCKER_HOST=ssh://user@host in .env to read logs from a remote
daemon while the AbuseIPDB key never leaves the local machine.
Flags:
| Flag | Purpose |
|---|---|
--since 24h |
only consider lines newer than now minus this duration |
-o FILE |
write the CSV to FILE instead of stdout |
--input FILE |
parse FILE (or - for stdin) instead of docker logs |
--submit |
POST the CSV to the AbuseIPDB bulk-report endpoint |
--env FILE |
env file to autoload (default .env; missing is ignored) |
Usage
$ make build
$ export DOCKER_CONTAINER_NAME=sshd IPABUSEDB_API_KEY=...
$ ./ipabusedb-docker-ssh --since 24h -o reports.csv
$ ./ipabusedb-docker-ssh --since 24h --submit
Submitting manually with curl instead of --submit:
$ ./ipabusedb-docker-ssh --since 24h > reports.csv && curl https://api.abuseipdb.com/api/v2/bulk-report -F csv=@reports.csv -H "Key: $IPABUSEDB_API_KEY"
Running as a container
The Dockerfile builds on git.eeqj.de/sneak/baseimage and installs the
program as a runit service (sv/ipabusedb-docker-reporter/run) that
sleeps INTERVAL seconds, then runs the reporter with
--since ${INTERVAL}s --submit, and repeats. The docker CLI is copied in
from the docker:cli image so the program can read logs through the
host's docker socket.
| Variable | Purpose |
|---|---|
DOCKER_CONTAINER_NAME |
container whose logs are read (required) |
IPABUSEDB_API_KEY |
AbuseIPDB API key (required) |
INTERVAL |
seconds between runs, and the report window (1200) |
$ make image
$ docker run -d --restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
-e DOCKER_CONTAINER_NAME=sshd \
-e IPABUSEDB_API_KEY=... \
-e INTERVAL=1200 \
ipabusedb-docker-reporter
Each run's CSV and the AbuseIPDB response go to the container log. If a required variable is missing the service logs an error, sleeps a minute and exits so runit can retry.
make check runs vet, the tests and the build. loglines_example.txt
holds sample docker logs -t output used by the tests;
example_parser_script.py is the reference script from AbuseIPDB that
this program replaces.