Вот решение с использованием OpenSSH >= 6.7 + socat:
OpenSSH >= 6.7 может использовать перенаправление сокетов домена Unix
Это означает, что конечной точкой обратного туннеля будет слушающий сокет UNIX вместо традиционного прослушивающего сокета TCP. Затем вы можете более легко управлять флотилией RPI с помощью простой схемы именования :имя сокета будет выбранным RPI (и фиксированным именем ), например OfficeDevice1991
. Это может быть даже уникальное свойство из RPI, если это действительное имя файла (, поскольку имена сокетов unix соответствуют соглашениям об именах файлов ). Например, его имя хоста, MAC-адрес его карты Ethernet или Wi-Fi...
SSH может обрабатывать сокеты unix для туннелей, а не для подключения к себе. Ему понадобится помощь ProxyCommand
, чтобы иметь возможность работать как клиент сокета unix -. socat может обрабатывать многие виды соединений, включая сокеты unix.
ОБНОВЛЕНИЕ:
Существует также особая проблема для обработки :файла сокета unix, который не удаляется при чистом выходе, и при этом он не был бы удален в любом случае, например, после сбоя. Для этого требуется опция StreamLocalBindUnlink=yes
. Сначала я не обнаружил, что, как следует из названия, этот параметр должен быть установлен на узле, создающем сокет unix. Так что в итоге он устанавливается на клиенте с локальным форвардом(-L
)или же на сервере (вsshd_config
)с удалённым форвардом(-R
). ОП нашел это там . В этом решении используется удаленная переадресация.
Конфигурация на VPS:
mkdir /rpi-access
(от имени пользователя root )отредактируйте файл sshd_config
(/etc/ssh/sshd_config
). Требуется эта дополнительная опция:
StreamLocalBindUnlink yes
В зависимости от параметров по умолчанию может также потребоватьсяAllowStreamLocalForwarding yes
ОБНОВЛЕНИЕ2:
Также установите в sshd_config
параметры ClientAliveInterval
и ClientAliveCountMax
, что позволит обнаруживать отключение в разумные сроки,например:
ClientAliveInterval 300
ClientAliveCountMax 2
Устаревшие соединения ssh должны быть обнаружены раньше на VPS (~10 мин с примером ), после чего соответствующий процесс sshd завершится.
Использование в RPI:
ssh -fN -R /rpi-access/OfficeDevice1991:localhost:22 -i /privatekeyfile useraccount@ip
В файле конфигурации это будет похоже на это:
Host ip
User useraccount
RemoteForward /rpi-access/OfficeDevice1991:localhost:22
IdentityFile /privatekeyfile
Повторяю еще раз :параметр StreamLocalBindUnlink yes
, установленный на sshd
на стороне VPS важен :только что созданный сокет не удаляется даже при обычном выходе. Этот параметр обеспечивает удаление сокета, если он существует до использования, что позволяет повторно использовать его для дальнейших повторных подключений. Это также означает, что нельзя рассматривать простое наличие сокета как означающее, что RPI подключен (, но см. далее ).
Теперь это можно делать на VPS:
ssh -o 'ProxyCommand=socat UNIX:/rpi-access/%h -' rpiuseraccount@OfficeDevice1991
В качестве файла конфигурации, учитывая, например, что имена RPI начинаются с OfficeDevice:
Host OfficeDevice*
User rpiuseraccount
ProxyCommand socat UNIX:/rpi-access/%h -
Чтобы сохранить ссылку, просто используйте цикл
RPI может запускать цикл, переподключающий ssh к VPS всякий раз, когда соединение прекращается. Для этого нельзя использовать фоновый режим (нет-f
). Также следует использовать механизм поддержания активности. TCPKeepAlive (уровень системы )или ServerAliveInterval (уровень приложения ). Я думаю, что TCPKeepAlive полезен только на стороне сервера (, принимающей соединение ), поэтому давайте лучше использовать ServerAliveInterval.
Его значение (, а также ServerAliveCountMax ), вероятно, следует адаптировать в зависимости от различных критериев :брандмауэр, сбрасывающий неактивные соединения через определенное время, желаемая задержка восстановления, не генерирующий бесполезный трафик,... давайте скажем 300 здесь.
OfficeDevice1991 RPI:
#!/bin/sh
while : ; do
ssh -N -o ConnectTimeout=30 -o ServerAliveInterval=300 -R /rpi-access/OfficeDevice1991:localhost:22 -i /privatekeyfile useraccount@ip
sleep 5 # avoid flood/DDoS in case of really unexpected issues
done
Даже если удаленная сторона еще не обнаружила предыдущую ошибку подключения и еще некоторое время работает старое подключение ssh,StreamLocalBindUnlink yes
в любом случае принудительно обновит сокет unix до нового соединения.
это уже обработано 1.
Не нужно customcommandsearch
. При правильных настройках в 1. простое использование ssh OfficeDevice1991
приведет к подключению к OfficeDevice1991.
При необходимости на VPS, только от имени root
пользователя, эта команда:
fuser /rpi-access/*
может показать, какие RPI подключены в настоящее время (, кроме тех, которые недавно потеряли соединение перед обнаружением ). Он не будет отображать устаревшие файлы сокетов unix, потому что к ним не привязан процесс.
Вы можете использовать rsync
с некоторым сценарием, который запускается при создании нового элемента в первом каталоге. что-то вроде rsync --avu delete /dirA /dirB
Это полезно:Как синхронизировать папки Для скрипта вы можете использовать inotify
для отслеживания действий по созданию/удалению в каталоге