> ## 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.

# Setting Up a Lager Box

> Turn an Ubuntu machine into a Lager Box

A **Lager Box** is an ordinary Ubuntu machine that runs the Lager Box software. This page
turns a machine you already have into one. That machine can be a mini PC on your bench, a
rack server, or a virtual machine.

<Note>
  If someone has already set up a box for you, you do not need this page. Go straight to
  [Adding your First Lager Box](/source/getting-started/adding-first-lager-box).
</Note>

***

## What You Need

**On the machine that will become the box:**

* An **x86-64** processor. This is the only supported box architecture.
* **Ubuntu 22.04 or newer**, including 24.04 LTS. See the note on Ubuntu 25.10 and later below.
* A network connection, and an IP address or hostname you can reach.
* An SSH server, and a **login account with `sudo`** whose password you know.
* **`git`** installed. Lager installs everything else the box needs, including Docker.
  Step 1 explains why you must spend the extra minute and install Docker yourself.

**On your computer:**

* **Python 3.10 or higher** and `pip3`.
* An SSH client (`ssh` and `ssh-keygen`).

Run this on the machine to check all three at once before you start:

```bash theme={null}
uname -m           # must be x86_64
lsb_release -ds    # Ubuntu 22.04 or newer
sudo --version     # see the sudo-rs note below
```

<Note>
  A first install builds the Lager container on the box itself. That takes roughly 14 minutes
  on ordinary box hardware. Plan for the box to be busy. `lager install` bounds the step at
  30 minutes by default.

  Slower hardware runs longer. An emulated guest, a low-power mini PC, or a throttled VM can
  exceed 30 minutes on a healthy build. Raise the budget with `--timeout <seconds>` or
  `LAGER_INSTALL_TIMEOUT`, so the build does not stop midway.
</Note>

<Warning>
  **Keep your own machine awake for the whole install.** The build runs on the box, but it is
  driven over SSH from the machine you launched `lager install` from. If that machine sleeps and
  the connection drops, the build goes with it. On macOS, run the install under `caffeinate -i`.
</Warning>

<Note>
  **Ubuntu 25.10 and later, including 26.04 LTS, install without any change.** Those releases
  default to `sudo-rs`, which rejects wildcards in command arguments. Lager used to write
  wildcard rules to `/etc/sudoers.d/`, so installation stopped early with
  `wildcards are not allowed in command arguments`. Since **lager 0.41.0** every rule Lager
  writes names its arguments exactly, and nothing needs switching back to classic `sudo`.

  On an older CLI, switch the box to classic `sudo` instead
  (`sudo update-alternatives --set sudo /usr/bin/sudo.ws`). Keep a second session open with a
  working root shell, in case the switch does not take.
</Note>

<Warning>
  **The box login account is root-equivalent by design.** Provisioning a box requires root, so
  installation grants that account passwordless `sudo` for the commands Lager needs. Anyone who
  can log in as that account can obtain root on the box. Prefer a dedicated user on a dedicated
  machine, and treat its SSH key accordingly. The
  [Install reference](/source/reference/cli/install) describes exactly which grants are written.
</Warning>

***

## Step 1: Prepare the Machine

SSH into the machine and install `git`:

```bash theme={null}
sudo apt update && sudo apt install -y git
```

Confirm the account can use `sudo`. You will be asked for its password once during
installation:

```bash theme={null}
sudo true
```

<Note>
  **Optional, but it makes a failure easier to read: install Docker yourself now.** The
  installer installs Docker when the machine does not have it. It runs that step over SSH, and
  it reports package problems with less detail than apt gives you directly. Install Docker by
  hand first, and any problem surfaces with a real error message, in front of you:

  ```bash theme={null}
  sudo apt install -y docker.io docker-compose-v2 docker-buildx
  sudo systemctl enable --now docker
  sudo usermod -aG docker $USER
  ```

  Log out and back in afterward so the group membership takes effect, then check `docker ps`
  works without `sudo`.
</Note>

<Note>
  The login account does not have to be named `lagerdata`. Pass its real name as `--user` in
  Step 3, and record that name with the box. Later commands then use the right account.
</Note>

Note the machine's IP address or hostname -- you need it in Step 3:

```bash theme={null}
ip -br addr
```

***

## Step 2: Install the Lager CLI

On your own computer, not on the box:

```bash theme={null}
pip3 install -U lager-cli
```

Check that it is available:

```bash theme={null}
lager --version
```

***

## Step 3: Run the Installer

`lager install` does the rest. It configures SSH keys and sudo, and it deploys the box code.
It installs Docker when the machine does not have it. It then builds and starts the Lager
container, and configures the firewall.

```bash theme={null}
lager install --ip <box-ip> --user <box-user>
```

The command checks SSH connectivity and prints a summary of its planned work. It asks you to
confirm before it changes anything.

**The first time, SSH will not be authorized yet.** Lager notices, and offers to fix it:

```
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]:
```

Accept it and enter the box account's password once. Lager installs a dedicated key at
`~/.ssh/lager_box`. Every later step, and every later command, then runs without a password.
If you decline, the install stops. It tells you to run `lager ssh-setup --box <name-or-ip>`,
which does the same thing on its own.

Deployment then runs, streaming its output. Leave it alone until it finishes.

**If it fails partway, fix what it reports and run the same command again.** `lager install`
is safe to re-run. It rewrites its own configuration each time and skips finished work, so a
second run continues rather than starts over.

<Note>
  To install a specific release instead of the latest code, add `--version` -- for example
  `--version v0.39.0`. See the [Install reference](/source/reference/cli/install) for every
  option.
</Note>

***

## Step 4: Networking and the Firewall

Installation configures a UFW firewall on the box. The firewall restricts the Lager service
ports to your VPN, the Docker bridge, and localhost. Port 22 always stays open, so the
firewall cannot lock you out of the machine.

How you point it at your network depends on what you use:

**Tailscale.** Nothing to do. If Tailscale runs on the box, the installer detects the
`tailscale0` interface and allows the Lager ports on it.

**A corporate VPN.** Name the interface explicitly. Find it on the box:

```bash theme={null}
ip -br link
```

Then pass it to the installer -- `cscotun0` for Cisco Secure Client, `tun0` for OpenConnect,
and so on:

```bash theme={null}
lager install --ip <box-ip> --user <box-user> --corporate-vpn cscotun0
```

<Warning>
  The interface must exist on the box **at the moment you run the installer**. If the VPN is not
  connected, the firewall step fails with `Corporate VPN interface <name> not found` and lists
  the interfaces it did find. Connect the VPN and run the install again.
</Warning>

**Neither.** Add `--skip-firewall` to leave UFW alone entirely, and secure the machine by
whatever means you already use.

***

## Step 5: Name the Box and Verify

When deployment finishes, the installer offers to add the box to your local configuration:

```
Add this box to your configuration? [Y/n]: y
Box name: bench-1
```

The name is yours to choose and is local to your computer. If you skipped that prompt, add it
by hand -- `--user` is required:

```bash theme={null}
lager boxes add --name bench-1 --ip <box-ip> --user <box-user>
```

Check that the box answers:

```bash theme={null}
lager hello --box bench-1
```

**Expected output:**

```
Box: bench-1
IP: 100.64.1.42
Version: 0.39.0

bench-1 is online and responding!
```

Then see what hardware it can find:

```bash theme={null}
lager instruments --box bench-1
```

An empty list is the correct answer before you connect any instruments.

***

## Running a Lager Box in a Virtual Machine

A VM works as a Lager Box, provided the guest is x86-64 and runs Ubuntu 22.04 or newer.
Everything above applies unchanged.

The one thing that differs is hardware access. Instruments and debug probes are USB devices,
and the Lager container reaches them through the host's `/dev`. **A USB device the guest cannot
see is a device Lager cannot use.** So if the box will drive real hardware, configure USB
passthrough in your hypervisor before you connect anything.

Pass through an **entire USB controller** rather than individual devices. A debug probe
re-enumerates when it resets, and Lager power-cycles USB hub ports as a normal part of
testing. Both events change or drop the device identity that per-device passthrough pins to.
A whole controller keeps working across them.

A VM with no hardware attached is still useful when you try Lager out. It needs no
passthrough at all.

### Emulated guests

An **emulated** x86-64 guest works, such as an x86 VM on an ARM host. Its first install runs
far slower than the figures above, and can take several hours.

The container build is the reason. The box image compiles a USB DAQ library from source as a
single-threaded C++ build. That takes a few minutes natively, and it is very slow under
emulation. Expect that step alone to run for hours.

Pull the pre-built image instead of building it. Deploy a release tag rather than `main`, so
that a published image exists to pull:

```bash theme={null}
lager install --ip <box-ip> --user <box-user> --version <release-tag>
lager update --box <box-name> --version <release-tag> --pull
```

Any published release tag works. `lager update --version` accepts a tag, a semver pin, a
branch, or a commit SHA. Only a release tag has a published image to pull.

When no image matches, `--pull` falls back to building on the box. Watch the output. If it
starts to compile, the pull missed and you are back on the slow path. See
[pre-built box images](/source/reference/cli/update#pre-built-box-images).

***

## Troubleshooting

<Accordion title="git is not installed on box">
  Installation stops before deploying anything. Install `git` on the box and run the command
  again:

  ```bash theme={null}
  sudo apt update && sudo apt install -y git
  ```
</Accordion>

<Accordion title="No SSH key on this machine is authorized on the box">
  Expected on a first install -- answer **yes** to the prompt that follows and enter the box
  account's password once. To do it as a separate step instead:

  ```bash theme={null}
  lager ssh-setup --box <box-ip>
  ```

  If the box rejects the password, confirm that you use the box account's own password.
  Confirm also that the box allows password authentication for that account.
</Accordion>

<Accordion title="Corporate VPN interface not found">
  The interface named by `--corporate-vpn` did not exist on the box when the firewall step ran.
  The error lists the interfaces that do exist. Connect the VPN, confirm the name with
  `ip -br link` on the box, and run the install again.
</Accordion>

<Accordion title="The install seems to have stopped">
  A first install builds the container image on the box. That is the longest step by far, and
  it can run for many minutes with little output. Let it run. The command gives up on its own
  after 30 minutes.
</Accordion>

<Accordion title="wildcards are not allowed in command arguments">
  The box runs `sudo-rs`, the default `sudo` on Ubuntu 25.10 and later, and the CLI is
  older than 0.41.0. Installation stops at the passwordless-sudo step with
  `visudo: invalid sudoers file` before anything is deployed.

  Upgrade the CLI (`pip install --upgrade lager-cli`) and run the install again. Since 0.41.0
  Lager writes no wildcard rules, and it installs cleanly under `sudo-rs`.

  If you cannot upgrade, switch the box to classic `sudo` instead. Keep a second session open
  with a working root shell, in case the switch does not take:

  ```bash theme={null}
  sudo update-alternatives --set sudo /usr/bin/sudo.ws
  sudo --version
  ```
</Accordion>

<Accordion title="Failed to install Docker">
  Installation prints the manual commands to run on the box. Run them **one at a time** rather
  than as a block, so that you see which one fails. The installer reports this whole sequence
  as a single error:

  ```bash theme={null}
  sudo apt-get update && sudo apt-get install -y docker.io docker-compose-v2
  sudo systemctl daemon-reload
  sudo systemctl enable docker
  sudo systemctl restart docker
  sudo usermod -aG docker <box-user>
  ```

  If `restart` is the step that fails, Docker itself does not start. A second install does
  not help. Ask it why:

  ```bash theme={null}
  systemctl status docker
  journalctl -xeu docker.service
  ```

  Once Docker runs, log out and back in so the group membership takes effect, then run
  `lager install` again. It detects the working Docker and skips this step.
</Accordion>

<Accordion title="The machine is not x86-64">
  x86-64 is the only supported box architecture. Check with `uname -m` on the machine. It must
  report `x86_64`. On any other architecture, an install can appear to succeed while the box has no
  hardware support.
</Accordion>

For problems that appear after the box is up and running, see
[Troubleshooting](/source/getting-started/troubleshooting).

***

## Next Steps

Your box is ready. Now connect to it and give it something to do:

* **[Adding your First Lager Box](/source/getting-started/adding-first-lager-box)** -- Add the box on any other machine that needs to reach it
* **[Setting Up Your Instruments](/source/getting-started/setting-up-instruments)** -- Discover the hardware connected to your box and define nets
