使用同一终端命令从局域网内部和外部进行SSH访问


10

我有一个Raspberry Pi(RPi),并且正在使用ssh对其进行远程连接。我已经设法正确设置了ssh,以便可以从局域网和Internet(使用在路由器上打开的特定端口)访问RPi。

假设一个用户名john和一个RPi名为raspi

内部局域网访问

ssh john@192.168.2.7
ssh john@raspi
ssh raspi

外部局域网访问

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

但是,我怎样才能简单地ssh raspi从LAN外部进行操作呢?有没有一种方法可以配置raspi使其指向两个IP地址,一个位于LAN中,另一个位于Internet上?

我基本上想要的是无论我是在家还是工作,都可以通过单一方式访问RPi。


您可以在本地局域网上运行DNS服务器,该DNS服务器使用本地局域网ip地址响应对“ raspi”名称的请求。现在,将同一名称解析为其他外部地址将需要以解析方式填充该名称(动态dns)。但是您可能需要比“ raspi”更长的名称。
ChuckCottrill 2013年

Answers:


7

仔细研究您的问题,看来您使用的是局域网内外的同一台计算机。我相应地修改了我的答案:

在中~/.ssh/config,添加:

Host raspi-wan
    HostName 12.34.56.78
    User john
    Port 1234

Host raspi-lan
    HostName 192.168.1.2
    User john
    Port 22

然后,您可以ssh raspi-wan从LAN外部,也可以从LAN ssh raspi-lan内部,而无需使用DNS服务器或/etc/hosts为所有用户进行编辑,甚至不需要以root用户身份进行任何操作。如果您希望名称raspi根据您所在的位置而有所不同,则可能需要使用一些Shell脚本魔术来检测您的网络并采取相应的措施。


1
感谢DopeGhoti,我非常满意您的解决方案,其中包括-wan-lan后缀。但是我的ssh不喜欢该Username字段(错误的配置选项)。没有它就可以正常工作。
Aeronaelius

2
抱歉,正确的语法是User john,不是UserName。我正在纠正我的答案以反映这一点,因此,一旦设置好配置,就可以ssh从命令行省略用户名。
DopeGhoti 2014年

5

仅通过ssh配置,这是完全可行的,而不必为lan和wan使用单独的别名或创建任何额外的端口转发。(但是您自然需要某种方法来检测您是否在局域网内)

在中~/.ssh/config,您需要添加如下内容:

Match host raspi exec "am_i_outside_of_my_lan"
    HostName 12.345.67.89
    Port 1234

代替am_i_outside_of_my_lan您要放置一个命令,该命令确定您是否在家庭网络内,如果不在家庭网络内,则返回0退出代码,否则返回其他代码。

host条件可能是不言自明的,但是该exec条件值得一些解释:它仅在给定命令以退出代码0(即退出)返回时匹配。没错

因此,换句话说,它的作用是host raspi将此规则限制为您尝试连接到主机raspi的方式,并且exec "am_i_outside_my_lan"进一步将其限制为仅在您从家庭网络外部进行连接时才适用。因此,您的家庭网络内部的ssh user@raspi功能与正常情况下完全相同,但在该网络之外,该规则匹配,而等效于ssh -p 1234 user@12.345.67.89

至于用什么代替am_i_outside_of_my_lan,则完全取决于您的设置。我确实建议将命令放在单独的脚本中,而不要尝试直接内联编写,因为引号似乎很难正确理解。

就个人而言,我使用以下Python脚本检测我是否在自己的网络内:(因为我的域名解析为我自己的网络内的本地ip)

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

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

如果没有类似的设置,则可能需要执行其他操作。(例如,您可以查看所连接的无线网络的名称,甚至可以查询某些what-is-my-ip服务来获取所连接的网络的外部ip)


这是正确的答案;很遗憾其他人获得了更多选票。
乔纳森·托默

@JonathanTomer:好吧,公平的是,我被问了三年后就回答了,而得分较高的答案是在几个小时内发布的,所以这只是“早起的鸟儿有蠕虫”的情况:P(我也有可以说我非常喜欢Ellis Hoag的通用解决方案的特定变体-使用arp非常聪明,并且使解决方案更加通用,因为不必在每个网络设置中都对网络检测命令进行调整)
Aleksi Torhamo

3

在您的计算机(连接- ING),你可以设置一个主机名12.345.67.89。打开/etc/hosts文件,并设置DNS条目:

12.345.67.89    raspi

然后,您的计算机会将“ raspi”转换为“ 12.345.67.89”,作为本地DNS解析过程的一部分。如果您使用多台机器,则必须对每台机器进行更改。问题是:它需要root权限才能进行编辑/etc/hosts,而您可能并非到处都有它。

如果您想从任何地方自动识别“ raspi”,对不起:不可能。这将需要将“ raspi”注册为域名,因为“ raspi”没有TLD,并且不依赖于任何DNS根服务器,因此不会发生。但是,您可以注册一个域名(比如说cfbaptista.me,然后将其指向您的WAN IP地址。通过一些端口转发,您将可以通过以下方式访问Raspberry Pi:

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

(依然,那是花钱几乎没有 ...)

关于user@部件,这取决于您在不同计算机上的登录名。如果连接机器远程机器上的名称相同,则无需指定。如果不是,则需要指定您在远程计算机上的身份。


注意:如另一个答案中所述,您可以在SSH配置中创建主机别名,当然不需要root。
13年


0

目标: ssh raspi应该在局域网内和公共Internet上工作。

为此,您需要确保名称解析为LAN上的内部IP,以及外部的公共IP。

首先,您应该获取一个域名,例如raspi.yourdomain.com。请访问http://freedns.afraid.org/获取免费域,以供业余使用。将域指向您的公共IP

对于局域网,我建议运行DNSMasq。开放的DD-WRT固件与DNSMasq紧密集成,可用于DHCP和DNS。您只需要告诉它您的搜索域(“ yourdomain.com”),它将根据每个客户端的请求名称自动分配DNS名称。为了使它起作用,raspi的/ etc / hostname应该读为raspi

设置完成后,raspi.yourdomain.com应该解析为LAN上的本地IP(只需确保您在所有计算机上都使用本地DNS)。

现在,您可能不想将端口22暴露给公共互联网,因为您将获得大量的嗅探器流量。因此,您的路由器可能会将raspi:22暴露为其他端口,例如1234。要在公用网络和内部网络上使用相同的端口,可以向raspi添加端口重定向规则。在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'

(将eth0更改为网络接口的名称,如下所示: ip linkifconfig,将1234更改为公共端口)

现在你可以 ssh -p 1234 raspi.yourdomain.com从公共和局域网中访问。

您可以在客户端计算机上的〜/ .ssh / config中添加一个条目,以将其简化为 ssh raspi,如@DopeGhoti所述。

如果要在同一公共IP上公开其他计算机的SSH端口,只需使用另一个DNS名称和公共端口重复该过程。干杯!


0

这是Aleksi Torhamo答案的简洁有效的版本,使用curl来获取您当前的公共ip,然后检查它是否与服务器的公共ip相匹配(即,您在同一本地网络上)。

在您的~/.ssh/config添加中

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

相信 ssh将按顺序处理所有匹配的指令,因此,从理论上讲,您应该能够执行诸如Match host raspi / User john / HostName 192.168.2.7之后的操作,Match host raspi exec "[[ $(curl -s ipinfo.io/ip) != '12.345.67.89' ]]" / HostName 12.345.67.89 / Port 1234并且仅需一次curl调用即可获得相同的效果,== '12.345.67.89'并假设第二条Match规则的失败导致了这种情况exec
FeRD '18

(你会突出部分必须确保在第一指定的每个参数Match是相同或者在第二个还指定了-如果你指定一个非标准的Port xxxx第一Match,并希望使用标准端口的第二Match,您必须使用a显式覆盖它,Port 22以使其不再继续使用port xxxx。)
FeRD

0

假设您的计算机连接到LAN时具有IP 192.168.1。*,则可以使用以下配置实现此目的,~/.ssh/config以便始终可以使用相同的命令(仅ssh raspi)进行连接:

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

该解决方案假定您的家庭网络只有一个路由器,我认为这是常见的情况。

加到你的 ~/.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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.