> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runlayer.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Linux (Detect only)

> Deploy AI Watch to Linux fleets via .deb / .rpm packages. Detect scans all users on a cron schedule; Enforce and Sessions are not available on Linux.

AI Watch deploys to Linux as a native package (`runlayer-aiwatch` `.deb` / `.rpm`) that installs the `aiwatch` binary and a cron entry. Every 15 minutes it scans **all users on the machine** for shadow AI — MCP servers, connectors/plugins, skills, and agents — and reports findings to your Runlayer tenant.

## What you get

Linux is **Detect-only**:

* Cron-scheduled shadow-AI scans across **all** users on the machine (root and service accounts included).
* No hooks, no Enforce, no Sessions, and no browser extension on Linux.
* In the dashboard, a Linux device shows **Detect = Active** and **Enforce / Sessions = Disabled**. That is the expected state, not an error.

## Supported distributions

Packages are x86\_64 and built on Ubuntu 22.04, so they require **glibc 2.35 or newer**:

| Supported              | Not supported               |
| ---------------------- | --------------------------- |
| Ubuntu 22.04+          | Ubuntu 20.04                |
| Debian 12+             | Debian 11                   |
| RHEL / Rocky / Alma 9+ | RHEL 8                      |
| Amazon Linux 2023      | Amazon Linux 2              |
| Current Fedora         | Alpine / musl-based distros |

A running cron daemon is required. The `.deb` depends on `cron | cron-daemon | cronie` and the `.rpm` depends on `cronie`, so a provider is pulled in automatically on install if missing.

<Warning>
  Do **not** install AI Watch inside WSL. Windows AI Watch already scans WSL home directories from the Windows host — a WSL install creates a duplicate device in the dashboard.
</Warning>

## Install

Download the `aiwatch-<version>-linux-x86_64.zip` deployment bundle from your Runlayer downloads access. It contains the `.deb`, the `.rpm`, `SHA256SUMS`, and the config templates. Contact your Runlayer account team if you don't have the bundle yet.

<Steps>
  <Step title="Verify the artifacts">
    Packages are not GPG-signed today; `SHA256SUMS` is the integrity check:

    ```bash theme={null}
    sha256sum -c SHA256SUMS
    ```
  </Step>

  <Step title="Install the package">
    <CodeGroup>
      ```bash Debian / Ubuntu theme={null}
      sudo apt-get install -y ./runlayer-aiwatch_<version>_amd64.deb
      ```

      ```bash RHEL / Fedora / Amazon Linux theme={null}
      sudo dnf install -y ./runlayer-aiwatch-<version>-1.x86_64.rpm
      ```
    </CodeGroup>

    The package installs:

    | Path                                    | Purpose                                                                 |
    | --------------------------------------- | ----------------------------------------------------------------------- |
    | `/usr/lib/runlayer/aiwatch/`            | The self-contained `aiwatch` bundle (plus a `/usr/bin/aiwatch` symlink) |
    | `/usr/lib/runlayer/run-aiwatch-scan.sh` | Root scan wrapper — enumerates users and runs per-user scans            |
    | `/etc/cron.d/runlayer-aiwatch`          | Cron entry: every 15 minutes as root                                    |
    | `/etc/runlayer/aiwatch/config.json`     | Managed config template (world-readable, non-secret)                    |
    | `/etc/runlayer/aiwatch/credentials`     | Credentials template (root-only, `0600`)                                |

    Nothing executes at install time — the first scan fires on the next cron tick after you configure the two files below.
  </Step>
</Steps>

## Configure

Configuration is two files under `/etc/runlayer/aiwatch/`. The split matters: per-user scan children run unprivileged and read `config.json`, so that file is world-readable by design — the org API key must never go in it.

### 1. `/etc/runlayer/aiwatch/config.json` (world-readable, non-secret)

Set `Host` to your tenant URL and keep `Sessions` and `Enforcement` at `false` — that is the Detect-only contract on Linux:

```json theme={null}
{
  "Host": "https://tenant.runlayer.com",
  "Sessions": false,
  "Enforcement": false
}
```

<Warning>
  **Never put the org API key in `config.json`.** The file is world-readable by design so unprivileged per-user scan children can read managed settings. The key belongs in the root-only `credentials` file below.
</Warning>

Optional tuning keys, with the same semantics as the macOS Configuration Profile keys (see [Deploy AI Watch](/shadow-ai/deploy)):

| Key              | Default     | Purpose                                                           |
| ---------------- | ----------- | ----------------------------------------------------------------- |
| `ProjectDepth`   | `7`         | Directory depth Detect scans walk under each user home (max `20`) |
| `ProjectTimeout` | `60`        | Per-scan time budget in seconds (max `300`)                       |
| `Username`       | OS username | Override for backend user attribution                             |
| `DeviceName`     | hostname    | Override for the device name                                      |

### 2. `/etc/runlayer/aiwatch/credentials` (root-only, `0600`)

Set the organization API key — the same `rl_org_...` key used by your macOS and Windows deployments, minted in **Settings → Organization API keys** with the **Shadow AI Scan** role:

```bash theme={null}
RUNLAYER_API_KEY=rl_org_xxxxxxxxxxxxxxxx
# Optional: override the backend host from config.json
#RUNLAYER_HOST=https://your-tenant.runlayer.com
```

Until `RUNLAYER_API_KEY` is set, the scan wrapper exits quietly without scanning — an unconfigured device produces no errors and no data.

## How it runs

`/etc/cron.d/runlayer-aiwatch` runs `/usr/lib/runlayer/run-aiwatch-scan.sh` as root every 15 minutes (the same cadence as the macOS LaunchAgent and the Windows `AIWatchScan` task). The wrapper:

* Enumerates **all** passwd users with an existing home directory — root and service accounts included; shared home directories are scanned once.
* Runs `aiwatch scan` for each user in its own child process **with privileges dropped to that user**, so one user's failure never aborts the others.
* Skips overlapping runs via a lock file — concurrent cron ticks never queue up.
* Routes all output to syslog, tagged `runlayer-aiwatch` (cron never emails root).

## Verify

On a test machine after configuring both files:

```bash theme={null}
# 1. Trigger a full all-users scan immediately (instead of waiting for cron)
sudo /usr/lib/runlayer/run-aiwatch-scan.sh; echo $?
# Expect 0. Non-zero means at least one user's scan failed — check syslog:
journalctl -t runlayer-aiwatch --since "10 min ago"

# 2. Preview findings for your own user locally, without submitting
aiwatch scan --dry-run
```

Then in the Runlayer dashboard, go to **Shadow AI → Devices**: the device appears with OS = Linux, **Detect = Active**, and **Enforce / Sessions = Disabled** within about 15 minutes. Disabled Enforce/Sessions is the correct Detect-only state on Linux.

## Updates

There is no auto-update on Linux. Upgrade through your configuration management (Ansible, Salt, Puppet, etc.) by installing the newer `.deb` / `.rpm` — the same install commands upgrade in place. Your edited `/etc/runlayer/aiwatch/config.json` and `credentials` files are preserved across upgrades (they are packaged as config files with `noreplace` semantics). Point your automation at your Runlayer downloads access to pick up the latest version.

## Uninstall

<CodeGroup>
  ```bash Debian / Ubuntu theme={null}
  sudo apt-get remove runlayer-aiwatch
  ```

  ```bash RHEL / Fedora / Amazon Linux theme={null}
  sudo dnf remove runlayer-aiwatch
  ```
</CodeGroup>

Removing the package deletes `/etc/cron.d/runlayer-aiwatch` immediately, so no stale schedule keeps firing. Edited config files under `/etc/runlayer/aiwatch/` remain unless you purge (`sudo apt-get purge runlayer-aiwatch` on Debian/Ubuntu).

## Troubleshooting

<AccordionGroup>
  <Accordion title="No device appears in the dashboard">
    * The wrapper exits quietly when `RUNLAYER_API_KEY` is missing from `/etc/runlayer/aiwatch/credentials` — confirm the key is set and the file is readable by root.
    * Confirm a cron daemon is running (`systemctl status cron` or `systemctl status crond`).
    * Run `sudo /usr/lib/runlayer/run-aiwatch-scan.sh; echo $?` and check `journalctl -t runlayer-aiwatch` for per-user errors.
    * Verify the device can reach your tenant host over HTTPS (443).
  </Accordion>

  <Accordion title="Manual wrapper run exits 0 instantly with no output">
    Either `RUNLAYER_API_KEY` is not configured (the unconfigured-device gate), or another scan run currently holds the lock — overlapping runs skip instead of queueing. Wait for the running scan to finish and retry.
  </Accordion>

  <Accordion title="Device shows Enforce / Sessions as Disabled">
    Expected. Linux is Detect-only: there are no hooks, no Enforce, no Sessions, and no browser extension. Only macOS and Windows support those features.
  </Accordion>
</AccordionGroup>
