Skip to content

Instantly share code, notes, and snippets.

@x-yuri
Last active November 21, 2020 12:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save x-yuri/b46ff418555db7263eaec415c4a036c9 to your computer and use it in GitHub Desktop.
Save x-yuri/b46ff418555db7263eaec415c4a036c9 to your computer and use it in GitHub Desktop.
What happens when you get disconnected from a server?

What happens when you get disconnected from a server?

There are basically two modes in which ssh can operate: 1) interactive, 2) non-interactive. These are not official terms. I'm using them here in place of otherwise wordy names like, "an ssh session with an allocated pseudo terminal." To run a command in non-interactive mode you do:

$ ssh host echo test

Interactive mode is entered when you either do:

$ ssh host -t echo test

Or:

$ ssh host

In non-interactive mode sshd forks the requested process (echo test in this case), and interacts with it via a pipe. In interactive mode, it does so via a pseudo terminal (that's what -t is there for). In interactive mode you interact with a remote process. That is, when you press Ctrl-C it's transmitted to the remote machine, and is passed to the program that is running remotely. In non-interactive mode Ctrl-C would kill your ssh client. In interactive mode some key sequences are treated specially, like ~. to close the connection. Particularly, when you do ssh host -t some command. Also, do note that interactive mode has some side effects, like converting \n to \r\n, or combining stdout and stderr.

In non-interactive mode, when you disconnect, the command remains running, e.g.:

$ ssh host sleep 100

But if it tries to write to stdout or stderr it would receive SIGPIPE, and die. You can confirm it this way:

$ ssh host 'for i in {1..100}; do echo $i; sleep 1; done'

Attach strace to the corresponding bash process in another console (strace -p PID). Then Ctrl-C the ssh command, and you'll see the following in the console with strace:

+++ killed by SIGPIPE +++

SIGPIPE is sent to processes that try to write to a pipe with no readers. Otherwise commands like yes | head would never terminate.

Let's inspect more closely what happens when you disconnect. Does the remote process die or not?

$ ssh host sleep 100
// disconnect

The sleep process remains.

$ ssh host -t sleep 100
// disconnect

The sleep process receives SIGHUP and dies.

$ ssh host 'sleep 100 &'
// disconnect

The sleep process remains.

$ ssh host -t 'sleep 100 &'

In this case ssh doesn't wait for sleep to finish, and disconnects. The sleep process is supposedly killed by SIGHUP.

$ ssh host -t 'sleep 100 & wait'
// disconnect

In this case sshd forks a bash process that executes the command above. When you disconnect, the bash process receives SIGHUP, which in its turn sends SIGHUP to its children.

$ ssh host
# sleep 100 &
# exit  // or Ctrl-D

The sleep process remains. Because when you exit normally, by default bash doesn't sends SIGHUP to background jobs.

$ ssh host
# shopt -s huponexit  // set huponexit option
# sleep 100 &
# exit  // or Ctrl-D

The sleep process receives SIGHUP.

$ ssh host
# sleep 100 &
// disconnect

The bash and sleep processes receive SIGHUP.

To sum it up, SIGHUP is sent to interactive sessions when you get disconnected. What happens when you exit normally depends on huponexit setting.

On a side note, what happens when you deploy using mina, you might ask. mina turns your deploy.rb into a shell script and executes ssh host -tt -- script. You can confirm it by running bundle exec mina deploy -s. At the beginning you'll see:

# Executing the following via 'ssh user@host -p port -tt':

So, in case you want to run a server of sorts, you've got to use nohup, or disown, or some such.

Further reading:

The TTY demystified
Using pseudo-terminals (pty) to control interactive programs
How to terminate remotely called “tail -f” when connection is closed?
What happens to a continuing operation if we do ssh and then disconnect?
Why doesn't SSH -t wait for background processes?
If I launch a background process and then log out, will it continue to run?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment