I am making an automatic remote SSH port forward request from my device every few minutes:
ssh -y -f -N -R port:localhost:22 user@server \
-o ExitOnForwardFailure=yes -o ServerAliveInterval=60 \
-o StrictHostKeyChecking=no
If the port forwarding is successful and I reboot my device and reset internet connection, I am unable to connect to it or make new port forwarding (this is normal and ok as my IP is changed and the port seems to be occupied). I have to wait about 1-2 hours so that the port is free again or I need to kill the process on my server.
I would like to send a script from my device before turning it off that would free the port, so that after reboot new port forward request is successful.
To summarize: How can I remotely cancel port forwarding from the device that requested it, instead of killing the process on the server?
Best Answer
tl;dr
Use these
sshd
options on the server (insshd_config
file):Client-side story
The simple answer is: just terminate the
ssh
on the client. Even if you force-kill it, the server should be notified the connection is terminated (because it's the kernel that does the job).…if the notification ever gets to the server, that is. I guess this is the problem. Networking on your device somehow drops before
ssh
is terminated and there is no way to notify the server this particular SSH connection is no more.Maybe you can redesign your client-side setup to ensure
ssh
terminates before anything is done to the network connection. I don't know the details of your client-side system, so I won't tell you exactly what you can do and how. Loose examples:systemd
units and their dependencies, if applicable; a wrapper overreboot
and/orshutdown
.Server-side story
I assume the SSH server is standard
sshd
. Its default config (sshd_config
) specifiesFrom
man 5 sshd_config
:This mechanism is not specific to SSH. Explanation:
(Source).
This explains why you "have to wait about 1-2 hours so that the port is free again".
Examples of how you can change these values (if you have the permissions):
temporarily
or
permanently by editing the
/etc/sysctl.conf
file, add:then invoke
sudo sysctl -p
to apply the change.But these are system-wide settings. In general any change will affect more than
sshd
. That's why it's better to use SSH-specific solution. Again fromman 5 sshd_config
:If only you can reconfigure
sshd
on the server, this is in my opinion the most elegant way. Let thesshd_config
contain lines like:Notes:
-o ServerAliveInterval=60
you use is a similar option forssh
; it allows the client to detect broken connection. It doesn't affect the server though.autossh
on the client.Back to the client
Let's suppose you cannot reconfigure the server nor the client. I know you said
but in this case killing it may be the best option. As
sshd
forks to serve particular connections, it's enough to kill just the right process without affecting the rest. To initiate killing from the client, you should modify the way you invokessh
. You said:Instead of this, you may run a script similar to the following one, just once (e.g. via
@reboot
in crontab). It tries to kill the saved PID (ofsshd
, on the server) first, then establish a tunnel and save itssshd
PID. If the tunnel cannot be established or gets terminated eventually, the script sleeps a while and loops.Notes: