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

# Install

> Install Lager box code onto a box

Deploy the Lager Box software, Docker container, and supporting tools onto a new or existing box.

## Syntax

```bash theme={null}
lager install [OPTIONS]
```

## Options

| Option                 | Type   | Default     | Description                                                                                                                         |
| ---------------------- | ------ | ----------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `--box TEXT`           | string |             | Box name (uses stored IP and username from `.lager` config)                                                                         |
| `--ip TEXT`            | string |             | Target box IP address or DNS hostname                                                                                               |
| `--user TEXT`          | string | `lagerdata` | SSH username                                                                                                                        |
| `--version TEXT`       | string | `main`      | Box version to deploy: a release tag (e.g. `v0.15.0`), a git branch, or a full 40-character commit SHA                              |
| `--skip-jlink`         | flag   |             | Skip J-Link installation (pyOCD is always installed)                                                                                |
| `--skip-firewall`      | flag   |             | Skip UFW firewall configuration                                                                                                     |
| `--skip-verify`        | flag   |             | Skip post-deployment verification                                                                                                   |
| `--corporate-vpn TEXT` | string |             | Corporate VPN interface name for firewall rules (e.g., `tun0`)                                                                      |
| `--yes`                | flag   |             | Skip confirmation prompts                                                                                                           |
| `--pull`               | flag   | on          | Use the pre-built box image when the target is a release tag (the default)                                                          |
| `--no-pull`            | flag   |             | Always build the box image on the box                                                                                               |
| `--timeout INTEGER`    | int    | `1800`      | Max seconds for the deploy step, which includes the container build. `0` disables the budget. Overridden by `LAGER_INSTALL_TIMEOUT` |
| `--help`               |        |             | Show help message and exit                                                                                                          |

Either `--box` or `--ip` is required. If both are provided, the command exits with an error.

## The Box Image

The slowest part of an install is the box's Docker image. A build on the box
takes roughly 14 minutes, and an install always pays the full cost. The
deployment prunes the builder cache before it starts, so there is never a warm
layer cache to reuse.

Every release tag publishes a pre-built image, and `lager install` uses it by
default: about 2 minutes instead of 14.

This only applies when `--version` names a **release tag**. Branches such as
`main` and `staging` have no published image, so they always build on the box.
Pinning a release tag is the difference between a two-minute install and a
fourteen-minute one.

The image is verified before it is used. Lager fetches it by immutable digest
rather than by tag, and the image must carry a label naming the exact version
you requested. Lager discards an image that is unlabeled or that claims a
different version. Three things can go wrong: the tag has no published image,
the box cannot reach the registry, or the image fails verification. In each
case the install falls back to a build on the box, exactly as it always did.
A slow install that works beats a fast one that does not.

Pass `--no-pull` to skip the pre-built image and always build. Setting
`LAGER_BOX_IMAGE_PULL=0` in the environment does the same for every command in
that shell.

## What Gets Installed

| Component        | Description                                                                   |
| ---------------- | ----------------------------------------------------------------------------- |
| Docker container | Lager service container (ports 5000 and 8765) with auto-restart               |
| pyOCD            | Open-source debug probe tool (automatic)                                      |
| J-Link           | SEGGER debug probe software (optional, skipped with `--skip-jlink`)           |
| UFW firewall     | Restricts service ports to VPN and localhost (skipped with `--skip-firewall`) |
| Box code         | Python libraries and services in `~/box`                                      |

## Installation Flow

1. **Resolve target** - Looks up box IP from `--box` name or uses `--ip` directly
2. **Verify SSH** - Tests key-based authentication and settles which identity the rest of the command offers
3. **Show summary** - Displays what will be installed and asks for confirmation
4. **Deploy** - Runs the deployment script. About 2 minutes when the pre-built
   image is used; a cold build on ordinary box hardware is roughly 14 minutes
   (see below). The step is bounded by `--timeout`, 30 minutes by default --
   raise it on slower hardware, where a healthy build can legitimately exceed
   the default
5. **Store version** - Writes the CLI version to `/etc/lager/version` on the box
6. **Add to config** - Optionally adds the box to your local `.lager` config

## Examples

```bash theme={null}
# Install to a new box by IP
lager install --ip 192.168.1.100

# Install to a stored box
lager install --box my-lager-box

# Install a specific release tag
lager install --ip 192.168.1.100 --version v0.15.0

# Install a specific branch with a custom user
lager install --ip 192.168.1.100 --user pi --version staging

# Install with corporate VPN firewall support
lager install --ip 192.168.1.100 --corporate-vpn tun0

# Skip optional components
lager install --ip 192.168.1.100 --skip-jlink --skip-firewall

# Force a local build of the box image instead of using the published one
lager install --box my-lager-box --version v0.39.1 --no-pull

# Non-interactive installation
lager install --ip 192.168.1.100 --yes
```

## Passwordless sudo

Installation configures passwordless `sudo` for the box login user. The CLI drives
the box over non-interactive SSH, where `sudo` has no terminal to prompt
against. The grants must be in place before provisioning runs.

Lager writes these files, and only these files, under `/etc/sudoers.d/`:

| File               | Written by                                                 | Grants                                                                                                                            |
| ------------------ | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `lagerdata-udev`   | `lager install`                                            | udev rule deployment, modprobe blacklist, Docker group and service control, firewall helper install/run, `/etc/lager` file writes |
| `lager-box-config` | `lager install`, `lager update`                            | `apt-get`, `sysctl`, and the path-scoped writes `lager box-config apply` needs                                                    |
| `lager-bench-json` | Operator, on boxes predating the grant in `lagerdata-udev` | Writing `/etc/lager/bench.json`                                                                                                   |

<Warning>
  **The box login user is root-equivalent by design.** Provisioning a box requires
  root. Deploying udev rules runs commands as root by construction, and `apt-get`
  executes arbitrary commands as root through its own configuration. Lager writes
  the grants above as specific commands, to keep the blast radius small and the
  file readable. They are **not a privilege boundary**. Anyone who can log in as
  the box user can obtain root on that box.

  Treat the box login account as equivalent to root when deciding who holds its
  SSH key, and prefer a dedicated user on a dedicated machine.
</Warning>

Each of the three files is **regenerated in full** on every run — that is what
keeps a box on the current grant shape. A grant added *inside* one of them is
lost the next time it is written, so each file opens with a header saying so.

Lager never reads, edits, or removes any other file in `/etc/sudoers.d/`. If you
or a box-management platform need additional grants, put them in a separate file
there. For example, `/etc/sudoers.d/zz-local` sorts after Lager's files, so its
rules win. Lager will leave that file alone, including during `lager uninstall`.

## SSH Authentication

Install requires key-based SSH authentication. It offers `~/.ssh/lager_box` —
the key `lager ssh-setup` and `lager install` generate — explicitly, because
that is not a filename ssh tries on its own. If the box does not accept it,
install falls back to your own default identities, so a box you authorized with
`ssh-copy-id` works unchanged.

If neither authenticates, install offers to set the key up for you:

```
No SSH key on this machine is authorized on the box.

Set up the lager_box key now? (one box-password prompt, then the rest of the
install runs unattended) [Y/n]:
```

Accepting prompts for the box password **once**, installs the key, and every
later step of the install runs unattended. `--yes` accepts it without asking.
Declining stops the install and points you at `lager ssh-setup --box <name-or-ip>`, which does the same thing as a separate step.

Install does not offer a password fallback for the deployment itself. A box
configured with `PasswordAuthentication no` never receives the password. The
resulting "password failed" message therefore described something that never
happened.

For new hosts, the SSH host key is accepted automatically. If the host key
changed since a previous connection, the command asks you to verify the change
manually first.

Install does not write to `~/.ssh/config`. Earlier versions added a per-IP
`Host` block naming the key. Another tool that regenerated the file deleted
that block, and the block also disabled host-key verification for the box.
The identity is passed per command instead.

## Notes

* For a step-by-step walkthrough, see [Setting Up a Lager Box](/source/getting-started/setting-up-a-lager-box)
* Requires SSH client tools (`ssh`, `ssh-keygen`) to be installed locally
* The deployment script is bundled with the `lager-cli` package
* After installation, verify connectivity with `lager hello --box <name>`
* Use `lager update` to deploy code updates to an already-installed box
* Use `lager uninstall` to remove Lager software from a box
