Set up ssh tunnel, the procd way

I wanted to set up a basic automatic tunnel to be able to ssh into my router behind NAT. The sshtunnel package, that seems to be current state of the art in ssh tunnels, was not a good fit for my 4 Mb router as it pulls the openssh client for some reason. So, I figured, I’ll do everything myself, given that dropbear seems to support setting up tunnels without a problem.

Here is what I ended up with:

#!/bin/sh /etc/rc.common



start_service() {
  [ $(ubus call network.interface.wan status | jsonfilter -e "@.up") = "true" ]

  if [ $wan_up -eq 0 ]; then
    procd_set_param command ssh -i "$identity_file" -T -N -y -K 60 -R "$port:localhost:22" -o ExitOnForwardFailure "$remote_user@$remote_host"
    logger -p -t 'sshtun' 'wan is up, starting'
    procd_set_param command tail -f /dev/null
    logger -p -t 'sshtun' 'wan is down, waiting'
  procd_set_param respawn 3600 5 -1

service_triggers() {
  procd_add_reload_interface_trigger wan

Now, I am not particularly fond of the `tail /dev/null` hack. It would be better if I could somehow tell procd to start my service when wan goes up and stop when it goes down, but I don’t know how to do this. Another thing is that there seem to be some issues when internet connectivity disappears without bringing wan down (the uplink is not very reliable as it is 3G via an rndis modem); sometimes the tunnel will disappear for an hour or so, even though the internet is accessible from the connected devices, and I am not sure what exactly is going on and how to debug this, since the router is already far away.

Therefore, I am looking for suggestions, actually any kind of ideas, how to make this service better and more robust. Any input is very welcome.


I'm using this init script for ssh remote tunnel:

#!/bin/sh /etc/rc.common


ssh_cmd="ssh -i ${ssh_keyfile} -K 60 -y -N -R ${ssh_localport}:${ssh_localip}:22 ${ssh_remoteuser}@${ssh_remotesrv} -p ${ssh_remoteport}"

    rc_procd start_service

    if [ $("${ssh_init}" enabled; printf "%u" ${?}) -eq 0 ]
        if [ -n "${ssh_boot}" ]
            return 0
        procd_open_instance "ssh-tunnel"
        procd_set_param command ${ssh_cmd}
        procd_set_param respawn ${respawn_retry:-10} ${respawn_threshold:-10} ${respawn_timeout:-10}
        procd_set_param stdout 1
        procd_set_param stderr 1

    procd_add_interface_trigger "interface.*" "${ssh_iface}" "${ssh_init}" restart

On boot the script only implements the service trigger to restart the service whenever the wan interface gets up or down ... hope this helps.

1 Like

Thanks. This script has helped me a lot. Much appreciated.

Hey everyone, I was thinking about packaging this script as a proper package, but I recently learned about WireGuard, which is a much better way to achieve the same.

Actually, before going with ssh I tried using OpenVPN, but it is too large and clumsy. Well, WireGuard is not, it is just perfect for this use case.

I'm glad you've got enthusiasm for wireguard, but no need to drop a link for it on every post you make. Even more inappropriate on long-dead threads.

Bottom line is that it is an interesting VPN project, but that doesn't replace ssh for tunnels or many other purposes (such as remote command execution).

It is also pretty much Linux only in scope and, as the front page of the wireguard site very clearly states

You should not rely on this code. It has not undergone proper degrees of security auditing and the protocol is still subject to change.

Jeff, I’m sorry, but I kinda feel that as the author of ssh-tun I get to post anything I want in threads devoted to it and threads that link to it. For example because I am not going to update ssh-tun any longer and feel like I should offer some alternative to those who come here looking for a tunnelling solution.

doesn’t replace ssh for tunnels or many other purposes (such as remote command execution)

With all due respect, I would like to point out that tunnels and command execution are different things. I’m not sure if you noticed, but this threads (and the other one) is about tunnelling, not remote code execution and WireGuard is indeed a proper solution for persistent tunnels, while ssh-tun or anything like that was a convenient hack all along.

It is also pretty much Linux only in scope

I’m not sure if you know that, but OpenWrt is Linux-only as well.

the front page of the wireguard site very clearly states

The disclaimer you cite is pretty much there only because, in reality, it has to be on any piece of software that relied on cryptography. If you look around a little you’ll see that there is a consensus that WireGuard is pretty solid. I think what is misleading for you is the fact that there is no such disclaimer on the website of openssl (on which, e.g. openssh relies), while there have to be 10 of them there, if they were honest.

I really just like to get sshuttle working openwrt if that's remotely possible.