一、场景如下:

  各个角色的对应关系如下:

角色 描述
APP 个人笔记本,属于内网IP
sshd server 公网 VPS ( 映射端口: port 2222 ),拥有公网IP
ssh client 内网机器,属于另一个内网IP
APPSRV

与 内网 ssh client 是同一台机器 ( 目的端口: hostport 22 )

  两个帐号:admin/password为“内网机器”ssh的登录帐号密码,VPS-user/password为“公网VPS”ssh的登录帐号密码

  网络连通情况:“内网机器”可以访问公网VPS,“个人笔记本”可以访问“公网VPS”,但是不可以访问“内网机器”;“公网VPS”不能访问“内网机器”,也不能访问“个人笔记本”

二、目标:实现私网的笔记本访问另一个私网的“内网机器”

三、思路:建立反向代理,把访问公网VPS某个端口的流量映射到“内网机器”的某个端口;然后建立正向代理,把“个人笔记本”对“内网机器”的访问流量、访问请求,通过代理发给“VPS”的那个映射端口

四、步骤:

  1、反向代理:“公网VPS”===>"内网机器",通过内网机器反向连接VPS

  在内网机器上配置:(ssh clinet) # ssh -CfnNT -R 2222:localhost:22 VPS-user@VPS

           (ssh clinet) # ssh -p 22 -qngfNTR 6666:localhost:22 VPS-user@VPS

  这样就把“内网机器”的22端口转发到了远程机器(VPS)的6666端口上

  查看内网机器的进程

  [ssh clinet ~]# ps aux | grep "ssh -p"
  root     14594  0.0  0.0  59856  1056 ?        Ss   11:16   0:00 ssh -p 22 -qngfNTR 6666:localhost:22 VPS-user@VPS

  查看公网VPS的端口情况,注意端口6666,只有本地环回地址可以访问

  [sshd server ~]# netstat -anpt | grep 6666
  tcp        0      0 127.0.0.1:6666              0.0.0.0:*                   LISTEN      10703/sshd

  这时候,在公网VPS上就可以通过ssh连接内网机器,打通了“公网VPS”到“内网机器”的访问通道

  [sshd server ~]# ssh -p 6666 admin@localhost
  admin@localhost's password:

  输入“内网机器”ssh帐号的密码“password”,就可以在公网VPS上实现到内网机器的ssh连接

  2、正向代理:“个人笔记本”===>“公网VPS”

  在“个人笔记本”上配置:[App ~] # ssh -p 6666 -qngfNTD 6767 VPS-user@VPS,这样,访问“个人笔记本”本机(127.0.0.1)端口6767的流量就流向了“内网机器”

  但是目前,上面配置是不生效的,因为“公网VPS”的端口6666,只允许它自己访问。解决办法有两个:

  a、思路:修改“公网VPS”的配置sshd_config,使其建立的SSH端口供所有IP访问

     方法:把“公网VPS”配置文件/etc/ssh/sshd_config里的配置“GatewayPorts no”修改为“GatewayPorts yes”,重新执行步骤1,执行完查看“公网VPS”的6666端口如下

    [sshd server ~]# netstat -anpt | grep 6666
    tcp        0      0 0.0.0.0:6666              0.0.0.0:*                   LISTEN      10703/sshd

  b、思路:不修改“公网VPS”的配置sshd_config,仍然采用默认配置“GatewayPorts no”,在“公网VPS”上增加一个本地端口映射,使新增加的端口供所有IP访问,或者供特定的IP访问

     方法:在“公网VPS”上配置:[sshd server~] # ssh -fCNL *:6667:localhost:6666 localhost,这一步执行需要“公网VPS”的root帐号密码

     查看“公网VPS”的进程和端口情况:

   [sshd server ~]# netstat -anpt | grep 6667
     tcp        0      0 0.0.0.0:6667              0.0.0.0:*                   LISTEN      1073/sshd

     [ssh server ~]# ps aux | grep "ssh -p"
     root     14594  0.0  0.0  59856  1056 ?        Ss   11:16   0:00  ssh -fCNL *:6667:localhost:6666 localhost

    然后重复执行步骤2,不过端口由6666修改为6667

    [App ~] # ssh -p 6667 -qngfNTD 6767 VPS-user@VPS,这样,访问“个人笔记本”本机(127.0.0.1)端口6767的流量就流向了“内网机器”

这个时候在“内网机器”上开启80端口的服务[ssh clinet~]# python -m SimpleHTTPServer 80

在“个人笔记本”上配置浏览器代理,要选用“socks5”

然后访问

   

五、保持连接的网络稳定

方法一、客服端发“心跳”,配置ssh_config

使用SSH客户端的ServerAliveInterval和ServerAliveCountMax选项。 ServerAliveInterval会在隧道无通信后的一段设置好的时间后发送一个请求给服务器要求服务器响应。如果服务器在 ServerAliveCountMax次请求后都没能响应,那么SSH客户端就自动断开连接并退出,将控制权交给你的监控程序。这两个选项的设置方法分别是在ssh时加入-o ServerAliveInterval=n和-o ServerAliveCountMax=m。其中n, m可以自行定义

方法二、服务端发“心跳”:配置sshd_config

ClientAliveInterval 60 服务器端向客户端请求消息的时间间隔为60秒

ClientAliveCountMax 3 表示服务器发出请求后客户端没有响应的次数达到3次, 就自动断开

这样的配置就能让一个SSH的配置保持长连接了

六、ssh配置含义:

-f 后台运行,后台认证用户/密码,通常和-N连用,不用登录到远程主机,将ssh转到后台运行,即认证之后,ssh 自动以后台运行。不再输出信息 告诉SSH客户端在后台运行

-C 允许压缩数据

-R 将端口绑定到远程服务器,反向代理,将远程主机(服务器)的某个端口转发到本地端指定机器的指定端口。工作原理是这样的, 远程主机上分配了一个socket侦听port端口, 一旦这个端口上有了连接, 该连接就经过安全通道转发出去,同本地主机host的hostport端口建立连接。可以在配置文件中指定端口的转发。

-L 将端口绑定到本地客户端,正向代理,将本地机(客户机)的某个端口转发到远端指定机器的指定端口。工作原理是这样的, 本地机器上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连接, 该连接就经过安全通道转发出去, 同远程主机host的hostport端口建立连接。可以在配置文件中指定端口的转发。

-L X:Y:Z的含义是,将IP为Y的机器的Z端口通过中间服务器映射到本地机器的X端口。

-D port指定一个本地机器 “动态的’’应用程序端口转发,工作原理是这样的, 本地机器上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连接, 该连接就经过安全通道转发出去, 根据应用程序的协议可以判断出远程主机将和哪里连接。

-n 将 stdio 重定向到 /dev/null,与 -f 配合使用

-N 不执行脚本或命令,即通知 sshd 不运行设定的 shell 通常与 -f 连用,告诉SSH客户端,这个连接不需要执行任何命令。仅仅做端口转发

-T 不分配 TTY 只做代理用

-q 安静模式,不输出错误/警告信息

-g  在-L/-R/-D参数中,允许远程主机连接到建立的转发的端口,如果不加这个参数,只允许本地主机建立连接

通过远程主机1跳到远程主机2:

命令格式:

ssh -t remoteserver1 ssh remoteserver2

说明:当远程主机remoteserver2无法直接到达时,可以使用-t参数,然后由remoteserver1跳转到remoteserver2。在此过程中要先输入remoteserver1的密码,然后再输入remoteserver2的密码,然后就可以操作remoteserver2了。

man sshd_config

man 5 shells

图示,正向代理:ssh -L

图示,反向代理:ssh -R

参考:

1、http://lvii.github.io/system/2013/10/08/ssh-remote-port-forwarding/

2、http://bobao.360.cn/learning/detail/4234.html

3、https://segmentfault.com/a/1190000002718360

4、http://www.dirk-loss.de/ssh-port-forwarding.htm

使用ssh从外网访问内网的更多相关文章

  1. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  2. 配置多层NAT和端口映射实现外网访问内网

    配置多层NAT和端口映射实现外网访问内网 背景和原理 通过配置NAT可以实现内网中不能直接访问外网的主机通过NAT代理访问内网,配置方法这里不再赘述(前文有介绍).本文以两层的NAT代理做模拟,通过端 ...

  3. [笔记] 使用frp从外网访问内网

    之前尝试过otunnel,也记录过使用方法,见[笔记] 使用otunnel从外网访问内网,但是用了几天发现还是不够稳定. 然后尝试frp,发现性能稳定,够用,将过程及配置分享在这里吧. 需求 内网机器 ...

  4. [笔记] 使用otunnel从外网访问内网

    需求 内网机器没有公网IP,但是可以访问外网,现在需要从外网访问内网机器. 举例,在家里机器A访问公司内网机器B. 前提 需要一台有公网IP的服务器S做中转,这样就可以打通AB两端了. A <- ...

  5. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  6. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  7. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  8. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  9. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  10. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

随机推荐

  1. fastjosn在低版本丢字段问题

    简单的说: 对于java bean中有字段类似pId这种写法,特征是第一个字母小写,第二个字母大写,在eclipse中生成的getter setter方法是 getpId, setpId. 在低版本的 ...

  2. 如何解决Jmeter导出的聚合报告是乱码易位问题

    在使用Jmeter这个工具的时候,有些单词不懂是什么意思,就切换到这个工具自带的中文语言: 当我们测试完毕,导出聚合报告(Summary Report)的时候: 1.有一些第一个Title下面的中文是 ...

  3. js 遍历对象属性(for in、Object.keys、Object.getOwnProperty) 以及高效地输出 js 数组

    js中几种遍历对象的方法,包括for in.Object.keys.Object.getOwnProperty,它们在使用场景方面各有不同. for in 主要用于遍历对象的可枚举属性,包括自有属性. ...

  4. python批量爬取文档

    最近项目需要将批量链接中的pdf文档爬下来处理,根据以下步骤完成了任务: 将批量下载链接copy到text中,每行1个链接: 再读txt文档构造url_list列表,利用readlines返回以行为单 ...

  5. redhat-2

    2016年5月16日-工作日志1 通过PXE安装RHEL7.2系统,部署satellite6.2(采用不是least-stable版本,是Satellite-6.2.0-RHEL-7-20160512 ...

  6. 【转】unity Animator 怎么判断一个动画播放结束

    关于unity Animator 怎么判断一个动画播放结束这里有几种方法.希望对大家有帮助.还有其他办法的可以分享一下 第一种方法:在动画结束帧后面加个动画事件,调用下含这个变量的函数接口不是可以了? ...

  7. 【.NET MVC分页】.NET MVC 使用pagelist 分页

    1.安装 2. 在NuGet程序包管理控制台 ,输入Install-Package PagedList.mvc 安装PagedList 和PageList.Mvc; 3. @{ Layout = nu ...

  8. 详解 MySQL 的计划任务

    注意:5.1以后才支持! 让MYSQL定期执行指定的一条命令.功能类似于crontab. 1. 检查你的MYSQL是否开了这个功能 SHOW VARIABLES LIKE 'event_schedul ...

  9. Codeforces Round #321 (Div. 2) C dfs处理(双向边叶子节点的判断)

    C. Kefa and Park time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...

  10. Spring MVC @PathVariable 特殊字符

    1.问题 SpringMVC项目中通过下面的URL进行GET请求.当version有多个小数点的时候.如version为1.0.1008.后台通过@PathVariable来获取version等于1. ...