Connect to home via ssh

Problem

The problem with a normal home network is that it is hidden behind a NAT. Moreover setting up port forwarding is not exactly trivial for end-user. Therefore, since we have a readily accessible remote server, we can leverage it for our purpose.

Solution

Basically now there are three devices under our control: - homecomputer - mymobile - cloudserver

We can then configure cloudserver as a bridge, as we are in control with it. That way we can, configure a ssh reverse tunnel homecomputer > cloudserver connection, and also another ssh reverse tunnel to mymobile > cloudserver . Then we should also create their corresponding ssh tunnels: homecomputer < cloudserver and mymobile < cloudserver.

SSH tunnel from home and phone to cloud

From homecomputer we can issue:

ssh -R 2222:localhost:22 \
  -L 2223:localhost:2223 \
  user@cloudserver

Here’s how it works:

  • The -R argument tells homecomputer to: expose port 22 on localhost, and any connection from cloudserver port 2222 should be accepted by our exposed port.
  • The -L argument tells homecomputer to: tunnel any connection made to localhost:2223 into port 2223 on cloudserver.

Then we just have to configure the reverse from mymobile:

ssh -R 2223:localhost:8022 \
  -L 8023:localhost:2222 \
  user@cloudserver

SSH tunnel between home and phone with cloud as a bridge

This way, from homecomputer to mymobile, I just have to run:

ssh -p 2223 localhost

And from mymobile to homecomputer, I just have to run:

ssh -p 8023 user@localhost

Even better, we should consider also adding -TNv argument to ssh.

Automatic configuration on home

Like the one we write in SSH proxy as VPN replacement, we can actually configure them as a systemd/user service:

# file ~/.config/systemd/user/remote-tunnel.service
[Unit]
Description=SSH tunnel to domain.tld

[Service]
Type=simple
Restart=always
RestartSec=10
ExecStart=/usr/bin/ssh -F %h/.ssh/config -N remote-tunnel

[Install]
WantedBy=default.target

This service will be run after user logs in to a session. It will be killed after the last session of that user is closed. If we want it to start at boot and would remain be open after the last session of a user is closed, we can let our service to linger:

loginctl enable-linger

Then we write a configuration file as follows:

# file ~/.ssh/config
# Equivalent to:
# ssh \
#   -R 2222:localhost:22 \
#   -L 2223:localhost:2223 \
#   -D 8257 \
#   user@cloudserver
Host remote-tunnel
    User                user
    HostName            domain.tld
    LocalForward        2223 localhost:2223
    RemoteForward       2222 localhost:22
    DynamicForward      8257
    ServerAliveInterval 120

It would then enable us to establish the tunnel (bonus the proxy port) as soon as we login into our account. Then connection to phone is as simple as:

ssh -p 2223 localhost

Automatic configuration on phone

I use termux on my phone. From my phone, we can also set a configuration file:

# ssh -R 2223:localhost:8022 \
#   -L 8023:localhost:2222 \
#   user@domain.tld
Host remote-tunnel
    User                user
    HostName            domain.tld
    LocalForward        8023 localhost:2222
    RemoteForward       2223 localhost:8022
    ServerAliveInterval 120

Therefore we can just do this to initiate connection:

ssh -TNv remote-tunnel

It can be done with the same tmux setup described in the SSH proxy as VPN replacement article. Then to connect to our computer, we invoke:

ssh -p 8023 user@localhost

Conclusion

The pattern is then:

ssh -R port:localhost:hostport \
  -L localport:localhost:remoteport \
  [user@]remotehost

Note that localhost in -L part is actually local to remotehost, not our localhost. Then for [user@]remotehost part, it means that the username is optional. If the username is not given, and only remote host is specified, ssh client will attempt to connect to the remotehost with the same username as the local computer’s username.

The map from homecomputer is then:

localhost:22 listens from cloudserver:2222
localhost:2223 forwarded to cloudserver:2223

The map from mymobile is then:

localhost:8022 listens from cloudserver:2223
localhost:8023 forwarded to cloudserver:2222

The map from cloudserver is then:

localhost:2222 to homecomputer:22
localhost:2223 to mymobile:8022
localhost:2223 from homecomputer:2223
localhost:2222 from mymobile:8023

Appendix

In an afterthought, we realized that we don’t really need to connect to and from our phone with this method most of the time. At home, we would prefer to connect to the phone via our home’s local network, simply because it’s much faster. Conversely, at work, we would prefer to connect to the phone via our work’s local network.

We would only need to connect to our home computer from our phone when we’re outside and our phone is not in the same network as our work computer. Even then when it does happen, our work computer would not be normally connected to our home computer.

It means our phone really only need to connect to home computer when we explicitly told it so. Therefore, our work computer can use a similar ~/.ssh/config as our phone, plus we can set up a systemd/user service.

At such event where we are outside and our work computer are also on, we can always connect to our home computer with extra steps from our phone: go to cloudserver, and then ssh -p 2222 user@localhost will serve the job well.

SSH tunnel between home and office

We put the following in our office’s ssh configuration:

# file ~/.ssh/config

Host remote-tun
    User                user
    HostName            domain.tld
    LocalForward        8022 localhost:2222
    RemoteForward       2223 localhost:22
    DynamicForward      8257
    ServerAliveInterval 120

Host home
    User                user
    HostName            localhost
    Port                8022
    ServerAliveInterval 120

Then we set up a systemd user service at work:

# file ~/.config/systemd/user/tunnel.service
[Unit]
Description=SSH tunnel to domain.tld

[Service]
Type=simple
Restart=always
RestartSec=10
ExecStart=/usr/bin/ssh -F %h/.ssh/config -N remote-tun

Therefore we can connect to our home computer with:

$ ssh home

Further reading

Read more from the sources below: