Много дней я размышлял над тем, как автоматизировать создание обратного туннеля.
У меня есть много удаленных Raspberry, использующих NAT внутри своих локальных сетей, и один Raspberry, который я использую как сервер, доступный из Интернета.
Я реализовал на своем сайте систему отправки на удаленные устройства Raspberry одиночных команд.
Каждый удаленный Raspberry каждую минуту проверяет (crontab) наличие доступных команд, и если таковая имеется, то загружает команду, создает исполняемый файл и запускает его. Вот код файла crontab:
#! /bin/bash
sudo wget -c --output-document=ipdiscover.php "www.myserver.com/checkforcommands.php";
comando=$(cat ipdiscover.php);
sudo rm "/esegui.sh";
echo "#! /bin/bash" >> /esegui.sh;
echo "" >> /esegui.sh;
echo -e $comando >> /esegui.sh;
echo "exit 0" >> /esegui.sh;
sudo chmod +x /esegui.sh;
sudo /esegui.sh;
sudo rm "ipdiscover.php";
sudo date >>/tmp/crontest.txt;
Эта система работает очень хорошо, но я не могу использовать ее для создания обратного туннеля.
Если на удаленном сервере я запускаю этот код:
sudo /usr/bin/ssh -gNnT -R 2222:localhost:22 pi@publicserverIP;
тогда все работает правильно, но если я запускаю его из скрипта crontab, он не работает.
Я создал сертификаты без пароля и отправил их с удаленного Raspberry на сервер, чтобы сделать доступ без входа в систему.
решение1
Вам не нужно запускать команды cron
через sudo
.
Создайте скрипт, подобный приведенному ниже, и поместите его в домашний каталог пользователя, который установит обратное SSH-подключение к вашему серверу:
#!/bin/sh
### reverseSSHscript.sh ###
### (use public key authentication, so you don't need
### to enter password for your server)
PrivateKeyToAccessCentralServer='/path/to/the/private/ssh/ServerKey.pem'
(
/usr/bin/nohup \
/usr/bin/ssh -gNnT \
-i "${PrivateKeyToAccessCentralServer}" \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=60 \
-o ServerAliveCountMax=1 \
-o TCPKeepAlive=no \
-o UserKnownHostsFile=/dev/null \
-o StrictHostKeyChecking=no \
-o CheckHostIP=no \
-R 2222:localhost:22 pi@publicserverIP
) &
Затем создайте задачу cron для ее запуска:
echo "@reboot User /path2the_script_shown_above/reverseSSHscript.sh" |
sudo tee /etc/cron.d/reverseSSH2home
Тогда это должно сработать.
Кстати, вы можете запустить этот скрипт под некоторыми ограничениями, User
а не как, root
просто чтобы быть в безопасности.
Вам также необходимо реализовать некоторую логику, reverseSSHscript.sh
которая проверяет, установлено ли уже соединение, чтобы предотвратить создание нескольких сеансов.
Периодически запускайте дополнительные проверки из cron, чтобы проверить, активен ли порт обратного подключения на вашем сервере; что-то вроде этого:
chkRemPort() {
# Connect to intermediate host and check if remote forwarded port is alive
echo $(/usr/bin/ssh -4 -f -q \
-o BatchMode=yes \
-o UserKnownHostsFile=/dev/null \
-o StrictHostKeyChecking=no \
-o CheckHostIP=no \
-i /path/to/the/private/ssh/ServerKey.pem \
pi@publicserverIP \
/bin/nc -w 3 -zv localhost 2222 2>&1 | /bin/grep succeeded > /dev/null ; \
[ $? -eq 0 ] && { echo 'OK'; } || { echo 'FAILED'; }; exit; )
}
Если проверка не удалась, попробуйте установить новый обратный сеанс с вашим сервером.
P.S.
Обратные порты на каждом Raspberry Pi должны быть разными, чтобы избежать конфликта между портами на вашем сервере.