# Layover

[![crates.io](https://img.shields.io/crates/v/layover.svg)](https://crates.io/crates/layover)
[![CI](https://github.com/Lukas-Dresel/ssh-layover/actions/workflows/ci.yml/badge.svg)](https://github.com/Lukas-Dresel/ssh-layover/actions/workflows/ci.yml)
[![license: MIT](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE)

**SSH through firewalls.** Layover relays your SSH connections over TLS port 443, so they look like normal HTTPS to restrictive networks.

> **[layover.sh](https://layover.sh)** — free public relay, ready to use.

```
You (airport wifi) ──TLS:443──▶ layover.sh ──TCP:22──▶ Your Server
```

## Install

```bash
cargo install layover
```

Or download a prebuilt binary from [Releases](https://github.com/Lukas-Dresel/ssh-layover/releases).

## Usage

```bash
ssh -o ProxyCommand="layover connect %h:%p" user@myserver.com
```

That's it — your SSH connection is tunneled through [layover.sh](https://layover.sh) over TLS on port 443.

### Permanent SSH config

Instead of typing `-o ProxyCommand=...` every time:

```bash
# Route specific hosts through Layover
layover setup --host myserver.com --host "*.work.com" --install

# Or route everything
layover setup --install
```

This writes to `~/.ssh/config`. Re-running `--install` replaces the previous Layover block, so it's safe to run multiple times. Preview first by omitting `--install`:

```bash
$ layover setup --host myserver.com
Host myserver.com
    ProxyCommand layover connect %h:%p --server layover.sh
```

## Self-hosting

You can run your own relay instead of using [layover.sh](https://layover.sh). You need a server with a public IP on port 443, a domain, and a TLS certificate.

```bash
# Get a cert
sudo certbot certonly --standalone -d relay.example.com

# Run the relay
layover serve \
  --cert /etc/letsencrypt/live/relay.example.com/fullchain.pem \
  --key /etc/letsencrypt/live/relay.example.com/privkey.pem
```

Then point clients at it:

```bash
# One-off
ssh -o ProxyCommand="layover connect %h:%p --server relay.example.com" user@myserver.com

# Environment variable
export LAYOVER_SERVER=relay.example.com

# Or persist in SSH config
layover setup --server relay.example.com --install
```

### Verbose mode

Use `-v` to log connection lifecycle details — useful for debugging or monitoring:

```bash
layover serve --cert cert.pem --key key.pem -v
```

```
layover: [#1 203.0.113.5:49152] accepted
layover: [#1 203.0.113.5:49152] TLS handshake complete
layover: [#1 203.0.113.5:49152] -> myserver.com:22
layover: [#1 203.0.113.5:49152] resolved myserver.com:22 -> 93.184.216.34:22
layover: [#1 203.0.113.5:49152] connected 10.0.0.1:54321 -> 93.184.216.34:22
layover: [#1 203.0.113.5:49152] closed (1234B up, 5678B down, 42.3s)
```

Connection IDs (`#1`, `#2`, ...) link all log lines for a single relay session.

### Development mode

For local testing without TLS:

```bash
# Server
layover serve --no-tls --listen 127.0.0.1:4443

# Client
ssh -o ProxyCommand="layover connect %h:%p --server 127.0.0.1:4443 --no-tls" user@myserver.com
```

## How it works

1. SSH invokes `layover connect` as a ProxyCommand
2. Client opens a TLS connection to the relay on port 443
3. Client sends the destination (`host:port`)
4. Relay authenticates via challenge-response, connects to the destination
5. Bytes flow bidirectionally: SSH <-> client <-> relay <-> destination
6. To the network, it all looks like HTTPS traffic

## CLI reference

### `layover connect <destination>`

ProxyCommand mode — bridges stdin/stdout through the relay to the destination.

| Flag | Default | Description |
|---|---|---|
| `--server` | `layover.sh` | Relay server address (also `LAYOVER_SERVER` env) |
| `--no-tls` | off | Disable TLS (dev only) |

### `layover serve`

Run a relay server.

| Flag | Default | Description |
|---|---|---|
| `--listen` | `0.0.0.0:443` | Bind address |
| `--cert` | required | TLS certificate (PEM) |
| `--key` | required | TLS private key (PEM) |
| `-v`, `--verbose` | off | Log connection details |
| `--no-tls` | off | Disable TLS (dev only) |

### `layover setup`

Generate or install SSH config.

| Flag | Default | Description |
|---|---|---|
| `--server` | `layover.sh` | Relay server address |
| `--host` | `*` | Host pattern(s) to route (repeatable) |
| `--install` | off | Write to `~/.ssh/config` |
| `--no-tls` | off | Include `--no-tls` in ProxyCommand |

When using `Host *` (the default), an exclusion entry for the relay server is automatically added to prevent routing loops.

## Building from source

```bash
git clone https://github.com/Lukas-Dresel/ssh-layover.git
cd ssh-layover
cargo build --release
```

## License

[MIT](LICENSE)
