To block an IP address safely, deny it at the earliest control point that sees a trustworthy client IP: usually a CDN or web application firewall for HTTP traffic, a network firewall for broader traffic, or the destination host when no earlier control exists. Scope the rule to the affected protocol, port, path, or service, verify it from outside that boundary, and record an exact removal method.
Before changing any firewall, keep an independent administrator session open or confirm out-of-band console access. Verify that the management path is allowed by a more specific rule. A mistaken address, rule order, or proxy assumption can lock out the operator along with the unwanted client.
The examples use the documentation-only addresses 203.0.113.77 and 2001:db8:1234::77. Replace them only after confirming the real source from a trusted network boundary. Every command marked State-changing modifies a firewall or its active data.
Choose the right place to block
Blocking close to the source reduces unnecessary work downstream, but only if that layer knows the real source address. Use the narrowest control that can stop the unwanted behavior without affecting unrelated users.
| Situation | Usually appropriate control | Why |
|---|---|---|
| HTTP request behind a CDN | CDN custom rule, managed challenge, or rate limit | The edge sees the connecting client and can protect the origin. |
| HTTP request on AWS | AWS WAF on the relevant web ACL | It can match an IP set and limit the rule to web traffic. |
| Non-HTTP traffic into a subnet | Network firewall or carefully reviewed network ACL | The control acts before the destination host. |
| Traffic directly reaching one server | Its existing host firewall manager | The rule affects only that host. |
| Abuse from authenticated accounts or rotating addresses | Authentication, authorization, rate limits, or account controls | An IP address is not a stable identity. |
Do not add the same deny independently at every layer unless the design requires defense in depth and each owner understands the overlap. Duplicate controls make verification and removal harder.
Establish the real client IP
On a directly exposed server, the network peer address is normally the source to evaluate. Behind a load balancer, reverse proxy, or CDN, the origin may see the proxy address instead. In that case:
- Identify the last trusted proxy that accepted the connection.
- Use that product's documented client-address field or header.
- Configure the origin to trust that header only when the connection came from approved proxy networks.
- Keep both the network peer and the derived client address in security logs.
Never trust an arbitrary X-Forwarded-For value supplied by an Internet client. Cloudflare, for example, documents CF-Connecting-IP for traffic from its edge to the origin and recommends it over X-Forwarded-For; the origin must still be protected so untrusted clients cannot bypass the edge and forge the header. See Cloudflare's HTTP header reference and origin-protection guidance.
Check IPv4 and IPv6 separately. Blocking one family does not block an equivalent route over the other. An IPv6 privacy address may also change more often than an assigned server address.
Confirm that a deny is proportionate
An IP can represent a company NAT gateway, mobile carrier, VPN exit, shared proxy, or accessibility service. It can also change while the same actor continues. Before blocking a range, estimate who else shares it and whether a narrower control works:
- rate-limit the affected route;
- require authentication or stronger authorization;
- challenge suspicious browser traffic at the edge;
- deny one method or path rather than every request;
- fix the exposed service or credential that made the traffic harmful.
Preserve a small evidence record: first and last observed time, trusted source field, destination, protocol, action, rule owner, reason, expiry, and ticket or incident reference. Do not copy request bodies, credentials, or session cookies into the record.
Block an IP with nftables on Linux
Use nftables only when it is the system's established firewall manager. Do not add direct nftables rules to a host managed by UFW, firewalld, Kubernetes policy automation, or a cloud agent; change the owning system instead.
Begin with inspection. These commands are read-only:
sudo nft list ruleset
sudo nft --handle list ruleset
The second form exposes rule handles, but handles can change when a ruleset is reloaded. For recurring incident blocks, a named set is easier to update and audit than inserting a new standalone rule for every address.
Add the following definitions to the system's existing, persistent nftables configuration. This is an insertion fragment, not a complete ruleset: the sets and lookup rules must be inside the same table, and the lookup rules must be inside an existing input base chain or a regular chain reached from it. The examples below assume the inet family and a table named filter. Keep the rules after the verified management allow rule and before any broader accept that would match the same traffic.
set incident_block_v4 {
type ipv4_addr
flags timeout
}
set incident_block_v6 {
type ipv6_addr
flags timeout
}
tcp dport 443 ip saddr @incident_block_v4 counter drop comment "incident-ip-block-v4"
tcp dport 443 ip6 saddr @incident_block_v6 counter drop comment "incident-ip-block-v6"
These lookup rules deny only TCP port 443. Change the protocol or destination port only after confirming the affected service; omitting that scope would turn the example into a host-wide source deny.
Validate a complete candidate file before applying it. This is read-only; --check parses and validates without applying the commands:
sudo nft --check --file /path/to/candidate.nft
Applying that file would be state-changing and must follow the host's approved persistent-firewall procedure. Do not copy a partial snippet over the active ruleset, and never flush the ruleset during an incident.
After the named sets and lookup rules already exist, add a temporary IPv4 element. This command is state-changing:
sudo nft add element inet filter incident_block_v4 \
'{ 203.0.113.77 timeout 30m comment "INC-1234" }'
For IPv6, use the IPv6 set. This command is state-changing:
sudo nft add element inet filter incident_block_v6 \
'{ 2001:db8:1234::77 timeout 30m comment "INC-1234" }'
The family and table in every command must exactly match the table containing the sets. The nftables man page documents typed named sets, element timeouts, comments, get element, and exact element deletion. A timeout is an upper bound on the entry's lifetime, not a durability guarantee: a ruleset reload or restart can remove a runtime-added element unless the owning persistence process preserves it. Track the change even when it has a timeout.
Verify the exact element with a read-only command:
sudo nft get element inet filter incident_block_v4 '{ 203.0.113.77 }'
sudo nft list set inet filter incident_block_v4
sudo nft get element inet filter incident_block_v6 '{ 2001:db8:1234::77 }'
sudo nft list set inet filter incident_block_v6
Remove an entry early if it is wrong or no longer needed. These commands are state-changing and target exact elements, not unstable rule positions:
sudo nft delete element inet filter incident_block_v4 '{ 203.0.113.77 }'
sudo nft delete element inet filter incident_block_v6 '{ 2001:db8:1234::77 }'
Then repeat the external verification and confirm the element is absent. If the existing design uses standalone rules, list the chain with --handle and delete only the verified handle; do not infer a handle from an old screenshot or ticket.
Block an IP with UFW on Ubuntu
Use this path only when UFW already owns the host firewall. Ubuntu documents --dry-run for previewing changes and deletion by repeating the full rule. That is safer than relying on a numbered position that can move.
Inspect current state with this read-only command:
sudo ufw status verbose
Preview a port-scoped deny. This is read-only because of --dry-run:
sudo ufw --dry-run deny proto tcp from 203.0.113.77 to any port 443
After confirming independent access, the current policy, and the exact source, apply it. This command is state-changing:
sudo ufw deny proto tcp from 203.0.113.77 to any port 443
Verify with the read-only status command:
sudo ufw status verbose
Remove the same rule by its full definition. This command is state-changing:
sudo ufw delete deny proto tcp from 203.0.113.77 to any port 443
The official Ubuntu UFW guide also documents status numbered, but deleting the complete rule avoids depending on its current number. When UFW's IPv6 support is enabled and the unwanted client uses IPv6, preview, add, verify, and delete a separate rule with the exact IPv6 source; an IPv4 rule does not cover it.
Block an IP with Windows Defender Firewall
Run firewall changes from an elevated PowerShell session. Create a stable internal rule name so verification and removal do not depend on a localized display name.
This command is state-changing:
New-NetFirewallRule `
-Name 'Incident-Block-TEST-NET-3' `
-DisplayName 'Incident block TEST-NET-3' `
-Direction Inbound `
-Action Block `
-RemoteAddress '203.0.113.77','2001:db8:1234::77' `
-Protocol TCP `
-LocalPort 443 `
-Profile Any `
-PolicyStore PersistentStore
This example covers the two documentation addresses on TCP port 443. Use a narrower profile or application when the evidence supports it. Profile Any is shown only to make the scope visible, not as a default recommendation.
Verify both the rule and its separate address-filter object. These commands are read-only:
$rule = Get-NetFirewallRule -PolicyStore ActiveStore -TracePolicyStore `
-Name 'Incident-Block-TEST-NET-3'
$rule | Select-Object Name, DisplayName, Enabled, Direction, Action, Profile, PolicyStoreSource, PolicyStoreSourceType
$rule | Get-NetFirewallAddressFilter | Select-Object LocalAddress, RemoteAddress
ActiveStore is the effective combination of applicable local and Group Policy stores; an unqualified query reads only the persistent store. If the rule is absent or inactive in ActiveStore, resolve the policy conflict before relying on it.
Microsoft documents that address conditions are represented by a separate NetFirewallAddressFilter. Its current command-line firewall guide covers creating, querying, and removing rules.
Remove only the stable rule name. This command is state-changing:
Remove-NetFirewallRule -PolicyStore PersistentStore `
-Name 'Incident-Block-TEST-NET-3'
Confirm that the same ActiveStore query no longer returns the local rule, then test the intended traffic again. Domain policy may recreate or override local policy, so identify the owning policy store before treating a local change as durable.
Block an IP in AWS
AWS controls are not interchangeable. Choose the one whose scope matches the traffic.
Security groups cannot create a deny
Amazon VPC security group rules allow traffic; they do not support explicit deny rules. Removing or narrowing an existing broad allow is state-changing, can affect every address that relied on it, and is not a safe substitute for a one-address deny without a full dependency review. Security groups are stateful, so return traffic for an allowed connection is handled automatically.
For HTTP or HTTPS protected by AWS WAF, use an IP set and a web ACL rule instead. For non-HTTP subnet traffic, consider a network ACL only after reviewing its much wider scope and stateless behavior.
Prefer AWS WAF for HTTP traffic
In AWS WAF, create or update a clearly named IP set for the relevant address family and add the exact CIDR. Use separate IPv4 and IPv6 IP sets when both families must be covered. Reference the set from a clearly named Block rule in the web ACL attached to the correct CloudFront distribution, Application Load Balancer, API Gateway API, or other supported resource. Creating the set, changing its addresses, adding or removing the rule, and changing its action or priority are all state-changing operations.
By default, an AWS WAF IP set match evaluates the web request's origin address. Use a forwarded address header only when the upstream boundary sets it reliably and the WAF forwarded-IP position and fallback behavior have been reviewed. Otherwise an attacker may choose the value being blocked.
Verify the named rule in the intended web ACL, confirm the protected resource uses that ACL, inspect sampled requests or configured WAF logs, and test the affected route from an authorized external source. AWS notes that IP set updates can propagate with temporary inconsistencies, so do not declare success from configuration state alone.
To reverse one block, remove the exact address from the named IP set. If the whole rule was created only for this incident, remove that named rule after confirming that no other entries depend on it. These are state-changing operations. Changing the action to Count is not equivalent to removal because evaluation continues to later rules. Verify that no other rule references the set before deleting the set itself.
Use a network ACL only with subnet-wide intent
A VPC network ACL can contain deny rules, but it applies at the subnet boundary. AWS evaluates rules from the lowest rule number and stops at the first match. Network ACLs are stateless, so response traffic needs an applicable rule in the opposite direction. The official network ACL guide recommends leaving gaps between rule numbers so later rules can be inserted.
Creating, replacing, reordering, or deleting a network ACL rule, and changing a subnet association, are all state-changing. Before adding a deny, model both directions, ports, IPv4 and IPv6, existing lower-number matches, every subnet using the ACL, and the independent management path. Record the unavoidable rule number as the removal target, then verify the effective association and both request and response paths. A host-specific incident rarely justifies a hurried subnet-wide NACL edit.
Block an IP with Cloudflare WAF
For HTTP traffic proxied through Cloudflare, use a current WAF custom rule. Cloudflare recommends custom rules rather than legacy IP Access rules for IP-based blocking.
For one address, a rule expression can be:
ip.src eq 203.0.113.77
For a maintained group, create a named IP list such as incident_block_ips and use:
ip.src in $incident_block_ips
Cloudflare's custom list documentation permits individual IPv4 and IPv6 addresses and CIDR ranges in an IP list. A list is less error-prone than duplicating a long inline expression across zones.
In the current dashboard, open Security rules, choose Create rule → Custom rules, give the rule a durable name, enter the expression, select Block or an appropriate challenge action, and deploy it. Creating or editing the list, deploying, reordering, enabling, disabling, or deleting the rule is state-changing. The custom-rule dashboard guide documents this workflow. List and custom-rule availability and quotas vary by account plan, so check the current account limits rather than designing around an assumed quota.
Verify the deployed rule expression and order, then inspect Cloudflare Security Events and an authorized external request. Also confirm that the origin cannot be reached directly around Cloudflare. To reverse the block, remove the exact list item or disable/delete the named rule; either is state-changing. Re-run the same verification after removal.
Verify the block without losing evidence
Configuration presence is necessary but not sufficient. A useful verification checks the real boundary and the intended scope:
- Confirm the exact active rule, set element, rule name, web ACL, or list item.
- Send a bounded, authorized request through the same path the unwanted client used. Do not replay destructive requests.
- Check the expected counter, WAF event, or firewall event at the layer that should deny it.
- Confirm the request did not reach the next layer when that evidence is available.
- Test a legitimate source and the management path to detect collateral damage.
- Confirm unaffected ports, paths, and IP families still behave as intended.
- Record the result, rule owner, expiry, and exact removal target.
A timeout-based element should be checked again after expiry. A manually managed block needs a review date; permanent incident entries tend to accumulate after their evidence has expired.
Do not build an automatic “log line to firewall deny” loop from this guide. Logs can be malformed or spoofed, parsers can select the wrong field, and high-cardinality attacks can exhaust rule limits. Automation needs bounded inputs, trusted provenance, approval policy, expiry, list-size limits, an allowlist for management and dependencies, and tested fail-safe behavior.
Use logs to decide, verify, and review
The most useful log record includes the network peer, trusted derived client address, proxy or edge identifier, service and route, action, timestamp, request ID, and firewall or WAF rule ID. Keep the peer and derived address in separate fields. Avoid placing tokens, cookies, full query strings, or request bodies in messages or labels.
Fluxtail can serve as a paid Starter or Pro logs-focused destination after a collector or receiver mapping delivers those fields. Its log payload guidance describes stable message, timestamp, severity, service, host, and label fields. Use search and filters or Live Tail to correlate an incident marker, service, host, and retained events when those values were actually collected and mapped.
Fluxtail does not execute firewall, WAF, or Cloudflare changes. Its built-in AI chat and its account-bound OAuth/PKCE hosted MCP access are separate investigation surfaces; neither makes an unverified IP address trustworthy. Keep raw events as evidence, connect only the intended account, limit searches to the relevant streams, and require explicit confirmation for any customer-owned automation that can change network policy.
Safe blocking checklist
Before the change:
- Confirm the source from a trusted boundary and record both peer and derived client addresses.
- Check IPv4 and IPv6, rule direction, protocol, port, path, and affected services.
- Prefer the earliest narrow control that can reliably see the source.
- Keep an independent admin session or out-of-band console and verify its allow path.
- Identify the existing firewall owner; do not mix managers.
- Choose a stable rule name, set element, list entry, or documented NACL rule number.
- Set an expiry or review time and write the exact removal step first.
After the change:
- Verify the active control and test through the real path.
- Confirm the unwanted request stops at the intended boundary.
- Test legitimate traffic and management access.
- Watch for address rotation, collateral blocking, and IPv6 bypass.
- Preserve minimal evidence and remove the block when it is no longer justified.
An IP deny is a tactical containment control. It works best when the source is trustworthy, the scope is narrow, the removal path is exact, and the underlying authentication, exposure, or abuse-control problem is addressed separately.