Install the Agent
The agent is what a device runs. It opens one outbound connection to the server and keeps it, which is what makes the machine reachable without anything listening on it.
$ curl -sSf https://cloud.shellhub.io/install.sh | sh
Nothing else is needed. Given no credential the agent pairs: it prints a code, you enter it in the console, and the device joins the namespace you pick. Quickstart walks that path end to end.
The script is served by the server it will register with, which writes its own address into it on the way out — port included. Fetch it from your own server and you get one that registers there.
What the script does
- Picks a method by looking at the machine: Docker, then Podman, then Snap, then WSL, then a native binary. The first one that works is used.
- Detects the architecture —
amd64,armv6,armv7,arm64,386. - Installs the agent and registers it to start at boot.
Force a method with INSTALL_METHOD when the choice is wrong for you:
$ curl -sSf https://cloud.shellhub.io/install.sh | INSTALL_METHOD=standalone sh
The methods
Docker
Picked when a rootful daemon is usable. Leaves a container running the agent, plus a
shellhub-agent wrapper on the host.
The wrapper is there because shellhub-agent login opens a browser during pairing, which an
agent inside a container cannot do. The container itself runs privileged, with the host’s
filesystem and process namespace: the agent opens shells as real unix users and forwards ports on
their behalf, and a confined container can do neither.
$ docker ps | grep shellhub # is it running
$ docker logs -f <container> # what it is doing
$ docker restart <container> # restart it
Podman
Picked when Podman is present and rootful. The same image and the same wrapper as Docker.
Rootful is a requirement, not a preference: the installer declines rootless, because an agent installed that way would appear to work and fail at the moment somebody tried to use it.
$ podman ps | grep shellhub # is it running
$ podman logs -f <container> # what it is doing
$ podman restart <container> # restart it
Snap
Picked when the snap command is present. Leaves the shellhub snap. The snap needs the tenant
named up front and cannot pair or take a provisioning key, so its device always lands pending until
somebody accepts it.
That snap is classic rather than strict, for the same reason the containers are privileged,
and classic snaps cannot be installed on Ubuntu Core — run the agent as a container under the
Docker snap there instead. Being a snap also means snapd refreshes it on its own schedule, so
the agent updates itself; sudo snap refresh --hold shellhub pins it.
$ snap services shellhub # is it running
$ sudo snap logs -f shellhub # what it is doing
$ sudo snap restart shellhub # restart it
WSL
Picked on WSL 2 with Ubuntu. Leaves a native binary under systemd, inside the distribution.
Each of those is a requirement rather than a description: version 2, Ubuntu, systemd enabled, and mirrored networking. The installer checks all four and stops on any of them.
$ systemctl status shellhub-agent # is it running
$ journalctl -u shellhub-agent -f # what it is doing
Standalone
Picked when nothing above matched. Leaves a binary and a systemd unit that starts it at boot.
That unit is the whole of it: no daemon, no container runtime, no snapd, which is what makes this the leanest way to run the agent.
$ systemctl status shellhub-agent # is it running
$ journalctl -u shellhub-agent -f # what it is doing
$ sudo systemctl restart shellhub-agent # restart it
What it configures
| Variable | Default | Meaning |
|---|---|---|
SERVER_ADDRESS |
the instance that served the script | Which server the agent talks to |
INSTALL_METHOD |
detected | Force a method rather than letting the script pick |
AGENT_VERSION |
fetched from $SERVER_ADDRESS/info |
Which agent version to install |
AGENT_IMAGE |
docker.io/shellhubio/agent:$AGENT_VERSION |
Container image, for the container methods |
INSTALL_DIR |
/usr/local/bin |
Where the binary goes, for standalone |
PROVISIONING_KEY |
— | Enrol without anybody accepting the device. See below |
TENANT_ID |
— | Which namespace to join. Deprecated: the device lands pending until somebody accepts it |
SKIP_BOOT_RESTART_CHECK |
— | Set to 1 to install under Podman without podman-restart.service |
SERVER_ADDRESS is filled in for you. Set it only to point somewhere other than where the script
came from.
Enrolling without accepting each device
Pairing asks somebody to approve the device, which is right for the machines in front of you and wrong for a hundred of them. A provisioning key carries the namespace and the rule for what happens on arrival, so devices enrol on their own, tagged:
$ curl -sSf https://cloud.shellhub.io/install.sh | PROVISIONING_KEY=<your-provisioning-key> sh
Uninstalling
$ curl -sSf https://cloud.shellhub.io/install.sh | sh -s uninstall
Standalone, WSL, Docker and Podman are supported. Other methods refuse rather than half-remove
themselves; a Snap install goes with snap remove shellhub.
Machines the script does not cover
The script assumes a machine that already exists, with somebody — or a provisioning script — running a command on it. These are not that command with a different flag.
Yocto and Buildroot are embedded build systems: the agent goes into the product image while the image is built, before there is a machine to run anything on. FreeBSD has its own packaging. Building from source is you producing the binary.
- Raspberry Pi — A card image that enrols itself on first boot.
- Yocto Project — The
meta-shellhubOpenEmbedded layer. - Buildroot — The ShellHub external tree, same idea.
- FreeBSD — The ShellHub ports tree.
- Building from Source — For a platform nothing above covers, or to run an agent you built yourself.
A unit coming off a line has no console to open and no link to click, so an image carries a provisioning key rather than waiting to be paired. And the key that identifies a device is generated by the agent on first start: one baked into an image makes every unit the same device, and one the unit cannot keep makes it a new device on every boot. See Agent Configuration for where that file lives.
Where to go next
- Quickstart — Accept the device and open a terminal on it.
- Agent Configuration — Every agent variable.
- Device Not Appearing — If it never shows up.