{"id":4909,"date":"2026-02-18T05:32:40","date_gmt":"2026-02-18T05:32:40","guid":{"rendered":"https:\/\/softcolontechnologies.com\/blogs\/?p=4909"},"modified":"2026-02-18T05:33:44","modified_gmt":"2026-02-18T05:33:44","slug":"what-is-ip-filtering-how-to-use-allow-and-deny-rules","status":"publish","type":"post","link":"https:\/\/www.softcolon.com\/blogs\/what-is-ip-filtering-how-to-use-allow-and-deny-rules\/","title":{"rendered":"What is IP Filtering? How to Use Allow and Deny Rules"},"content":{"rendered":"<h2 class=\"text-3xl font-semibold mt-14 mb-8 \">Introduction<\/h2>\n<p class=\" text-lg my-6\">When you deploy a web application, not all traffic is created equal. Some endpoints should only be accessible from your office network. Some admin dashboards should never be accessible from the public internet. Some IP addresses are known to be malicious and should be blocked entirely.<\/p>\n<p class=\" text-lg my-6\"><strong>IP filtering<\/strong> is a security technique that allows you to control which devices (identified by their IP address) can access your website or specific parts of it.<\/p>\n<p class=\" text-lg my-6\">Think of it like a nightclub&#8217;s VIP list:<\/p>\n<ul class=\"list-disc ml-6 my-6\">\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>Whitelist (Allow List):<\/strong> Only people on the VIP list can enter<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>Blacklist (Block List):<\/strong> Anyone on the &#8220;banned&#8221; list can&#8217;t enter, but everyone else can<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>Route-specific filtering:<\/strong> Some rooms are only for VIPs, but the main floor is open to everyone<\/p>\n<\/li>\n<\/ul>\n<p class=\" text-lg my-6\">Caddy makes implementing these rules simple through a feature called &#8220;matchers&#8221; that intercept requests before they reach your application.<\/p>\n<hr \/>\n<h2 class=\"text-3xl font-semibold mt-14 mb-8 \">Understanding IP Addresses and CIDR Notation<\/h2>\n<p class=\" text-lg my-6\">Before we dive into the configuration, let&#8217;s understand how to specify IP addresses in Caddy.<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Single IP Address<\/h3>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\"><span class=\"hljs-number\">203.0<\/span><span class=\"hljs-number\">.113<\/span><span class=\"hljs-number\">.10<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\">This refers to one specific device. Every device connected to the internet has a unique IP address (similar to a home address).<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">IP Range Using CIDR Notation<\/h3>\n<p class=\" text-lg my-6\">Instead of listing every IP individually, you can specify ranges using CIDR notation:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\"><span class=\"hljs-number\">10.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">8<\/span>\n<span class=\"hljs-number\">192.168<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">16<\/span>\n<span class=\"hljs-number\">172.16<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">12<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\"><strong>What does<\/strong> <code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">\/8<\/code>, <code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">\/16<\/code>, <code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">\/12<\/code> mean?<\/p>\n<p class=\" text-lg my-6\">The number after the slash represents how many bits of the IP address are &#8220;fixed&#8221; (network portion) and how many can vary (host portion).<\/p>\n<ul class=\"list-disc ml-6 my-6\">\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>10.0.0.0\/8<\/strong>: The first 8 bits (10) are fixed, the rest (0.0.0) can be anything \u2192 covers 10.0.0.0 to 10.255.255.255 (16 million addresses)<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>192.168.0.0\/16<\/strong>: The first 16 bits (192.168) are fixed \u2192 covers 192.168.0.0 to 192.168.255.255 (65,536 addresses)<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>172.16.0.0\/12<\/strong>: The first 12 bits are fixed \u2192 covers a large private network range<\/p>\n<\/li>\n<\/ul>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Common Private IP Ranges (for internal networks)<\/h3>\n<p class=\" text-lg my-6\">These IP ranges are reserved for private networks and never used on the public internet:<\/p>\n<table>\n<thead>\n<tr>\n<th>Range<\/th>\n<th>Size<\/th>\n<th>Common Use<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>10.0.0.0\/8<\/td>\n<td>16 million IPs<\/td>\n<td>Large corporate networks, data centers<\/td>\n<\/tr>\n<tr>\n<td>172.16.0.0\/12<\/td>\n<td>1 million IPs<\/td>\n<td>Medium corporate networks, Docker networks<\/td>\n<\/tr>\n<tr>\n<td>192.168.0.0\/16<\/td>\n<td>65,536 IPs<\/td>\n<td>Small office\/home networks, most common<\/td>\n<\/tr>\n<tr>\n<td>127.0.0.1\/8<\/td>\n<td>256 IPs<\/td>\n<td>Localhost (your own machine)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<hr \/>\n<h2 class=\"text-3xl font-semibold mt-14 mb-8 \">Use Cases for IP Filtering<\/h2>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">1. <strong>Protecting Admin Dashboards<\/strong><\/h3>\n<p class=\" text-lg my-6\">Your Node.js application has an admin panel at <code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">\/admin<\/code> that only your team should access. Without IP filtering, anyone on the internet could find it (either by guessing the URL or through search engines).<\/p>\n<p class=\" text-lg my-6\"><strong>Solution:<\/strong> Only allow the <code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">\/admin<\/code> route from your office IP address or your company&#8217;s VPN.<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">2. <strong>Securing Internal APIs<\/strong><\/h3>\n<p class=\" text-lg my-6\">You have internal APIs that should only be called from your backend servers or monitoring tools, not from the public internet.<\/p>\n<p class=\" text-lg my-6\"><strong>Example:<\/strong> A <code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">\/metrics<\/code> endpoint that exposes server health information should only be accessible from your monitoring service.<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">3. <strong>Blocking Known Attackers<\/strong><\/h3>\n<p class=\" text-lg my-6\">If you notice a specific IP address repeatedly attacking your site, you can block it immediately.<\/p>\n<p class=\" text-lg my-6\"><strong>Example:<\/strong> An IP address is flooding your API with requests trying to guess user IDs. Block it to prevent the attack.<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">4. <strong>Geographic Restrictions<\/strong><\/h3>\n<p class=\" text-lg my-6\">Some companies must comply with laws that require them to block access from certain countries. IP filtering is one tool for this.<\/p>\n<p class=\" text-lg my-6\"><strong>Example:<\/strong> A game published in the US might need to block IPs from countries with different regulations.<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">5. <strong>VPN or Proxy Requirements<\/strong><\/h3>\n<p class=\" text-lg my-6\">Force users to go through your company VPN before accessing the application.<\/p>\n<p class=\" text-lg my-6\"><strong>Example:<\/strong> A company requires all remote employees to connect through a VPN before accessing internal tools.<\/p>\n<hr \/>\n<h2 class=\"text-3xl font-semibold mt-14 mb-8 \">How Caddy IP Filtering Works<\/h2>\n<p class=\" text-lg my-6\">Caddy uses a feature called <strong>matchers<\/strong> to intercept requests. Here&#8217;s the flow:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">Incoming Request\n    \u2193\nCaddy checks matchers (@allowed_ips<span class=\"hljs-punctuation\">,<\/span> @blocked_ips<span class=\"hljs-punctuation\">,<\/span> etc.)\n    \u2193\nDoes request match? \n    \u251c\u2500 YES \u2192 Execute the handle block\n    \u2514\u2500 NO \u2192 Continue to next rule\n    \u2193\nIf no rules matched \u2192 Execute default handler\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\">The key directive is <code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">remote_ip<\/code>, which tells Caddy to examine the IP address of the client making the request.<\/p>\n<hr \/>\n<h2 class=\"text-3xl font-semibold mt-14 mb-8 \">Pattern 1: Whitelist (Allow Only Specific IPs)<\/h2>\n<p class=\" text-lg my-6\">This is the most restrictive approach: only allow traffic from IPs you explicitly specify. Everything else is blocked.<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Basic Example: Allow Two Specific IPs<\/h3>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">example.com <span class=\"hljs-punctuation\">{<\/span>\n    @allowed_ips <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">203.0<\/span><span class=\"hljs-number\">.113<\/span><span class=\"hljs-number\">.10<\/span> <span class=\"hljs-number\">198.51<\/span><span class=\"hljs-number\">.100<\/span><span class=\"hljs-number\">.25<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @allowed_ips <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    respond <span class=\"hljs-string\">\"Access denied\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\"><strong>How this works:<\/strong><\/p>\n<ol class=\"list-decimal ml-6 my-6\">\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">Request arrives from an IP address<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">Caddy checks: &#8220;Is this IP in my allowed list (203.0.113.10 or 198.51.100.25)?&#8221;<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">If YES: Request goes to your Node.js app (reverse_proxy)<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">If NO: Respond with &#8220;Access denied&#8221; (HTTP 403 status code)<\/p>\n<\/li>\n<\/ol>\n<p class=\" text-lg my-6\"><strong>Real-world example:<\/strong><\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">myapp.example.com <span class=\"hljs-punctuation\">{<\/span>\n    @allowed_ips <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">192.168<\/span><span class=\"hljs-number\">.1<\/span><span class=\"hljs-number\">.100<\/span> <span class=\"hljs-number\">192.168<\/span><span class=\"hljs-number\">.1<\/span><span class=\"hljs-number\">.101<\/span> <span class=\"hljs-number\">203.45<\/span><span class=\"hljs-number\">.67<\/span><span class=\"hljs-number\">.89<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @allowed_ips <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    respond <span class=\"hljs-string\">\"Access denied\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\">Your office has two workstations (192.168.1.100 and 192.168.1.101) and a remote worker on a specific IP (203.45.67.89). Only these devices can access the app.<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Allow a Range of IPs<\/h3>\n<p class=\" text-lg my-6\">Instead of listing IPs individually, use CIDR notation:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">example.com <span class=\"hljs-punctuation\">{<\/span>\n    @allowed_ips <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">10.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">8<\/span> <span class=\"hljs-number\">192.168<\/span><span class=\"hljs-number\">.1<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">24<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @allowed_ips <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    respond <span class=\"hljs-string\">\"Access denied\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\"><strong>What this allows:<\/strong><\/p>\n<ul class=\"list-disc ml-6 my-6\">\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">10.0.0.0\/8<\/code>: Any IP starting with 10 (company network)<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">192.168.1.0\/24<\/code>: Any IP from 192.168.1.0 to 192.168.1.255 (small office network)<\/p>\n<\/li>\n<\/ul>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Allow Your VPN Network<\/h3>\n<p class=\" text-lg my-6\">Many companies use VPNs to allow remote workers secure access:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">internal-app.example.com <span class=\"hljs-punctuation\">{<\/span>\n    @vpn_users <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">10.8<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">24<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @vpn_users <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    respond <span class=\"hljs-string\">\"VPN access required\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\">Now only users connected to the company VPN (which assigns IPs in the 10.8.0.0\/24 range) can access the app.<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Whitelist with Error Messages<\/h3>\n<p class=\" text-lg my-6\">Provide helpful error messages to blocked users:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">admin.example.com <span class=\"hljs-punctuation\">{<\/span>\n    @allowed_ips <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">10.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">8<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @allowed_ips <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    respond <span class=\"hljs-string\">\"Admin access is restricted to the internal network. If you're trying to access from outside, please use the VPN.\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<hr \/>\n<h2 class=\"text-3xl font-semibold mt-14 mb-8 \">Pattern 2: Blacklist (Block Specific IPs)<\/h2>\n<p class=\" text-lg my-6\">This is less restrictive: allow everyone except IPs you explicitly block. Useful for blocking known attackers.<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Basic Example: Block Known Abusive IPs<\/h3>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">example.com <span class=\"hljs-punctuation\">{<\/span>\n    @blocked_ips <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">192.0<\/span><span class=\"hljs-number\">.2<\/span><span class=\"hljs-number\">.50<\/span> <span class=\"hljs-number\">203.0<\/span><span class=\"hljs-number\">.113<\/span><span class=\"hljs-number\">.99<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @blocked_ips <span class=\"hljs-punctuation\">{<\/span>\n        respond <span class=\"hljs-string\">\"Access denied\"<\/span> <span class=\"hljs-number\">403<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\"><strong>How this works:<\/strong><\/p>\n<ol class=\"list-decimal ml-6 my-6\">\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">Request arrives<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">Caddy checks: &#8220;Is this IP in my blocklist?&#8221;<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">If YES: Respond with 403 Forbidden<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">If NO: Allow the request through to your Node.js app<\/p>\n<\/li>\n<\/ol>\n<p class=\" text-lg my-6\"><strong>Execution order matters:<\/strong> The blacklist rule is checked first. If the IP is blocked, the request never reaches your application, which is more efficient.<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Blocking a Range<\/h3>\n<p class=\" text-lg my-6\">Block an entire network range:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">example.com <span class=\"hljs-punctuation\">{<\/span>\n    @blocked_ips <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">192.0<\/span><span class=\"hljs-number\">.2<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">24<\/span> <span class=\"hljs-number\">203.0<\/span><span class=\"hljs-number\">.113<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">24<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @blocked_ips <span class=\"hljs-punctuation\">{<\/span>\n        respond <span class=\"hljs-string\">\"Your network has been blocked due to suspicious activity\"<\/span> <span class=\"hljs-number\">403<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\">This blocks two entire subnets (256 IPs each).<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Blocking Known Botnet IPs<\/h3>\n<p class=\" text-lg my-6\">If you&#8217;ve identified an attacker using a specific IP range:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">example.com <span class=\"hljs-punctuation\">{<\/span>\n    @botnet <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">198.51<\/span><span class=\"hljs-number\">.100<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">24<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @botnet <span class=\"hljs-punctuation\">{<\/span>\n        respond <span class=\"hljs-string\">\"Access denied\"<\/span> <span class=\"hljs-number\">403<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    # Log the attack attempt\n    log <span class=\"hljs-punctuation\">{<\/span>\n        output stdout\n        format single_line\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Blacklist with Monitoring<\/h3>\n<p class=\" text-lg my-6\">Block and log the attack:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">example.com <span class=\"hljs-punctuation\">{<\/span>\n    @attack_ips <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">192.0<\/span><span class=\"hljs-number\">.2<\/span><span class=\"hljs-number\">.100<\/span> <span class=\"hljs-number\">203.0<\/span><span class=\"hljs-number\">.113<\/span><span class=\"hljs-number\">.200<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @attack_ips <span class=\"hljs-punctuation\">{<\/span>\n        # Log suspicious access attempts\n        log <span class=\"hljs-punctuation\">{<\/span>\n            output stdout\n            format json\n        <span class=\"hljs-punctuation\">}<\/span>\n        respond <span class=\"hljs-string\">\"Access denied\"<\/span> <span class=\"hljs-number\">403<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<hr \/>\n<h2 class=\"text-3xl font-semibold mt-14 mb-8 \">Pattern 3: Route-Specific IP Filtering<\/h2>\n<p class=\" text-lg my-6\">Only apply IP restrictions to certain routes (URLs). Other routes remain open to everyone.<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Allow \/admin Route Only from Internal Network<\/h3>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">example.com <span class=\"hljs-punctuation\">{<\/span>\n    handle_path \/admin<span class=\"hljs-comment\">\/* {\n        @internal {\n            remote_ip 10.0.0.0\/8 192.168.0.0\/16\n        }\n\n        handle @internal {\n            reverse_proxy localhost:3000\n        }\n\n        respond \"Admin access requires internal network access\" 403\n    }\n\n    handle {\n        reverse_proxy localhost:3000\n    }\n}\n<\/span><\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\"><strong>How this works:<\/strong><\/p>\n<ol class=\"list-decimal ml-6 my-6\">\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">If the request path starts with <code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">\/admin\/<\/code>:<\/p>\n<ul class=\"list-disc ml-6 my-6\">\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">Check if the IP is in the internal network (10.0.0.0\/8 or 192.168.0.0\/16)<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">If YES: Allow it<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">If NO: Respond with 403<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">For all other paths (<code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">\/<\/code>): Allow everyone<\/p>\n<\/li>\n<\/ol>\n<p class=\" text-lg my-6\"><strong>Real-world example:<\/strong><\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">User at office (IP<span class=\"hljs-punctuation\">:<\/span> <span class=\"hljs-number\">10.5<\/span><span class=\"hljs-number\">.20<\/span><span class=\"hljs-number\">.15<\/span>)\n    \u251c\u2500 Access \/admin \u2192 ALLOWED (internal IP)\n    \u2514\u2500 Access \/products \u2192 ALLOWED (public route)\n\nUser on public internet (IP<span class=\"hljs-punctuation\">:<\/span> <span class=\"hljs-number\">203.45<\/span><span class=\"hljs-number\">.67<\/span><span class=\"hljs-number\">.89<\/span>)\n    \u251c\u2500 Access \/admin \u2192 BLOCKED (not internal IP)\n    \u2514\u2500 Access \/products \u2192 ALLOWED (public route)\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Multiple Protected Routes<\/h3>\n<p class=\" text-lg my-6\">Protect several admin routes:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">example.com <span class=\"hljs-punctuation\">{<\/span>\n    handle_path \/admin<span class=\"hljs-comment\">\/* {\n        @internal {\n            remote_ip 10.0.0.0\/8\n        }\n\n        handle @internal {\n            reverse_proxy localhost:3000\n        }\n\n        respond \"Admin panel requires internal access\" 403\n    }\n\n    handle_path \/api\/internal\/* {\n        @internal {\n            remote_ip 10.0.0.0\/8\n        }\n\n        handle @internal {\n            reverse_proxy localhost:3000\n        }\n\n        respond \"Internal API requires internal access\" 403\n    }\n\n    handle_path \/metrics {\n        @internal {\n            remote_ip 10.0.0.0\/8 127.0.0.1\n        }\n\n        handle @internal {\n            reverse_proxy localhost:3000\n        }\n\n        respond \"Metrics endpoint requires internal access\" 403\n    }\n\n    # Public routes\n    handle {\n        reverse_proxy localhost:3000\n    }\n}\n<\/span><\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\">This protects:<\/p>\n<ul class=\"list-disc ml-6 my-6\">\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">\/admin\/*<\/code> &#8211; Admin dashboard<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">\/api\/internal\/*<\/code> &#8211; Internal APIs<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">\/metrics<\/code> &#8211; Health metrics<\/p>\n<\/li>\n<\/ul>\n<p class=\" text-lg my-6\">All other routes are public.<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Subdomain-Based Access Control<\/h3>\n<p class=\" text-lg my-6\">Different subdomains with different IP restrictions:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\"># Public website - open to everyone\nwww.example.com <span class=\"hljs-punctuation\">{<\/span>\n    reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n\n# Admin dashboard - internal only\nadmin.example.com <span class=\"hljs-punctuation\">{<\/span>\n    @internal <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">10.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">8<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @internal <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3001<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    respond <span class=\"hljs-string\">\"Admin access requires internal network\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n\n# API for partner integrations - partners only\napi.example.com <span class=\"hljs-punctuation\">{<\/span>\n    @partners <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">203.0<\/span><span class=\"hljs-number\">.113<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">24<\/span> <span class=\"hljs-number\">198.51<\/span><span class=\"hljs-number\">.100<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">24<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @partners <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3002<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    respond <span class=\"hljs-string\">\"Partner API access only\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<hr \/>\n<h2 class=\"text-3xl font-semibold mt-14 mb-8 \">Pattern 4: Combining Whitelists and Blacklists<\/h2>\n<p class=\" text-lg my-6\">Apply both allow and block rules for fine-grained control.<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Allow a Range, but Block Specific IPs Within It<\/h3>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">example.com <span class=\"hljs-punctuation\">{<\/span>\n    # First<span class=\"hljs-punctuation\">,<\/span> block known bad IPs\n    @blocked_ips <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">10.5<\/span><span class=\"hljs-number\">.20<\/span><span class=\"hljs-number\">.50<\/span> <span class=\"hljs-number\">10.5<\/span><span class=\"hljs-number\">.20<\/span><span class=\"hljs-number\">.51<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @blocked_ips <span class=\"hljs-punctuation\">{<\/span>\n        respond <span class=\"hljs-string\">\"Your IP has been blocked\"<\/span> <span class=\"hljs-number\">403<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    # Then<span class=\"hljs-punctuation\">,<\/span> allow the larger range\n    @allowed_ips <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">10.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">8<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @allowed_ips <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    # Block everyone else\n    respond <span class=\"hljs-string\">\"Access denied\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\"><strong>Logic:<\/strong><\/p>\n<ol class=\"list-decimal ml-6 my-6\">\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">Check if IP is in blocklist \u2192 If yes, block it<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">Check if IP is in allowlist \u2192 If yes, allow it<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">Block everyone else<\/p>\n<\/li>\n<\/ol>\n<p class=\" text-lg my-6\">This is useful when you have a large trusted network but need to block specific compromised devices within that network.<\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Allow Specific IPs, Block Others from Same Range<\/h3>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">internal.example.com <span class=\"hljs-punctuation\">{<\/span>\n    @trusted_ips <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">192.168<\/span><span class=\"hljs-number\">.1<\/span><span class=\"hljs-number\">.10<\/span> <span class=\"hljs-number\">192.168<\/span><span class=\"hljs-number\">.1<\/span><span class=\"hljs-number\">.11<\/span> <span class=\"hljs-number\">192.168<\/span><span class=\"hljs-number\">.1<\/span><span class=\"hljs-number\">.12<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    @blocked_ips <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">192.168<\/span><span class=\"hljs-number\">.1<\/span><span class=\"hljs-number\">.99<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @blocked_ips <span class=\"hljs-punctuation\">{<\/span>\n        respond <span class=\"hljs-string\">\"Your device is blocked\"<\/span> <span class=\"hljs-number\">403<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @trusted_ips <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    respond <span class=\"hljs-string\">\"Access denied\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\">Only three specific devices (192.168.1.10, .11, .12) can access, even though they&#8217;re all on the 192.168.1.0\/24 network. Device .99 is explicitly blocked.<\/p>\n<hr \/>\n<h2 class=\"text-3xl font-semibold mt-14 mb-8 \">Real-World Scenarios<\/h2>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Scenario 1: E-Commerce Company with Admin Dashboard<\/h3>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">shop.example.com <span class=\"hljs-punctuation\">{<\/span>\n    # Admin routes - internal network only\n    handle_path \/admin<span class=\"hljs-comment\">\/* {\n        @internal {\n            remote_ip 10.0.0.0\/8 203.45.67.0\/24\n        }\n\n        handle @internal {\n            reverse_proxy localhost:3001\n        }\n\n        respond \"Admin access restricted\" 403\n    }\n\n    # Known bot\/crawler IPs\n    @bad_bots {\n        remote_ip 192.0.2.50 192.0.2.51 192.0.2.52\n    }\n\n    handle @bad_bots {\n        log {\n            output stdout\n        }\n        respond \"Automated access not allowed\" 403\n    }\n\n    # Everything else - public shop\n    handle {\n        reverse_proxy localhost:3000\n    }\n}\n<\/span><\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Scenario 2: SaaS Application with Team Access<\/h3>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">app.example.com <span class=\"hljs-punctuation\">{<\/span>\n    # Team members on VPN\n    @team <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">10.8<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">24<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    # Specific partner company\n    @partners <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">203.0<\/span><span class=\"hljs-number\">.113<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">25<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    # Block known attackers\n    @blocked <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">192.0<\/span><span class=\"hljs-number\">.2<\/span><span class=\"hljs-number\">.100<\/span> <span class=\"hljs-number\">192.0<\/span><span class=\"hljs-number\">.2<\/span><span class=\"hljs-number\">.101<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @blocked <span class=\"hljs-punctuation\">{<\/span>\n        respond <span class=\"hljs-string\">\"Access denied\"<\/span> <span class=\"hljs-number\">403<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @team <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @partners <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    respond <span class=\"hljs-string\">\"Access requires VPN or partner credentials\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Scenario 3: API with Different Access Tiers<\/h3>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">api.example.com <span class=\"hljs-punctuation\">{<\/span>\n    # Premium tier - restricted to premium client IPs\n    handle_path \/api\/v1\/premium<span class=\"hljs-comment\">\/* {\n        @premium {\n            remote_ip 198.51.100.0\/24\n        }\n\n        handle @premium {\n            reverse_proxy localhost:3001\n        }\n\n        respond \"Premium API requires premium subscription\" 403\n    }\n\n    # Standard tier - broader access\n    handle_path \/api\/v1\/standard\/* {\n        @authorized {\n            remote_ip 203.0.113.0\/24 198.51.100.0\/24 172.16.0.0\/16\n        }\n\n        handle @authorized {\n            reverse_proxy localhost:3002\n        }\n\n        respond \"Standard API access restricted\" 403\n    }\n\n    # Public tier - anyone\n    handle_path \/api\/v1\/public\/* {\n        reverse_proxy localhost:3003\n    }\n\n    respond \"Not found\" 404\n}\n<\/span><\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<hr \/>\n<h2 class=\"text-3xl font-semibold mt-14 mb-8 \">Common Mistakes to Avoid<\/h2>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Mistake 1: Not Accounting for Proxies and Load Balancers<\/h3>\n<p class=\" text-lg my-6\">When your traffic goes through a proxy, Caddy might see the proxy&#8217;s IP, not the real user&#8217;s IP.<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\"># \u274c WRONG - If you're behind Cloudflare<span class=\"hljs-punctuation\">,<\/span> you'll block Cloudflare's IPs!\nexample.com <span class=\"hljs-punctuation\">{<\/span>\n    @allowed <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">192.168<\/span><span class=\"hljs-number\">.1<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">24<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @allowed <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    respond <span class=\"hljs-string\">\"Access denied\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\"><strong>Solution:<\/strong> Tell Caddy to look at the <code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">X-Forwarded-For<\/code> header that proxies add:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\"># \u2705 CORRECT\nexample.com <span class=\"hljs-punctuation\">{<\/span>\n    @allowed <span class=\"hljs-punctuation\">{<\/span>\n        header X-Forwarded-For <span class=\"hljs-number\">192.168<\/span><span class=\"hljs-number\">.1<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">24<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @allowed <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    respond <span class=\"hljs-string\">\"Access denied\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\">Or if using Cloudflare:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\"># \u2705 CORRECT for Cloudflare\nexample.com <span class=\"hljs-punctuation\">{<\/span>\n    @allowed <span class=\"hljs-punctuation\">{<\/span>\n        header CF-Connecting-IP <span class=\"hljs-number\">192.168<\/span><span class=\"hljs-number\">.1<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">24<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @allowed <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    respond <span class=\"hljs-string\">\"Access denied\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Mistake 2: Wrong CIDR Notation<\/h3>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\"># \u274c WRONG - Invalid CIDR\n@internal <span class=\"hljs-punctuation\">{<\/span>\n    remote_ip <span class=\"hljs-number\">10.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">33<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\">CIDR numbers must be between 0-32. A <code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">\/33<\/code> doesn&#8217;t exist.<\/p>\n<p class=\" text-lg my-6\"><strong>Solution:<\/strong> Use valid CIDR ranges:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\"># \u2705 CORRECT\n@internal <span class=\"hljs-punctuation\">{<\/span>\n    remote_ip <span class=\"hljs-number\">10.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">8<\/span>\n    remote_ip <span class=\"hljs-number\">192.168<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">16<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Mistake 3: Forgetting That Order Matters<\/h3>\n<p class=\" text-lg my-6\">Rules are evaluated in order. If you have a blocking rule after an allowing rule, the blocking rule might never execute.<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\"># \u274c WRONG - Whitelist will match first<span class=\"hljs-punctuation\">,<\/span> blacklist never checked\nexample.com <span class=\"hljs-punctuation\">{<\/span>\n    @allow_all <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">10.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">8<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @allow_all <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    @blocked_ips <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">10.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.50<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @blocked_ips <span class=\"hljs-punctuation\">{<\/span>\n        respond <span class=\"hljs-string\">\"Blocked\"<\/span> <span class=\"hljs-number\">403<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\"><strong>Solution:<\/strong> Put blocklists before allowlists:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\"># \u2705 CORRECT\nexample.com <span class=\"hljs-punctuation\">{<\/span>\n    @blocked_ips <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">10.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.50<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @blocked_ips <span class=\"hljs-punctuation\">{<\/span>\n        respond <span class=\"hljs-string\">\"Blocked\"<\/span> <span class=\"hljs-number\">403<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    @allow_all <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">10.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">8<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @allow_all <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Mistake 4: Blocking Yourself During Testing<\/h3>\n<p class=\" text-lg my-6\">When you deploy IP filtering, make sure you don&#8217;t accidentally block yourself!<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\"># \u274c WRONG - If your office IP is <span class=\"hljs-number\">192.168<\/span><span class=\"hljs-number\">.1<\/span><span class=\"hljs-number\">.100<\/span><span class=\"hljs-punctuation\">,<\/span> you'll be locked out!\nexample.com <span class=\"hljs-punctuation\">{<\/span>\n    @internal <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">10.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">8<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @internal <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    respond <span class=\"hljs-string\">\"Access denied\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\"><strong>Solution:<\/strong><\/p>\n<ol class=\"list-decimal ml-6 my-6\">\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">Find your real IP address:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-bash whitespace-pre-wrap break-words text-gray-300\">curl ifconfig.me\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">Include it in the allow list before deploying:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">@internal <span class=\"hljs-punctuation\">{<\/span>\n    remote_ip <span class=\"hljs-number\">192.168<\/span><span class=\"hljs-number\">.1<\/span><span class=\"hljs-number\">.100<\/span> <span class=\"hljs-number\">10.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">8<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">Test from a different IP to verify blocking works:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-bash whitespace-pre-wrap break-words text-gray-300\"><span class=\"hljs-comment\"># Test with a different IP using a proxy or VPN<\/span>\ncurl -H <span class=\"hljs-string\">\"X-Forwarded-For: 203.0.113.1\"<\/span> https:\/\/example.com\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<\/li>\n<\/ol>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Mistake 5: Not Updating Rules Regularly<\/h3>\n<p class=\" text-lg my-6\">IP addresses for cloud services, CDNs, and partners change. Your IP filtering rules become outdated.<\/p>\n<p class=\" text-lg my-6\"><strong>Solution:<\/strong><\/p>\n<ul class=\"list-disc ml-6 my-6\">\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">Keep a comment with the date you last reviewed the rules:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\"># Last reviewed<span class=\"hljs-punctuation\">:<\/span> <span class=\"hljs-number\">2025<\/span><span class=\"hljs-number\">-01<\/span><span class=\"hljs-number\">-15<\/span>\n@partner_ips <span class=\"hljs-punctuation\">{<\/span>\n    remote_ip <span class=\"hljs-number\">203.0<\/span><span class=\"hljs-number\">.113<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">24<\/span>  # Partner A's office\n    remote_ip <span class=\"hljs-number\">198.51<\/span><span class=\"hljs-number\">.100<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">24<\/span>  # Partner B's office\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">Subscribe to IP range updates from partners<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\">Regularly audit your rules (monthly or quarterly)<\/p>\n<\/li>\n<\/ul>\n<hr \/>\n<h2 class=\"text-3xl font-semibold mt-14 mb-8 \">Testing IP Filtering Rules<\/h2>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Test 1: Check Your Own IP<\/h3>\n<p class=\" text-lg my-6\">Find your current IP address:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-bash whitespace-pre-wrap break-words text-gray-300\">curl ifconfig.me\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\">Output: <code class=\"break-words rounded bg-[#24292E] px-2 py-1 text-[#EEEEEE]\">203.45.67.89<\/code><\/p>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Test 2: Verify Blocking Works<\/h3>\n<p class=\" text-lg my-6\">Using curl with a spoofed IP header:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-bash whitespace-pre-wrap break-words text-gray-300\"><span class=\"hljs-comment\"># Simulate request from blocked IP<\/span>\ncurl -H <span class=\"hljs-string\">\"X-Forwarded-For: 192.0.2.50\"<\/span> https:\/\/example.com\n\n<span class=\"hljs-comment\"># Expected response: 403 Forbidden<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Test 3: Verify Allowing Works<\/h3>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-bash whitespace-pre-wrap break-words text-gray-300\"><span class=\"hljs-comment\"># Simulate request from allowed IP<\/span>\ncurl -H <span class=\"hljs-string\">\"X-Forwarded-For: 10.0.0.50\"<\/span> https:\/\/example.com\n\n<span class=\"hljs-comment\"># Expected response: 200 OK (or your app's response)<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Test 4: Check Caddy Logs<\/h3>\n<p class=\" text-lg my-6\">View Caddy logs to see IP filtering in action:<\/p>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-bash whitespace-pre-wrap break-words text-gray-300\"><span class=\"hljs-comment\"># If Caddy is running as a service<\/span>\n<span class=\"hljs-built_in\">sudo<\/span> journalctl -u caddy -f\n\n<span class=\"hljs-comment\"># Or if running in Docker<\/span>\ndocker logs -f caddy-container-name\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<p class=\" text-lg my-6\">Look for access logs showing allowed\/denied requests.<\/p>\n<hr \/>\n<h2 class=\"text-3xl font-semibold mt-14 mb-8 \">Complete Production-Ready Examples<\/h2>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Admin Dashboard Setup<\/h3>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\"># Main public site\nexample.com <span class=\"hljs-punctuation\">{<\/span>\n    reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3000<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n\n# Admin dashboard - internal only\nadmin.example.com <span class=\"hljs-punctuation\">{<\/span>\n    @internal <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">10.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">8<\/span> <span class=\"hljs-number\">203.45<\/span><span class=\"hljs-number\">.67<\/span><span class=\"hljs-number\">.100<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @internal <span class=\"hljs-punctuation\">{<\/span>\n        reverse_proxy localhost<span class=\"hljs-punctuation\">:<\/span><span class=\"hljs-number\">3001<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    log <span class=\"hljs-punctuation\">{<\/span>\n        output stdout\n        format json\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    respond <span class=\"hljs-string\">\"Admin access requires internal network access\"<\/span> <span class=\"hljs-number\">403<\/span>\n<span class=\"hljs-punctuation\">}<\/span>\n<\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<h3 class=\"text-2xl mt-10 mb-4 font-bold \">Multi-Tier API<\/h3>\n<div class=\"relative group\">\n<pre class=\"relative bg-[#1a1a1a] border border-gray-700 rounded-lg overflow-x-auto my-8 p-6\"><code class=\"hljs language-json whitespace-pre-wrap break-words text-gray-300\">api.example.com <span class=\"hljs-punctuation\">{<\/span>\n    # Block known attackers first\n    @attackers <span class=\"hljs-punctuation\">{<\/span>\n        remote_ip <span class=\"hljs-number\">192.0<\/span><span class=\"hljs-number\">.2<\/span><span class=\"hljs-number\">.0<\/span>\/<span class=\"hljs-number\">24<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    handle @attackers <span class=\"hljs-punctuation\">{<\/span>\n        log <span class=\"hljs-punctuation\">{<\/span> output stdout <span class=\"hljs-punctuation\">}<\/span>\n        respond <span class=\"hljs-string\">\"Access denied\"<\/span> <span class=\"hljs-number\">403<\/span>\n    <span class=\"hljs-punctuation\">}<\/span>\n\n    # Premium customers\n    handle_path \/premium<span class=\"hljs-comment\">\/* {\n        @premium {\n            remote_ip 198.51.100.0\/24\n        }\n\n        handle @premium {\n            reverse_proxy localhost:3001\n        }\n\n        respond \"Premium access required\" 403\n    }\n\n    # Standard customers\n    handle_path \/standard\/* {\n        @standard {\n            remote_ip 203.0.113.0\/24 198.51.100.0\/24\n        }\n\n        handle @standard {\n            reverse_proxy localhost:3002\n        }\n\n        respond \"Standard access required\" 403\n    }\n\n    # Public API\n    handle_path \/public\/* {\n        reverse_proxy localhost:3003\n    }\n\n    respond \"Not found\" 404\n}\n<\/span><\/code><\/pre>\n<p><button class=\"absolute top-4 cursor-pointer right-4 p-2 rounded-md bg-[#24292e] hover:bg-gray-700 border border-gray-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200\" title=\"Copy code\"><\/button><\/div>\n<hr \/>\n<h2 class=\"text-3xl font-semibold mt-14 mb-8 \">Key Takeaways<\/h2>\n<ol class=\"list-decimal ml-6 my-6\">\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>IP filtering is a critical security tool<\/strong> for protecting sensitive routes and admin panels.<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>Understand CIDR notation<\/strong> to efficiently manage IP ranges instead of listing individual IPs.<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>Use whitelists (allow lists) for maximum security<\/strong> when protecting sensitive resources.<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>Use blacklists (block lists) for reactive blocking<\/strong> of known attackers.<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>Order matters:<\/strong> Put blacklists before whitelists so blockers execute first.<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>Test thoroughly<\/strong> before deploying, especially when using whitelists, to avoid locking yourself out.<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>Account for proxies<\/strong> &#8211; if your traffic goes through a proxy or CDN, use the appropriate headers (X-Forwarded-For, CF-Connecting-IP).<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>Update regularly<\/strong> &#8211; IP addresses change, so review your rules monthly.<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>Combine with other security<\/strong> &#8211; IP filtering is one layer, use it alongside other protections like authentication and authorization.<\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><strong>Monitor and log<\/strong> &#8211; Enable logging to track blocked requests and identify attack patterns.<\/p>\n<\/li>\n<\/ol>\n<hr \/>\n<h2 class=\"text-3xl font-semibold mt-14 mb-8 \">Further Reading<\/h2>\n<ul class=\"list-disc ml-6 my-6\">\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><a class=\"! !underline\" href=\"https:\/\/caddyserver.com\/docs\/caddyfile\/matchers#remote-ip\" target=\"_blank\" rel=\"noopener noreferrer\">Caddy Documentation &#8211; Remote IP Matcher<\/a><\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><a class=\"! !underline\" href=\"https:\/\/caddyserver.com\/docs\/caddyfile\/directives\/handle\" target=\"_blank\" rel=\"noopener noreferrer\">Caddy Documentation &#8211; Handle Directive<\/a><\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><a class=\"! !underline\" href=\"https:\/\/en.wikipedia.org\/wiki\/Classless_Inter-Domain_Routing\" target=\"_blank\" rel=\"noopener noreferrer\">CIDR Notation Explained<\/a><\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><a class=\"! !underline\" href=\"https:\/\/tools.ietf.org\/html\/rfc1918\" target=\"_blank\" rel=\"noopener noreferrer\">Private IP Address Ranges (RFC 1918)<\/a><\/p>\n<\/li>\n<li class=\" text-lg my-2\">\n<p class=\" text-lg my-6\"><a class=\"! !underline\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/X-Forwarded-For\" target=\"_blank\" rel=\"noopener noreferrer\">X-Forwarded-For Header<\/a><\/p>\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Introduction When you deploy a web application, not all traffic is created equal. Some endpoints should only be accessible from your office network. Some admin dashboards should never be accessible from the public internet. Some IP addresses are known to be malicious and should be blocked entirely. IP filtering is a security technique that allows&#8230;<\/p>\n","protected":false},"author":1,"featured_media":4910,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[212,236],"tags":[220],"class_list":["post-4909","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops-infrastructure","category-digital-transformation","tag-web","th-blog blog-single has-post-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.softcolon.com\/blogs\/wp-json\/wp\/v2\/posts\/4909","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.softcolon.com\/blogs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.softcolon.com\/blogs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.softcolon.com\/blogs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.softcolon.com\/blogs\/wp-json\/wp\/v2\/comments?post=4909"}],"version-history":[{"count":2,"href":"https:\/\/www.softcolon.com\/blogs\/wp-json\/wp\/v2\/posts\/4909\/revisions"}],"predecessor-version":[{"id":4913,"href":"https:\/\/www.softcolon.com\/blogs\/wp-json\/wp\/v2\/posts\/4909\/revisions\/4913"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.softcolon.com\/blogs\/wp-json\/wp\/v2\/media\/4910"}],"wp:attachment":[{"href":"https:\/\/www.softcolon.com\/blogs\/wp-json\/wp\/v2\/media?parent=4909"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.softcolon.com\/blogs\/wp-json\/wp\/v2\/categories?post=4909"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.softcolon.com\/blogs\/wp-json\/wp\/v2\/tags?post=4909"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}