10

I have a Raspberry Pi (RPi) and I am making remote connections to it using ssh. I have managed to set up ssh correctly such that I can access the RPi both from a local area network and from the internet (using a specific port that I opened on my router).

Assuming an user name john and a RPi named raspi:

Inside LAN access

ssh john@192.168.2.7
ssh john@raspi
ssh raspi

Outside LAN access

ssh -p 1234 john@12.345.67.89
ssh -p 1234 12.345.67.89

But how can I simply do ssh raspi from outside my LAN?. Is there a way to configure raspi to point to two IP-adresses, one in a LAN and one over the internet?

What I basically want is to access my RPi in a single way, no matter whether I am at home or work.

  • You could run a DNS server on your local lan which responds to the request for the "raspi" name with the local lan ip address. Now resolving that same name to a different outside address would require that name be populated (dynamic dns) in such a way that it also resolves. But you will probably need a longer name than "raspi". – ChuckCottrill Dec 30 '13 at 23:31
  • See this Q&A: unix.stackexchange.com/questions/61655/… – slm Dec 31 '13 at 2:56
6

Looking closer at your question, it appears you're using the same computer from both in- and outside of the LAN. I have revised my answer accordingly:

In your ~/.ssh/config, add:

Host raspi-wan
    HostName 12.34.56.78
    User john
    Port 1234

Host raspi-lan
    HostName 192.168.1.2
    User john
    Port 22

Then, you can ssh raspi-wan from outside the LAN, or ssh raspi-lan from inside the LAN without faffing about with DNS servers or editing /etc/hosts for all users, or even needing to do anything as root. If you want the name raspi to resolve differently depending upon where you are, that will probably require some shell scripting magic to detect your network and act accordingly.

  • 1
    Thanks DopeGhoti, I am very comfortable with your solution to include a -wan and -lan postfix. My ssh however did not like the Username field (Bad configuration option). It is working fine without it. – Aeronaelius Jan 6 '14 at 13:14
  • 2
    I'm sorry, the correct syntax is User john, not UserName. I am correcting my answer to reflect this, and once you have thusly set your config, you can omit the username from the ssh command line. – DopeGhoti Jan 6 '14 at 16:44
4

This is perfectly doable with just the ssh config, without having to use separate aliases for lan and wan or creating any extra port forwards. (But you naturally need some way to detect whether you're inside your lan or not)

In ~/.ssh/config, you'll want to add something like this:

Match host raspi exec "am_i_outside_of_my_lan"
    HostName 12.345.67.89
    Port 1234

In place of am_i_outside_of_my_lan you'll want to place a command that determines whether you're inside your home network or not, and returns with 0 exit code if you're outside it, and something else otherwise.

The host condition is probably self-explanatory, but the exec condition warrants some explanation: It matches only when the given command returns with exit code 0, ie. no error.

So in other words, what this does is the host raspi part restricts this rule to when you try to connect to the host raspi, and the exec "am_i_outside_my_lan" further restricts it so that it only applies when you're connecting from outside of your home network. So inside your home network ssh user@raspi does exactly what it normally would, but outside of it the rule matches and it instead does the equivalent of ssh -p 1234 user@12.345.67.89.

As for what to use in place of am_i_outside_of_my_lan, that depends entirely on your setup. I do suggest placing the commands in a separate script instead of trying to write it inline, because the quoting seems to be a bit hard to get right.

Personally, I used the following Python script to detect whether I'm inside my own network: (Since my domain name resolves to a local ip inside my own network)

#! /usr/bin/env python
import socket, sys

sys.exit(socket.gethostbyname('mydomain.com').startswith('192.168.1.'))

If you don't have a similar setup, you might have to do something else. (For example, you could look at the name of the wireless network you're connected to, or even query some what-is-my-ip service to get the external ip of the network you're connected to)

  • This is the correct answer; it's very sad that others have more votes. – Jonathan Tomer Mar 19 at 4:39
  • @JonathanTomer: Well, to be fair, I answered this 3 years after it was asked, whereas the higher-scoring answers were posted within hours, so it's just a case of "the early bird gets the worm" :P (I also have to say that I quite like Ellis Hoag's specific variant of this general solution - using arp is quite clever, and makes the solution more generic, as in the network detection command doesn't have to be tuned for every network setup) – Aleksi Torhamo Mar 19 at 13:01
2

On your computer (the connect-ing one), you can set a hostname for 12.345.67.89. Open your /etc/hosts file, and set a DNS entry :

12.345.67.89    raspi

Your machine will then transform "raspi" into "12.345.67.89" as part of a local DNS resolving process. If you use several machines, the change must be made on each and every one of them. Problem is : it requires root access to edit /etc/hosts, and you might not have it everywhere.

If you want "raspi" to be recognised automatically from anywhere, then sorry : not possible. This would require the registration of "raspi" as a domain name, which cannot happen as "raspi" has no TLD, and wouldn't depend of any DNS root server. However, you can register a domain name (let's say cfbaptista.me, and point it to your WAN IP address. With some port forwarding, you will be able to access your Raspberry Pi with :

ssh (you@)(raspi.)cfbaptista.me

(still, that's spending money for almost nothing...)

Concerning the user@ part, it depends on your login name on the different machines. If you have the same name on the connecting machine and on the remote one, then no need to specify. If not, you need to specify who you are on the remote machine.

0

Goal: ssh raspi should work inside the LAN and on the public Internet.

To do this you need to make sure that the name resolves to the internal IP on the LAN, and the public IP from outside.

First, you should obtain a domain name such as raspi.yourdomain.com. Check out http://freedns.afraid.org/ for free domains for hobby use. Point the domain at your public IP

For the LAN, I recommend running DNSMasq. The open DD-WRT firmware tightly integrates with DNSMasq, using it for DHCP and DNS. You just have to tell it your search domain ("yourdomain.com") and it will auto-assign DNS names based on each client's requested name. To make this work, raspi's /etc/hostname should read raspi.

Once this is set up, raspi.yourdomain.com should resolve to the local IP on your LAN (just make sure you're using the local DNS on all your machines).

Now, you probably don't want to expose port 22 to the public internet, because you will get a ton of sniffer traffic. So you may have your router exposing raspi:22 as some other port, say 1234. To use the same port on both public and internal networks, you can add a port redirect rule to raspi. On Linux:

sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 1234 -j REDIRECT --to-port 22
sudo sh -c 'iptables-save > /etc/iptables/iptables.rules'

(change eth0 to the name of your network interface as shown by ip link or ifconfig, and 1234 to your public port)

Now you can ssh -p 1234 raspi.yourdomain.com from both public and LAN.

You can add an entry to ~/.ssh/config on your client machine to shorten this to just ssh raspi, as mentioned by @DopeGhoti.

If you want to expose additional machines' SSH ports on the same public IP, just repeat the process with another DNS name and public port. Cheers!

0

Here's a succinct, working version of Aleksi Torhamo's answer using curl to grab your current public ip and then checking if it matches your server's public ip (i.e., you're on the same local network).

In your ~/.ssh/config add

Match host raspi exec "[[ $(curl -s ipinfo.io/ip) == '12.345.67.89' ]]"
  User john
  HostName 192.168.2.7

Match host raspi exec "[[ $(curl -s ipinfo.io/ip) != '12.345.67.89' ]]"
  User john
  HostName 12.345.67.89
  Port 1234
  • I believe ssh will process all matching directives, in order, so in theory you should be able to do something like Match host raspi / User john / HostName 192.168.2.7 followed by Match host raspi exec "[[ $(curl -s ipinfo.io/ip) != '12.345.67.89' ]]" / HostName 12.345.67.89 / Port 1234 and get the same effect with only one curl invocation, letting the == '12.345.67.89' case be assumed by the failure of the second Match rule's exec. – FeRD Mar 3 '18 at 23:51
  • (You'd jut have to make sure that every argument specified in the first Match is either the same or also specified in the second one — if you specified a non-standard Port xxxx in the first Match, and wanted to use the standard port in the second Match, you'd have to explicitly override it back with a Port 22 so it doesn't continue to use port xxxx.) – FeRD Mar 3 '18 at 23:56
0

Assuming your machine has IP 192.168.1.* when connected to your LAN, you can achieve this with the following configuration in ~/.ssh/config so that you can always use the same command (just ssh raspi) to connect:

Match Originalhost raspi Exec "ifconfig | grep 192\.168\.1\."
    HostName 192.168.1.2
    User john
    Port 22

Host raspi
    HostName 12.34.56.78
    User john
    Port 1234
0

This solution assumes that your home network has a single router which I believe is the common case.

Add to your ~/.ssh/config

Match host raspi exec "test $(arp 192.168.1.1 | awk '{print $4}') = ROUTER_MAC_ADDRESS"
        Hostname 192.168.2.7
        User john

Host raspi
        Hostname 12.345.67.89
        Port 1234
        User john

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.