github shellhub-io/shellhub v0.30.0

one hour ago

This release moves the gateway into the server process, puts the namespace's devices on a map on the Dashboard, and cuts what the server holds and writes for each connected device. Self-hosted installs change shape: read the two upgrade notes below before you pull.


The gateway runs inside the server

Upgrading? The gateway container is gone. The server now publishes ports 80 and 443 and keeps its certificates, ACME account and DNS provider tokens in a new gateway_data volume. With SHELLHUB_AUTO_SSL=true, copy the old gateway's store into that volume before the server first starts, as Upgrade describes, or the server asks the CA for every certificate again and can hit Let's Encrypt's rate limits. Compose files that override the gateway service break. SHELLHUB_GATEWAY_STREAM_BUFFER_SIZE and SHELLHUB_GATEWAY_API_MAX_CONNS are removed.

Caddy now runs as a library inside the server, and each request goes straight to the API router instead of through a second process (#7780). Before, the gateway kept an upstream socket and a stream buffer for every agent tunnel. Around 56,000 devices that memory got it OOM-killed, and a single upstream address capped the source ports near 64,500. SHELLHUB_GATEWAY turns the embedded gateway on. Compose sets it to true; a Kubernetes or load-balancer setup that reaches the server on :8080 keeps working without it.

Each tunnel also costs less once connected: 16.7 KB and 2 goroutines, down from 22.8 KB and 3 (#7781).

Forwarded client addresses trust only loopback

Upgrading? If ShellHub sits behind your own load balancer or reverse proxy, set SHELLHUB_PROXY_TRUSTED_IPS to its address ranges. With SHELLHUB_PROXY=true the server refuses to start until you do. Without it the server runs but records the proxy's address for every client, so the login lockout and GeoIP rules key on that one address.

.env used to ship SHELLHUB_PROXY_TRUSTED_IPS="0.0.0.0/0 ::/0", which let any peer set the client address through X-Real-IP or X-Forwarded-*. The default is now empty: only loopback may set it (#7857). The bundled gateway hands requests to the router in process, so the stock stack records the real client without any entry.

Devices on a map

The Dashboard shows the namespace's devices on a map, with online and offline counts (#7816). /dashboard/map lets you pan, zoom, filter by status and list the devices in an area. Picking one opens a summary with its SSHID, platform, agent version and tags, and a Connect button (#7844).

Every edition now places devices out of the box: the server image ships DB-IP City Lite and refreshes it monthly. SHELLHUB_GEOIP_DATABASE=maxmind switches to GeoLite2 with your own key, falling back to DB-IP when it cannot load. SHELLHUB_MAP_STYLE picks the map style; the default is a bundled outline that makes no outside request. The API gains GET /api/devices/locations and latitude, longitude and located filters on GET /api/devices.

Rules hold when tags move and devices are renamed

Access policies, public keys and firewall rules select devices by tag or by a pattern over the device name. A role allowed to move tags or rename devices, but not to edit a rule, could still change which devices that rule covers. Tag moves and renames now answer 403 when they would do that (#7835). Operators, and API keys with the operator role, are the ones affected.

Invitations are accepted by their code

PATCH /api/namespaces/{tenant}/invitations/accept now takes { "code": "..." } from the invitation link, and answers 400 without it and 404 for an unknown code (#7824). The console already sends it; a script that calls the endpoint with no body needs updating.


Also in this release

Features

  • Agents spread their reconnects after a tunnel drops, with a jittered delay that starts at 10 s and doubles up to 2 min, so a server restart no longer brings the whole fleet back at once. A pending device under SHELLHUB_REQUIRE_ACCEPTED_TUNNEL can now take up to 2 min to come online after it is accepted (#7782)
  • Web Endpoints appear only to roles that may connect to devices; observers no longer see them (#7841)
  • The docs site sets canonical URLs, descriptions and social cards, stops redirecting every internal link, and serves a Markdown copy of each page plus llms.txt and llms-full.txt (#7817)

Fixes

  • Searching devices or containers with a tag selected now requires the tag. Before, the search also listed every match by name, tagged or not (#7808)
  • A device whose server process crashed or stopped now gets its disconnect recorded within about 15 minutes, so orphaned pending ephemeral devices are cleaned up (#7811)
  • The enrollment webhook closes its connection after each answer and refuses answers over 4 KB (#7812)
  • A request body that cannot be read answers 400 instead of 422 (#7801)
  • Parallel requests can no longer push a namespace past its custom field limit (#7805)
  • A terminal restored from another namespace stays in view when the destination page loads late (#7802)

Performance

  • An open tunnel writes its device row on every other heartbeat instead of every one (#7869)
  • An agent's periodic re-authentication reads the namespace without its members and rewrites the device row only when something changed (#7871)
  • Sorted lists order their tiebreak in the sort's own direction, so Postgres reads the index without re-sorting. Rows that tie on the sort column now come back in ascending tiebreak order when the sort is ascending (#7870)

Cloud

  • Firewall rules hold when tags move and devices are renamed, like the core rules above
  • Listing web endpoints requires permission to connect to devices
  • Reading one firewall rule applies the same membership check as listing them
  • The billing customer can be read only with the owner's permission
  • A web endpoint whose device is unreachable answers a gateway error, and a client that disconnects is recorded as 499
  • Admin user routes reject a malformed user ID and answer 404 for an unknown user
  • The recording archiver finds its sessions through a new index and pages them by ID

Under the hood

  • API routes, in the core and in Cloud, are declared in tables that state each route's access (#7806, #7838, #7858)
  • The caller's identity, scope and origin are derived on the server and carried on the request context; each request field binds from one source (#7813, #7818, #7821, #7827)
  • User tokens are issued from one sign-in module, and tenant IDs are minted by the server (#7828, #7832)
  • Console cleanups: shared tab row, OTP cells, list filters, device connect and detail code (#7787, #7798, #7807, #7853)
  • golang.org/x/net 0.62.0 and other dependency updates via Dependabot and Renovate (#7859)

Full Changelog: v0.29.3...v0.30.0

Don't miss a new shellhub release

NewReleases is sending notifications on new releases.