Durante muchos días me he preguntado cómo automatizar el establecimiento de un túnel inverso.
Tengo muchas Raspberry remotas que usan NAT dentro de sus LAN y una Raspberry que uso como servidor, accesible desde Internet.
Implementé en mi sitio web un sistema para enviar comandos únicos remotos de Raspberries.
Cada Raspberry remoto comprueba cada minuto (crontab) la presencia de comandos disponibles y, si los hay, descarga el comando, crea un archivo ejecutable y lo ejecuta. Aquí está el código del archivo 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;
Este sistema funciona muy bien, pero no puedo usarlo para establecer el túnel inverso.
Si, en el servidor remoto, ejecuto este código:
sudo /usr/bin/ssh -gNnT -R 2222:localhost:22 pi@publicserverIP;
entonces todo funciona correctamente, pero si lo ejecuto desde el script crontab, no funciona.
Creé los certificados sin contraseña y los envié desde la Raspberry remota al servidor para no poder iniciar sesión.
Respuesta1
No es necesario ejecutar comandos cron
desde sudo
.
Cree un script como este a continuación y colóquelo en el directorio de inicio del usuario que establecerá una conexión SSH inversa a su servidor:
#!/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
) &
Luego crea la tarea de cron para ejecutarla:
echo "@reboot User /path2the_script_shown_above/reverseSSHscript.sh" |
sudo tee /etc/cron.d/reverseSSH2home
Entonces debería funcionar.
Por cierto, es posible que desee ejecutar este script bajo algunas restricciones User
en lugar de hacerlo root
simplemente para estar seguro.
También debe implementar alguna lógica que reverseSSHscript.sh
verifique si la conexión ya está establecida, para evitar la creación de múltiples sesiones.
Ejecute también algunas comprobaciones adicionales desde cron periódicamente para comprobar si el puerto de conexión inversa todavía está activo en su servidor; algo como esto:
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; )
}
Si la verificación falla, intente establecer una nueva sesión inversa en su servidor.
PD:
Los puertos invertidos en cada Raspberry Pi deben ser diferentes para evitar conflictos entre los puertos de su servidor