Nov 02

1.直接寻找可用的 IP.

通过网络上的 ping 工具,检测得到 Google GHS 的 IP,分别打开下面列表中的网址,查询的地方输入 ghs.google.com 或者 ghs.googlehosted.com,里面得到的每一个 A Records 或响应 IP 就对应一个可以尝试的 GHS IP 地址,然后在本地通过 ping 测试验证是否能用。

http://bgp.he.net/dns/ghs.google.com
https://cloudmonitor.ca.com/en/dnstool.php
http://ping.chinaz.com/

可以将需要绑定的域名直接绑定到 A 记录,如果你有多个域名需要绑定的话,当一个 IP 被屏蔽的话,就需要修改所有的 A 记录。这里有一个小技巧,你可以添加一个可用的 IP 到域名 ghs.domain.com,然后通过 cname 的形式绑定 GAE 域名,这样当需要修改时仅仅需要修改一条 A 记录就可以了。

或者你可以使用网上仍然可用的由 GDG 维护的 ghs 替代域名:

www.goofan.net.g.xgslb.net

当然,这个需要添加 cname 记录。

2.使用 Nginx 直接反向代理
如果有 VPS 的话,可以直接安装 Ngrok,利用 Ngrok 反向代理 GAE,这种方法简单粗暴,一定能成功。但是如果你有多个 GAE 应用的话,就需要添加多段类似的代码,如果嫌麻烦的话可以参考下面第 3 种方法。

server
{
        listen   80;
        server_name xxx.com;

        location /
        {
                proxy_pass http://yyy.appspot.com;
                proxy_set_header Host "yyy.appspot.com";
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

3.使用 Nginx 反向代理 Google GHS
最好使用单独的 VPS 来反向代理 Google GHS,代码如下所示,然后添加 A 记录 ghs 到 VPS 的 IP,添加 cname 需要绑定的域名 到 ghs.domain.com。

upstream ghs {
   ip_hash;
   server ghs.google.com;
   server 72.14.203.121;
   server 72.14.207.121;
   server 74.125.43.121;
   server 74.125.47.121;
   server 74.125.53.121;
   server 74.125.77.121;
   server 74.125.93.121;
   server 74.125.95.121;
   server 74.125.113.121;
   server 216.239.32.21;
   server 216.239.34.21;
   server 216.239.36.21;
   server 216.239.38.21;
}

server {
   listen       80;
   server_name  ghs.domain.com;
#下行中的ghs换成自己定义的名称。
    log_format  ghs  '$remote_addr - $remote_user [$time_local] "$request" '
               '$status $body_bytes_sent "$http_referer" '
               '"$http_user_agent" $http_x_forwarded_for';
#下行中两处ghs换成自己定义的名称。
   access_log  /home/log/ghs.log ghs;

   location / {
     proxy_redirect off;
     proxy_set_header Host $host;
     proxy_pass http://ghs;
     proxy_set_header  X-Real-IP  $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_redirect false;
   }

}

server {
   listen       443;
   server_name  ghs.domain.com;
   log_format  mail  '$remote_addr - $remote_user [$time_local] "$request" '
               '$status $body_bytes_sent "$http_referer" '
               '"$http_user_agent" $http_x_forwarded_for';
   access_log  /home/log/mail.log mail;

   location / {
     proxy_redirect off;
     proxy_set_header Host $host;
     proxy_pass http://ghs;
     proxy_set_header  X-Real-IP  $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_redirect false;
   }
}

参考资料:
1.http://steven-wang.appspot.com/nginx-reverse-proxy-122001.html
2.Install Nginx and config Google ghs proxy

Nov 02

VPS 系统在最小化安装后,执行一些命令时候,提示 locale 设置错误,具体如下:

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
        LANGUAGE = (unset),
        LC_ALL = (unset),
        LANG = "zh_CN"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").

错误提示是没有设置好 locale 相关环境变量,因此尝试将其设置:

export LANGUAGE=en_US.UTF-8
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8

解决办法是:

vi /etc/locale.gen,找到# en_US.UTF-8 UTF-8,去掉前面的#号;

执行一下命令,可以看到,提示 en_US.UTF-8 已经生成:

# locale-gen en_US.UTF-8
Generating locales (this might take a while)...
  en_US.UTF-8... done
Generation complete.

接着更新

# update-locale en_US.UTF-8

重新执行之前有报错的命令,已经不再报错。

参考资料:
1.http://blog.sina.com.cn/s/blog_4da051a60102vfrf.html
2.https://www.thomas-krenn.com/en/wiki/Perl_warning_Setting_locale_failed_in_Debian

Nov 01

Debian 新系统更新时,有提示:

Get:8 http://security.debian.org wheezy/updates/non-free Translation-en [14 B] 
Hit http://ftp.debian.org wheezy/contrib i386 Packages                         
Hit http://ftp.debian.org wheezy/non-free i386 Packages                   
Hit http://ftp.debian.org wheezy/contrib Translation-en
Hit http://ftp.debian.org wheezy/main Translation-en
Hit http://ftp.debian.org wheezy/non-free Translation-en
Fetched 729 kB in 2s (350 kB/s)              
Reading package lists... Done
W: There is no public key available for the following key IDs:
9D6D8F6BC857C906
W: There is no public key available for the following key IDs:
7638D0442B90D010

解决办法:

apt-get install debian-keyring debian-archive-keyring

参考资料:http://unix.stackexchange.com/questions/75807/no-public-key-available-on-apt-get-update

Nov 01

前面也写了一篇关于 Ngrok 搭建的文章:《树莓派上 Ngrok 的编译与使用》,但是看到《搭建 ngrok 服务实现外网访问局域网内的网站》这篇文章使用纯手工编译的步骤很详细,尤其是 go 语言的配置那部分内容,所以将文中的主要内容复制下来,以备不时之需。

事先的准备工作:添加 ngrok 服务域名的 DNS 解析。

选择支持泛解析的 DNS 服务商,如 Cloudns、DNSpod 国际版、zoneedit 等,分别添加 A 记录:

ngrok.chun.pro 记录值 1.2.3.4
*.ngrok.chun.pro 记录值 1.2.3.4

1.安装必要的工具和语言环境

sudo apt-get install build-essential golang mercurial git

2.升级 go 语言环境

# 看看是不是小于等于 1.2.1
go version
# 卸载
sudo apt-get purge golang*
#下载最新版并解压 https://golang.org/dl/
wget https://storage.googleapis.com/golang/go1.7.3.linux-386.tar.gz
tar -C /usr/local -xzf go1.7.3.linux-386.tar.gz
#创建目录
mkdir ~/.go
# 设置环境变量
vi ~/.profile
export GOROOT=/usr/local/go
export GOPATH=~/.go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
source .profile

# 升级
sudo update-alternatives --install "/usr/bin/go" "go" "/usr/local/go/bin/go" 0
sudo update-alternatives --set go /usr/local/go/bin/go
go version

3.下载 ngrok 源码并编译服务端

git clone https://github.com/tutumcloud/ngrok.git ngrok
cd ngrok

#生成并替换源码里默认的证书,注意域名要修改为你自己的,这里是一个虚拟的测试域名
NGROK_DOMAIN="ngrok.chun.pro"
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.csr
openssl x509 -req -in server.csr -CA base.pem -CAkey base.key -CAcreateserial -days 10000 -out server.crt

cp base.pem assets/client/tls/ngrokroot.crt
cp server.crt assets/server/tls/snakeoil.crt
cp server.key assets/server/tls/snakeoil.key

#开始编译,服务端客户端会基于证书来加密通讯,保证了安全性
GOOS=linux GOARCH=amd64 make release-server release-client
GOOS=linux GOARCH=386 make release-server release-client
GOOS=linux GOARCH=arm make release-server release-client
GOOS=linux GOARCH=arm64 make release-server release-client
GOOS=linux GOARCH=ppc64 make release-server release-client
GOOS=linux GOARCH=ppc64le make release-server release-client
GOOS=linux GOARCH=mips64 make release-server release-client
GOOS=linux GOARCH=mips64le make release-server release-client

GOOS=windows GOARCH=amd64 make release-server release-client
GOOS=windows GOARCH=386 make release-server release-client

GOOS=darwin GOARCH=amd64 make release-server release-client
GOOS=darwin GOARCH=386 make release-server release-client
GOOS=darwin GOARCH=arm make release-server release-client
GOOS=darwin GOARCH=arm64 make release-server release-client

GOOS=android GOARCH=arm make release-server release-client

GOOS=dragonfly GOARCH=amd64 make release-server release-client

GOOS=freebsd GOARCH=amd64 make release-server release-client
GOOS=freebsd GOARCH=386 make release-server release-client
GOOS=freebsd GOARCH=arm make release-server release-client

GOOS=netbsd GOARCH=amd64 make release-server release-client
GOOS=netbsd GOARCH=386 make release-server release-client
GOOS=netbsd GOARCH=arm make release-server release-client

GOOS=openbsd GOARCH=amd64 make release-server release-client
GOOS=openbsd GOARCH=386 make release-server release-client
GOOS=openbsd GOARCH=arm make release-server release-client

GOOS=plan9 GOARCH=amd64 make release-server release-client
GOOS=plan9 GOARCH=386 make release-server release-client

GOOS=solaris GOARCH=amd64 make release-server release-client

4.启动服务端
在服务器上运行下面的命令启动ngrok服务端

./bin/ngrokd -domain="ngrok.chun.pro" -httpAddr=":8081" -httpsAddr=":8082"

注意,这里 httpAddr 和 httpsAddr 是 ngrok 服务转发 http 和 https 请求的端口,为了避免和 Nginx/Apache 等的 80 端口冲突,使用了 8081 和 8082。

默认还会启动一个 4443 端口,用于跟活动的客户端进行通讯,如果需要更换端口,使用 -tunnelAddr=”:xxx”参数

现在你可以在浏览器里访问 http://ngrok.chun.pro:8081了,如果有一行提示,表示 ngrok 的服务端已经运行起来了

Tunnel ngrok.yourdomain.com:8081 not found

然后再访问 http://pi.ngrok.chun.pro:8081,如果有下面的提示,表示 A 记录也已经生效了。

Tunnel pi.ngrok.chun.pro:8081 not found

5.配置客户端参数

vi ngrok.cfg
# 填写如下信息,server_addr 指定了服务端的域名和与客户端通信的端口
server_addr: ngrok.chun.pro:4443
trust_host_root_certs: false

6.启动客户端

./ngrok -config=./ngrok.cfg -subdomain pi 127.0.0.1:80

如果连接正常,会有提示:

ngrok                                                        (Ctrl+C to quit)
Tunnel Status                 online
Version                       1.7/1.7
Forwarding                    http://pi.ngrok.chun.pro:8081 -> 127.0.0.1:80
Web Interface                 127.0.0.1:4040
# Conn                        5
Avg Conn Time                 192.70ms

7.nginx 反向代理 8081 端口

server {
        listen 80;
        server_name ngrok.chun.pro;
        location / {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host:8081;
                proxy_set_header X-Nginx-Proxy true;
                proxy_set_header Connection "";
                proxy_pass http://127.0.0.1:8081;
        }
}

现在可以直接在浏览器访问 pi.ngrok.chun.pro,而不需要加 :8081 端口号。

另外,使用 Docker 搭建 Ngrok 服务器可以参考这篇文章:https://hteen.cn/docker/docker-ngrok.html

Jul 23

1. 配置 ngrok 的编译环境

sudo apt-get install git bison build-essential mercurial
bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-

installer)
echo "[[ -s "$HOME/.gvm/scripts/gvm" ]] && source "$HOME/.gvm/scripts/gvm"" >> ~/.bashrc
source ~/.bashrc
gvm install go1.4
gvm use go1.4
export GOROOT_BOOTSTRAP=$GOROOT

参考资料:https://medium.com/@unnikked/how-to-compile-ngrok-on-a-raspberry-pi-d5a78ce4b15c#.vdw95rslb

2. 编译 ngrok

git clone https://github.com/inconshreveable/ngrok.git ngrok
cd ngrok

NGROK_DOMAIN="example.com"

openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=$NGROK_DOMAIN" -days 5000 -out 

rootCA.pem
openssl genrsa -out device.key 2048
openssl req -new -key device.key -subj "/CN=$NGROK_DOMAIN" -out device.csr
openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out 

device.crt -days 5000

cp rootCA.pem assets/client/tls/ngrokroot.crt
#cp device.crt assets/server/tls/snakeoil.crt
#cp device.key assets/server/tls/snakeoil.key

编译 linux 64 bit 版本的 ngrok

GOOS=linux GOARCH=amd64 ./make.bash
GOOS=linux GOARCH=amd64 make release-client

编译 linux 32 bit 版本的 ngrok

cd ~/.gwm/gos/go1.4/src
GOOS=linux GOARCH=amd64 ./make.bash

cd ~/ngrok
GOOS=linux GOARCH=amd64 ./make.bash

GOOS=linux GOARCH=arm ./make.bash
GOOS=linux GOARCH=arm make release-client

GOOS=windows GOARCH=amd64 ./make.bash
GOOS=windows GOARCH=amd64 make release-client

GOOS=windows GOARCH=386 ./make.bash
GOOS=windows GOARCH=386 make release-client

参考资料:http://www.mamicode.com/info-detail-1230154.html
http://tonybai.com/2014/10/20/cross-compilation-with-golang/

3. 测试 ngrok 服务端和客户端

sudo cp ngrok /usr/local/ngrok/
sudo cp ngrokd /usr/local/ngrok/
sudo vim /usr/local/ngrok/ngrok.cfg

服务端

sudo ./ngrok -tlsKey=device.key -tlsCrt=device.crt -domain="$NGROK_DOMAIN" -httpAddr=”:8000" -httpsAddr=”:8001"

客户端

#ngrok.cfg
server_addr: "zisu.org:4443"
trust_host_root_certs: false
inspect_addr: disabled

tunnels:
    web:
        proto:
            http: 8081
    app:
        proto:
            http: 8765
    ssh:
        remote_port: 222
        proto:
            tcp: 22
./ngrok -subdomain web -proto=http -config=ngrok.cfg 8081
./ngrok -config=ngrok.cfg start web

如果服务端和客户端测试没有问题,可以设置为自启动

服务端:

sudo vim /etc/init.d/ngrokd

#!/bin/sh
### BEGIN INIT INFO
# Provides:          ngrokd
# Required-Start:    $local_fs $remote_fs $network
# Required-Stop:     $local_fs $remote_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: ngrokd
# Description:
#
### END INIT INFO

NAME=ngrokd
DAEMON=/usr/local/ngrok/$NAME
KEY=/usr/local/ngrok/server.key
CRT=/usr/local/ngrok/server.crt
DOMAIN="example.com"
HTTPADDR=":8080"
HTTPSADDR=":8081"

[ -x "$DAEMON" ] || exit 0

case "$1" in
  start)
    echo "Starting $NAME..."
    start-stop-daemon --start --chuid root --exec $DAEMON --quiet --oknodo --background -- -tlsKey=$KEY -tlsCrt=$CRT -domain=$DOMAIN -httpAddr=$HTTPADDR -httpsAddr=$HTTPSADDR || return 2
    ;;
  stop)
    echo "Stopping $NAME..."
    start-stop-daemon --stop --exec $DAEMON --quiet --oknodo --retry=TERM/30/KILL/5 || return 2
    ;;
  restart)
    $0 stop && sleep 2 && $0 start
    ;;
  *)
    echo "Usage: $0 {start|stop|restart}"
    exit 1
    ;;
esac
exit 0
sudo update-rc.d ngrokd defaults

客户端:

sudo vim /etc/init.d/ngrok

#!/bin/sh
### BEGIN INIT INFO
# Provides:          ngrok
# Required-Start:    $local_fs $remote_fs $network
# Required-Stop:     $local_fs $remote_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: ngrok
# Description:
#
### END INIT INFO

NAME=ngrok
DAEMON=/usr/local/ngrok/$NAME
CONFIG=/usr/local/ngrok/ngrok.cfg
TUNNELS="web ssh"

[ -x "$DAEMON" ] || exit 0

case "$1" in
  start)
    echo "Starting $NAME..."
    start-stop-daemon --start --chuid pi --exec $DAEMON --quiet --oknodo --background -- -config $CONFIG start $TUNNELS || return 2
    ;;
  stop)
    echo "Stopping $NAME..."
    start-stop-daemon --stop --exec $DAEMON --quiet --oknodo --retry=TERM/30/KILL/5 || return 2
    ;;
  restart)
    $0 stop && sleep 2 && $0 start
    ;;
  *)
    echo "Usage: $0 {start|stop|restart}"
    exit 1
    ;;
esac
exit 0
sudo update-rc.d ngrok defaults

参考资料:http://www.tuicool.com/articles/MRJjmuv

4. 使用 supervisor 后台运行 ngrok

sudo apt-get install supervisor

在 supervisord.conf 添加如下配置

[include]
files = supervisord.d/*.conf

sudo vim ngrok.conf

[program:ngrok]
directory               = /usr/local/ngrok
command                 = /usr/local/ngrok/ngrok -config=ngrok.cfg -log=stdout
process_name            = %(program_name)s_%(process_num)s
numprocs                = 1 
autostart               = true
autorestart             = true

stdout_logfile          = /var/log/supervisor/ngrok_stdout.log
stdout_logfile_maxbytes = 10MB
stderr_logfile          = /var/log/supervisor/ngrok_error.log
stderr_logfile_maxbytes = 10MB

启动 supervisor

sudo supervisorctl reread 
sudo supervisorctl add ngrok 
sudo supervisorctl update ngrok 
sudo supervisorctl status

启动和停止 ngrok

sudo supervisorctl start ngrok 
sudo supervisorctl stop ngrok

参考资料:https://natapp.cn/article/supervisor

5. 修改 DNS 解析

同时将 example.com 和 *.example.com 解析到 VPS 上,可直接设置将其 A 记录解析到 VPS 的 IP 上,使用二级域名也是可以,但是需要选择支持泛解析的 DNS 服务商,像 DNspod。

6. 常见问题

编译成功的 ngrok 在 Linux 和 Windows 上都可以正常运行,但是 arm 版本在 Raspberry Pi 上会出现内存泄漏的问题,一般运行一段时间后内存耗尽后就会自动退出。

https://github.com/inconshreveable/ngrok/issues/109

解决方法就是在配置文件 ngrok.cfg 下添加 inspect_addr: disabled,关闭管理界面。

#sudo vim ngrok.cfg

server_addr: "domain.com:4443"
trust_host_root_certs: false
inspect_addr: disabled

同时将记录以正常文本的形式输出,即在启动命令后面加入 -log=stdout 选项。

./ngrok -config=ngrok.cfg -log=stdout start web

在程序能正确运行无错误时,甚至可以将记录输出到 /dev/null 文件,ngrok 正常输出的 log 实在太多了。

./ngrok -config=ngrok.cfg -log=stdout start web >/dev/null

7. ngrok 与 nginx 配合使用
上面的配置是针对单独的 VPS 用来搭建 ngrok 的情况,但是,如果 VPS 上的 80 端口还要用于其它服务的话,就需要修改 nginx 的配置。

server {    
    listen  80;  
    server_name *.domain.com;  
      
    root   html;
    index  index.html index.htm index.php;

    location / {
        proxy_pass  http://127.0.0.1:8000;
        #Proxy Settings
        proxy_redirect     off;
        #proxy_set_header Host downloads.openwrt.org;
        proxy_set_header   Host             $host:8000;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        proxy_max_temp_file_size 0;
        proxy_connect_timeout      90;
        proxy_send_timeout         90;
        proxy_read_timeout         90;
        proxy_buffer_size          4k;
        proxy_buffers              4 32k;
        proxy_busy_buffers_size    64k;
        proxy_temp_file_write_size 64k;
   }
}  

server {
    listen 443;
    server_name *.*.domain.com;
 
    ssl on;
    ssl_certificate /etc/fullchain.pem;
    ssl_certificate_key /etc/privkey.pem;

    root   html;
    index  index.html index.htm index.php;
 
    location / {
        proxy_pass  https://127.0.0.1:8001;
        #Proxy Settings
        proxy_redirect     off;
        #proxy_set_header Host downloads.openwrt.org;
        proxy_set_header   Host             $host:8001;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        proxy_max_temp_file_size 0;
        proxy_connect_timeout      90;
        proxy_send_timeout         90;
        proxy_read_timeout         90;
        proxy_buffer_size          4k;
        proxy_buffers              4 32k;
        proxy_busy_buffers_size    64k;
        proxy_temp_file_write_size 64k;
   }
}

上述配置中需要修改的是 server_name 处的域名,proxy_pass 和 proxy_set_header 处的端口号,共计6处。然后测试 nginx 能否通过。

sudo nginx -t
sudo nginx -s reload

参考资料:https://segmentfault.com/q/1010000004277269