Skip to Content
PluginsLW Firewall

LW Firewall

Lightweight WordPress firewall - rate-limits endpoints, blocks bots, bans repeat offenders, and adds security headers.

Overview

Requires WordPress6.6+
Requires PHP8.1+
Tested up to6.7
LicenseGPL-2.0-or-later
GitHublwplugins/lw-firewall 

Installation

bash
composer require lwplugins/lw-firewall

Or upload the lw-firewall folder to /wp-content/plugins/ and activate through the Plugins menu. The MU-plugin worker is installed automatically on activation.

To find a setting, use the Quick search field at the top of the settings sidebar (or press Cmd/Ctrl+K) and type its name: the match opens on its tab, scrolled into view and highlighted.

Features

How It Works

LW Firewall installs an MU-plugin worker that intercepts requests before WordPress fully loads, protecting your server from bots, brute-force attacks, DDoS, and vulnerability scanners.

Processing order:

  1. IP Whitelist - whitelisted IPs skip all checks
  2. IP Blacklist - blacklisted IPs get 403 immediately
  3. Geo Blocking - block entire countries (Cloudflare header or CIDR lookup)
  4. Auto-Ban - previously banned IPs get 403
  5. 404 Flood - IPs with excessive 404s get 429
  6. Bot Blocking - User-Agent matching (all requests)
  7. Endpoint Detection - filter params, cron, xmlrpc, login, REST API
  8. Rate Limiting - per-IP counters with auto-ban escalation

Endpoint Protection

EndpointProtection
WooCommerce filtersRate limit + bot blocking
wp-login.phpBrute-force rate limiting
wp-cron.phpDDoS rate limiting
xmlrpc.phpDDoS/brute-force rate limiting
REST API (/wp-json/)Rate limiting
404 pagesVulnerability scanner blocking

WooCommerce filter protection sets a visitor cookie (lwfw_v, plus lwfw_c for a moment during the check). With LW Cookie 1.9.7 or newer, both are declared as strictly necessary automatically and are never blocked.

Geo Blocking

  • Block visitors by country (Cloudflare or CIDR fallback)
  • Enabled by default for CN, RU, IN, VN, ID, BD
  • Apache-level geo blocking via .htaccess - blocks before PHP loads
  • Configurable block action (403 Forbidden or redirect to homepage)

Bot Blocking

  • User-Agent based blocking (20+ bad bots blocked by default)
  • Applies to all requests, not just specific endpoints

IP Management

  • IP whitelist and blacklist with CIDR range support
  • Automatic server/localhost IP whitelisting
  • Full IPv6 support

Auto-Ban

  • Escalating protection for repeat offenders
  • Per-IP violation counters

Security HTTP Headers

  • X-Content-Type-Options
  • X-Frame-Options
  • And other configurable security headers

Storage Backends

BackendDescription
APCuFastest - in-memory, per-process
RedisFast - shared across processes
FileFallback - always works

Auto-detection picks the best available backend.

Two-Factor Login

Optional and off by default. After the password, users confirm the sign-in with one of these:

  • Authenticator app (TOTP) - any standard app; 10 one-time recovery codes are created when it is set up.
  • Passkeys (WebAuthn) as a second factor, up to 10 per account.
  • Passwordless passkey sign-in - a “Sign in with a passkey” button on the login page. A passkey replaces both the password and the second step.

Around the sign-in:

  • Required roles with a grace period. Pick the roles that must use a second factor. During the grace period (7 days by default) they only get a reminder; afterwards they are taken to the setup page at login instead of being locked out. The forced setup is confirmed with a code sent to the account’s e-mail address.
  • Remember this device for a number of days (0 = off, the default), with a button to forget all remembered devices.
  • Notifications. The account owner gets an e-mail when a second factor, the recovery codes or the remembered devices change.
  • Self-service on the profile page: set up or remove the authenticator app, add and remove passkeys, create new recovery codes. Sensitive steps ask for the password while the account has no second factor; once it has one, they ask for a second factor (authenticator code, passkey or recovery code).
  • Two-Factor tab in the settings with usage per role, the options above and an optional switch that disables application passwords for users who have a second factor.
  • Admin reset. An administrator can reset any user’s two-factor login from that user’s profile.

Two-factor login needs the PHP sodium and openssl extensions. Without them it stays off and an admin notice explains why.

I lost my phone

WayHow
Recovery codeChoose “Use a recovery code” on the second step. Each code works once.
Another administratorUse the reset button on your user profile.
WP-CLIwp lw-firewall 2fa reset <user>
Emergency off switchAdd define( 'LW_FIREWALL_TWOFA_ENABLED', false ); to wp-config.php. Two-factor login switches off at once.

Known interactions

  • A captcha-type plugin that checks fields posted to the login form refuses passkey sign-in, because that request carries no password. Use the passkey only as a second factor there.
  • Signing in on a host name that is not the site’s home/site URL host (for example a www alias) needs the lw_firewall_passkey_allowed_origins filter:
php
add_filter( 'lw_firewall_passkey_allowed_origins', function ( array $origins ): array { $origins[] = 'https://www.example.com'; return $origins; } );
  • Passkeys belong to the site’s domain. Moving the site to a new domain invalidates them; the authenticator app and the recovery codes keep working.
  • Password logins outside the login page (XML-RPC apps, REST API login plugins, AJAX login forms of themes or page builders) are refused for accounts that use a second factor, and for accounts in a required role once their grace period ends: those requests cannot show the second step. Give integrations an application password instead, and keep Block Application Passwords off for those accounts.
  • On multisite the two-factor settings are network-wide, because a sign-in is valid on every site of the network. A network administrator sets them in the main site’s Two-Factor tab; the other sites show them read-only. Network-activate the plugin so that every site asks for the second factor.

Additional Features

  • Cloudflare-aware IP detection (CF-Connecting-IP with IP range validation)
  • Import/Export settings as JSON
  • Optional request logging with viewer
  • wp-config.php constant overrides

Settings

Configure under LW Plugins > Firewall. The settings page uses a tabbed interface with these tabs:

TabDescription
GeneralFirewall toggle, storage backend, rate limits
ProtectionEndpoint protection toggles
Bot BlockingUser-Agent blocklist management
IP RulesWhitelist and blacklist management
Geo BlockingCountry-based blocking
SecurityHTTP security headers
LogsRequest log viewer
Import/ExportTransfer settings between sites
WooCommerceFilter parameter rate limiting
Two-FactorTwo-factor login: required roles, grace period, remember device, passwordless passkey login, usage per role

WP-CLI Commands

Status

bash
wp lw-firewall status

Shows firewall status overview: enabled, storage, rate limit, worker status, etc.

Configuration

bash
# List all settings wp lw-firewall config list wp lw-firewall config list --format=json # Set a value wp lw-firewall config set rate_limit 50 wp lw-firewall config set enabled true wp lw-firewall config set storage apcu wp lw-firewall config set action 429 # Reset to defaults wp lw-firewall config reset --yes

Blocked Bots

bash
# List blocked User-Agents wp lw-firewall bots list wp lw-firewall bots list --format=json # Add a bot wp lw-firewall bots add "newbot/1.0" # Remove a bot wp lw-firewall bots remove "newbot/1.0"

Logs

bash
# View recent logs wp lw-firewall logs list wp lw-firewall logs list --limit=50 wp lw-firewall logs list --format=json # Clear all logs wp lw-firewall logs clear --yes

Worker Management

bash
# Install/reinstall the MU-plugin worker wp lw-firewall worker install # Remove the worker wp lw-firewall worker remove

IP Management

bash
# List whitelist or blacklist wp lw-firewall ip list whitelist wp lw-firewall ip list blacklist wp lw-firewall ip list whitelist --format=json # Add an IP or CIDR range wp lw-firewall ip add whitelist 192.168.1.100 wp lw-firewall ip add blacklist 10.0.0.0/8 # Remove an IP or CIDR range wp lw-firewall ip remove whitelist 192.168.1.100 wp lw-firewall ip remove blacklist 10.0.0.0/8

Geo Blocking

bash
# List blocked countries wp lw-firewall geo list wp lw-firewall geo list --format=json # Add a country (ISO 3166-1 alpha-2 code) wp lw-firewall geo add CN wp lw-firewall geo add RU # Remove a country wp lw-firewall geo remove CN # Update CIDR cache for all blocked countries wp lw-firewall geo update

Two-Factor Login

bash
# Usage per role, or one user's factors wp lw-firewall 2fa status wp lw-firewall 2fa status alice # Remove every factor, recovery code and remembered device of a user wp lw-firewall 2fa reset alice --yes

Configuration via wp-config.php

Settings can be overridden via constants in wp-config.php:

php
define( 'LW_FIREWALL_ENABLED', true ); define( 'LW_FIREWALL_STORAGE', 'apcu' ); define( 'LW_FIREWALL_RATE_LIMIT', 50 ); define( 'LW_FIREWALL_RATE_WINDOW', 120 ); define( 'LW_FIREWALL_ACTION', '429' ); define( 'LW_FIREWALL_LOG_ENABLED', true ); // Emergency off switch for two-factor login define( 'LW_FIREWALL_TWOFA_ENABLED', false );

AI Abilities

When used with LW Site Manager, the following abilities are available for AI agents. All abilities are registered under the firewall category and require manage_options capability.

lw-firewall/get-options (readonly)

Returns all LW Firewall settings merged with defaults.

Input: none

Output:

json
{ "success": true, "options": { "enabled": true, "rate_limit": 30, "rate_window": 60, "ip_blacklist": [], "ip_whitelist": [], "blocked_bots": ["gptbot", "claudebot"], "geo_enabled": true, "blocked_countries": ["CN", "RU"] } }

lw-firewall/get-log (readonly)

Returns recent blocked request log entries. Requires log_enabled to be active in settings.

Input:

FieldTypeDefaultDescription
limitinteger25Number of entries to return (1-100)

Output:

json
{ "success": true, "entries": [ { "ip": "1.2.3.4", "reason": "rate_limit", "ua": "...", "url": "/wp-login.php", "time": "2025-01-01 12:00:00" } ], "total": 42 }

lw-firewall/list-blocked (readonly)

Returns all IP addresses and CIDR ranges currently on the manual blacklist.

Input: none

Output:

json
{ "success": true, "ips": ["1.2.3.4", "10.0.0.0/8"], "total": 2 }

lw-firewall/block-ip (write)

Adds an IP address or CIDR range to the blacklist.

Input:

FieldTypeRequiredDescription
ipstringyesIP address (e.g. 1.2.3.4) or CIDR range (e.g. 10.0.0.0/8)

Output:

json
{ "success": true, "message": "1.2.3.4 has been added to the blacklist." }

Errors: 400 missing_ip, 400 invalid_ip

lw-firewall/unblock-ip (write)

Removes an IP address or CIDR range from the blacklist.

Input:

FieldTypeRequiredDescription
ipstringyesIP address or CIDR range to remove

Output:

json
{ "success": true, "message": "1.2.3.4 has been removed from the blacklist." }

Errors: 400 missing_ip, 404 ip_not_found

Notes:

  • The blacklist changes (block-ip / unblock-ip) are persisted immediately.
  • Auto-banned IPs (set by the auto-ban system in storage) are separate from the manual blacklist and cannot be managed through these abilities.
  • Log entries are only available when log_enabled is true in the firewall settings.

FAQ

Does it work without WooCommerce?

Yes. WooCommerce filter protection is optional. The firewall also protects wp-login.php, wp-cron.php, xmlrpc.php, REST API, and 404 floods independently.

What storage backend should I use?

APCu is fastest (in-memory, per-process). Redis is fast and shared across processes. File-based is the fallback that always works. Auto-detection picks the best available.

Will it block legitimate users?

Rate limits are per-IP. Casual users will not trigger them. Only bots and attackers sending many requests in a short window get blocked. You can whitelist trusted IPs.

Does it support Cloudflare?

Yes. It automatically detects the real visitor IP via the CF-Connecting-IP header with Cloudflare IP range validation to prevent spoofing.

I lost my phone and cannot sign in. What now?

Use one of your recovery codes on the second step; each works once. If you have no code left, another administrator can reset your two-factor login from your user profile, or run wp lw-firewall 2fa reset <user>. If every administrator is locked out, add define( 'LW_FIREWALL_TWOFA_ENABLED', false ); to wp-config.php: two-factor login switches off at once and accounts sign in with their password again.

Passkey sign-in does not work on my site.

Three known cases: a captcha-type plugin that checks the login form fields refuses it (the request has no password); a host name other than the site address (for example a www alias) needs the lw_firewall_passkey_allowed_origins filter; and moving the site to a new domain invalidates existing passkeys. See Two-Factor Login above.

An app or plugin can no longer sign in with my password.

For an account with a second factor, and for an account in a required role once its grace period ends, password logins outside the login page are refused (XML-RPC apps, REST API login plugins, AJAX login forms). Create an application password on the user’s profile for the integration instead.

Does two-factor login work on multisite?

Yes. The settings are network-wide: a network administrator sets them on the main site, and the other sites show them read-only. Network-activate the plugin so that every site asks for the second factor.