Dec 14th, 2016

check external ip and geoip with ngx_mruby

この記事はmruby Advent Calendar 2016の14日目の記事です。 前日は@takumakumeさんのpmilterでmrubyを用いてメールのDDoSを軽減するでした。

スマフォなどでもグローバルIPが割り振られる事はなくなった現在で、external ipを知りたくなる場合は多いものです。
IPを確認するという行為はよくあることで、下記のようにたくさんサービスがありますが、これを自作しようとするものです。
簡単ですね。

http://ifconfig.io/
http://ifconfig.co/
http://ifconfig.me/
http://httpbin.org/
https://myexternalip.com
http://inet-ip.info
http://www.ugtop.com/spill.shtml

構築するにあたり色々と面倒なRackを挟むようなものではなく、より簡単に作れて軽量なものを作りたいので、組み込み型のmrubyとそれをnginxで使えるようした@matsumotory氏作のngx_mrubyを使います。

ビルド準備

構築環境は例によってdebian jessieを使います。
ngix_mrubyはビルドする必要がありますので、必要なライブラリをインストールすることから始めます。

$ sudo apt-get -qqy install git curl wget make gcc libc-dev libc6-dev ruby ruby2.1 ruby2.1-dev rake bison libcurl4-openssl-dev libssl-dev libhiredis-dev libmarkdown2-dev libcap-dev libcgroup-dev libpcre3 libpcre3-dev

ビルドするディレクトリを$HOME以下に作成する事とし、githubからngx_mrubyのソースをダウンロードし解凍します。

$ curl -fsSLo ngx_mruby.tgz https://github.com/matsumoto-r/ngx_mruby/tarball/master
$ mkdir ngx_mruby && tar -zxf ngx_mruby.tgz -C ngx_mruby --strip-components 1
$ cd ngx_mruby

mrubyライブラリ組み込みとビルド

ここでおもむろにビルド開始しても良いのですが、すこし変更点があります。デフォルトでは@mattn_jpさんのmruby-jsonが組み込まれますが、JSONを出力する際にインデントを伴って整形してくれる機能(pretty_printというようですが)がIIJのmruby-iijsonの方に存在するので、こちらに変更します。

--- a/build_config.rb
+++ b/build_config.rb
@@ -18,7 +18,7 @@ MRuby::Build.new('host') do |conf|
   conf.gem :github => 'iij/mruby-process'
   conf.gem :github => 'iij/mruby-pack'
   conf.gem :github => 'iij/mruby-socket'
-  conf.gem :github => 'mattn/mruby-json'
+  conf.gem :github => 'iij/mruby-iijson'
   conf.gem :github => 'mattn/mruby-onig-regexp'
   conf.gem :github => 'matsumoto-r/mruby-redis'
   conf.gem :github => 'matsumoto-r/mruby-vedis'

また既存のDebianのNginxに合わせるためnginxビルドのための環境変数を下記のように設定します。

$ export NGINX_CONFIG_OPT_ENV="--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=www-data --group=www-data \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_stub_status_module \
--with-http_auth_request_module \
--with-threads \
--with-stream \
--with-stream_ssl_module \
--with-http_slice_module \
--with-file-aio \
--with-http_v2_module"

設定が終われば、build.shを実行します。

$ bash build.sh

問題なく終了すれば、(現時点で最新1.11.7!nginxの)ソースがビルドされ、mrubyが組み込まれたものがbuild/nginx-[NGINX_VERSION]/objsにできています。 インストールします。

$ cd build/nginx-1.11.7
$ sudo make install

インストールは終わったら、nginxの状況を確認します。

$ sudo -i
# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: [emerg] mkdir() "/var/cache/nginx/client_temp" failed (2: No such file or directory)
nginx: configuration file /etc/nginx/nginx.conf test failed

私の環境では上のようなエラーが表示されましたが、原因はなぜかディレクトリが作成できていないようです。

# mkdir -p /var/cache/nginx/client_temp
# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

できました。念のためnginx -Vでmrubyが組み込まれてビルドしているこを確認してください。

# nginx -V

nginxの設定とmrubyでipを返すコード

さてnginx.confの設定ですが、詳細な設定方法は公式のドキュメントに譲らせていただいて、nginx.confを下記のように書き換えます。

worker_processes  1;
events { }

http {
  server {
    listen       80;

    location / {
      mruby_content_handler_code '
        Nginx.echo("hello")
      ';
    }
  }
}

nginxの起動スクリプトなども用意する必要はありますが、こちらも省略させてもらって下記のように起動します。 defaultで/etc/nginx/nginx.confが設定されるので、-c以降は本来不要ですが・・・。

# nginx -c /etc/nginx/nginx.conf

起動できていれば、curlで以下のようにしてmrubyを確認することができます。

# curl localhost
hello

ようやくexternal ipの取得のコードを組み込みますが、以下のようにすれば良いだけです。簡単ですね。

--- a/nginx.conf
+++ b/nginx.conf
@@ -7,7 +7,8 @@ http {

     location / {
       mruby_content_handler_code '
-        Nginx.echo("hello")
+        req = Nginx::Request.new
+        Nginx.echo(req.var.remote_addr)
       ';
     }
   }

編集が終わればnginxをリロードし、外部からcurlでアクセスすればIPが帰ってきます。

# nginx -s reload

これだけでは芸が無いのでJSONで返すようにしてみます。

--- a/nginx.conf
+++ b/nginx.conf
@@ -8,7 +8,9 @@ http {
     location / {
       mruby_content_handler_code '
         req = Nginx::Request.new
-        Nginx.echo(req.var.remote_addr)
+        hash = {}
+        hash["origin"] = req.var.remote_addr
+        Nginx.echo JSON.generate(hash, {pretty_print: true, indent_with: 2})
       ';
     }
   }

するとこうなります。mruby-iijsonの機能であるpretty_printの指定を有効にしてインデント幅を指定することで綺麗に整形されます。

# curl localhost
{
  "origin": "127.0.0.1"
}

GeoIP組み込み

少し欲をだしてIP情報のGEOIP情報も同時に出してみます。 まずはGeoIPのライブラリが必要ですので、インストールするのですが debian ではGeoIPのデータベースが3種類あり、以下のようになっています。

geoip-database - IP lookup command line tools that use the GeoIP library (country database)
geoip-database-extra - IP lookup command line tools that use the GeoIP library (ASN/city database)
geoip-database-contrib - GeoLite binary database (downloader)

このうち一番情報量が多いのが geoip-database-contrib なのでこちらを採用します。contrib を有効にする必要がありますので、/etc/apt/sources.listの情報を変更します。

--- a/sources.list
+++ b/sources.list
@@ -1,9 +1,9 @@
-deb http://httpredir.debian.org/debian jessie main
-deb-src http://httpredir.debian.org/debian/ jessie main
+deb http://httpredir.debian.org/debian jessie main contrib
+deb-src http://httpredir.debian.org/debian/ jessie main contrib

-deb http://security.debian.org/ jessie/updates main
-deb-src http://security.debian.org/ jessie/updates main
+deb http://security.debian.org/ jessie/updates main contrib
+deb-src http://security.debian.org/ jessie/updates main contrib

 # jessie-updates, previously known as 'volatile'
-deb http://httpredir.debian.org/debian/ jessie-updates main
-deb-src http://httpredir.debian.org/debian/ jessie-updates main
+deb http://httpredir.debian.org/debian/ jessie-updates main contrib
+deb-src http://httpredir.debian.org/debian/ jessie-updates main contrib

編集が終われば以下のようにしてインストールします。

$ sudo apt update && sudo apt install geoip-bin libgeoip-dev geoip-database-contrib

インストールが終わったら、ngx_mrubyをビルドしたディレクトリに戻り nginxビルドのための環境変数を下記のように設定します。 前回からは最後の1行を追加しただけです。

$ export NGINX_CONFIG_OPT_ENV="--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=www-data --group=www-data \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_stub_status_module \
--with-http_auth_request_module \
--with-threads \
--with-stream \
--with-stream_ssl_module \
--with-http_slice_module \
--with-file-aio \
--with-http_v2_module \
--with-http_geoip_module "

次は build_config.rbのGeoIPのモジュールの組み込みでコメントを外します。

--- a/build_config.rb
+++ b/build_config.rb
@@ -45,7 +45,7 @@ MRuby::Build.new('host') do |conf|
   #conf.gem :github => 'mattn/mruby-mysql'

   # have GeoIPCity.dat
-  # conf.gem :github => 'matsumoto-r/mruby-geoip'
+  conf.gem :github => 'matsumoto-r/mruby-geoip'

   # Linux only for ngx_mruby
   # conf.gem :github => 'matsumoto-r/mruby-capability'

修正が終わったら先のビルドで使ったディレクトリを消去してから、再度ビルドを行います。

$ rm -rf build && bash build.sh

ビルドが成功している事を確認して、インストールするのですが、現在動いているnginxはkillしてから行います。

$ cd build/nginx-1.11.7/
$ sudo kill $(pgrep nginx | head -n 1)
$ make install

次にnginx.confの修正ですが、ソースを見るとgeoip_orgが無いようなのでそれ以外について出力してみます。

--- a/nginx.conf
+++ b/nginx.conf
@@ -7,10 +7,25 @@ http {

     location / {
       mruby_content_handler_code '
+        geoip = GeoIP.new "/usr/share/GeoIP/GeoIPCity.dat"
         req = Nginx::Request.new
-        Nginx.echo(req.var.remote_addr)
+        ip = req.var.remote_addr
+
         hash = {}
-        hash["origin"] = req.var.remote_addr
+        hash["origin"] = ip
+        begin
+          geoip.record_by_name(ip)
+        rescue => err
+          hash["error"] = err
+        else
+          hash["country-code"] = geoip.country_code
+          hash["city"]         = geoip.city if geoip.city != "N/A"
+          hash["region"]       = geoip.region if geoip.region != "N/A"
+          hash["region-name"]  = geoip.region_name if geoip.region_name != "N/A"
+          hash["timezone"]     = geoip.time_zone if geoip.time_zone != "N/A"
+          hash["loc"]          = "#{geoip.latitude.round(4)}:#{geoip.longitude.round(4)}"
+        end
+
         Nginx.echo JSON.generate(hash, {pretty_print: true, indent_with: 2})
       ';
     }

これでnginxを再起動して、外からアクセスすると次のような感じで表示されると思います。(サーバ内部からアクセスするとエラーとなりますので、外からアクセスしてください)

$ curl [SERVER-IP]
{
  "origin": "xxx.xx.xxx.xxx",
  "country-code": "JP",
  "city": "Tokyo",
  "region": "40",
  "region-name": "Tokyo",
  "timezone": "Asia/Tokyo",
  "loc": "35.xxxx:139.xxxx"
}

まとめ

ちょっと細かく書きすぎたせいで予定していた分の3割もかけていないのですが、mrubyのソースをインラインで書いているので、修正するたびにnginxのリロードが必要となってますが、別ファイルとするとnginxのリロードは必要とせず、編集すればすぐ反映されるという点もお手軽に試せて良い感じです。今回はそこまでできませんでしたが、難しくはありませんので、試してもらえればと思います。

参考文献

@hsbtさんのnginx 実践入門 9 章の "Lua による nginx の拡張" を ngx_mruby を用いて実現したサンプルコード


Dec 12th, 2016

Linode vs DigitalOcean vs ConoHa

気がつけば7ヶ月ぶりのブログとなってしまった。もう少し頻度をあげようと思っていたのだけど、この体たらくである。ブログのネタを見つける度に少しずつ書いたものがあったりはするのだけど、いつの間にか旬を外していたり、書く気がなくなったりで、ズルズルときてしまった。

というよう相変わらずな状況はさておき、久しぶりなVPSの比較を書いてしまうことにする。

以前行ったのはLinodeとさくらVPSの比較で、2010年12月なので6年ぶりとなる。今回はメインで使っているLinodeDigitalOceanConoHaの三つで比較を行ってみた。

ブログを書くにあたり、$10 Showdown: Linode vs. DigitalOcean vs. Amazon Lightsailを参考に項目追加などを行っているが、オリジナルも是非見て欲しい。比較対象の一つがAmazon LightsailからConoHaになってしまっているが。

比較を行うにあたりリージョンに関しては、LinodeはできたばかりのTokyo2、DigitalOceanは比較的新しいSFO2、ConoHaはJapanをそれぞれ選択し、プランごとの差を吸収するため千円に近いプランをそれぞれ選択した。選択したプラン毎による比較はそれぞれ下記のようになる。

- Linode DigitalOcean ConoHa
メモリ 2GB 1GB 1GB
CPU 1 Core 1 Core 2 Core
ストレージ 24GB SSD 30GB SSD 50GB
転送量 2TB 2TB unlimited
追加転送代金 $0.02/GB $0.02/GB --
帯域 In 40GBbps 1Gbps 100Mbps
帯域 Out 125MBbps 1Gbps 100Mbps
料金 (月あたり) $10/月 $10/月 900円/月
料金 (時間あたり) $0.015/時 $0.015/時 1.3円/時

また比較を行う上でできる限り公平にみるために、全て新規に作成しdebian 8 jessie amd64上で行い、同じsysctlの調整を行っている。

カーネル・CPUの比較

- Linode DigitalOcean ConoHa
uname -r 4.8.6-x86_64-linode78 3.16.0-4-amd64 3.16.0-4-amd64
cpu model name E5-2697 v4 @ 2.30GHz E5-2650L v3 @ 1.80GHz E5-2660 v3 @ 2.60GHz
cpu cache size 4096 KB 30720 KB 4096 KB
cpuinfo gist gist gist

CPU

sysbench --test=cpu run
- Linode DigitalOcean ConoHa
Execution Time 12.7867s 15.0757s 10.7636s
Execution Number of Events 10000 10000 10000
Execution Time Taken by Events 12.7852 15.0714 10.7614
Minimum per Request 1.24ms 1.40ms 1.07ms
Average per Request 1.28ms 1.51ms 1.08ms
Maximum per Request 2.00ms 5.16ms 2.63ms

Memory (read)

sysbench --test=memory run
- Linode DigitalOcean ConoHa
Execution Time 45.0777s 96.9033s 46.1627s
Execution Number of Events 104857600 104857600 104857600
Execution Time Taken by Events 35.1409 75.6979 36.3354
Minimum per Request 0.00ms 0.00ms 0.00ms
Average per Request 0.00ms 0.00ms 0.00ms
Maximum per Request 0.78ms 8.51ms 1.97ms
Transfer per second 2271.63 MB 1056.72 MB 2218.24 MB

Memory (write)

sysbench --test=memory --memory-oper=write run
- Linode DigitalOcean ConoHa
Execution Time 44.6995s 102.0323s 46.5992s
Execution Number of Events 104857600 104857600 104857600
Execution Time Taken by Events 32.8248 78.9135 36.6818
Minimum per Request 0.00ms 0.00ms 0.00ms
Average per Request 0.00ms 0.00ms 0.00ms
Maximum per Request 0.76ms 7.12ms 1.93ms
Transfer per second 2290.85 MB 1003.60 MB 2197.46 MB

File I/O

sysbench --test=fileio prepare
sysbench --test=fileio --file-test-mode=rndrw run
sysbench --test=fileio cleanup
- Linode DigitalOcean ConoHa
Execution Time 1.5128s 4.8597s 4.2003s
Execution Number of Events 10000 10000 10000
Execution Time Taken by Events 0.2035 0.8871 1.5646
Minimum per Request 0.00ms 0.00ms 0.00ms
Average per Request 0.02ms 0.09ms 0.16ms
Maximum per Request 0.54ms 7.04ms 6.47ms
Requests per second 6610.36 MB 2057.74 MB 2380.78 MB

IOPS

ioping [Option] /
- Linode DigitalOcean ConoHa
disk seek rate (-R) 14.8k iops, 57.9 MiB/s 9.63k iops, 37.6 MiB/s 7.16k iops, 28.0 MiB/s
disk sequential speed (-RL) 3.02k iops, 755.1 MiB/s 3.23k iops, 806.9 MiB/s 2.46k iops, 614.4 MiB/s
disk asynchronous I/O (-RA) 14.0k iops, 54.8 MiB/s 10.6k iops, 41.3 MiB/s 6.24k iops, 24.4 MiB/s
disk cached I/O (-RC) 1.10M iops, 4.18 GiB/s 1.02M iops, 3.90 GiB/s 1.41M iops, 5.38 GiB/s
disk direct I/O (-RD) 16.5k iops, 64.4 MiB/s 11.3k iops, 44.1 MiB/s 7.41k iops, 28.9 MiB/s

Network

speedtest-cli --simple --server [NUMBER]

ネットワークスピードのベンチマークには、参考にしたブログと同じ speedtest-cli を利用した。 ベンチマークのターゲットには無指定の場合とつくば市のSoftEtherと石川県美濃市のJAISTの三つで比較した。

- Linode DigitalOcean ConoHa
無指定
Ping 7.277ms 10.454ms 4.054ms
Download Mbit/s 352.69 1409.92 126.14
Upload Mbit/s 57.70 42.71 324.46
つくば市のSoftEther
Ping 44.203ms 492.954ms 76.996ms
Download Mbit/s 393.21 44.91 121.43
Upload Mbit/s 199.99 31.52 709.90
石川県美濃市のJAIST
Ping 164.623ms 153.968ms 21.749ms
Download Mbit/s 391.09 266.47 127.16
Upload Mbit/s 213.18 31.51 519.94

ruby compile speed test

time rbenv install 2.3.3

ソースをダウンロードする時間の影響を排除するために、2回実行して2回目の時間を掲載する。

- Linode DigitalOcean ConoHa
real 6m13.333s 7m40.884s 4m9.846s
user 5m32.687s 6m40.272s 4m42.552s

まとめ

現時点で日本を拠点として3つを比較した場合のコストパフォーマンスを考慮した順位は、ConoHa、Linode、DigitalOceanの順番だろうか。ConoHaは1GBプランでCPUが二つあるのがお得感があり、実際にCPUベンチやrubyのコンパイルスピードでそれが顕著に出ている。メモリの読み書きでもLinodeとConoHaに差はそれほどなく、アメリカの大統領選以降円安に寄っている現状では数百円程度ではあるがConoHaの方が良いようだ。

Linodeはこれまで長い間いっぱいになっていたTokyoリージョンから場所を移して、新宿にオープンしたばかりのTokyo2のリージョンでは、ロケーション的な優位性が見られ、Downloadスピードは安定して350MB以上となっている。翻ってConoHaのUpload速度は謎である。

DigitalOceanはロケーションの優位性がないネットワークスピードに関しては仕方ないにしても、それ以外のベンチマークでもよいパフォーマンスが出ていないので、3社でベンチマークを比較した場合には、格段に落ちる格好となってしまった。だがDigitalOceanの強みは他の所にあるのでまだまだ使い続けるつもり。

ということで3社の比較を書いてみたのだけど、だれかの参考になれば幸いです。


May 17th, 2016

letsencrypt.sh for Let's Encrypt DNS challenge

無料でSSL証明書を発行してくれるサービスのletsencryptには、DNSでドメイン認証を行う方法がありサーバ側は既に対応済みだが、公式のクライアントはまだ問題があるらしく対応していない。公式の代わりにLukas Schauer氏のletsenrypt.shがDNS認証に対応してあるので、それを使ってLetsEncrypt証明書の管理をしている。その備忘録。

hookスクリプト

letsencrypt.shのDNS認証部分については、大まかに下記のような流れになっている。

  • letsencryptのサーバにCommonNameを申請
  • letsencryptのサーバからDNSのテキストレコードに登録する値を取得
  • 取得した値を_acme-challenge.COMMON-NAME.という名前でテキストレコードとしてDNSに登録
  • 登録されたレコードをletsencryptが確認
  • 確認ができれば証明書を発行

この処理について別途追加する必要があり、それぞれのDNS事情にあった認証を行えるようになっている。有名どころなDNSプロバイダについては、有志によってスクリプトが作成されているが、そこからリンクされているroute53のrubyスクリプトはサブドメインを渡した場合に不具合があるので、そのままでは動かなかった。
利用してるものは、もう少し手を加えているが、動くように修正したものが下記。

#!/usr/bin/env ruby

require 'aws-sdk'
require 'domain_name'

# ------------------------------------------------------------------------------
#   Credentials
# ------------------------------------------------------------------------------
# pick up AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY by default from
# environment
Aws.config.update({
  region: 'ap-northeast-1',
})
# ------------------------------------------------------------------------------

def setup_dns(common_name, domain, txt_challenge)
  route53 = Aws::Route53::Client.new()
  hosted_zone = route53.list_hosted_zones_by_name(
      {dns_name: "#{domain}."}).hosted_zones[0]
  changes = []
  changes << {
    action: "UPSERT",
    resource_record_set: {
      name: "_acme-challenge.#{common_name}.",
      type: "TXT",
      ttl: 60,
      resource_records: [
        value: "\"#{txt_challenge}\"",
      ],
    },
  }
  resp = route53.change_resource_record_sets({
    hosted_zone_id: hosted_zone.id,
    change_batch: {
      changes: changes,
    },
  })
  sleep 20
end

def delete_dns(common_name, domain, txt_challenge)
  route53 = Aws::Route53::Client.new()
  hosted_zone = route53.list_hosted_zones_by_name(
      {dns_name: "#{domain}."}).hosted_zones[0]
  changes = []
  changes << {
    action: "DELETE",
    resource_record_set: {
      name: "_acme-challenge.#{common_name}.",
      type: "TXT",
      ttl: 60,
      resource_records: [
        value: "\"#{txt_challenge}\"",
      ],
    },
  }
  resp = route53.change_resource_record_sets({
    hosted_zone_id: hosted_zone.id,
    change_batch: {
      changes: changes,
    },
  })
  sleep 10
end

if __FILE__ == $0
  hook_stage = ARGV[0]
  common_name = ARGV[1]
  txt_challenge = ARGV[3]

  domain = DomainName(common_name).domain

  puts "   hook_stage: #{hook_stage}"
  puts "  common_name: #{common_name}"
  puts "       domain: #{domain}"
  puts "txt_challenge: #{txt_challenge}"

  if hook_stage == "deploy_challenge"
    setup_dns(common_name, domain, txt_challenge)
  elsif hook_stage == "clean_challenge"
    delete_dns(common_name, domain, txt_challenge)
  end

end

rubygemのaws-sdk最新版とdomain_nameが必要。

このスクリプトではhook_stagedeploy_challengeclean_challengeの場合の処理しか無いが、証明書作成ができた時点にもhook_stagedeploy_certが指定され、txt_challengeに作成された証明書のpathが指定されて、このhookスクリプトが呼ばれる。

letsencrypt.sh 利用方法

letsencrypt.shのインストールおよび利用方法について、簡単にまとめておく。 /etc/letsencrypt.shを基準とするようにしてある。

cd /etc
git clone https://github.com/lukas2511/letsencrypt.sh
cd letsencrypt.sh

同じディレクトリ上にconfig.shがあれば、スクリプト実行時にデフォルト値として動作するようになっているので、作成しておく。 CHALLENGETYPEをdns-01、RENEW-DAYSは45日、秘密鍵は毎回再作成、hookスクリプトの指定を行っている。

CA="https://acme-v01.api.letsencrypt.org/directory"
LICENSE="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf"
CHALLENGETYPE="dns-01"
HOOK="/etc/letsencrypt.sh/hook.rb"
HOOK_CHAIN="no"
RENEW_DAYS="45"
ACCOUNT_KEY="/etc/letsencrypt.sh/private_key.pem"
ACCOUNT_KEY_JSON="/etc/letsencrypt.sh/private_key.json"
KEYSIZE="4096"
WELLKNOWN="/etc/letsencrypt.sh/.acme-challenges"
PRIVATE_KEY_RENEW="yes"
OPENSSL_CNF="/usr/lib/ssl/openssl.cnf"
CONTACT_EMAIL=""
LOCKFILE="/etc/letsencrypt.sh/lock"

同様にdomains.txtが同じディレクトリにあれば、記載してあるコモンネームを利用するようになっていて、1行に1証明書で作成される。1行に複数のコモンネームを指定可能で、複数のコモンネームを1枚の証明書で作成できるようになっている。以下は実際に作ったサンプル。

d6rkaiz.com mta.d6rkaiz.com blog.d6rkaiz.com
deny.jp mta.deny.jp

実際の運用には下記のようなスクリプトを作成し、cronで毎月1回実行している。

#!/bin/bash

PATH=/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LEDIR=/etc/letsencrypt.sh

set -e
tagname="letsencrypt_renew"

${LEDIR}/letsencrypt.sh -c -x | logger -t ${tagname}
${LEDIR}/letsencrypt.sh -gc | logger -t ${tagname}

svcs="nginx postfix dovecot"
for svc in ${svcs}
do
  service $svc restart | logger -t ${tagname}
done

Next page