Connection Denied

Authorization runs before ShellHub contacts the device, so a refused connection fails at the server and never reaches the agent. In the web terminal you get an access-denied banner; a native client sees the raw error.

First: is it actually a denial?

Two things look like failures and are not.

The login is waiting, not refused. A key that is not yet an identity parks the login until somebody approves it in the console. So does a policy demanding re-authentication. Check for a pending approval before assuming a denial. See Login Approvals.

The device is not there. If the device is offline or was never accepted, there is nothing to connect to and the failure is not about authorization. See Device Not Appearing.

1. Are you a member of the namespace?

Checked before any policy is consulted. If the account is not a member, nothing else matters.

Check the namespace in the SSHID is the one you mean — root@**mycompany**.device@server — and that the account was actually invited and accepted.

2. Is a deny policy matching?

Deny is evaluated before allow and beats it, however specific your allow is.

The denial reason names the responsible policy internally, but you will not see it, so look at your denies directly. They are usually few, and usually broad — a namespace-wide “no root anywhere” is a common shape and it catches cases nobody was thinking about when the allow was written.

Fix it by narrowing the deny, not by adding allows. No allow can win against a deny.

Also check for a deny that cannot be evaluated — an invalid CIDR in a source IP. A deny that cannot be evaluated fails closed, which means a typo in a deny policy refuses connections it was never meant to match.

3. Does any allow actually cover this?

The most common case, and it usually means what it says: nothing grants it.

Work through it in this order:

Is there any allow for this principal at all? A new member starts with nothing. Only the owner is covered by the starter policy. See Members.

Is this an automation? An all-members allow does not cover an API key, which is not a member. It needs a policy naming it. See SSH Access.

Does the filter cover this device? A tag filter matches only devices actually carrying the tag; check the device has it.

Does it cover this login? A policy granting deploy does not permit ssh root@…. Check the username in the SSHID, not just the device.

Is the connection attributed to the identity you think? If you hold several keys, the session is attributed to whichever your client offered first. IdentitiesOnly yes in your SSH config removes the ambiguity. See SSH Client Configuration.

4. Is a source IP restriction excluding you?

A policy with a source IP list only matches connections from those ranges. Connecting from somewhere new — home instead of the office, a different VPN — silently stops matching.

On a self-hosted server behind a load balancer, check SHELLHUB_SSH_PROXY_TRUSTED_IPS for SSH clients and SHELLHUB_PROXY_TRUSTED_IPS for the web terminal. Set wrong, every connection appears to come from the balancer and source IP matching is operating on the wrong address entirely. See Ports and Connectivity.

The namespace has no policies at all

A new namespace with zero policies refuses everything, and ShellHub short-circuits it — refusing immediately rather than proceeding toward a login that could never succeed.

This happens after upgrading a legacy namespace without writing policies first. The owner keeps working, through the seeded Owner access policy; nobody else does. See Upgrading a Legacy Namespace.

Legacy namespaces

If the namespace is still legacy, none of the above applies. Access is decided by the key’s device ACL and by firewall rules — see Public Keys and Firewall Rules.

The four reasons, for reference

Reason What it means
user is not a member of the namespace Step 1 above
denied by policy "<name>" Step 2 — a deny matched
denied: policy "<name>" could not be evaluated Step 2 — a deny failed closed on a source IP it could not parse
no policy grants "<login>" on this device Step 3 — nothing allowed it

Where to go next

esc