---
title: Machines and gateways
description: "Set up a gateway, an always-on device that reaches machines inside a network, import machines from a CSV, and manage the workspace inventory."
new_in: "2.2"
---

A **gateway** is an always-on computer inside a network, with Ysra installed
and `ysra serve` running, that reaches the [machines](../machines/overview.md)
there over SSH. Use one when you look after many machines in one network:
your own computer isn’t always on, and reaching each machine from it doesn’t
scale. This page covers setting a gateway up, importing machines, the
inventory and offline behaviour; approvals and refusals are on
[How machines work](../machines/overview.md).

## The rule

A gateway only connects out: no port is opened on it or on anything behind
it. Addresses, users, keys and pinned host keys stay on the gateway; Ysra’s
servers see only labels. A gateway is a [device](../devices/overview.md) that
also reaches machines, so every change still needs a person’s OK, and
destructive steps on production still need the machine’s name typed.

| Ysra’s servers see | Stays on the gateway |
|---|---|
| Each machine’s name, kind, groups, tags, environment, observe or change, production | Addresses, host names, users, ports, keys, pinned host keys |

## Set up a gateway

On a computer in the network that stays on, as the user who will run Ysra:

1. Install Ysra:

    ```bash
    curl -fsSL https://ysra.ai/install.sh | sh -s -- --device
    ```

2. Sign it in. It shows a short code, valid for 10 minutes:

    ```bash
    ysra login --device
    ```

3. In the desktop app, open **Settings → Devices → Approve a device**, type
   the code, check the name, and choose **Approve**.
4. Keep it serving a folder for this network’s procedures and notes. Add
   `--install-service` to keep it running after you log out:

    ```bash
    ysra serve --folder /srv/ops-docs
    ```

Full steps: [Install on a server or edge device](../install/device.md).

## Add many machines at once { #add-many-machines-at-once }

On the gateway, list the machines in a CSV file and import it:

```bash
ysra machines import machines.csv
```

```csv title="machines.csv"
name,host,user,port,kind,groups,tags,environment,mode,production,reads,identity_file
web-01,web-01.example.com,deploy,22,linux,web;frontend,nginx,prod,observe,yes,ask,~/.ssh/id_ed25519
db-01,db-01.example.com,ops,22,linux,data,postgres,prod,observe,yes,ask,
cam-edge-03,cam-03.lab.example.com,ysra,22,jetson,vision,gpu;camera,lab,change,no,allowed,
core-sw-01,core-sw-01.example.com,admin,22,network,network,,prod,observe,yes,ask,
```

| Column | Required | Values |
|---|---|---|
| `name` | Yes | What Ysra and you call the machine |
| `host` | Yes | Its address or host name. Stays on the gateway |
| `user`, `port` | No | The SSH user and port |
| `kind` | No | `linux`, `jetson`, `esxi`, `network`, `oss`, `other` |
| `groups`, `tags` | No | Several values separated by `;` |
| `environment` | No | `prod`, `staging`, `lab`, `dev` |
| `mode` | No | `observe` (default) or `change` |
| `production` | No | `yes` or `no` |
| `reads` | No | `ask` (default) or `allowed`; see [below](#let-an-unattended-gateway-look) |
| `identity_file` | No | The SSH key file to use |

The header row is required. If a line has a mistake, nothing is imported and
Ysra names the lines to fix.

### Confirming the host keys

Ysra fetches every host key, lists each fingerprint, and asks once:
`Pin these 3 host keys and add the machines? [y/N]`.

| Situation | What happens |
|---|---|
| A fingerprint doesn’t match the machine | Answer no. Once pinned, a different computer answering at that address is refused |
| A machine wasn’t reached | Reported and not added. Fix it and import again; machines already added are replaced, not duplicated |
| `--yes` | Confirms without asking. Only when you have already checked the fingerprints |

The machines appear in Ysra within a minute, the next time `ysra serve`
reports in. Their addresses go into Ysra’s own SSH configuration on the
gateway, `~/.ysra/targets/ssh_config`; your `~/.ssh/config` is never touched.

<!-- media: machines-gateway-import | Importing machines on a gateway | On a gateway, run `ysra machines import machines.csv` with 4 rows (one unreachable); the fingerprint table; answer y; then the desktop Machines page shows the 3 machines grouped by groups -->

## Let an unattended gateway look { #let-an-unattended-gateway-look }

Normally the first read on a machine asks for an OK, and nobody sits at a
gateway to give it. Allow reads per machine, on the gateway itself:

```bash
ysra machines reads web-01 allowed
ysra machines reads web-01 ask        # back to asking
```

| With reads allowed | Still true |
|---|---|
| Ysra looks without asking: logs, status, configuration | Changes need a person’s approval, one at a time or with a [signed approval](../machines/approvals.md) |
| Fixed rules still decide what counts as a read | It can only be set on the gateway, never from the app or by Ysra |

## The machine inventory

Each workspace has one list of machines. To pair a gateway with it, open
**Settings → Devices** in the desktop app, find the gateway, and choose **Use
its machines in *workspace***. Then open **Machines** in the sidebar
(++cmd+6++, or ++ctrl+6++ on Windows and Linux); the page is described under
[Machines](../desktop/machines.md).

| Shown | Detail |
|---|---|
| Groups and tags | Organise the list: by site, role, anything in the CSV |
| Kind, observe or change, production | As the gateway holds them; change them on the gateway |
| Last readings | Stay visible when the gateway is offline, marked with when they were taken |

## Asking about machines in a thread

Ask in plain words: *are all the web servers on the same nginx version?*
Ysra checks them read-only and opens a **Machines** panel beside the thread
with each machine it looked at, what ran, and where your documents and the
machine disagree (a procedure saying 1.24 while the machine reports 1.26).
Asking changes nothing; a change goes through the usual
[approval](../machines/overview.md#approvals).

## Where each part is available { #from-the-terminal-the-web-app-and-your-phone }

| Where | What you can do |
|---|---|
| **Desktop app** | The full [Machines panel](../desktop/machines-panel.md); sign, see and withdraw approvals |
| **Terminal**, in a thread on a gateway | Follow runs and investigations, answer the question about adding a fix to a runbook, `/machines`, `/runs`, `/approvals` (see and withdraw) |
| **Web app** | A **Runbooks** page |
| **Phone** | No machines or approvals |

## What happens when …

### The gateway goes offline

A gateway is online while `ysra serve` is connected; it reconnects on its own
after a dropped connection. While it is offline:

| What | What happens |
|---|---|
| A new thread or command for its machines | “*gateway* isn’t connected right now. Run `ysra serve` there.” |
| A scheduled run | Doesn’t start; the thread says so and Ysra tries again at the next time |
| The inventory | Keeps the last readings, marked with when they were taken |

### You log out of the gateway

`ysra serve` stops unless it runs as a service: use `--install-service` and
run `loginctl enable-linger` once. See
[Keep it available after you log out](../install/device.md#5-keep-it-available-after-you-log-out-linux).

## Where addresses end up

!!! warning

    If you upload an IP map or an inventory spreadsheet into your workspace
    files, those addresses are stored in Ysra. Importing the same list with
    `ysra machines import` keeps them on the gateway.

Use the import for anything that says where a machine is; use files for
procedures and notes that refer to machines by name.

## Related

- [How machines work](../machines/overview.md) — approvals, the production flag, and what Ysra refuses.
- [Devices](../devices/overview.md) — what a device is, and what it can and can’t reach.
- [Runbooks](../machines/runbooks.md) — a written procedure on one machine, step by step.
- [The gateway’s machine list](../machines/machine-list.md) — the file the machines are kept in.
