RaspberryPi
Elasticsearch
OpenVPN
TinkerBoard

OpenVPNで自宅RaspberryPiサーバを公開

More than 1 year has passed since last update.

Google Cloud Compute Engine の micro インスタンスが無料で使えるようになりました。みなさん使っていますか?僕は http://manga.dog/ で使っています。が、しかし、新しい機能を追加しようと思ったのですが、どうも全文検索エンジンの Elasticsearch を使わないといけないようです。そして Elasticsearch はメモリを食いまくるので現在の micro インスタンスに同居させるのはとても難しい。Amazon Elasticsearch Service を使って機能を実装してはみたのだけど、そもそも無料の micro インスタンスを使っていたので有料サービスを使うのは負けた気がする!そこで自宅に転がっていた Raspberry Pi3 に Elasticsearch を入れシステムに組み込み勝利をつかみ取ることにしました。


必要な機能


  • ラズパイで Elasticsearch を動かす

  • アプリケーションサーバから自宅のラズパイにアクセスする

このような機能が必要なのですが、まぁいわゆる自宅サーバを公開すればよいわけですね。一般的には自宅のルーターに外部からきたアクセスを特定の機器にルーティングする設定をおこなう方法だと思います。でもこの方法だと自宅のIPが変わるとアクセスできなくなってしまいます。それを回避するためにダイナミックDNSを使います。でもこの方法はかっこ悪いなと前々から思っていました。

そこで VPN を使った方法で構築したいと思います。全体の構成はこのようになります。

VPNサーバ公開.png

VPNサーバを無料なGoogle Cloud Compute Engineに立てます。ラズパイは自宅からVPNサーバに接続します。するとサーバとクライアントは 10.8.0.1 と 10.8.0.6 の仮想ネットワーク上のIPアドレスで接続されます。繋がってしまえば簡単ですね。サーバに飛んできたHTTPリクエスを nginx をプロキシサーバにしてラズパイに投げてしまえばよいのです。

手順としては以下の4段階になります。


  1. VPNサーバの設定

  2. Raspberry Pi3 を VPN サーバに接続する

  3. Raspberry Pi3 で Elasticsearch を動かす

  4. VPNサーバに nginx でプロキシサーバを立てる

それでは設定していきます。


VPNサーバの設定

環境: Google Cloud Compute Engine

OS: Ubuntu 16.04 LTS

開放ポート: 80-TCP, 1194-UDP

サーバを用意したら80と1194のポートを開放してください。1194はUDPになります。

まずは更新します。

$ sudo apt-get update

$ sudo apt-get upgrade

openvpn と git をインストールします。easy-rsa という鍵を作成するツールのリポジトリも取得します。

$ sudo apt install openvpn git

$ git clone https://github.com/OpenVPN/easy-rsa.git

鍵がいくつも必要になるので作っていきます。作成した鍵は /etc/openvpn/keys にコピーします。

ca.crt を作ります。phrase と Common Name は適当なものを入力してください。

$ cd easy-rsa/easyrsa3

$ ./easyrsa init-pki

$ ./easyrsa build-ca
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
Common Name (eg: your user, host, or server name) [Easy-RSA CA]: google
$ sudo mkdir /etc/openvpn/keys
$ sudo cp pki/ca.crt /etc/openvpn/keys

server.crtserver.key を作成します。途中で ca.key の phrase を求められるので入力します。

$ ./easyrsa build-server-full server nopass

Enter pass phrase for /home/akiraak/easy-rsa/easyrsa3/pki/private/ca.key:
$ sudo cp pki/issued/server.crt /etc/openvpn/keys
$ sudo cp pki/private/server.key /etc/openvpn/keys

dh.pem を作成します。こちらも ca.key の phrase を入力します。このキーの作成は少し時間がかかります。

$ ./easyrsa gen-dh

$ sudo cp pki/dh.pem /etc/openvpn/keys

crl.pem を作成します。途中で ca.key の phrase を入力します。

$ ./easyrsa gen-crl

Enter pass phrase for /home/akiraak/easy-rsa/easyrsa3/pki/private/ca.key:
$ sudo cp pki/crl.pem /etc/openvpn/keys
$ sudo chmod o+r /etc/openvpn/keys/crl.pem

クライアントの鍵を作成します。[client-name] に適当な名前を入れてください。僕の場合はクライアントがラズパイなので ras としました。また、クライアント鍵の phrase が求められるので適当なものを入力し、その後に ca.key の phrase も入力します。

$ ./easyrsa build-client-full [client-name]

Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
Enter pass phrase for /home/akiraak/easy-rsa/easyrsa3/pki/private/ca.key:

ca.crt とクライアントの鍵はラズパイにアップロードする必要があるのでローカル環境にダウンロードしておきます。

$ cp pki/ca.crt ~

$ cp pki/issued/[client-name].crt ~
$ cp pki/private/[client-name].key ~

$ scp XXX.XXX.XXX.XXX:~/ca.crt ~/vpn/
$ scp XXX.XXX.XXX.XXX:~/ras.crt ~/vpn/
$ scp XXX.XXX.XXX.XXX:~/ras.key ~/vpn/

/etc/openvpn/server.conf を作成します。各パラメーターの詳しい説明は以下の記事を参考にしてください。

OpenVPNのインストールとセットアップからインターネット接続までのガイドブック


/etc/openvpn/server.conf

port   1194

proto udp
dev tun

ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/server.crt
key /etc/openvpn/keys/server.key
dh /etc/openvpn/keys/dh.pem
crl-verify /etc/openvpn/keys/crl.pem

ifconfig-pool-persist /etc/openvpn/ipp.txt

server 10.8.0.0 255.255.255.0

push "route 10.8.0.0 255.255.255.0"

client-to-client
keepalive 10 120
comp-lzo

user nobody
group nogroup

persist-key
persist-tun

status /var/log/openvpn-status.log
log /var/log/openvpn.log
log-append /var/log/openvpn.log

verb 3


openvpn コマンドで動作するか確認します。

$ sudo openvpn --config /etc/openvpn/server.conf

ログはこのようになります。


/var/log/syslog

Jul  3 01:13:09 vpn2 ntpd[1613]: Listen normally on 6 tun0 10.8.0.1:123

Jul 3 01:13:09 vpn2 ntpd[1613]: Listen normally on 7 tun0 [fe80::b142:7fdf:3c3c:7f79%3]:123
Jul 3 01:13:09 vpn2 ntpd[1613]: new interface(s) found: waking up resolver

ifconfig でIPが割り振られているか確認します。 10.8.0.1 となっていますね。

$ ifconfig

tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:10.8.0.1 P-t-P:10.8.0.2 Mask:255.255.255.255
inet6 addr: fe80::b142:7fdf:3c3c:7f79/64 Scope:Link
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:3 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 B) TX bytes:144 (144.0 B)

openvpn での実行を止めて、サービスで起動させます。

$ sudo systemctl start openvpn@server

自動起動になっていないので有効にします。

sudo systemctl enable openvpn@server

VPNサーバの設定は以上です。


Raspberry Pi3 を VPN サーバに接続する

OS は Ubuntu MATE 16.04.2 LTS を使用します。Mac を使ったインストール方法も書いておきます。

ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img.xz をダウンロードします。次に SDカードをアダプタなどを使い Mac の USB に刺します。

$ diskutil list

/dev/disk0 (internal, physical):
#: TYPE NAME SIZE IDENTIFIER
0: GUID_partition_scheme *500.3 GB disk0
1: EFI EFI 209.7 MB disk0s1
2: Apple_CoreStorage Macintosh HD 499.4 GB disk0s2
3: Apple_Boot Recovery HD 650.0 MB disk0s3

/dev/disk1 (internal, virtual):
#: TYPE NAME SIZE IDENTIFIER
0: Apple_HFS Macintosh HD +499.0 GB disk1
Logical Volume on disk0s2
DF19241A-6A88-40A6-AC98-2B2929C13B2A
Unencrypted

/dev/disk2 (external, physical):
#: TYPE NAME SIZE IDENTIFIER
0: FDisk_partition_scheme *31.4 GB disk2
1: Windows_FAT_32 PI_BOOT 66.1 MB disk2s1
2: Linux 31.4 GB disk2s2

SDカードは /dev/disk2 と認識されているようです。

dfMounted on を確認し、unmount します。

$ df

Filesystem 512-blocks Used Available Capacity iused ifree %iused Mounted on
/dev/disk1 974700800 735691904 238496896 76% 3494843 4291472436 0% /
devfs 389 389 0 100% 674 0 100% /dev
map -hosts 0 0 0 100% 0 0 100% /net
map auto_home 0 0 0 100% 0 0 100% /home
/dev/disk2s1 128912 42672 86240 34% 512 0 100% /Volumes/PI_BOOT

$ sudo diskutil unmount "/Volumes/PI_BOOT"

イメージをSDカードにコピーします。このとき /dev/rdisk2 と disk の前に r を入れます。またbs=1m も追加します。これをしないと何時間もかかってしまうので注意が必要です。

$ xzcat ~/Downloads/ubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img.xz | sudo dd of=/dev/rdisk2 bs=1m

contrl+t で進捗を確認できます。

終わったらSDカードをラズパイに刺せば Ubuntu MATE が起動します。

更新します。

$ sudo apt-get update

$ sudo apt-get upgrade
Reading package lists... Done
Building dependency tree
Reading state information... Done
You might want to run 'apt-get -f install' to correct these.
The following packages have unmet dependencies:
libc6-dev : Depends: libc6 (= 2.23-0ubuntu9) but 2.23-0ubuntu5 is installed
E: Unmet dependencies. Try using -f.

-f を使わないと更新ができないようです。

$ sudo apt-get -f upgrade

openvpn をインストールします。

$ sudo apt-get install openvpn

VPNサーバで作成した鍵をラズパイにアップロードし、 /etc/openvpn/keys に配置します。

$ scp ~/vpn/ca.crt XXX.XXX.XXX.XXX:~

$ scp ~/vpn/ras.crt XXX.XXX.XXX.XXX:~
$ scp ~/vpn/ras.key XXX.XXX.XXX.XXX:~
$ sudo mkdir /etc/openvpn/keys
$ sudo mv ca.crt /etc/openvpn/keys
$ sudo mv ras.crt /etc/openvpn/keys
$ sudo mv ras.key /etc/openvpn/keys

/etc/openvpn/keys/pass にクライアント鍵の phrase を入れておきます。

$ sudo vi /etc/openvpn/keys/pass

/etc/openvpn/client.conf にクライアントの設定を記載します。XXX.XXX.XXX.XXX はVPNサーバのIPアドレスを入れてください。


/etc/openvpn/client.conf

client

dev tun
proto udp

remote XXX.XXX.XXX.XXX 1194

resolv-retry infinite
nobind

persist-key
persist-tun

ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/ras.crt
key /etc/openvpn/keys/ras.key
askpass /etc/openvpn/keys/pass

comp-lzo
verb 3


openvpn コマンドで接続できるか試します。

$ sudo openvpn --config /etc/openvpn/client.conf

別ウィンドウで ifconfig を実行してみます。 10.8.0.6 とIPが割り振られたようです。

$ ifconfig

tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:10.8.0.6 P-t-P:10.8.0.5 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:3 errors:0 dropped:0 overruns:0 frame:0
TX packets:3 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:252 (252.0 B) TX bytes:252 (252.0 B)

VPNサーバに ping が届くか確認します。

$ ping 10.8.0.1

PING 10.8.0.1 (10.8.0.1) 56(84) bytes of data.
64 bytes from 10.8.0.1: icmp_seq=1 ttl=64 time=68.8 ms
64 bytes from 10.8.0.1: icmp_seq=2 ttl=64 time=58.9 ms

逆にVPNサーバからラズパイに ping を打ってみます。

$ ping 10.8.0.6

PING 10.8.0.6 (10.8.0.6) 56(84) bytes of data.
64 bytes from 10.8.0.6: icmp_seq=1 ttl=64 time=63.5 ms
64 bytes from 10.8.0.6: icmp_seq=2 ttl=64 time=59.5 ms

問題がなさそうなので、openvpn の実行を終了し、サービスの起動と自動起動の設定を行います。

$ sudo service openvpn start

$ sudo systemctl enable openvpn


ラズパイで Elasticsearch を動かす

オフィシャルのインストール方法はこちらに書いてあります。

Install Elasticsearch with Debian Package

インストールします。

$ wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -

$ echo "deb https://artifacts.elastic.co/packages/5.x/apt stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-5.x.list
$ sudo apt-get update
$ sudo apt-get install elasticsearch
$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.4.3.deb
$ sudo dpkg -i elasticsearch-5.4.3.deb

Elasticsearch は初期設定だとメモリを2GB使いますが、Raspberry Pi3 は1GBしか積んでいないので、jvm の設定を変更して512MBにします。


/etc/elasticsearch/jvm.options

#-Xms2g

#-Xmx2g
-Xms512m
-Xmx512m

外部のPCからアクセスできるように設定を追記します。


/etc/elasticsearch/elasticsearch.yml

network.host: 0.0.0.0

http.port: 9200
transport.host: localhost
transport.tcp.port: 9300

実行します。

$ sudo service elasticsearch start

起動には時間がかかります。ログを確認します。

$ tail -f /var/log/elasticsearch/elasticsearch.log

[2017-07-03T21:17:00,200][INFO ][o.e.n.Node ] [d0hREp4] starting ...
[2017-07-03T21:17:04,266][INFO ][o.e.t.TransportService ] [d0hREp4] publish_address {127.0.0.1:9300}, bound_addresses {127.0.0.1:9300}
[2017-07-03T21:17:04,471][WARN ][o.e.b.BootstrapChecks ] [d0hREp4] system call filters failed to install; check the logs and fix your configuration or disable system call filters at your own risk
[2017-07-03T21:17:08,265][INFO ][o.e.c.s.ClusterService ] [d0hREp4] new_master {d0hREp4}{d0hREp4RSZq1h-A-VUWbvw}{FSLOhsEiQfGR9w81wvmmgg}{localhost}{127.0.0.1:9300}, reason: zen-disco-elected-as-master ([0] nodes joined)
[2017-07-03T21:17:08,639][INFO ][o.e.h.n.Netty4HttpServerTransport] [d0hREp4] publish_address {10.0.1.30:9200}, bound_addresses {[::]:9200}
[2017-07-03T21:17:08,680][INFO ][o.e.n.Node ] [d0hREp4] started
[2017-07-03T21:17:08,713][INFO ][o.e.g.GatewayService ] [d0hREp4] recovered [0] indices into cluster_state

多くのログが吐かれますが、このようになれば起動しています。

自動起動の設定もしておきます。

$ sudo systemctl enable elasticsearch

動いているかローカルで確認してみます。

$ wget http://localhost:9200

$ cat index.html
{
"name" : "d0hREp4",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "QIfUBpUkTvm8NdxRmlQERg",
"version" : {
"number" : "5.4.3",
"build_hash" : "eed30a8",
"build_date" : "2017-06-22T00:34:03.743Z",
"build_snapshot" : false,
"lucene_version" : "6.5.1"
},
"tagline" : "You Know, for Search"
}

大丈夫なようなので、VPNサーバからも確認してみます。

$ wget http://10.8.0.6:9200

$ cat index.html
{
"name" : "d0hREp4",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "QIfUBpUkTvm8NdxRmlQERg",
"version" : {
"number" : "5.4.3",
"build_hash" : "eed30a8",
"build_date" : "2017-06-22T00:34:03.743Z",
"build_snapshot" : false,
"lucene_version" : "6.5.1"
},
"tagline" : "You Know, for Search"
}


VPNサーバに nginx でプロキシサーバを立てる

さて、最後にプロキシサーバを立てます。これで外部からVPNサーバのパブリックなIPアドレスにアクセスすると、ラズパイにクエリが転送されるようになります。

nginx をインストールします。

$ sudo apt-get install nginx

プロキシサーバの設定を書きます。XXX.XXX.XXX.XXX はVPNサーバのIPアドレスを入れてください。


/etc/nginx/conf.d/ras.conf

server {

server_name XXX.XXX.XXX.XXX;
proxy_set_header Host $http_host;

location / {
proxy_pass http://10.8.0.6:9200;
}
}


nginx を再起動します。

$ sudo service nginx restart

最後にブラウザでアクセスして動作確認します。

elasticsearch.png

Elasticsearch on ラズパイの完成です。


性能

Elasticksearch へのデータのバルクインサートは、AWS の t2.small.elasticsearch で2分くらいかかっていたものがラズパイだと120分かかりました。インデックス作成がものすごく遅いのかな?search は2〜3倍遅いくらいなので実用はできています。


おわりに

ラズパイをサーバにするのは面白いですね。電気代も月50円もかからないようですし、スペースも取らないのでいろいろ設置したくなります。こんなのとか楽しそう。

vpn.png

あと、Raspberry Pi3 での設定方法を書きましたが、実際の運用は Asus Tinker board(CPU1.5倍速, メモリ2GB, ラズパイと同じ形なのでケースが使いまわせる) で行っています。ただこのボードはアメリカだと7,000円で買えるのですが、日本だと16,000円と割に合わないので Raspberry Pi3 の設定を書きました。


Asus Tinker Board 発売

Raspberry Pi3と同サイズで性能2倍のASUS製「Tinker Board」が国内発売

日本での公式な販売が決まったようです。

ラズパイと同様の手順で設定が可能ですが、OSがDebianなのでコマンドが少し変わります。



  • ifconfig/sbin/ifconfig


  • sudo service [サービス名] startsudo systemctl start [サービス名]

メモリが2GB搭載されているので Elasticsearch の使用メモリを1GBにします。


/etc/elasticsearch/jvm.options

#-Xms2g

#-Xmx2g
-Xms1g
-Xmx1g