Closing connection after executing reboot using ssh command
The command reboot -f
never returns (unless you didn't have permission to cause a reboot). At the point where it is issued, the SSH client is waiting for something to do, which could be:
- the SSH server notifying the client that something happened that requires its attention, for example that there is some output to display, or that the remote command has finished;
- some event on the client side, such as a signal to relay;
- a timer firing up to cause the client to send a keepalive message (and close the connection if the server doesn't reply).
Since the SSH server process is dead, the SSH client won't die until the timer fires up.
If you run ssh remotehost 'reboot -f >/dev/null &'
, then what happens is:
- The remote shell launches the
reboot
command in the background. - Because the server-side shell command has exited and there is no process holding the file descriptor for standard output open, the SSH server closes the connection.
- The
reboot
command causes the machine to reboot.
However, this is not reliable: depending on timing, step 3 might happen before step 2. Adding a timer makes this unlikely:
ssh remotehost '{ sleep 1; reboot -f; } >/dev/null &'
To be absolutely sure that the server side is committed to running reboot
, while making sure that it doesn't actually reboot before notifying the client that it is committed, you need an additional notification to go from the server to the client. This can be output through the SSH connection, but it gets complicated.
I found this solution to perform the best for me.
Use -o "ServerAliveInterval 2"
with your ssh
command, like so:
$ ssh -o "ServerAliveInterval 2" root@remotehost reboot
The said option makes the client side poke the server over a secure channel every 2 seconds. Eventually as the rebooting proceeds, it will stop to respond and the client will tear the connection down.
Some answers were close, but the right answer is:
ssh [email protected] "nohup sudo reboot &>/dev/null & exit"
explanation:
- you want to
exit
as the last command so the status of the last command is 0 (success). You can prepend a sleep if you wish, but it is not necessary - you need to run reboot in the background, because otherwise the server will close the connection and you will get an error. It will still reboot on most systems but if you are scripting the return status will be error (not 0) even with the command executing properly
- running on the background is not enough, as the
stdin
andstdout
are still attached to the virtual terminal through SSH, so the connection will not be closed. You need to do two extra things for the SSH session to end and leave the command running on the background.- 1) you need to redirect
stdout
andstderr
to/dev/null
so they are not redirected by the virtual terminal that holds the SSH session. This is the&>/dev/null
part. - 2) you need to redirect
stdin
to an unreadable file in the same fashion. That is what the shell builtinnohup
does.
- 1) you need to redirect
With only a command running on the background dettached from the terminal in every way, exit
will close the session and because there are no stdin
or stdout
left on the virtual terminal SSH will terminate the connection without errors.