NovaPanel
Docs

Web Application Firewall

Protect a site with the Coraza WAF and OWASP Core Rule Set — the three modes, per-category tuning, the one-click WooCommerce fix, and the safe rollout for a live store.

NovaPanel's Web Application Firewall inspects incoming HTTP requests and blocks the ones that look like attacks — SQL injection, cross-site scripting, path traversal, and the rest of the OWASP catalogue — before they ever reach your app. It runs on Coraza, a modern Go-native WAF engine embedded directly in Caddy, reading the industry-standard OWASP Core Rule Set (CRS). Because it lives inside the web server there's no extra proxy or network hop: every request is evaluated in microseconds as it's served.

The WAF is a Pro feature. On Community the panel returns the setting as unavailable; upgrade to Pro (or Developer) to enable it. It's configured per site, so you can lock down a WordPress install while leaving a static marketing page untouched.

Where to find it

In the customer panel, open Web Application Firewall and pick the site from the selector in the top-right. Each site has its own mode and rule configuration.

The three modes

  • Off — no filtering. Requests reach your app unchecked.
  • Detection only — the WAF inspects every request and logs matches, but never blocks anything. Nothing on your site changes for visitors. This is the safe mode for a live store: you get full visibility into what would be blocked without risking a broken checkout.
  • Blocking — matching requests are rejected with an HTTP 403 and logged. This is full protection.

Use Blocking for anything you can turn on and forget — a fresh WordPress site, an API, a static app. Use Detection only first on anything with complex form submissions (WooCommerce, checkout, page builders, rich-text editors) where a false positive would be an outage.

Recommended rollout for a live or e-commerce site

Some legitimate traffic looks like an attack to a generic ruleset — a WooCommerce add-to-cart POST or a page-builder save can trip a CRS rule and earn a 403. Don't discover that on a customer's checkout. Roll out like this:

  1. Set the site to Detection only and apply. Nothing gets blocked yet.
  2. Let real traffic flow for a day — place a test order, save a few pages, click through the site the way a customer would.
  3. Watch the site's Caddy log for CRS matches. Each logged match names the rule ID that fired (for example a 942xxx hit on an add-to-cart request means the SQL Injection category flagged a legitimate order).
  4. Find the rule ID's category in the table below, turn just that one category off, and switch the site to Blocking.

You end up with full blocking everywhere except the one class of rule that conflicted with your app — instead of the all-or-nothing choice of leaving the whole firewall off.

Running WooCommerce? You can skip most of that — see the one-click toggle below.

WooCommerce & WordPress compatibility

A handful of CRS rules reliably misfire on standard WooCommerce and WordPress traffic. The two most common:

  • Add to cart — product names with accented or non-English characters (é, ü, ñ…) get encoded in the request and trip rule 920540 (Protocol Enforcement), returning a 403.
  • Checkout — WooCommerce's order-attribution field is named wc_order_attribution_session_start_time, and the WAF reads the text session_start inside it as PHP injection (rule 933150). The checkout order summary then spins forever, because the blocked request never returns.

Rather than switch off whole categories to clear these, turn on WooCommerce / WordPress compatibility. It excludes exactly the specific rules known to false-positive on WooCommerce core flows (920540, 933150, 933151) and nothing else — every other rule, including SQL injection and XSS, stays fully enforced. This lets a store run in full Blocking mode without breaking cart or checkout.

The same toggle also fixes the other common WordPress false positive: editing content in the admin area. A logged-in admin saving a post, a product, or a widget legitimately submits HTML and JavaScript — a page-builder layout, a WooCommerce Vouchers template, an embed — which the XSS rules read as an attack and block with a 403 on /wp-admin/post.php. Because the admin area is already behind WordPress login, the toggle runs the firewall in detection-only mode inside /wp-admin/ (still logged, never blocked), so admins can work freely while your public-facing pages, forms and comments stay fully protected.

Firewall events — see what was blocked

The WAF page shows a Recent firewall events panel for the selected site: every request the firewall blocked or flagged in the last 48 hours, with the time, the URL, the client IP, and the exact CRS rule IDs that fired. This is the fastest way to tell a real attack from a false positive on your own traffic — no digging through server logs. If one of the rules is blocking something legitimate, click the rule-ID chip to disable that rule for this site in one step (it's added to the disabled-rules list and applied immediately).

Disabling a single rule

For anything you'd rather clear by hand, use Disable specific rules. Enter the exact CRS rule IDs (comma-separated) — the ones shown in the events panel or next to a blocked request in the Caddy log, for example 942200. This drops just those rules, the most precise way to clear a false positive without weakening a whole class of protection. It's the surgical alternative to a category toggle.

If the firewall engine isn't installed

The WAF runs as a module inside Caddy. On rare installs the build service that produces the firewall-enabled Caddy is briefly unavailable, and the installer falls back to stock Caddy without the module — in which case the WAF page warns you and per-site WAF can't be enforced. Fix it from Admin → Settings → Firewall engine: click Install firewall engine and NovaPanel fetches and swaps in a firewall-enabled Caddy in the background (no reinstall, no downtime, and it rolls back automatically if anything fails). It also self-heals on the next panel restart if a site has WAF enabled. Once it shows "WAF module installed," your per-site settings take effect.

Blocking xmlrpc.php (WordPress hardening)

WordPress's xmlrpc.php endpoint is a well-known attack surface — used for pingback-based DDoS and brute-force amplification — that almost no modern site actually needs. Turn on Block xmlrpc.php and NovaPanel returns a 403 for that path at the web-server layer, before the request reaches PHP or even the WAF. This both hardens the site and stops the bot traffic against xmlrpc from filling your logs. It works whether or not the WAF is enabled. Leave it off only if you rely on the WordPress mobile app or Jetpack, which use that endpoint.

Rule categories

All eight categories are active by default. Turning one off removes that entire class of CRS rules for the site, so a single false positive never forces you to disable the whole firewall. The categories map to stable CRS rule-ID ranges (shown so you can match them against your log):

  • SQL Injection — CRS 942, SQLi payloads.
  • Cross-Site Scripting — CRS 941, XSS payloads.
  • Remote Code Execution — CRS 932/933, command & PHP injection.
  • Remote File Inclusion — CRS 931, RFI attempts.
  • Local File Inclusion — CRS 930, path traversal / LFI.
  • Scanner Detection — CRS 913, scanners & hostile bots.
  • Protocol Enforcement — CRS 920/921, malformed HTTP abuse.
  • Session Fixation — CRS 943, session-fixation patterns.

Category toggles apply in both Detection and Blocking mode. In Detection they change what gets logged; in Blocking they change what gets a 403.

How it works under the hood

Each site's WAF settings are written into that site's own Caddy configuration. When you hit Apply changes, NovaPanel rewrites the config and reloads Caddy instantly — there's no downtime and no separate service to restart. Blocking mode maps to Coraza's SecRuleEngine On; Detection only maps to SecRuleEngine DetectionOnly. Disabling a category emits a rule-range removal after the CRS include, so that class of rules is dropped cleanly.

A blocked request returns HTTP 403 and is recorded in the site's Caddy access log together with the CRS rule ID that fired — that log is your source of truth for tuning.

Troubleshooting

  • A WooCommerce cart or checkout returns 403 (or checkout spins forever). Turn on WooCommerce / WordPress compatibility and re-apply — that covers the two rules that break WooCommerce out of the box, with no need to touch categories.
  • Another legitimate request is being blocked (403). Switch the site to Detection only, reproduce the action, and read the CRS rule ID from the Caddy log. Then either enter that ID under Disable specific rules (precise) or turn off its category above (broad), and go back to Blocking. This keeps every other protection in place.
  • Not sure whether the WAF is the cause. Flip to Detection only. If the 403 disappears, the WAF was blocking it and the log will tell you which rule.
  • The option is unavailable. The WAF requires a Pro (or Developer) licence — see Upgrading your licence.

Related: hotlink protection

Separate from the WAF, NovaPanel has a per-site Hotlink Protection page (under Security). It stops other websites from embedding your images and files directly — hotlinking — which loads your content on their pages using your bandwidth. Turn it on and requests for your media files (images, video, PDFs) are blocked when they come from another site, while direct visits, search engines, and your own pages keep working. You can set which file types are protected and allow specific extra sites (a CDN or partner) if needed.

Next steps