I found the article that describes how to access a Linux machine behind a home router with SSH tunnels. https://juliansimioni.com/blog/howto-access-a-linux-machine-behind-a-home-router-with-ssh-tunnels/

How safe is such setup? I'm not an expert, so not sure if there are any pitfalls.

My use case is almost the same as the authors:

  • Ubuntu Desktop that I need to connect to. The desktop is behind a WiFi router. External IP is dynamic.
  • My Linux laptop from which I need to connect.
  • I need to set everything up once due to dynamic IP address.
  • I can get a Linux VM in a cloud with a static IP address.

If I go with that solution, is it possible to use public keys instead of password authentication in such setup?


That proposal opens a reverse-tunneled port from the NAT'd system (the final destination SSH server on your LAN) to the world. It's clunky; if you want that sort of thing, just set up port forwarding from your router.

The "proper" SSH solution would be to accept SSH connections on your public-facing system (router) and use it as a jump host into your network. Then you're as secure as your router's SSH plus your NAT'd system's SSH (the port-forward and reverse-tunnel solutions have zero security for the router and rely solely on the security of your NAT'd system).

After you've set up ssh open to the world on your router (which, by the way, should not allow root to log into, or at least not without a key), you can connect like this:

ssh -J username@my-router me@lan-system

This will connect as username to the router, then immediately forward a connection to the lan system as user me. (Specifying a user is optional, it'll default to your local user name.) This is all performed from your local client's perspective, so if you're using SSH keys (which you requested—and you should), the private keys all live on your local system, not the jump box (the router).

This SSH jump host guide has some good examples, including how to use your ~/.ssh/config to make it automatic (so you'd type ssh lan-system instead).

To set up key-based authentication

On your local client my-laptop, create a key (make an RSA key if ed25519 is unsupported, see that link):

me@my-laptop:/home/me$ ssh-keygen -t ed25519 -a 100

Make sure it has a password on it. We'll get to saving the password with ssh-agent later. This will create ~/.ssh/id_ed25519 (your private key) and ~/.ssh/id_ed25519.pub (your public key) by default, which is fine. You can also use -C "comment about your key" if you want something other than the default username@host.

Now you can copy the public key to the jump box (my-router):

me@my-laptop:/home/me$ ssh username@my-router "mkdir -p .ssh; chmod 700 .ssh; cat >>.ssh/authorized_keys" <~/.ssh/id_ed25519.pub

This should be the last time you'll be prompted for your router user's password.

This runs three commands on the router. First, it ensures you have a ~/.ssh directory. Then, it ensures its permissions are correct (700 is drwx------). Finally, it appends the input to your list of authorized keys. After that, we're piping the public key via standard input (think of this like passing a ball; you hand the ball to ssh and it instructs the remote system to hold onto it in that prescribed location).

You should now be able to log in with the key, but let's set up your SSH agent first.

There's a good chance you're already running an SSH agent, so let's just try it:

me@my-laptop:/home/me$ ssh-add ~/.ssh/id_ed25519
Enter passphrase for /home/me/.ssh/id_ed25519: [your typing will be invisible]
Identity added: /home/me/.ssh/id_ed25519

If that worked, you're good to go. If not, you'll need to launch an agent:

me@my-laptop:/home/me$ ssh-add ~/.ssh/id_ed25519
Could not open a connection to your authentication agent.
me@my-laptop:/home/me$ eval `ssh-agent -s`
Agent pid 1234567
me@my-laptop:/home/me$ ssh-add ~/.ssh/id_ed25519
Enter passphrase for /home/me/.ssh/id_ed25519: [your typing will be invisible]
Identity added: /home/me/.ssh/id_ed25519

You should look into how to do this for your whole desktop environment rather than per-shell, but you could just add eval `ssh-agent -s` to your ~/.bashrc if you're willing to deal with having to run ssh-add in each terminal you open rather than having it managed centrally.

You should now be able to run ssh username@my-router and log in automatically with your agent's unlocked key.

Let's connect to the NAT'd system lan-system now. This should look familiar:

me@my-laptop:/home/me$ ssh -J username@my-router me@lan-system "mkdir -p .ssh; chmod 700 .ssh; cat >>.ssh/authorized_keys" <~/.ssh/id_ed25519.pub

This will automatically jump through my-router and request your me password for lan-system, then it will install your key. After that, you can run ssh -J username@my-router me@lan-system and log in seamlessly with your agent.

Finally, you can shorten this command line by putting this stanza into your ~/.ssh/config file:

Host lan-system
  ProxyJump username@my-router
  UserName me

This will let you run ssh lan-system on its own. The UserName line is unnecessary if you have the same username. The same goes for the username@ part of the ProxyJump line.

| improve this answer | |
  • Thank you, Adam. One thing I didn't get is how to install OpenSSH to a wifi router. It likely has some Linux on it, but I'm not sure. I searched for that but couldn't find anything. Found only recommendations to set up port forwarding on the router side. – PetroCliff Apr 12 at 5:31
  • Port forwarding is fine, as I noted. Otherwise, for an embedded system like a router running a more usable OS like OpenWRT, I recommend Dropbear SSH. – Adam Katz Apr 13 at 1:38

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.