Localtonet Now Has a Built-In Web Application Firewall: What It Does and Why You Need It
The moment you create a Localtonet tunnel and get a public URL, automated scanners find it. Not in days. In minutes. They probe for SQL injection, try to access admin panels, look for configuration files left exposed, and test hundreds of known attack patterns on the assumption that most self-hosted services have no protection layer. Until now, protecting a tunneled service required either paying for an expensive enterprise WAF or accepting the risk. Localtonet now ships a fully built-in Web Application Firewall at no extra cost, embedded directly into the reverse proxy that powers every tunnel. This post explains what it does, how it makes decisions, and how to configure it for your service.
What Happens When You Open a Tunnel (Without a WAF)
When you expose a local service to the internet through a tunnel, the URL is public. It does not matter that it is a home server or a development environment. Automated scanners crawl the entire internet continuously, and a new hostname appears on their radar almost immediately after it goes live.
Within the first hour of a new tunnel being active, you can expect:
' OR '1'='1 or UNION SELECT to every URL parameter they find. If your service connects to a database and has no input validation, one successful probe can dump the entire database.
/wp-admin, /.env, /admin, /config.php, /phpmyadmin. If any of these exist and are accessible, they are found within minutes.
../../etc/passwd test whether your service will accidentally serve files outside its intended directory. A single vulnerable endpoint can expose your entire server filesystem.
None of this is targeted at you personally. It is automated, indiscriminate, and constant. The WAF runs as an invisible layer in front of your tunnel and handles all of it before a single malicious packet reaches your service.
What Is a Web Application Firewall?
A traditional firewall controls which ports and IP addresses can communicate with a server. It works at the network level and is good at blocking entire countries or IP ranges. But it cannot understand HTTP traffic. It cannot see that a URL parameter contains a SQL injection payload, or that a request body contains a malicious script tag.
A Web Application Firewall (WAF) operates at the application layer. It reads every HTTP request in full, including the URL, every parameter, every header, every cookie, and the request body, and decides whether it looks like a legitimate user or an attack before the request reaches your application. Think of it as a security guard who checks IDs and searches bags at the door, rather than a fence around the building.
Enterprise WAFs cost thousands of dollars a month. The Localtonet WAF is included.
AWS WAF starts at $5/month plus $1 per million requests, plus $5 per rule set per month. Cloudflare WAF requires a Business plan at $200/month or more. Akamai and Imperva charge thousands of dollars per month for their full enterprise WAF products. The Localtonet WAF runs in-process, embedded directly into the same reverse proxy that handles your tunnels, with zero additional infrastructure cost and no per-request fees.
How the WAF Makes Decisions: Scoring, Not Guessing
Most simple firewalls work on binary rules: if the request matches this pattern, block it. This approach causes a lot of false positives. A developer testing their own API from a script might get blocked because their request looks slightly unusual. A legitimate user with an uncommon browser setup might be mistakenly challenged.
The Localtonet WAF uses an anomaly scoring model. Instead of blocking on a single rule match, it assigns a score to each suspicious signal it finds in a request. The scores accumulate. Only when the total crosses a threshold does the WAF take action, and even then, the action is proportional to the score rather than an immediate hard block.
How the scoring works in plain terms
Imagine a request arriving at your tunnel. The WAF checks it against dozens of rules. Each rule can add points to a running score:
- Missing
Accept-Languageheader (minor bot signal): +2 points - User-Agent is empty (stronger bot signal): +4 points
- URL contains
../path traversal attempt: +7 points - URL contains full SQL
UNION SELECTpayload: +10 points
The WAF adds these up and responds proportionally. A score of 2 is just logged. A score of 12 gets a challenge. A score of 20 is blocked. A single rule returning 10 (a definitive attack payload) blocks immediately, no accumulation needed.
This proportional approach has one important consequence: it dramatically reduces false positives. A developer calling an API without browser headers gets a slightly elevated score but not enough to be challenged. The same request with a SQL injection payload in the body gets blocked instantly.
The Four Responses: From "Let Through" to "Blocked"
The WAF has four possible responses to any incoming request, applied in order based on the accumulated score:
Allow (score is 0 or request is whitelisted)
The request shows no suspicious signals. It passes through to your service immediately. This is the response for the vast majority of legitimate traffic.
Log (low score, below challenge threshold)
Something minor was flagged (unusual browser headers, a slightly odd User-Agent, a path that resembles a scanner probe). The request still reaches your service, but the WAF records the event. Over time, if this IP keeps generating low-level signals, its rate limits tighten automatically.
Challenge (score above challenge threshold)
The request is suspicious enough to warrant verification. The WAF serves an invisible JavaScript proof-of-work puzzle. A real browser solves it in about 200 milliseconds without showing the user anything visible. A bot or script that cannot execute JavaScript fails silently and is filtered out. The user sees a very brief pause and then the page loads normally.
Block (definitive attack or IP banned)
A single rule returned a score of 10 (an unambiguous attack pattern like a textbook SQL injection payload), or the IP is on a threat intelligence blocklist, or the client has passed the JavaScript challenge but continues generating high scores and has failed the CAPTCHA escalation. The request is rejected with no further processing.
The Challenge System: How Bots Are Filtered Without Annoying Humans
The challenge system is one of the most carefully designed parts of the WAF. The goal is to let real users through while stopping automated tools, without making legitimate users jump through hoops.
Step 1: JavaScript Proof-of-Work
When the anomaly score crosses the challenge threshold, the WAF serves an intermediate page with a JavaScript puzzle. The browser runs the puzzle in a background thread (a Web Worker), finds a solution, and the page loads automatically. The user sees a loading screen for roughly 200 milliseconds. Bots and scripts that do not execute JavaScript never solve the puzzle and never get through.
Once solved, the browser receives an encrypted cookie that proves it passed. Subsequent requests from the same browser carry this cookie and skip the challenge entirely.
Step 2: Behavioral CAPTCHA (only if the challenge was not enough)
A client that passed the JavaScript challenge but continues generating high anomaly scores gets escalated to a behavioral CAPTCHA. The CAPTCHA system first attempts invisible behavioral verification (mouse movement analysis, canvas rendering, timing). If that passes with a high confidence score, nothing is shown to the user at all. If confidence is low, a simple drag-to-complete slider puzzle appears. This is only triggered for clients that remain suspicious after already passing the JavaScript challenge.
A browser loading a page cannot pause to solve a puzzle mid-render. All static file extensions are permanently excluded from challenge logic. A challenge is only ever served in response to a page or API request, never in response to an asset request. This ensures the challenge page itself loads and displays correctly.
Sensitivity Levels: How Aggressive the WAF Is
Not every service needs the same level of protection. A personal note-taking tool accessed only by you needs different settings than a public API that receives thousands of requests per day from unknown users. Sensitivity controls how quickly the WAF escalates from logging to challenging to blocking.
| Level | Challenge Triggers At | Block Triggers At | Best For |
|---|---|---|---|
| Low | Score 15 | Score 25 | Internal tools, developer environments, APIs where false positives are more disruptive than attacks |
| Medium | Score 12 | Score 20 | Private services shared with a small group of known users |
| Standard (default) | Score 10 | Score 15 | Most home server services. The right balance for public-facing services with unknown visitors. |
| High | Score 7 | Score 12 | Public services that handle sensitive data. Login portals, password managers, financial tools. |
| Paranoid | Score 5 | Score 8 | Maximum protection. Even mildly unusual requests get challenged. Expect some legitimate users to see the challenge. Use when security matters more than convenience. |
What the WAF Protects Against
The WAF checks every request against three layers of rules, running from fastest to most thorough.
Layer 1: Pre-Filter Rules (runs first, very fast)
Pre-filter rules examine the metadata of the request without reading the content. They catch the most obvious threats immediately and are designed to run in under 0.1 milliseconds each.
| Rule | What It Does |
|---|---|
| IP Reputation | Checks the visitor's IP against 6 threat intelligence feeds updated every 6 hours: Spamhaus DROP/EDROP, Blocklist.de, Firehol Level 1, IPsum, and optionally AbuseIPDB. IPs from known attack sources are scored 8 or blocked immediately if manually banned. |
| Bot Detection | Identifies automated tools by matching 25+ patterns in the User-Agent (sqlmap, nikto, dirbuster, Playwright, Puppeteer, python-requests, and more), checking for missing browser headers that all real browsers always send, and verifying Chrome Client Hints. Legitimate API clients and verified search engine bots are explicitly exempted. |
| Request Size Limits | Rejects requests with abnormally large URLs, headers, or bodies. Oversized requests are common in buffer overflow attempts and memory exhaustion attacks. |
| HTTP Protocol Validation | Verifies the request is structurally valid HTTP. Catches null bytes in headers, CRLF injection, invalid HTTP methods, and requests with both Content-Length and Transfer-Encoding headers present simultaneously (a common HTTP request smuggling technique). |
| Geo-Blocking | Optionally blocks specific countries or restricts access to an allowlist of countries. Uses the MaxMind GeoLite2 database for IP-to-country resolution. Unlike other rules, geo-blocking cannot be bypassed by passing the JavaScript challenge. |
Layer 2: OWASP Rules (inspects request content)
These rules implement the OWASP Top 10 protections by scanning URLs, parameters, headers, cookies, and request bodies for attack payloads. All patterns are pre-compiled at startup for maximum speed.
../ sequences in all encoding variants. Score is elevated to 10 when the target is a known sensitive file like /etc/passwd, /etc/shadow, or web.config.
; ls, | cat, && whoami), backtick execution, and PowerShell patterns. Detects both Linux and Windows variants.
$gt, $where, $regex) in JSON request bodies and URL parameters.
Layer 3: Advanced Rules (sophisticated and stateful attacks)
Advanced rules go beyond simple pattern matching. They analyze behavior over time, check request context, and catch attack techniques that do not leave obvious signatures in a single request.
| Rule | What It Catches |
|---|---|
| Scanner Detection | Identifies security scanners by their path probing patterns and speed. An IP that visits 10 or more distinct paths within 60 seconds is flagged as scanning, regardless of what those paths are. |
| Credential Stuffing | Tracks login attempts per IP. More than 10 attempts per minute or 50 per hour on configured login paths triggers escalating responses. Passing a challenge resets the counter. |
| File Upload Protection | Validates uploaded files by checking the actual file content (magic bytes) against the declared file type. Blocks PHP, JSP, ASP shell uploads, executable files, and polyglot files that are valid as both an image and executable code. |
| HTTP Request Smuggling | Detects all three smuggling variants (CL.TE, TE.CL, TE.TE) including obfuscated Transfer-Encoding headers. A request with both Content-Length and Transfer-Encoding present scores 8. |
| WAF Bypass Detection | Catches bypass techniques specifically: IP spoofing via X-Forwarded-For, Unicode normalization attacks (fullwidth characters that normalize to dangerous ASCII), double URL encoding, and parameter pollution. |
| GraphQL Protection | Limits query depth to prevent exponential backend load, blocks schema introspection on production APIs, and detects batch query abuse. |
| TLS Fingerprinting | Compares the JA3 TLS fingerprint of the connection with the claimed User-Agent. A connection whose TLS fingerprint matches sqlmap or Metasploit but claims to be Chrome is flagged. |
| Honeypot Trap | Any request to configured decoy paths (/wp-admin, /.env, /xmlrpc.php) is flagged as malicious. Legitimate applications do not have these paths. Only scanners looking for vulnerable software probe them. |
| ASN Reputation | Flags requests from datacenter/VPS IP ranges (AWS, Hetzner, DigitalOcean) that claim to be desktop browsers. Real home users do not browse from data centers. |
Rate Limiting: Protecting Against Floods and Scrapers
Rate limiting runs as a separate layer before the rule engine and can trigger independently. It has four levels:
| Limit Type | Default | What It Stops |
|---|---|---|
| Per IP per second | 20 requests/sec | Burst flooding, DDoS from a single source |
| Per IP per minute | 500 requests/min | Sustained scraping or crawling from one IP |
| Per path per minute | Configurable | Credential stuffing on login endpoints (e.g. 10 req/min on /login) |
| Per domain total | Configurable | Traffic spikes that would overwhelm a small home server regardless of source |
Rate limits are adaptive. The WAF tracks the average anomaly score for each IP over a sliding window. IPs that have been generating suspicious signals consistently have their rate limits automatically tightened, even if their current request looks clean. An IP that has been mildly suspicious for the last 100 requests is treated with more caution than a fresh IP with a clean history.
The WAF Dashboard
Every domain's WAF has a dedicated dashboard that shows what is happening in real time and lets you adjust all settings without any restart or redeployment.
The dashboard has five sections:
Overview
A live summary showing total requests, blocked count, challenged count, logged events, allowed requests, and the current block rate. The "Top Triggered Rules" table shows which rules are firing most often, which helps identify what type of attack traffic is targeting your service. "Top Blocked IPs" shows the most active attackers. The IP Lookup tool lets you check any IP's ban status, threat intelligence hits, and recent anomaly score instantly.
Configuration
All the core settings in one place: WAF mode (Prevention for active blocking, Detection for log-only), sensitivity level, rate limiting thresholds, request size limits, and toggles for each protection module (Honeypot Traps, WebSocket Inspection, Threat Intelligence, Adaptive Rate Limiting, GraphQL Protection, TLS Fingerprinting, Credential Stuffing, and more). All changes take effect immediately without restarting anything.
Rules
The complete list of all 30+ built-in rules with their rule IDs, categories, priorities, and enable/disable toggles. Below the rule list is the custom rules section, where you define your own match conditions (field, match type, value, action, and score). Over 50 pre-built rule templates are available for common scenarios: blocking specific CVEs, challenging admin panel access, enforcing API key presence, blocking specific countries from specific paths, and more.
Events
A real-time log of every WAF event with full detail: time, action taken (LOG, CHALLENGE, CAPTCHA, BLOCK), anomaly score, visitor IP, country flag, HTTP method, URL path, and which specific rules fired. Events stream live as they happen, so you can watch the attack log update in real time while testing or after enabling protection on a new service.
Security
IP and path management: whitelist trusted IPs or CIDR ranges that should bypass all WAF checks, whitelist specific paths that should always be allowed (health check endpoints, webhook receivers from known services), configure geo-blocking by country, and manually ban or unban specific IPs or entire subnets with a configurable duration.
Custom Rules: Your Own Security Logic
The built-in rules cover the OWASP Top 10 and dozens of additional attack categories. But every service has unique characteristics that generic rules cannot anticipate. The custom rules system lets you write your own match conditions without any code.
Each custom rule specifies:
- Field to match: URL, query string, a specific header, a specific cookie, the request body, User-Agent, HTTP method, and more
- Match type: Contains, Equals, Starts with, Ends with, or Regex
- Match value: The string or pattern to look for
- Action: Block, Challenge, CAPTCHA, Log, or Allow (allow rules are useful as exceptions to built-in rules)
- Score: How much to add to the anomaly total if matched
Example custom rules you might add:
| Use Case | Field | Match | Value | Action |
|---|---|---|---|---|
| Challenge all admin panel access | URL | Starts with | /admin | Challenge |
| Block access from a specific IP | IP (via Security tab) | Equals | 1.2.3.4 | Block |
| Require API key header on API paths | Header: X-Api-Key | Equals (negated) | (empty) | Block |
| Log all requests with a specific referer | Header: Referer | Contains | competitor.com | Log |
| Block a specific bot by User-Agent | User-Agent | Contains | BadBot/1.0 | Block |
Performance: How Much Latency Does This Add?
A WAF that adds 200ms to every request would be unusable. The Localtonet WAF runs in-process alongside the reverse proxy, with no network hop to an external security service. Typical overhead:
How to Enable the WAF for Your Tunnel
Open the WAF dashboard for your tunnel domain
In the Localtonet dashboard, navigate to your HTTP tunnel and click WAF. This opens the WAF Enterprise Dashboard for that domain.
Start in Detection mode
Enable the WAF with Mode: Detection first. Detection mode runs all the rules and logs every event but does not block or challenge any traffic. Let it run for a day or two while you review the Events tab to understand what traffic your tunnel receives and whether any legitimate requests would be flagged.
Whitelist your own IP and any service IPs
In the Security tab, add your own IP address to the whitelist so your own access is never challenged. Add any webhook sender IPs (GitHub, Stripe, etc.) if they need to reach your tunnel without going through the challenge flow.
Switch to Prevention mode
Once you are satisfied that legitimate traffic is clean and any false-positive rules are adjusted, switch to Prevention mode. The WAF now actively blocks and challenges suspicious traffic. Start with Standard sensitivity (the recommended default) and adjust up or down based on your service's needs.
If you switch to Prevention mode and legitimate users start seeing challenge pages unexpectedly, you can switch back to Detection mode instantly from the Configuration tab without losing any event history. Identify the rule that is causing false positives in the Events tab, disable it or add a whitelist entry, then switch back to Prevention. There is no deployment step and no restart required.
Recommended Settings by Service Type
| Service | Sensitivity | Key settings to configure |
|---|---|---|
| Nextcloud / Immich | Standard | Whitelist your own IP. Enable credential stuffing protection. Set /login as a login path. Geo-block if you only access from specific countries. |
| Vaultwarden (password manager) | High | Whitelist your own IP and trusted devices. Enable credential stuffing with low thresholds. Geo-block to only your country. Challenge all /admin access. |
| Home Assistant | High | Whitelist your home network. Consider AllowedOnly geo-blocking to just your country. Challenge /lovelace and /config paths. |
| Jellyfin / Plex | Standard | Whitelist family members' IPs if static. Enable bot detection to prevent content indexing by scrapers. No body inspection needed for streaming. |
| n8n / Uptime Kuma | Standard | Whitelist your IP. Challenge admin paths. If n8n receives webhooks from external services, whitelist those sender IPs so webhook delivery is not challenged. |
| Development API / webhook receiver | Low | Use Detection mode or Low sensitivity to avoid false positives during development. Whitelist your own IP and any CI/CD runner IPs. |
Frequently Asked Questions
Will the WAF block my own access to my services?
It should not at Standard sensitivity, especially if you use a normal browser. But to be safe, whitelist your own IP address in the Security tab before switching to Prevention mode. Whitelisted IPs skip all WAF rules entirely, including rate limiting. If you have a dynamic home IP, you can whitelist your home network's /24 range instead of a single address, or use the Detection mode period to confirm your own traffic does not trigger any rules before switching to active blocking.
Will it break webhooks from GitHub, Stripe, or other services?
Webhook senders are API clients: they send POST requests without browser headers. The WAF's API client exemption prevents bot detection from flagging them based on missing Accept or Accept-Language headers. However, some webhook payloads (especially security-related webhooks that include vulnerability data) can contain patterns that look like attack payloads and trigger OWASP rules. The safest approach is to whitelist the known sender IP ranges (GitHub publishes its IP ranges, Stripe publishes theirs) in the Security tab. Alternatively, whitelist the specific path that receives webhooks so that path bypasses the WAF entirely.
What is the difference between Detection mode and Prevention mode?
In Detection mode, the WAF runs all its rules and records every event with full detail, but takes no blocking action. All traffic reaches your service normally. This mode is for learning: you can see exactly what traffic your tunnel receives, which rules would have fired, and what scores would have been assigned, without risking any legitimate traffic being blocked. In Prevention mode, the WAF actively blocks and challenges traffic based on the scoring thresholds. You can switch between modes instantly from the Configuration tab at any time.
Does the challenge system affect SEO or Google crawling?
Googlebot, Bingbot, and other verified search engine crawlers are on the WAF's good-bot whitelist. Verification uses reverse DNS lookup to confirm that a request claiming to be Googlebot actually comes from Google's published IP ranges. Verified crawlers bypass bot detection entirely and receive normal responses. Unverified bots claiming to be Googlebot but not originating from Google's IP ranges are correctly treated as suspicious.
Does it cost extra?
No. The WAF is included with all Localtonet HTTP tunnel subscriptions at no additional cost. It runs in-process alongside the reverse proxy that already handles your tunnel traffic, with no external WAF service, no per-request fees, and no bandwidth charges for blocked requests.
Your Tunnel Is Live. Is It Protected?
The Localtonet WAF is available now for all HTTP tunnels. Enable Detection mode in your tunnel's WAF dashboard to start seeing what is hitting your service, then switch to Prevention when you are ready. No additional cost, no external service, no configuration required to get started.
Open WAF Dashboard โ