Skip to content
All guides

Docs Protection

Protection

SSH, auth, and container log watches with custom RE2 filters and auto-bans.

Overview

Protection is Foster’s intrusion watchdog (not Fail2Ban or nginx). It watches auth/SSH — and optional container logs — and bans offenders through Foster’s firewall chain. The panel shows status, active bans, attempt counters, and a recent event feed.

Counters sync to the panel about every 30 seconds and remain visible offline from the last sync.

Modules

  • Toggle modules: SSH, auth, web, and containers.
  • Set aggression 1–5 (higher levels = fewer retries / shorter windows).
  • The web module is reserved until Foster proxy access logs are fully wired — it may show unavailable.

Bans

  • View active bans and unban an IP from the panel.
  • Manually block an IP (default duration 24h, or permanent).
  • Sensitive actions may require 2FA step-up when enabled.

Container watches

Container watches are Foster’s log-based filtering system. You attach a filter (built-in or custom) to any container you choose. The agent then actively tails that container’s logs (docker logs -f) and, when a line matches the filter, extracts the attacker address and bans it through the same Protection / firewall path as SSH and auth modules.

Advanced Protection (Medium/Max — protection.blocklist) is required for live tails and watch/filter create/update/delete. See Containers for runtime tooling.

How it works

  1. Create or pick a filter — a named detector with a Go RE2 regex (or a built-in like MySQL auth).
  2. Attach it to a container — bind filter → container name (for example foster_mysql or any app container).
  3. Agent watches logs — only containers with an enabled watch are tailed.
  4. Match → ban — when a log line matches and captures a usable IP, Protection records the attempt and bans per aggression settings.

Built-in filters

  • mysql_authMySQL auth / abort. Matches Access denied for user '…'@'ip' and Aborted connection … host: 'ip'. MySQL must emit those lines (typically log_error_verbosity ≥ 3).

Custom filters

On the Protection → Containers UI you can create your own filters (account-scoped). Each filter has a name, optional description, and a RE2 regex pattern. Once saved, you can attach that filter to any container on the server — Foster keeps tracking that container’s stdout/stderr logs continuously while the watch is enabled.

Requirements (important)

The container must actually log the behavior you care about. Filters only see lines that appear in the container’s Docker logs. If your app or database never prints the attack pattern (failed login, rate-limit abuse, probe, etc.), the filter will never fire — even when attached correctly.

  • Enable verbose / auth / access logging in the app or database config.
  • Confirm with docker logs <container> that the expected lines show up.
  • Patterns must capture the attacker as a named group (?P<ip>…) or (?P<host>…).
  • The captured value must resolve to a usable IP (hostnames that aren’t IPs are ignored).

Attach to a container

  1. Open Protection → Containers (Advanced Protection required).
  2. Create a custom filter, or select a built-in / saved filter.
  3. Choose the target container and attach the watch (enable binding).
  4. You can attach the same filter to multiple containers, or multiple filters to one container.
  5. Remove a watch anytime; deleting a custom filter also drops watches that used it.

Regex rules (Go RE2)

  • Syntax is Go RE2 (same family as many Google tools) — no backreferences or lookaround.
  • You must include exactly one of: (?P<ip>…) or (?P<host>…) for the attacker address.
  • (?i) at the start makes the pattern case-insensitive.
  • Prefer anchoring to distinctive log text so normal traffic doesn’t false-trigger bans.

Regex examples

MySQL / MariaDB access denied (similar to the built-in detector):

(?i)Access denied for user '[^']+'@'(?P<host>[^']+)'

Matches a line like:

Access denied for user 'root'@'203.0.113.40' (using password: YES)

Postgres authentication failure (when Postgres logs the client address):

(?i)password authentication failed for user ".*?"(?:.*?\b)?(?P<ip>\d{1,3}(?:\.\d{1,3}){3})

Only works if your Postgres log line includes the client IP — verify with real logs first.

Generic “failed login from IP” style application log:

(?i)failed login.*\bfrom\b\s+(?P<ip>\d{1,3}(?:\.\d{1,3}){3})

Example matching line:

[auth] failed login for admin from 198.51.100.22

Nginx / app “denied” with remote address field:

(?i)client denied by.*client:\s*(?P<ip>\d{1,3}(?:\.\d{1,3}){3})

Tip: start from a real log line copied from the container, then wrap the IP/host portion in (?P<ip>…) or (?P<host>…) and escape only what’s needed for RE2.

Threat blocklist

A global threat feed syncs into Foster on a schedule. Higher plans can check membership; the Protection UI can show feed size/stats. Listing an IP as known-bad complements local bans — it does not replace module configuration.

Notes

  • High aggression can ban legitimate users (shared NAT, CI, flaky clients). Unban removes Foster’s ban and firewall block for that IP — it does not fix the underlying attack source.
  • Container watches only fire when matching lines appear in that container’s logs. Attaching a filter does nothing if the process never logs the pattern (wrong verbosity, logs to a file inside the container that Docker doesn’t stream, or a different message format).
  • Custom filters that are too broad can ban healthy clients — test patterns against sample logs before enabling on production containers.
  • Built-in MySQL watching expects error-verbosity high enough to print client hosts on auth failures.