# Linux server

URL: https://shellz.dev/docs/install/linux

> Install shellz on a systemd Linux server, what the installer changes, and supported distributions.

One command installs shellz on a Linux server and starts recording every login on it. This page covers requirements, what changes on the server, and distribution-specific notes.

## Requirements

- Linux with systemd, on amd64 (x86_64) or arm64 (aarch64).
- Root access through `sudo`.
- `curl` and OpenSSL 3, used by the installer to download and verify the release.
- If the server runs OpenSSH, its `sshd_config` must include `/etc/ssh/sshd_config.d/*.conf`. Current versions of every supported distribution do.
- Outbound HTTPS (port 443) to `api.shellz.dev`, `ingest.shellz.dev` and `releases.shellz.dev`.

## Supported distributions

| Distribution | Status |
|---|---|
| Ubuntu 24.04 | Tested |
| Debian 13 | Tested |
| Rocky Linux 9, AlmaLinux 9 | Tested, including with SELinux enforcing |
| Fedora 44 | Tested |
| Arch Linux | Tested |
| Ubuntu 22.04, Debian 12, RHEL 9, Amazon Linux 2023 | Expected to work (same packages and OpenSSL 3) |
| Amazon Linux 2, RHEL, Rocky and Alma 8, anything with OpenSSL 1.x | Not supported. The installer refuses and says why. |

LXC containers, systemd-nspawn machines and Proxmox guests count as servers, because they boot their own systemd. To record inside application containers (Docker, Kubernetes and so on), see [Choose an install method](https://shellz.dev/docs/install.md).

## Install

In the dashboard, open **~/servers** and click **Add server**. Copy the command and run it on the server:

```bash
curl -fsSL https://get.shellz.dev | sudo sh -s -- szt_<join token>
```

Each join token works once and expires after 10 minutes. It also carries the fingerprint of your org's public key, so the server only trusts keys from your org.

The server appears in **~/servers** under its hostname, without the domain part. If that name is taken, shellz adds a number (`web-2`).

The installer refuses to run, without changing anything, if:

- it isn't running as root, on systemd, on amd64 or arm64;
- `curl` or OpenSSL 3 is missing (it names the package to install for your package manager);
- it's running inside an application container;
- sshd doesn't read `/etc/ssh/sshd_config.d` (it tells you the `Include` line to add);
- the server is already enrolled.

If the release signature or checksum doesn't match, it stops before installing anything.

## What the installer changes

| What | Where |
|---|---|
| The shellz binary | `/usr/local/bin/shellz` |
| The session shell | `/usr/local/libexec/shellz-shell`, also added to `/etc/shells` |
| The recorder service | `/etc/systemd/system/shellz-recorder.service`, enabled at boot |
| Configuration (no secrets) | `/etc/shellz` |
| State: server key, pinned org keys, policy, spool | `/var/lib/shellz` (root only) |
| Recorder socket | `/run/shellz/broker.sock` |
| SSH setting | `/etc/ssh/sshd_config.d/00-shellz.conf`, containing `PermitUserRC no` |
| Login shells | root and regular accounts (UID from `UID_MIN` up to 59999) are switched to the session shell. Original shells are saved and restored on removal. |

On SELinux systems, shellz also installs a one-rule policy module so recorded sessions keep the login's own SELinux context. SELinux is never set to permissive.

Nothing else on the server changes. shellz doesn't install packages, open ports, or modify PAM.

### Why `PermitUserRC no`

OpenSSH runs `~/.ssh/rc` for each login before the shell starts, which would let a user run commands outside the recording. shellz turns it off.

### Service accounts

Accounts below `UID_MIN` (usually 1000) other than root, and accounts whose shell is `nologin` or `false`, keep their shells. If any of them does start a login session, the session auditor notices and, depending on the [recording policy](https://shellz.dev/docs/guides/recording-policy.md), ends it and raises an alert.

## Check that it's working

```bash
sudo /usr/local/bin/shellz status
```

`Recorder running` and `Sessions N active` mean the server is recording. Then SSH in from another terminal and watch the session appear in the dashboard. `--json` prints the same information as JSON for monitoring tools.

## Distribution notes

### Rocky, Alma, RHEL and Fedora

sudo's `secure_path` on these distributions doesn't include `/usr/local/bin`, so `sudo shellz status` reports "command not found". Use the full path, `sudo /usr/local/bin/shellz status`. Every hint shellz prints already does.

With SELinux enforcing, the installer needs `semodule` (package `policycoreutils`, installed by default). Logins mapped to confined SELinux users (`user_u`, `staff_u`, `sysadm_u`, `guest_u`, `xguest_u`) aren't supported: they can't reach the recorder, so their logins are refused, or let through unrecorded under fail-open.

### Arch Linux

Check that `/etc/ssh/sshd_config` contains `Include /etc/ssh/sshd_config.d/*.conf`. Current Arch packages ship it; older configurations may not.

### Unprivileged LXC containers

shellz can't set the immutable flag (`chattr +i`) on its files in an unprivileged LXC container. It still installs and records, still repairs changes every 15 seconds, and raises one `immutable-unsupported` warning.

## Docker on the same server

If Docker runs on the server, the same install records container sessions too. See [Docker host](https://shellz.dev/docs/install/docker-host.md).

## Troubleshooting

**"This server is already enrolled."** shellz is already installed. Run `sudo /usr/local/bin/shellz status`. To move the server to another org, [remove it](https://shellz.dev/docs/guides/updates-and-removal.md#removing-shellz) first.

**"This join token is no longer valid."** Tokens work once and expire after 10 minutes. Click **Add server** for a new command.

**"The join token checksum does not match."** The token was cut off or mistyped while copying. Copy the whole command again.

**"sshd does not read sshd_config.d."** Add `Include /etc/ssh/sshd_config.d/*.conf` near the top of `/etc/ssh/sshd_config`, then run the install command again. Nothing was changed.

**OpenSSL 1.x.** Amazon Linux 2 and EL8 ship OpenSSL 1.1, which can't verify the Ed25519 release signature. Upgrade to a distribution with OpenSSL 3.
