# Firewall Rules

> **Availability**
>
> Firewall rules are on **Cloud** and **Enterprise**.
>
> [See all editions →](https://docs.shellhub.io/about/editions)

> **This is for legacy namespaces**
>
> In a new namespace firewall rules are bypassed entirely: they remain stored and manageable, and are never consulted. Access is decided by [access policies](https://docs.shellhub.io/manage/access-control/access-policies) instead.
>
> [Upgrading a legacy namespace →](https://docs.shellhub.io/manage/access-control/migrating-from-legacy)

Firewall rules restrict what public keys otherwise permit. Where a key says “this key may reach these devices as these users”, a firewall rule says “and not from there, not as that, not to that one”.

![The Firewall Rules page showing a table of rules with Priority, Action, Source IP, Username, Device Filter, and Status columns](https://docs.shellhub.io/img/shots/firewall-rules.png)

## Anatomy

![The New Firewall Rule drawer with Status, Priority, Policy, Source IP, Username, and Device filter fields](https://docs.shellhub.io/img/shots/firewall-add-rule.png)

| Field         | Meaning                                                   |
| ------------- | --------------------------------------------------------- |
| Status        | Whether the rule is active                                |
| Priority      | Evaluation order — rules are considered in priority order |
| Policy        | Allow or deny                                             |
| Source IP     | Which client addresses the rule matches                   |
| Username      | Which unix login the rule matches                         |
| Device filter | Which devices — all, a hostname pattern, or tags          |

## Priority, and why it is the hard part

Rules are evaluated in priority order and the first match decides. That makes the rule set order-dependent, and order-dependence is where firewall rule sets go wrong: inserting a rule at the wrong priority silently changes what the rules below it do.

Access policies are not ordered this way — deny is always evaluated before allow, regardless of what order the policies were created in. That is one of the reasons for the change.

## The source IP difference

This is the one to understand before migrating.

A firewall rule can **grant** on source IP: “allow from this range”. An access policy’s source IP only **narrows** a grant that already matched — an empty list matches everything, and no source IP ever grants on its own.

So a firewall rule that grants access to a range has no direct equivalent. The replacement policy needs a real subject — a user, a role, an API key — with the addresses as a restriction on top. See [Upgrading a Legacy Namespace](https://docs.shellhub.io/manage/access-control/migrating-from-legacy).

> **Careful**
>
> Source addresses are resolved through `SHELLHUB_SSH_PROXY_TRUSTED_IPS` for SSH clients and `SHELLHUB_PROXY_TRUSTED_IPS` for the web terminal. Behind a load balancer without those set correctly, every connection appears to come from the balancer and both firewall rules and policy source IPs are matching on the wrong thing. See [Ports and Connectivity](https://docs.shellhub.io/about/ports-and-connectivity).

## Where to go next

- [Public Keys](https://docs.shellhub.io/manage/access-control/public-keys) — What these rules restrict.
- [Upgrading a Legacy Namespace](https://docs.shellhub.io/manage/access-control/migrating-from-legacy) — Translating rules to policies.
