# Servers and SSH

Source: https://laraport.app/docs/servers/

> Add servers over SSH or import them from ~/.ssh/config: keys, host keys, jump hosts, sudo for Docker, and checking every server at once.

## Adding servers

On the home screen:

- `a` adds a server, `e` edits the selected one, `d` deletes it. Deleting names the container settings that go with it.
- `ctrl+t` in the form tests the connection by running `docker version`.
- `i` imports servers from your `~/.ssh/config`.

## Importing from ~/.ssh/config

`i` on the home screen reads `~/.ssh/config` and offers every concrete `Host` as a server, with its `HostName`, `User`, `Port`, the first `IdentityFile` that exists, and `ProxyJump` as the [jump host](#jump-host-bastion). A jump through another `Host` of the file becomes that host's address.

The file is read the way `ssh` reads it: the first value found wins, `Host *` and patterns with `!` apply, `Include` files are read, and `Match` blocks are skipped.

Left out of the list:

- hosts already configured, by the same name, or the same user, host and port;
- aliases of a machine that is already in the list;
- git hosts such as `github.com`, `gitlab.com` and `bitbucket.org`.

Every host in the list starts chosen.

| Key | Action |
|---|---|
| `space` | Choose or unchoose a host |
| `a` | All or none |
| `enter` | Import the chosen hosts |
| `esc` | Close without importing |

A host that does not pass the checks of the server form is reported and skipped. The config is written once, with all the imported servers.

## Server options

| Field | Description |
|---|---|
| `name` | Shown in the server list, unique |
| `type` | `ssh` for a remote server, `local` for this machine's Docker |
| `host`, `port`, `user` | The SSH connection. `port` defaults to 22 |
| `key` | Private key file. Empty: `ssh-agent`, then your default keys |
| `jump_host` | `[user@]host[:port]` of an SSH bastion, like `ssh -J`. User defaults to the server's, port to 22 |
| `jump_key` | Key for the bastion. Empty: the server's `key`, then `ssh-agent` |
| `docker_cmd` | How to run Docker there. Default: `docker` |
| `root_path` | Default Laravel root for this server's containers |
| `read_only` | Refuse everything that would change the server. See [Read-only servers](https://laraport.app/docs/read-only/) |

## Authentication

laraport tries, in this order:

1. The `key` file from the config, with its `passphrase` if one is set.
2. `ssh-agent`, through `SSH_AUTH_SOCK`.
3. The standard key files: `~/.ssh/id_ed25519`, `~/.ssh/id_rsa`, `~/.ssh/id_ecdsa`.

Passphrases cannot be entered in the UI. Load such keys into `ssh-agent` instead.

## Host keys

Host keys are checked against `~/.ssh/known_hosts`, the file OpenSSH uses.

- A server you have never connected to is trusted on first use and its key is recorded (`accept-new`). With `host_key_check: strict` it is refused instead, and the error shows the fingerprint and the `ssh-keyscan` command to add it.
- A server whose key differs from the recorded one is refused with a "host key mismatch" error. That is what a man-in-the-middle attack looks like. If the server was reinstalled, remove the old entry with `ssh-keygen -R <host>`.

## Jump host (bastion)

For servers reachable only through a bastion, set `jump_host`. laraport connects to the bastion, opens a tunnel from it to the server (what `ssh -J` does) and runs the session through it.

- Both host keys are checked, each under its own name.
- If the bastion or the tunnel drops, the chain is re-established on the next action.
- The bastion must allow TCP forwarding (`AllowTcpForwarding yes`, the OpenSSH default).
- The interactive shell uses your system `ssh` with `-J`, so it follows the same route.

## When Docker needs sudo

If the SSH user is not in the `docker` group, set:

```yaml
docker_cmd: "sudo -n docker"
```

This needs passwordless sudo for docker. Every docker call laraport makes on that server goes through it, the shell and logs included. The same field takes `docker --context prod`.

## Dropped connections

A dropped connection (a network change, a laptop going to sleep, a server restart) is noticed through SSH keepalives every 30 seconds, and the next action reconnects. There is no need to go back to the server list.

## Checking every server

`c` on the home screen checks all servers at once. Each is checked on a connection of its own, in parallel, which is closed afterwards. A line under each server then shows its state:

- `✓ 21/26 running` when all is well;
- or what is wrong: `2 down: shop-worker, mailpit`, `1 unhealthy`, the disk and the load, the warnings of the [server panel](https://laraport.app/docs/container-list/#the-server-panel), or why the server could not be reached.

"Down" counts only containers that should run. Left out are stopped containers you hid, old Swarm tasks a newer one replaced, and one-off containers that exited with 0. A Swarm service without a running task counts once.

To check every server each time laraport starts, switch on **Check servers on start** in Settings (`check_servers_on_start: true`).
