17

I want to set up an alias in my config file that has the same result as this command:

ssh -N devdb -L 1234:127.0.0.1:1234

My .ssh/config entry for devdb:

Host devdb
User someuser
HostName the_hostname
LocalForward 1234 127.0.0.1:1234

What do I put in the above config to not start a shell?

2
  • +1 for good question which got me thinking about how to make tunneling to random things quicker (i don't do it often enough to remember the switches, but i usually use the same ports, it's only the host that changes).
    – WEBjuju
    Feb 14 '18 at 17:47
  • notaverb.com/setup Feb 14 '18 at 20:43
31

So in ssh.c for OpenSSH 7.6p1 we find

            case 'N':
                    no_shell_flag = 1;
                    options.request_tty = REQUEST_TTY_NO;

so -N does two things:

  • the no_shell_flag only appears in ssh.c and is only enabled for the -W or -N options, otherwise it appears in some logic blocks related to ControlPersist and sanity checking involving background forks. I do not see a way an option could directly set it.
  • according to readconf.c the request_tty corresponds to the RequestTTY option detailed in ssh_config(5).

This leaves (apart from monkey patching OpenSSH and recompiling, or asking for a ssh_config option to toggle no_shell_flag with...) something like:

Host devdb
 User someuser
 HostName the_hostname
 LocalForward 1234 127.0.0.1:1234
 RequestTTY no
 RemoteCommand cat

Which technically does start a shell but that shell should immediately replace itself with the cat program which should then block allowing the port forward to be used meanwhile. cat is portable, but will consume input (if there is any) or could fail (if standard input is closed). Another option would be to run something that just blocks.

3
  • 1
    +1 for doing it within .ssh/config...well done!
    – WEBjuju
    Feb 14 '18 at 17:48
  • Awesome research on this answer! Thank you! Oct 28 '18 at 3:04
  • I prefer RemoteCommand exec sleep infinity.
    – thomas
    Nov 20 '19 at 1:16
3

@thrig has the right answer based on your desire to do this solely within .ssh/config

One might also consider using a function with defaults to make other tunnel commands quick (especially if the tunnel does not change but only the host).


sshn() {
  # set your desired host and port forwarding as default
  # and allow them to be passed in if you should need it

  host="${1:-devdb}"
  port="${2:-1234:127.0.0.1:1234}"

  # now all you have to do is `sshn` and it will connect

  echo "executing ssh -N $host -L $port"
  ssh -N "$host" -L "$port"
}

Here are three examples of it in use: with no args the defaults specified in the function are used:

$ sshn
executing -N devdb -L 1234:127.0.0.1:1234

with tunnel default, run on a different host:

$ sshn host2
executing ssh -N host2 -L 1234:127.0.0.1:1234

with both defaults, run a full one-off to a new host/tunnel:

$ sshn host3 12345:127.0.0.1:12345
executing ssh -N host3 -L 12345:127.0.0.1:12345
0

A more useful remote command based on @thrig's answer:

Host someHost
Hostname 1.2.3.4
LocalForward 15673 localhost:15672
RequestTTY no
RemoteCommand bash -c 'echo "Listening on port 15673"; read -r -d '' _'

The read -r -d '' _ will block the connection until user press control+c.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.