Menu
Homerun docs

These are the canary docs, read from main: they can describe changes no release has shipped yet. Read the v1.0.78 docs.

Blocked paths and IP bans

Advanced mode: simple mode hides the Blocked paths panel (unless the service already blocks paths) and the IP bans settings tab. Everything here keeps working either way, and a hidden page still opens from a link.

Bots scan every public address for the same things: .env files, .git folders, WordPress login pages, database dumps. A service can tell Traefik to turn those requests away before they reach the app, and Homerun can ban an address that keeps trying.

#Blocked paths

On a service's Security tab, Blocked paths takes one pattern per line. A request whose path matches one of them gets a 403 and never reaches the app.

  • A pattern matches whole path segments anywhere in the path: .git blocks /.git, /.git/config and /app/.git/HEAD, but not /.github.
  • Starting a pattern with / matches from the root only: /admin blocks /admin and /admin/users, not /blog/admin.
  • * matches anything, slashes included (*.sql blocks /backups/db.sql), and ? matches one character.
  • Matching ignores case.

A pattern that would match every path (* or /*) is refused: stop the service or turn on its login wall instead.

Presets add a ready-made list to the box, which you can then edit:

  • WordPress probes: wp-admin, wp-login.php, wp-config.php*, wp-content, wp-includes, wp-json, xmlrpc.php. Don't use it on a real WordPress site.
  • Sensitive files: .env and .env.*, .git, .git-credentials, .gitconfig, .svn, .hg, .aws, .ssh, .htpasswd, .htaccess, .npmrc, .DS_Store, SQL dumps, backups and editor swap files, private keys.
  • Admin tools: phpmyadmin, phpinfo.php, adminer.php, server-status, cgi-bin.

Saving redeploys a running service, since the rule is part of its Traefik routing; a stopped service picks it up on its next deploy. Blocked paths apply on every one of the service's domains, before its login wall, and its pull request previews and canary inherit them.

Visitors see the Blocked path page, branded and worded under Settings → Error pages. Without Traefik's dynamic config directory (Settings → Networking), Traefik answers a bare 403 instead, and blocked requests aren't counted towards a ban.

#IP bans

Every blocked request is counted against the address it came from. An address that makes too many of them is banned on every service at once: Traefik answers all its requests with a 403 until the ban ends. Settings → IP bans sets the rule, on by default:

  • Blocked requests: how many it takes (10 by default),
  • Within: in how many minutes (10 by default, up to a day),
  • Ban for: how many hours the ban lasts (0, for good, by default).

Monitoring → Blocked IPs (admins) opens on a summary of the last week, including Most banned on, the service the most banned addresses were caught on, and has two views. Addresses lists the banned addresses, newest first, a page at a time and searchable by address, host or reason: why and until when, who is behind each one and the user agent it sent, each with an Unban button, and under Being counted every address that requested a blocked path within the window but isn't banned yet: how many requests it made against the threshold, the last host and path it asked for, and when. Expired bans are lifted within a minute. Turning bans off keeps blocking the paths and only stops new bans; bans already in place stay until they expire or you lift them.

Right after a ban, Homerun looks up who is behind the address: its reverse DNS name, the network (AS) announcing it and its country through Team Cymru's DNS service, and the network's owner and abuse contact over RDAP (rdap.org). The result shows on Blocked IPs and in the ban's notification; a lookup that fails leaves those fields blank. Bans placed before this existed are looked up a few a minute. By service ranks the services by how many banned addresses were caught on them; an address that hit several services counts on each.

When the lookup found an abuse contact, Report abuse on the ban emails it the address, when it was banned, the host and what it asked for, over the instance's SMTP, and the ban then shows when it was reported; an address is only ever reported once. Email the abuse contact automatically under Settings → IP bans, off by default, sends that report on its own as soon as a new ban's lookup finds a contact.

The dashboard's own address is never blocked by a ban, so a banned admin can still sign in and lift it.

The rule and the CrowdSec push can also be set from Terraform with homerun_ip_ban_settings, see Infrastructure as code.

#Blocked request stats

Monitoring → Blocked IPs opens on a Summary of the last 7 days across every service, and each service's Observability → Blocked IPs has the same summary for that service alone, above the addresses that hit it (marked Banned when they are): how many addresses were blocked and how many requests they made, the blocked-path pattern hit most and its share, how much Mean and Disrespect mode junk went back (fake files and insults, in bytes), and the share of blocked requests that got junk instead of a 403. Every request a blocked path turns away counts, bans on or off, except from an address that's already banned (Traefik refuses those before they reach a blocked path). Requests are kept for 7 days.

#Mean mode and Disrespect mode

Two more toggles on Settings → IP bans, both off by default, change what a blocked request gets back while it still counts towards a ban:

  • Mean mode: a request for a secret-shaped path (.env and .env.*, .git/config, wp-config.php and other PHP configs, .aws/credentials, an SSH private key, a .sql dump, an archive or .bak) gets a 200 and a fake file instead of the blocked page. The secrets in it look real (an AKIA… AWS key, an sk_live_… Stripe key) but are random, and an archive is half a megabyte of junk. A scanner that trusts it wastes its time on dead credentials.
  • Disrespect mode: the same fake files, with every secret an insult (PROD_API_KEY=fuckyou) and an archive's bytes spelling one out, and any other blocked path gets a one-line insult instead of the blocked page.

Both only answer paths you blocked on a service: add .env, .git or *.sql to its blocked paths for scanners to get there.

To hear about bans as they happen, turn on IP banned for a channel under Profile → Notifications (it's off by default): each new ban sends the address, until when, the host it was hitting and the reason, linking to Blocked IPs. See Notifications.

Which address gets banned. It's the address Traefik sees the request come from. Behind Homerun's own Pangolin tunnel (Newt credentials set on the DNS page), that's the visitor: Homerun tells Traefik to believe the visitor address Pangolin forwards, from the tunnel container and nothing else. Behind any other proxy or tunnel (Cloudflare's proxy, a load balancer, a Newt you run yourself), it's the proxy. Homerun never bans a private, loopback, link-local or carrier-grade NAT address (which is how a tunnel or a Docker network reaches Traefik), nor an address in Cloudflare's published proxy ranges, so a proxy can't get every visitor behind it banned. Behind such a proxy, blocked paths still work; bans just don't happen. Only requests that really went through a blocked-paths router count: requesting the Blocked path page directly never does.

#CrowdSec

If a CrowdSec agent guards the server in front of Homerun (a Pangolin server, typically, with its firewall bouncer), Homerun can hand it every ban, so the address is dropped at that server before it reaches yours, on every port.

  1. On the CrowdSec host, register Homerun as a machine: cscli machines add homerun --password <password>. A bouncer key won't do, bouncers can only read decisions.
  2. Make the Local API reachable from Homerun over HTTPS. By default it only listens on 127.0.0.1:8080 on its own host.
  3. Under Settings → IP bans → CrowdSec, enter the LAPI URL, the machine id and its password, and save. Saving logs in first and refuses credentials that don't work. Clear the URL to stop.

Each new ban becomes a CrowdSec ban decision for the ban's length (ten years for a ban for good) and shows up in cscli decisions list, with "homerun:" and the reason as its scenario. Unban on Blocked IPs deletes every decision on that address, CrowdSec's own included. CrowdSec expires decisions itself. A failed push shows up among Homerun's own errors on System Logs, and the ban still applies in Homerun's own Traefik.

Monitoring → CrowdSec (admins) reads the Local API live, in three tabs, each paged:

  • Decisions: every decision CrowdSec's bouncers enforce right now from its own scenarios, manual bans and Homerun's, with the address's country and network when CrowdSec knows them, its reason and origin and when it ends. Bans Homerun pushed are marked Homerun. Delete lifts one decision; it doesn't lift Homerun's own ban on the same address, which stays under Blocked IPs. New decision bans an address through CrowdSec only, for a number of hours (0 for ten years) with a reason. Homerun's own Traefik isn't told.
  • Alerts: what CrowdSec's scenarios caught in the last 24 hours.
  • Community blocklist: the addresses the CrowdSec community reported, tens of thousands of them, searchable by address or scenario. Homerun reads the list at most once a minute.

A firewall bouncer drops everything from a banned address, the dashboard included when it's served through the same server. Homerun's own exception for the dashboard doesn't reach that far: lift the ban from another network, or with cscli decisions delete --ip <address> on the CrowdSec host.

This guide lives in the project repo: edit it there, and this page follows within a day.