内网穿透配置

内网穿透 (NAT 穿透,NAT Penetration),是指通过流量转发/代理,使得没有公网IP的内网服务器能够被外网访问。为了实现内网穿透,我们需要一台内网服务器和一台公网中转服务器。公网中转服务器是用来做流量转发的。

通过内网穿透,我们还可以绕过跳板机,访问内网服务。

内网穿透的基本原理就是:

  • 首先,内网服务器向公网服务器主动建立一条持续的TCP通路,用于内网和公网服务器之间的数据传输;
  • 然后,外网机器如果需要访问内网服务器,那么可以先连接到公网中转服务器,然后公网服务器通过上一步建立的TCP通路,把请求转发到内网服务器。

常见的内网穿透工具有autossh、ngrok、frp、花生壳等。

1. autossh

autossh 是用来监听、重启 SSH 会话的工具。内网服务器可以通过 autossh 与公网服务器建立一个持续的 SSH 的数据通路。

通过 autossh,我们可以几分钟就搭建好一个 SSH 反向隧道,也是本人使用最多的一种方法。

下面简单介绍一下搭建步骤。

1.1 在内网服务器上安装 autossh

1
2
$ yum install autossh            # Centos, RedHat, Fedora
$ apt-get install autossh # Ubuntu, Debian

1.2 配置免密登录

  • 在内网服务器生成 SSH RSA公、密钥
1
$ ssh-keygen -q -t rsa -N '' -f ~/.ssh/id_rsa
  • 将内网服务器的~/.ssh/id_rsa.pub的内容写入到公网服务器 ~/.ssh/authorized_keys
1
2
3
4
5
6
7
#!/bin/bash
IP='XXX.XXX.XXX.XXX' # 公网服务器IP
PORT='22' # 公网服务器端口
USERNAME='root' # 公网服务器用户名
PASSWORD='XXXXXXXXXXXX' # 公网服务器密码
sshpass -p "${PASSWORD}" "ssh-copy-id -f -i \
~/.ssh/id_rsa.pub -p ${PORT} ${USERNAME}@${SERVER}"
  • 检查内网服务器是否可以免密登录到公网服务器

1.3 在公网服务器上启动 sshd

1
2
$ service ssh restart
$ service ssh status # 检查 sshd 状态

1.4 在内网服务器启动 autossh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
PUBLIC_IP='XXX.XXX.XXX.XXX' # 公网服务器IP
PUBLIC_SSH_PORT='22' # 公网服务器 sshd 进程端口
PUBLIC_USERNAME='root' # 公网服务器用户名
PUBLIC_PROXY_PORT='2022' # 公网服务器代理端口

PORT_MONITOR='5680' # 监听SSH反向隧道的端口

autossh -M ${PORT_MONITOR} -fN \
-o "PubkeyAuthentication=yes" \
-o "StrictHostKeyChecking=false" \
-o "PasswordAuthentication=no" \
-o "ServerAliveInterval 60" \
-o "ServerAliveCountMax 3" \
-R ${PUBLIC_PROXY_PORT}:localhost:22 \
${PUBLIC_USERNAME}@${PUBLIC_IP} -p ${PUBLIC_SSH_PORT}

然后,可以在公网服务器上检查一下SSH方向隧道是否成功建立。

1
$ netstat -panlt | grep ${PUBLIC_PROXY_PORT}

1.5 外网机器登录到内网服务器

1
2
3
4
5
6
7
PUBLIC_IP='XXX.XXX.XXX.XXX'      # 公网服务器IP
PUBLIC_PROXY_PORT='2022' # 公网服务器代理端口
INTRA_USERNAME='root' # 内网服务器用户名
INTRA_PASSWORD='XXXXXX' # 内网服务器密码

ssh ${PUBLIC_IP} -l ${INTRA_USERNAME} -p ${PUBLIC_PROXY_PORT}
# 然后输入内网服务器密码即可登录

把外网机器的 ~/.ssh/id_rsa.pub 添加到内网服务器的 ~/.ssh/authorized_keys中,可以实现外网机器到内网服务器的免密登录。

autossh 有时候会出现莫名的中断,很难受,不知道是为啥?可能是ssh/sshd_condig的配置问题吧。最好是配一个tmux吧,不然程序跑一半就中断了,会奔溃的!

2. Ngrok

Ngrok 官网:https://ngrok.com/

Ngrok Github主页:https://github.com/inconshreveable/ngrok

Ngrok 2.x 的版本都不开源了,Ngrok 官网注册,就可以免费使用。而且不需要自己的公网服务器(Ngrok官方免费了提供公网服务器)就可以实现内网穿透,但是只对免费用户开放一个反向隧道。去官网注册一下就可以使用了。

但是,我感觉免费的 Ngrok 2.x 有点卡啊,所以我一般就用来临时代理一下 HTTP 服务。

当然,Github 上有 1.7.1 版本的 Ngrok,我们也可以在自己的公网服务器上搭建一个 Ngrok 服务器,但是,过程相对于 autossh 会稍微麻烦一些。

但是相比autossh,Ngrok 应该是功能更完善的内网穿透工具了,它可以反向代理 HTTP,TCP 端口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
(base) [xingw@localhost ~]$ ./ngrok --help
NAME:
ngrok - tunnel local ports to public URLs and inspect traffic

DESCRIPTION:
ngrok exposes local networked services behinds NATs and firewalls to the
public internet over a secure tunnel. Share local websites, build/test
webhook consumers and self-host personal services.
Detailed help for each command is available with 'ngrok help '.
Open http://localhost:4040 for ngrok's web interface to inspect traffic.

EXAMPLES:
ngrok http 80 # secure public URL for port 80 web server
ngrok http -subdomain=baz 8080 # port 8080 available at baz.ngrok.io
ngrok http foo.dev:80 # tunnel to host:port instead of localhost
ngrok http https://localhost # expose a local https server
ngrok tcp 22 # tunnel arbitrary TCP traffic to port 22
ngrok tls -hostname=foo.com 443 # TLS traffic for foo.com to port 443
ngrok start foo bar baz # start tunnels from the configuration file

VERSION:
2.3.27

AUTHOR:
inconshreveable -

COMMANDS:
authtoken save authtoken to configuration file
credits prints author and licensing information
http start an HTTP tunnel
start start tunnels by name from the configuration file
tcp start a TCP tunnel
tls start a TLS tunnel
update update ngrok to the latest version
version print the version string
help Shows a list of commands or help for one command

3. ssh 远程转发

通过 ssh 远程转发,可以通过公网服务器,将内网的服务转发出去。

比如:在内网服务器执行下面的命令,就可以通过公网服务器的PUBLIC_PORT 访问到内网服务器的的 LOCAL_PORT 服务了。

1
$ ssh -fN -R <PUBLIC_PORT>:localhost:<LOCAL_PORT> <PUBLIC_IP>

其他的穿透工具,我就没有使用过了。

坚持原创技术分享,您的支持将鼓励我继续创作!