# Installing Continuum Local

> Prerequisites, sizing, installation on Linux, Windows, Docker, Kubernetes or a Node.js host, and enrolling the agent with Blueprintr.

Continuum Local ships as Debian and RHEL packages, a Windows installer, a
container image, a Helm chart, and a single JavaScript file for a host that
already runs Node.js. Every format runs the same agent file. Install the format
your estate already manages, give it an enrolment token from Blueprintr, run
`continuum-local check`, then start it.

> [!NOTE]
> The packages, the Windows installer, the container image and the Helm chart
> are published from release 0.2.0. Release 0.1.0 is the JavaScript file only.

## Before you start

| Requirement | Detail |
| --- | --- |
| Plan and permission | The organisation that owns the agent is on Enterprise (a team's agent uses its parent organisation's plan), and you have `continuum_integrations.manage` on that organisation or team. |
| Outbound HTTPS | Port 443 from the agent's host to `blueprintr.io` and `agents.blueprintr.io`, directly or through a proxy, as [network requirements](/foliums/blueprintr-user-guide/continuum/local-agent/network-requirements) describes. The agent accepts no inbound connections. |
| Routes to your systems | From the agent's host to each monitoring system on its API port (see the [connector table](/foliums/blueprintr-user-guide/continuum/local-agent#what-it-serves)), and UDP 161 to any device you sweep over SNMP. |
| Linux packages | systemd, and glibc 2.28 or later (RHEL 8, Debian 10, Ubuntu 20.04 or newer), on x86-64 or arm64. |
| Windows | 64-bit Windows Server. |
| Containers | linux/amd64 or linux/arm64. |
| Node.js host | Node.js 24 or later. Every other format includes its own runtime. |

### Sizing

The agent runs up to four relay and probe jobs at a time (`maxConcurrentJobs`,
1 to 16) and one network sweep alongside them. It ships with these limits:

| Format | Limits as shipped |
| --- | --- |
| Linux packages | Memory capped at 512 MB by the systemd unit (`MemoryMax`). Raise it with `sudo systemctl edit continuum-local`. |
| Helm chart | Requests 50m CPU and 96 MiB memory, memory limit 256 MiB, no CPU limit, and a 64 MiB PersistentVolumeClaim for state. |

Run one copy of each agent. Two processes sharing one enrolled identity take
work from the same queue, which adds no redundancy. For another site or network
segment, create another agent. An organisation or team may register up to 25
agents, and a revoked agent counts until you delete it.

## Download and verify

Download from the [download page](https://blueprintr.io/download/continuum-local)
while signed in to an account on an Enterprise plan; for anyone else the page
reports not found. Check the signature before you install. The page prints the
commands for the release you are viewing, and
[Releases and verification](/foliums/blueprintr-user-guide/continuum/local-agent/releases)
explains them.

The commands below use `$V` for the version you downloaded, for example
`V=0.2.0`.

## Linux packages

### Debian and Ubuntu

```bash
sudo apt install ./continuum-local_${V}_amd64.deb
sudo cp /etc/continuum-local/config.example.json /etc/continuum-local/config.json
sudo -e /etc/continuum-local/config.json
sudo chown root:continuum-local /etc/continuum-local/config.json
sudo chmod 640 /etc/continuum-local/config.json
sudo continuum-local check /etc/continuum-local/config.json
sudo systemctl enable --now continuum-local
```

On arm64, install the `_arm64.deb`. What to put in `config.json` is under
[Enrol the agent](#enrol-the-agent). The package creates a `continuum-local`
system account and a systemd unit, and leaves the service disabled until you
enable it.

### RHEL, Rocky and Alma

```bash
sudo dnf install ./continuum-local-${V}-1.x86_64.rpm
```

On arm64, install the `.aarch64.rpm`. Then follow the Debian steps from `cp`
onwards.

### What the packages install

| Path | Contents |
| --- | --- |
| `/etc/continuum-local/config.json` | Your configuration, which you create. Owned by `root:continuum-local` with mode 0640, so the service reads it and cannot change it. |
| `/etc/continuum-local/environment` | Environment variables for the service. Root only (0600), and kept on upgrade. |
| `/var/lib/continuum-local` | The state directory: the enrolled identity and any credentials sent from Blueprintr. Mode 0700. |
| `/usr/lib/continuum-local` | The agent and its Node.js runtime. |
| `/usr/bin/continuum-local` | The command for `check`, `discover`, `probe` and `walk`. |

The service runs as the unprivileged `continuum-local` account, with no
capabilities and a read-only filesystem apart from its state directory. Its
logs are in the journal: `journalctl -u continuum-local`.

Run the `continuum-local` command with `sudo`. As root it reads
`/etc/continuum-local/environment` the way systemd does, then switches to the
`continuum-local` account, so `check` sees the same proxy, certificates and file
permissions as the service.

### Proxy settings

Put proxy variables in the environment file, or set `proxy` and `noProxy` in
`config.json`, which take precedence:

```bash
sudo -e /etc/continuum-local/environment
```

```text
HTTPS_PROXY=http://proxy.corp.example:3128
NO_PROXY=localhost,.corp.example
```

```bash
sudo systemctl restart continuum-local
```

The agent sends only its traffic to Blueprintr through the proxy. Its
connections to your own systems stay direct. If the proxy re-signs TLS, set the
proxy's root certificate as `extraCaFile` in `config.json`: the agent trusts that
file for Blueprintr and never for your own systems. Variables used in `env:`
references also go in the environment file, such as `SOLARWINDS_PASSWORD` for
`"password": "env:SOLARWINDS_PASSWORD"`.

## Windows

> [!STEPS]
>
> === Run the installer
>
> Run `continuum-local-<version>-x64.msi` as an administrator. It installs to
> `C:\Program Files\Continuum Local` and registers the **Blueprintr Continuum
> Local** service (`ContinuumLocal`), which runs as `LocalService`. A first
> install leaves the service stopped and set to Manual.
>
> === Create the configuration
>
> In an elevated PowerShell, copy the example and edit it as described under
> [Enrol the agent](#enrol-the-agent):
>
> ```powershell
> Copy-Item "C:\Program Files\Continuum Local\config.example.json" `
>   "C:\ProgramData\Continuum Local\config.json"
> notepad "C:\ProgramData\Continuum Local\config.json"
> ```
>
> === Check it
>
> ```powershell
> & "C:\Program Files\Continuum Local\runtime\node.exe" `
>   "C:\Program Files\Continuum Local\continuum-local.mjs" `
>   check "C:\ProgramData\Continuum Local\config.json"
> ```
>
> === Enable and start the service
>
> ```powershell
> Set-Service -Name ContinuumLocal -StartupType Automatic
> Start-Service -Name ContinuumLocal
> ```

The installer gives `C:\ProgramData\Continuum Local` its own access list: the
service reads `config.json` but cannot change it, and writes only to `state\`
and `logs\`. Service logs are in `C:\ProgramData\Continuum Local\logs`. Set a
proxy with `proxy` and `noProxy` in `config.json`, because environment variables
added to the service are replaced on every upgrade.

> [!NOTE]
> The installer and its service wrapper, WinSW, are not Authenticode-signed.
> Check the `.msi` against the signed `SHA256SUMS` before you run it. The Windows
> installer has not been run on a customer's server, so treat the first install
> as a test.

## Docker

```bash
docker run -d --name continuum-local --restart=unless-stopped \
  -v /etc/continuum-local:/etc/continuum-local:ro \
  -v continuum-local-state:/var/lib/continuum-local \
  ghcr.io/blueprintr-io/continuum-local:$V
```

The image runs as the unprivileged `node` user (uid 1000) and reads
`/etc/continuum-local/config.json`, so uid 1000 needs read access to that file
on the host. The `continuum-local-state` volume keeps the enrolled identity.
Without it, a new container enrols again and fails, because the token is
already spent. Check the configuration with the same mounts:

```bash
docker run --rm \
  -v /etc/continuum-local:/etc/continuum-local:ro \
  -v continuum-local-state:/var/lib/continuum-local \
  ghcr.io/blueprintr-io/continuum-local:$V check
```

Give a proxy as `-e HTTPS_PROXY=... -e NO_PROXY=...`, or in the configuration.
Once you have verified the image, run it by the digest that `cosign verify`
prints: a tag can be moved, a digest cannot.

## Kubernetes

```bash
kubectl create secret generic continuum-local-config --from-file=config.json
helm install agent oci://ghcr.io/blueprintr-io/charts/continuum-local \
  --version $V --set existingSecret=continuum-local-config
```

To install from a file instead, use `continuum-local-helm-chart-<version>.tgz`
from the download page in place of the `oci://` address.

The chart runs one replica with the `Recreate` strategy, as a non-root user with
a read-only root filesystem, and creates no Service or Ingress. Its main values:

| Value | Default | Meaning |
| --- | --- | --- |
| `existingSecret` | none | A Secret with a `config.json` key. Keeps credentials out of your values file. |
| `config` | `{}` | The configuration inline, instead of a Secret. It puts credentials in your values file. |
| `configRevision` | none | Any string. Changing it restarts the pod, which Kubernetes does not do when a Secret changes. |
| `persistence.enabled` | `true` | Keeps the enrolled identity on a PersistentVolumeClaim of `persistence.size` (64Mi). With it off, state is lost whenever the pod is replaced, and the next start fails because the token is already spent. |
| `persistence.storageClass`, `persistence.existingClaim` | none | Your own storage class or claim. |
| `image.repository`, `imagePullSecrets` | `ghcr.io/blueprintr-io/continuum-local`, none | For a registry mirror. `image.tag` defaults to the chart's version. |
| `extraEnv`, `extraVolumes`, `extraVolumeMounts` | none | Proxy variables and extra CA files. The chart's `values.yaml` has examples. |

Without `existingSecret` or `config`, the agent does not start. After you edit
the Secret, restart the agent:

```bash
kubectl rollout restart deployment/agent-continuum-local
```

## A host with Node.js

Requires Node.js 24 or later. Download `continuum-local-<version>.mjs`, write
`config.json` beside it, owned by the account that runs the agent with mode
0600, then:

```bash
node continuum-local-$V.mjs check ./config.json
node continuum-local-$V.mjs ./config.json
```

Run it under whatever supervises long-running processes on that host. It exits
cleanly on SIGTERM or SIGINT.

## Configuration and state locations

| Install | Configuration | State directory |
| --- | --- | --- |
| Debian, Ubuntu, RHEL, Rocky, Alma | `/etc/continuum-local/config.json` | `/var/lib/continuum-local` |
| Windows | `C:\ProgramData\Continuum Local\config.json` | `C:\ProgramData\Continuum Local\state` |
| Docker | `/etc/continuum-local/config.json`, mounted from the host | The volume at `/var/lib/continuum-local` |
| Kubernetes | The Secret, mounted at `/etc/continuum-local/config.json` | The PersistentVolumeClaim, at `/var/lib/continuum-local` |
| Node.js host | The path you pass | See below |

The state directory contains the enrolled identity (`agent-state.json`, mode
0600) and any integrations configured from Blueprintr. `statePath` in the
configuration overrides it on every format. Without it, the agent uses
`CONTINUUM_LOCAL_STATE_DIR` when set, then a systemd `StateDirectory=`, then
`%ProgramData%\Continuum Local\state` on Windows, then
`/var/lib/continuum-local` for `/etc/continuum-local/config.json` on Linux, and
otherwise the configuration file's own directory.

## Enrol the agent

> [!STEPS]
>
> === Create the agent in Blueprintr
>
> In **Settings → Continuum** on the organisation or team, under **Continuum
> Local**, choose **Add an agent**, name it and choose **Create**.
>
> === Copy the token
>
> Choose **Copy enrollment token**. The token is shown once, works once and
> expires after 24 hours.
>
> === Put it in the configuration
>
> The smallest configuration that enrols:
>
> ```json
> {
>   "apexUrl": "https://blueprintr.io",
>   "displayName": "DC1 agent",
>   "enrollmentToken": "the token you copied"
> }
> ```
>
> `enrollmentToken` also accepts a reference such as `"env:CL_TOKEN"` or
> `"file:/etc/continuum-local/token"`. If you started from
> `config.example.json`, delete the sample proxy, integrations and discovery
> block you do not use, since they contain example hosts and ranges.
>
> === Check and start
>
> Run `check` as shown for your format, then start the agent. It confirms its
> state directory is writable before it sends the token, then exchanges the token
> for its own credential and writes that to the state directory.
>
> === Confirm it is online
>
> Within a minute of starting, the agent's status in the panel changes from
> **Waiting to be installed** to **Online**, followed by "connected through the
> gateway" or "polling (no gateway connection)". The agent polls when it has no
> gateway connection, so both states serve work.
>
> === Remove the token
>
> Delete the `enrollmentToken` line. It is spent, and the agent logs a reminder
> at each start while the line is there.

An expired, spent or revoked token gets the same refusal. Issue another with
**New token** on the agent, or for a revoked agent, create a new agent. If the
owning organisation's plan is inactive, enrolment is refused with a message
that says so, and the token is not spent.

Next, add your on-premise connections in Blueprintr and copy the configuration
block the panel prints for each into `integrations`: see
[Continuum Local](/foliums/blueprintr-user-guide/continuum/local-agent). Every
setting is in the
[configuration reference](/foliums/blueprintr-user-guide/continuum/local-agent/configuration).

## Running the check

Run [`continuum-local check`](/foliums/blueprintr-user-guide/continuum/local-agent/configuration#the-check-command)
on every new install, after every configuration change and before you contact
support. It tests the configuration, the state directory, the certificate
roots, the route to Blueprintr and a TLS handshake with each integration host,
without enrolling or spending the token.
