← Back to Wiki
Networking / Security

Allow One Device Past a UniFi Category Content Filter

Most home routers with a zone-based firewall let you block a whole traffic category — social media, gaming, whatever — for an entire network in one rule. Sooner or later one specific device needs an exception without lifting the block for everyone else. The obvious fix (add a more specific "allow" rule) turns out to have a real, non-obvious catch on at least one popular controller's API.

Share on X

The setup: a category block scoped to a whole network

Zone-based firewalls (UniFi, pfSense, OPNsense, and similar) can match traffic by app/traffic category rather than just IP and port — "block this entire network from reaching anything tagged Social Media," for example. It's a clean way to apply a blanket restriction (parental controls, focus rules, whatever the reason) without maintaining a domain or IP blocklist by hand. The rule's source is the network as a whole, its destination is the traffic category, and the action is block.

The obvious way to carve out one exception: add a second rule matching that specific device (by its client identity, not the whole network) against the same category, action allow, and make sure it evaluates before the broad block. Zone-based firewalls stop at the first matching rule, so a more specific allow ranked ahead of a broad block works exactly like you'd expect — everyone else still hits the block, this one device hits the allow first and never reaches it.

The gotcha: the API can create rules, but it won't reorder them

A POST to create a new rule silently ignores any priority/index you send — it always appends to the end of that rule chain. And a PUT to an existing rule to change its priority can return a success response while leaving the actual order completely untouched. Neither call errors. Both just quietly don't do the ordering part of what you asked. If you create your new "allow this device" rule expecting it to land above the existing block, then test and find the device is still blocked, the instinct is to assume the new rule is misconfigured — when the actual problem is that it's sitting after the block in evaluation order and never gets reached at all.

Confirm this before debugging anything else: pull the full rule list back down and sort by whatever priority/index field the API returns. If your new specific-allow rule has a higher index number than the broad block it's supposed to preempt, that's the entire problem — the rule content is fine, the position is wrong.

The reliable fix: delete and recreate the rule you can't move

Since new rules always append to the end of the chain, you can use that consistently to your advantage: create your specific exception rule first, then delete the broad block rule and immediately recreate it with identical settings. The recreated block gets a fresh append-to-the-end placement — which now lands it after your exception rule, since that one was created first and already occupies an earlier slot. No drag-and-drop reordering required, no manual index math, just delete-then-recreate in the right sequence.

This opens a brief window where the broad block is completely absent — from the moment you delete it to the moment the recreated copy is confirmed live, typically a couple of seconds over a scripted API call. For a low-stakes category block (the kind of thing this guide is about) that's a negligible risk. For anything security-relevant — isolating an untrusted network, blocking a known-bad destination — that gap is not acceptable, and this specific technique is the wrong tool. Use the controller's UI drag-and-drop reorder for those instead; it typically applies as a single atomic change with no window where the rule is simply gone.

Verifying it actually worked

Re-fetch the full rule list one more time after recreating the block, and confirm the final order directly — don't infer it from "the delete succeeded" and "the create succeeded" individually. Then test from the actual exempted device, not just by reading the config back: load something that falls under the blocked category and confirm it loads, since a correctly-ordered rule set that doesn't match the traffic the way you assumed is still a failure, just a quieter one.

A note on scale: exempt the one device, not everyone else

There's a second way to solve this same problem — instead of adding a higher-priority allow for the one device you want to exempt, you flip the broad block's own source from "the whole network" to "every device on this network except the one I want exempted." That works, but it doesn't scale: it means maintaining an explicit list of every other device's identity by hand, and on any network with phones or tablets that use per-network randomized identifiers, that list drifts out of date as those identifiers rotate — silently un-blocking devices that were supposed to stay restricted. Exempting the one specific device you actually care about, rather than enumerating everyone else, is both less work and doesn't rot over time.