# ProxyJump и bastion-хосты через ~/.ssh/config

Индекс LLMS: [llms.txt](/llms.txt)

---

Иногда сервер живет в приватной сети, без публичного IP. Единственная точка входа — bastion host с белым адресом. Руками набирать `ssh -J user@bastion user@private` каждый раз — лишняя боль. Разберу, как настроить всё через `~/.ssh/config`, чтобы ходить в приватные сети в одно касание.

## Зачем нужен bastion host

Bastion (jump host, jump box) — промежуточный сервер с публичным доступом, через который проксируются соединения к инфраструктуре без внешних адресов. Типичная схема:

```
Лaptop → Bastion (публичный IP) → Private server (10.0.1.5)
```

Bastion не обязан быть «защищенным как Форт-Нокс» — он просто открытый узел. Весь access control держится на ключах и, при необходимости, на security groups / firewall.

> [!NOTE]
> Bastion-хост не терминальная точка — он только проксирует трафик. На нем не нужно поднимать VPN или дополнительные сервисы.

## ProxyJump — современный синтаксис

`-J` (ProxyJump) появился в OpenSSH 7.3. Параметр принимает хост в формате `[user@]host[:port]` и поднимает SOCKS5-прокси через указанный узел.

Базовый вызов:

```bash
ssh -J user@bastion.example.com user@10.0.1.5
```

Аутентификация на обоих хостах по ключам. Если пользователь совпадает, указывать его не обязательно:

```bash
ssh -J bastion.example.com 10.0.1.5
```

С портом, отличным от 22:

```bash
ssh -J bastion.example.com:2222 10.0.1.5
```

Через конфиг то же самое описывается компактно:

```
Host private-server
    HostName 10.0.1.5
    ProxyJump bastion.example.com
```

После этого `ssh private-server` подключается через bastion автоматически.

## ProxyCommand — классический подход

ProxyJump — обертка над `ProxyCommand`. Если нужно больше контроля или работа с более старым OpenSSH, используй `ProxyCommand` напрямую.

```bash
ssh -o ProxyCommand="ssh -W %h:%p bastion.example.com" 10.0.1.5
```

`-W` пробрасывает stdin/stdout на целевой хост. В конфиге:

```
Host private-server
    HostName 10.0.1.5
    ProxyCommand ssh -W %h:%p bastion.example.com
```

Разница с ProxyJump минимальна, но `ProxyCommand` позволяет подставить переменные, условия и цепочки команд.

## Несколько хопов подряд

Цепочка из двух bastion-хостов:

```bash
ssh -J bastion1.example.com,bastion2.example.com 10.0.1.5
```

В конфиге:

```
Host private-server
    HostName 10.0.1.5
    ProxyJump bastion1.example.com,bastion2.example.com
```

OpenSSH соединяет хосты последовательно: laptop → bastion1 → bastion2 → private-server. Проверь, что ключи есть на каждом узле.

Для сложных сценариев `ProxyCommand` с `nc` (netcat) дает больше гибкости:

```
Host dmz-server
    HostName 192.168.1.10
    ProxyCommand ssh -W %h:%p bastion.example.com

Host private-server
    HostName 10.0.1.5
    ProxyCommand ssh -W %h:%p dmz-server
```

Цепочка работает, но каждый хоп добавляет задержку. Для интерактивной работы больше двух хопов — признак проблемы в архитектуре сети.

## Полный пример конфига

```
# Bastion host (публичный вход)
Host bastion
    HostName bastion.example.com
    User admin
    Port 22
    IdentityFile ~/.ssh/id_ed25519
    ForwardAgent yes
    ServerAliveInterval 60
    ServerAliveCountMax 3

# Приватный сервер через bastion
Host private-web
    HostName 10.0.1.5
    User appuser
    ProxyJump bastion
    IdentityFile ~/.ssh/id_ed25519
    ServerAliveInterval 60
    ServerAliveCountMax 3

# Приватная база данных
Host private-db
    HostName 10.0.2.10
    User dbadmin
    ProxyJump bastion
    IdentityFile ~/.ssh/id_ed25519
    LocalForward 5433 127.0.0.1:5432
```

> [!TIP]
> `ForwardAgent yes` на bastion позволяет агенту пробросить ключи дальше. Не включать, если не доверяешь bastion-машине.

`LocalForward` в примере пробрасывает порт PostgreSQL с приватного сервера на локальный `localhost:5433`. Удобно для подключения IDE или psql.

Проверить, что конфиг читается без ошибок:

```bash
ssh -G private-web | grep -E '^(hostname|proxyjump)'
```

Если видишь правильные значения — конфиг подхватился.

## Типичные ошибки и решения

**Connection timeout при ProxyJump**

Проверь, что bastion доступен напрямую:

```bash
ssh bastion.example.com echo ok
```

Если не проходит — проблема в сети, не в конфиге.

**Permission denied (publickey) на bastion**

Убедись, что ключ добавлен в ssh-agent:

```bash
ssh-add ~/.ssh/id_ed25519
ssh-add -l
```

Если агент пустой — добавь ключ и проверь `ssh -vT bastion`.

**Работает в одну сторону, не работает в другую**

ProxyJump туннелирует TCP. ICMP (ping) не пройдет. Проверяй соединение через `nc -zv host port` или `ssh -v`.

**Agent refused operation при пробросе агента**

Проверь переменную `SSH_AUTH_SOCK`:

```bash
echo $SSH_AUTH_SOCK
```

Если пусто — запусти агент:

```bash
eval "$(ssh-agent -s)"
ssh-add
```

**Медленное подключение через цепочку**

Проверь MTU. Иногда MTU в VPN/LAN меньше, чем нужно для TCP-over-TCP. Добавь в конфиг:

```
Host *
    IPQoS lowdelay throughput
```

Для совсем медленных каналов попробуй сжатие:

```
Host *
    Compression yes
```

ProxyJump покрывает 90% случаев. Если нужна визуализация или UI-менеджер — смотри в сторону sssh-config или Terminator, но для консольной работы `~/.ssh/config` с ProxyJump достаточно.
