Заворачиваем ssh-тунели в systemd-сервис

Часто возникает необходимость держать постоянное SSH-соединение через туннель. Чтобы не возиться с его ручным восстановлением после перезагрузки системы, проще всего настроить туннель как systemd-сервис и использовать SSH-ключи вместо паролей.

Хорошая идея — оформить такой сервис в виде шаблона, который будет подтягивать параметры туннеля из конфигурационного файла. Это сильно упрощает жизнь: можно быстро добавлять, удалять, изменять туннели, запускать и останавливать их.

Для этого понадобится заранее настроенная работа через SSH-ключи — иначе всё работать не будет.

Создаём шаблон systemd-сервиса

Путь до файла:

/etc/systemd/system/secure-tunnel@.service

Содержимое:

[Unit]
Description=Setup a secure tunnel to %I
After=network.target
[Service]
Environment="LOCAL_ADDR=localhost"
EnvironmentFile=/etc/default/secure-tunnel@%i
ExecStart=/usr/bin/ssh -NT -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -L ${LOCAL_ADDR}:${LOCAL_PORT}:${REMOTE_HOST}:${REMOTE_PORT} ${TUSER}@${TARGET}
# Restart every >2 seconds to avoid StartLimitInterval failure
RestartSec=5
Restart=always
[Install]
WantedBy=multi-user.target

Что означают переменные в этом файле

  • ${LOCAL_ADDR} — локальный IP, на который будет привязан туннель
  • ${LOCAL_PORT} — порт на локальном интерфейсе
  • ${REMOTE_HOST} — удалённый хост, до которого прокидываем соединение
  • ${REMOTE_PORT} — порт на удалённой стороне
  • ${TARGET} — SSH-шлюз, через который строится туннель
  • ${TUSER} — имя пользователя для подключения к SSH-шлюзу

Создаём конфигурационный файл для туннеля

Путь до файла:

/etc/default/secure-tunnel@example_tunnel1

Этот файл содержит параметры конкретного туннеля. Пример содержимого:

TARGET=gateway1
TUSER=root
LOCAL_ADDR=127.0.0.1
LOCAL_PORT=49998
REMOTE_PORT=443
REMOTE_HOST=10.1.1.1

Здесь те же переменные, что и в шаблоне:

  • LOCAL_ADDR — IP-адрес на локальной машине
  • LOCAL_PORT — локальный порт, на который привязываем туннель
  • REMOTE_HOST — хост на удалённой стороне
  • REMOTE_PORT — порт на удалённой стороне
  • TARGET — SSH-шлюз
  • TUSER — пользователь для подключения к TARGET

Как видно, параметры из шаблона и из конфигурационного файла полностью совпадают — один в один.

Дальше работаем с ним как и с любым другим systemd-сервисом.

Единственное на что еще может стоит обратить внимание: если при каждом просмотре systemctl status вы видите, что сервис работает всего несколько секунд — скорее всего, проблема с подключением или в настройках туннеля.