内网服务器端口被外网访问的几种方法

需求

在局域网内部的主机端口需要被外网访问。直接访问内网IP肯定不行,那就想办法把内网IP和端口号映射到外网的IP和端口号。

 

简单来说,有几种方法可以映射:

  1. 路由器端口转发 (需要路由器管理权限)
  2. ssh 反向隧道 (需要公网服务器)
  3. ngrok 服务器转发 (需要公网服务器或注册ngrok会员)

一句话介绍如何选择方案

如果你有路由器管理权限就在路由器上配,最省事简单。

如果你有自己的公网服务器,不想装其他软件就用,用ssh反向隧道,如果想加点管理功能,以后用着方便,用ngrok自建服务器。

如果你没有自己服务器,可以翻墙,就用ngrok注册用户服务。

如果你没有自己服务器,不能翻墙,试试在国内搜索ngrok的服务,有一些开放的服务器。

路由端口转发

原理

路由器具有公网的地址,访问路由器公网地址的端口,路由器把端口转发到内网服务器的某个端口。

配置

随路由器种类不同而不同。

优缺点

优点:内网服务器无需配置

缺点:需要路由器的管理权限,并且知道路由器的公网IP地址

ssh 反向隧道

原理

ssh tunnel有两种,转发本地端口到远端,转发远端端口到本地。这里用的是后者,前者常用于翻墙。

配置

在内网机器~/.ssh/config文件中配置ssh连接方式。

 Host cli-ssh-tunnel
	HostName      myserver.com
	User          ubuntu
	Port          22
	IdentityFile  ~/.ssh/tunnel.pem
	RemoteForward 2222 localhost:22
	ServerAliveInterval 30
	ServerAliveCountMax 3

RemoteForward 第一个参数是远端端口号,第二个参数是映射到本地的端口号。运行命令:

ssh cli-ssh-tunnel

用autos做自动ssh重连(autossh介绍配置:链接)

autossh -M 0 -f -T -N cli-ssh-tunnel

在外网服务器/etc/ssh/sshd_config配置GatewayPorts选项

GatewayPorts yes

这样才能绑定到外网的公网IP,否则会一直绑定到127.0.0.1的地址。

优缺点

优点:无需路由权限,无需安装第三方软件,方便快捷的临时解决方案

缺点:管理功能少,配置多个比较复杂。

ngrok 服务器转发

原理

和ssh服务器转发原理类似,只是增加了方便的API命令行接口和一系列管理功能。

配置

ngrok官方服务器

如果是翻墙用户可以直接注册ngrok账户就获得了ngrok提供的服务器。

在客户端下载ngrok官方的客户端就可以完成端口映射。(客户端需要翻墙能力)

自建ngrok服务器

如果是墙内用户,可以自己搭建私有ngrok服务器。编译ngrok的源码生成服务器端和客户端的可执行文件。

来源:搭建 ngrok 服务实现内网穿透 (有修改)

sudo apt-get install build-essential golang mercurial git
git clone https://github.com/inconshreveable/ngrok.git ngrok

生成证书,TLS加密通信用的。这里的域名一定要写对,如果是二级域名就写二级域名

NGROK_DOMAIN="imququ.com"
openssl genrsa -out base.key 2048
openssl req -new -x509 -nodes -key base.key -days 10000 -subj "/CN=$NGROK_DOMAIN" -out base.pem
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=$NGROK_DOMAIN" -out server.csropenssl x509 -req -in server.csr -CA base.pem -CAkey base.key -CAcreateserial -days 10000 -out server.crt

需要用自己的证书替换ngrok的证书

cp base.pem ngrok/assets/client/tls/ngrokroot.crt

编译

sudo make release-server release-client

如果一切正常,ngrok/bin 目录下应该有 ngrok、ngrokd 两个可执行文件。

sudo ./bin/ngrokd -tlsKey=server.key -tlsCrt=server.crt -domain="imququ.com" -httpAddr=":8081" -httpsAddr=":8082"

到这一步,ngrok 服务已经跑起来了,可以通过屏幕上显示的日志查看更多信息。httpAddr、httpsAddr 分别是 ngrok 用来转发 http、https 服务的端口,可以随意指定。ngrokd 还会开一个 4443 端口用来跟客户端通讯(可通过 -tunnelAddr=”:xxx” 指定),如果你配置了 iptables 规则,需要放行这三个端口上的 TCP 协议。

自建ngrok客户端

如果要把 linux 上的服务映射出去,客户端就是前面生成的 ngrok 文件。但我用的是 Mac,需要指定环境变量再编一次:

sudo GOOS=darwin GOARCH=amd64 make release-server release-client

这样在 ngrok/bin 目录下会多出来一个 darwin\_amd64 目录,这里的 ngrok 文件就可以拷到 Mac 系统用了。

写一个简单的配置文件,随意命名如 ngrok.cfg:

server_addr: imququ.com:4443
trust_host_root_certs: false

指定子域、要转发的协议和端口,以及配置文件,运行客户端:

./ngrok -proto=http -config=ngrok.cfg 80

不出意外可以看到这样的界面,这说明已经成功连上远端服务了

ngrok 自建的域名问题

  1. http方式转发时,外网地址用多级域名进行区分(比如ngrok.example.com会分配your service.ngrok.example.com的地址,需要在DNS提供商处修改,支持三级域名泛匹配 *.ngrok.example.com -> IP

优缺点

优点:使用方便,有管理功能,安全性高(tls加密)

缺点:需要额外安装第三方软件

使用Jekyll在github上搭建技术博客

Jekyll是一种静态网页生成工具,虽然有很多其他优秀的同类工具,Jekyll最大优点是Github原生支持。你不用在本地编译,Github自动会帮你编译Jekyll的资源文件生成静态网页。

选择一个好看的主题

Jekyll的主题好的真的不多,而且加上Jekyll3.x比较大的版本更新导致很多2.x的优秀框架都不兼容了,所以选择很窄,还需要自己试。最好的办法是看到github上好的Jekyll项目直接Clone一份。

我选择了hyde主题,就遇到没有升级到3.x的问题。需要自己改一下_config.yml

Dependencies
highlighter:      rouge

Permalinks
permalink:        pretty

Setup
title:            Hyde
tagline:          'A Jekyll theme'
description:      'A brazen two-column <a href="http://jekyllrb.com" target="_blank">Jekyll</a> theme that pairs a prominent sidebar with uncomplicated content. Made by <a href="https://twitter.com/mdo" target="_blank">@mdo</a>.'
url:              http://hyde.getpoole.com
baseurl:          /

author:
  name:           'Mark Otto'
  url:            https://twitter.com/mdo

paginate:         5

Custom vars
version:          2.1.0

github:
  repo:           https://github.com/poole/hyde

Gems
gems: [jekyll-paginate]

部署到github

直接用git工具push到gh-pages分支,你就能访问了。但是直接部署后你会发现css文件都404了。

解决静态文件404无法找到的问题

假如github pages的地址是 xxx.github.io/yyy,那么css的地址生成逻辑是:

<link rel="stylesheet" href="{{ site.baseurl }}public/css/poole.css">

这里baseurl是xxx.github.io,所以就会访问 xxx.github.io/public/css/poole.css。一个临时的解决方法是在config里加上baseurl的选项

baseurl: /blog

但这里又带来一个问题。github pages支持绑定到自己的域名,如果你绑定到了blog.example.com 的域名后,你是希望baser恢复到/而不是/blog下的。github上有个issue讨论这个问题:链接,但最后也没有什么结果。我们暂时不绑定自定义的域名,所以就先在config中把baseurl改成/blog (github项目名是blog)

另外,post的url地址也需要修改,以前是

<a href="{{ post.url }}">

修改为

<a href="{{site.baseurl}}{{ post.url }}">

如果在本地调试,用jekyll serve时必须指定参数--baseurl='',否则会访问到/blog下的url。

 github pages 延时更新的问题

注意:部署到更新有一些延时的,感觉是修改静态文件延时最大,更新post的话马上就能生效

修改Jekyll模板

默认的hyde模板会显示博客的所有内容,而我希望能在首页只显示概要内容。所以,我们需要对模板进行改造。

修改index.html的内容,使用Jekyll自带的 excerpt功能不是很理想,所以还是采用比较土的办法:

{{ post.content }} 
修改为
{{ post.content | truncatewords:50 | strip_html }}

开始写一篇吧

可以先在编辑器里写好后,把markdown直接复制到github网页中新建的md文件里。

_posts_的文件格式参照其他文件就可以了。有几个注意的地方:

  1. 文件名的格式是固定的,用来指明创建时间
  2. 如果用ulysses工具生成markdown默认不会在##前空行,这可能导致二级标题或者代码段不能被识别出来。Jekyll中需要在##标记前空行。现在暂时只能在ulysses里写作时注意空行。
  3. 现在ulysses本地图片还不能自动上传。

未来的工作

写一个mac上的app,支持ulysses一键发布到github pages。需要的主要功能:

  • 支持markdown兼容(比如上面说到的空行问题,换行问题,Jekyll语法转义问题)
  • 支持文件自动上传

可能会更方便的功能:

  • 主题选择和编辑