VPS に VPN サーバをたてて iPhone からアクセス(第1回)

レンタル VPS で VPN サーバを動かして iPhone からのネットアクセスをセキュアにする(ついでに自宅 LAN にリモートアクセスできるようにする)というお話の第1回です。今回は VPN について調べたことなどをご紹介します。具体的な構築作業については次回から。

まえがき

以前から、外出先で iPhone を使うときのネットアクセスの安全性が気になっていました。4G LTE 回線を使った通信は、まぁ、ちゃんとした通信事業者の専用回線を使っているわけなので、あまり心配していません(HTTP 通信の中身を見て画像データを勝手に圧縮したり、特定の Web サービスとの通信を識別して課金操作したり、特定のプロトコルの通信を遮断したりと、不安要素はありますが)。問題なのは、公衆無線 LAN (Wi-Fi) を使うときです。

最近は HTTPS (SSL/TLS) が普及してきたので Google とか Twitter とか使うぶんにはあまり気にしなくても良いのですが、一般の Web サイトは HTTPS 化されていないことも多いです(特に日本国内の Web サイトは遅れている印象)。あと、DNS は暗号化されていないので、「どこのサーバにアクセスしたか」はバレバレです。アクセスを遮断される可能性や、ニセのサーバに誘導される危険もあります。これに関して DNSSEC は役に立ちません(目的が違う)。ちなみに、有名な Google Public DNS では独自の “DNS-over-HTTPS” というサービスを提供しているそうです。

そんなわけで、iPhone からのネットアクセスを VPN で保護したいなぁ、と思いつつ先延ばしになっていたのですが、先日、Impress INTERNET Watch で VPN サービスの紹介記事を読みました。

記事を読んで思ったのですが、特定の企業(しかも通信事業者じゃない)にすべての通信を預けてしまうのは、ちょっとイヤ。使用している通信プロトコルの詳細は非公開だろうし、アプリやサーバの実装の安全性も不透明です。しかも有料。

今まで VPN についてちゃんと調べたことはなかったのですが、一般論として、「固定のグローバル IP アドレスを持つ Linux サーバ」があれば、おそらく VPN サーバをたてられるんじゃないかと思っていました。そして、タイミングのいいことに、実験用にレンタルしている VPS が余っていました(しばらく使っていなかったので解約しようかと思ってた)。

諸事情により時間的な余裕もあったので、VPN の構築にトライ!

VPN とは?

注:この連載記事で言う「VPN」は、正しくは「インターネット Layer 2 VPN」のことです。

VPN (Virtual Private Network) は、既存の TCP/IP ネットワークの上にセキュアな Layer 2 通信路を構築する技術です。「既存の TCP/IP ネットワーク」というのは、たいてい、インターネットのことを指しますが、大きな組織の内部ネットワークで特定の部門間を繋ぐ場合も話は同じです。「Layer 2 通信路」というのは OSI 参照モデルの第2層(データリンク層)のことで、ふつうに言えばイーサネット (Ethernet) のことです。つまり、VPN は、異なる Ethernet ネットワークに存在している機器の間で、インターネットを経由した Ethernet 通信ができるようにする技術です。

通常、Ethernet のパケット(正確には「フレーム」)はルータを越えられません。ひとつの Ethernet スイッチ/ハブに接続している機器どうし、あるいはカスケード接続された複数の Ethernet スイッチ/ハブのいずれかに接続している機器の間で、直接 Ethernet フレームを送受信します。この「直接 Ethernet フレームをやりとりできるネットワーク」のことを Ethernet 用語では「セグメント」と呼びます。TCP/IP で「サブネット」と言ったときは、多くの場合、この「セグメント」のことを指しています(階層的な大規模ネットワークでは違います)。また、「LAN」(Local Area Network) という言葉もほぼ同義語です(定義は曖昧ですが)。

Ethernet ブリッジというものがあります。ふたつのセグメントをブリッジで接続すると、単一のセグメントとして使うことができます。スイッチ/ハブをカスケード接続したのと同じようなネットワーク構成になります。スイッチ/ハブとの違いと言えば、ブリッジは通常2個のポートしか持たず、ふたつのセグメントを接続する役目に特化している、という点くらいでしょうか。実際のところ、物理的にネットワークを構築するときにブリッジを使うことはほとんと無いでしょう。しかし、VPN を構築するときには「ブリッジ」という用語がよく出てきます。

VPN を使うと、複数の物理的なセグメントを、単一のセグメントにすることができます(仮想ブリッジ機能)。また、セグメントの外に存在する機器を、そのセグメントに接続されているように機能させることもできます(リモートアクセス機能)。

VPN を使うための第一条件は、VPN で接続させたい機器どうしで直接、あるいは仲介する VPN サーバとそれぞれの機器の間で、TCP/IP 通信が可能なことです。後者の場合、複数の VPN サーバを連携させることも可能なので、同じ VPN サーバへの TCP/IP 通信が必須というわけではありません。また、別の条件として、VPN で接続させたい機器の片方、あるいは仲介する VPN サーバが、固定のグローバル IP アドレスを持っていることが望ましいです。しかし、この条件は回避する手段があるので、必須条件ではありません。これらの条件は使用する VPN 方式によって異なります。

VPN にもいろいろある

ひと言で「VPN」と言っても、様々な方式があります。また、それぞれの方式には、複数の実装(その方式を実現するためのハードウェアやソフトウェア)があります。ひとつの実装で複数の方式に対応しているものもあります。方式や実装の違いにより、実現可能なネットワーク構成や、VPN 接続する機器に対する条件、通信の安全性・安定性・速度などが異なります。

メジャーな VPN の方式には以下のようなものがあるみたいです:

  • PPTP
  • L2TP/IPsec (L2TPv3 over IPsec)
  • EtherIP over IPsec
  • OpenVPN
  • IKEv2
  • MS-SSTP
  • SoftEther VPN

これらの比較記事もあります:

VPN の実装もいろいろあります:

  • ハードウェアによる実装
    • Cisco などの企業向けルータ
    • NEC などのホームルータ
  • ソフトウェアによる実装
    • OpenVPN
    • strongSwan
    • SoftEther VPN
    • OS 組み込みのクライアント機能(Windows / macOS / iOS / Android 等)

この連載記事では、サーバとして SoftEther VPN Server の Linux 版を、クライアント機器として iPhone と Windows PC を使います。

VPN でやりたいこと

今回、VPN を構築して実現したいことは、次の3点です:

  1. iPhone からのネットアクセスを VPN サーバ経由にして暗号化。
    https://ja.softether.org/4-docs/2-howto/5.VPN_for_Home/2.Comfortable_Network_Anywhere
    ただし、VPN サーバは自宅ではなくクラウド (VPS) に設置。
  2. iPhone から自宅の Windows PC にリモートアクセス。
    https://ja.softether.org/4-docs/2-howto/1.VPN_for_On-premise/1.Ad-hoc_VPN
  3. iPhone から自宅 LAN にリモートアクセス。
    https://ja.softether.org/4-docs/2-howto/5.VPN_for_Home/1.Remote_Access

3番目の意図は、自宅 LAN 上にある(VPN クライアント機能のない)機器にもリモートアクセスしたい、というものです。たとえば NAS とか。

xyzzy めも

xyzzy は Windows 上で動く Emacs 風なテキストエディタです。

EmacsLisp の代わりに CommonLisp を使います。

markdown-mode

xyzzy/site-lisp/siteinit.l に以下の行を追加。

1
2
(load-library "markdown-mode")
(push '("\\.md$" . markdown-mode) *auto-mode-alist*)

C# はじめました

以前から作りたいと思っていたプログラム(+Web サービス)が
意外に簡単にできそうなことが判明したので、
トライしてみることにしました。

作りたいプログラムは C# で作られたソフトウェアのプラグインなので、
まずは C# のお勉強です。

C# は過去に何回か大きな進化があった、という知識だけはあったので、
できるだけ新しい本で勉強したいところ。
ちょっと調べてみると、他言語習得済みのプログラマに好評な本がありました。

猫でもわかるC#プログラミング 第3版    
粂井 康孝 (著) / SBクリエイティブ    
3版 (2016/2/27)    
https://www.amazon.co.jp/C-3-ebook/dp/B01C804DL6/

初めてマンガ以外の電子書籍を買いました。しかも Kindle です。
タブレットは持っていないので PC で読むわけですが、
本当に長文を読めるのか、かなり不安でした。

結果、あっさり読めました。

読むスピードも紙媒体に比べて特に遅いという印象はありませんでした。
まぁ、内容が簡単だった、ということもあるかもしれませんが。

以下、感想。

本書は、プログラミング初心者にはちょっと厳しい本かもしれません。
オブジェクト指向言語の基本概念やインタフェースの存在意義などの
詳しい説明は無く、ほぼ構文のみの説明になっています。
Java か C++ あたりの知識がないとたぶん理解できません。
逆に言うと、他言語習得済みのプログラマには便利だと思います。

とりあえず本書で概要を把握して、あとはリファレンス本で詳細を学ぶのが早そう。

C# についての印象:

  • オーバーライドの構文が不自然。
    newoverridevirtual の必要性が不明。
    C++ の virtual は関数呼び出しオーバヘッドの削減のためと認識していますが、
    C# に果たしてそこまでの性能追求が必要なのか疑問。
    逆に sealed って書かせたほうが統一感があってよかったのでは?
  • 複数のインタフェースを継承したとき同じシグネチャのメソッドがあると、
    それぞれのインタフェースに対して実装を書かないといけないのがよくわからない。
    あるクラスのあるシグネチャのメソッドは、単一の機能を持つべきではないの?
  • switch 文が fall through 禁止なのに break 文が必須なのが意味不明。
  • ビット演算子の優先順位が低い。C言語の悪いところをマネしなくていいのに・・・。
  • checked / unchecked 機能はちょっとうれしいかも。
  • ジェネリックの反変性がよく理解できなかった。要調査。

とりあえず C# の概要はわかったので、
Visual Studio 2015 をインストールして遊んでみるつもりです。

pagenation を無効化したい

Hexo の過去記事ページ (archives) やタグごとのページで
pagenation (複数ページへの分割)をやめたい。

デフォルトでこの機能はあって、_config.yml で設定可能です。

アーカイブページの pagenation を無効化する

https://github.com/hexojs/hexo-generator-archive

1
2
3
4
5
archive_generator:
per_page: 0
yearly: true
monthly: true
daily: false

Tags ページの pagenation を無効化する

https://github.com/hexojs/hexo-generator-tag

1
2
tag_generator:
per_page: 0

Markdown の改行を無視してほしい

Hexo (というか Markdown 一般)で文章を書いているとき、
段落の途中で改行を入れることが普通にあります。
物理的な1行が長すぎるとテキストエディタで扱いにくいし、
git の diff も見づらくなってしまいます。

Hexo の Markdown 処理系は、ひとかたまりのテキスト(空行を区切りとする一段落)を
ひとつのパラグラフ(HTML の p 要素)に変換してくれます。
このとき、元のソースファイルの改行をそのまま保存して HTML に出力します。

例)

1
2
今日はいい天気ですね。
明日も晴れるでしょうか?

1
2
<p>今日はいい天気ですね。
明日も晴れるでしょうか?</p>

さて、これはこれで一見すると問題無さそうですが、
現状の Web ブラウザでは、通常、改行が半角スペースとして解釈されてしまいます。

今日はいい天気ですね。 明日も晴れるでしょうか?

厳密に言うと、CSS の white-space プロパティの値とその解釈に依存していて、
通常の設定 (white-space: normal) ではブラウザがコンテキストに従って
「よきに計らって」くれることになっているのですが(半角スペース1個と解釈せずに
削除してしまってもよい)、まぁ、そこは CJK 文字圏のマイナーさということで、
Firefox とか Google Chrome とかは無条件で改行文字を半角スペースに変換します。
https://www.w3.org/TR/CSS2/text.html#white-space-prop

ちなみに CSS3 (CSS Text Module Level 3) のドラフトでは、
中国語・日本語・Yi 文字に挟まれた改行(や半角スペースなど)は
無視するように明記されています(期待!)
https://drafts.csswg.org/css-text-3/#propdef-white-space

閑話休題。

Hexo には、この問題を解決するためのプラグインがあります。
https://github.com/lotabout/hexo-filter-fix-cjk-spacing

導入は簡単で、単に NPM パッケージをインストールするだけです。

1
$ npm install hexo-filter-fix-cjk-spacing --save

あとは普通に hexo server とか hexo generate とか hexo deploy とかすれば、
自動的に日本語文字間の改行を削除してくれます。
原稿(Markdown ソースファイル)には手を加える必要がありません。

作者の Jinzhou Zhang さん に感謝!

なお、
この記事の話は _config.ymlbreaks: false を指定している前提です。
breaks: true の場合はそもそも「ソースファイルの改行をそのまま反映してください」
という意味になるので、
ソースファイルの改行ごとに自動的に HTML の <br /> 要素が追加されます。

Perl めも

導入

1
2
3
4
5
6
7
8
9
10
$ \curl -L https://install.perlbrew.pl | bash
$ echo 'source ~/perl5/perlbrew/etc/bashrc' >> ~/.bashrc
$ bash
$ perlbrew list
$ perlbrew available
$ perlbrew available | grep -E '^ perl-5\.[1-9]?[02468]\.' | nice -19 xargs -n 1 perlbrew install
$ perlbrew list
$ perlbrew switch perl-5.24.1
$ perl -v
$ perlbrew install-cpanm

アップデート

1
$ perlbrew self-upgrade

CPAN モジュールのローカルインストール

1
$ cpanm -L lib URL::Encode

おやくそく

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env perl

use strict;
use warnings;
use utf8;

use lib './lib/lib/perl5';

use Carp qw/confess/;

use Data::Dumper;
$Data::Dumper::Purity = 1;

定数を使う

http://d.hatena.ne.jp/fbis/20090612/1244806476

1
2
3
4
5
6
7
8
9
10
11
use constant DNS_SERVER_LIST => [
'8.8.8.8', # Google Public DNS
'8.8.4.4', # Google Public DNS
'' # default
];
use constant DNS_ROUND_ROBIN_LIMIT => 10;

my @result;
foreach my $server (@{DNS_SERVER_LIST()}) {
push(@result, nslookup($fqdn, $server, DNS_ROUND_ROBIN_LIMIT));
}

Encode モジュールの罠

Encode::encode()Encode::decode() で第3引数に Encode::FB_CROAK
を指定すると、第2引数に指定した文字列を破壊するらしい。

CAVEAT: the input scalar STRING might be modified in-place depending on what is set in CHECK.

したがって、次のようにやると元の文字列 @nslookup_raw が破壊されます。
実際には、長さゼロの文字列の配列になってしまいました。

1
2
3
4
5
my @nslookup_raw = `nslookup -type=A $host 2>&1`;
my @nslookup =
map {s/\r?\r\n$/\n/; $_}
map {use Encode qw/decode/; decode("shiftjis", $_, Encode::FB_CROAK)}
@nslookup_raw;

とりあえず次のように定義して使うのが安全っぽい。

1
2
3
4
5
6
7
8
9
sub decode {
use Encode qw//;
return Encode::decode("shiftjis", shift, Encode::FB_CROAK | Encode::LEAVE_SRC);
}

sub encode {
use Encode qw//;
return Encode::encode("UTF-8", shift, Encode::FB_CROAK | Encode::LEAVE_SRC);
}

半角カナを全角カナに変換

1
2
3
4
sub hankaku2zenkaku {
use Lingua::JA::Regular::Unicode;
return katakana_h2z(shift);
}

encodeURIComponent

1
2
3
4
sub encode_uri_component {
use URL::Encode qw//;
return URL::Encode::url_encode_utf8(shift);
}

SSH 鍵の新規作成

新規に SSH 鍵を作成したので、メモ。

上記最後の IPA の PDF の p.14-15 の表をみると、
米国 NIST では 2031 年以降は、3072bit 以上の RSA か、
256bit 以上の ECDSA か、どちらかしか推奨しないらしい。

2017/Jan/22 時点での GitHub のオススメは RSA 4096bit のようです。
https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/

古いプログラムとの互換性とか考えなければ ed25519 が安心で高速で最強らしい。

鍵の生成

とりあえず鍵はひととおり作っておく:

1
2
3
4
5
6
7
8
9
10
$ ssh-keygen -o -a 100 -t rsa -b 4096 -C 'hoge@example.com'
$ ssh-keygen -o -a 100 -t ecdsa -b 521 -C 'hoge@example.com'
$ ssh-keygen -o -a 100 -t ed25519 -C 'hoge@example.com'
$ chmod 400 ~/.ssh/id_*
$ chmod 444 ~/.ssh/id_*.pub
$ ssh -V > ~/.ssh/memo.txt 2>&1
$ uname -a >> ~/.ssh/memo.txt
$ \grep '^VERSION=' /etc/os-release >> ~/.ssh/memo.txt
$ date >> ~/.ssh/memo.txt
$ chmod 400 ~/.ssh/memo.txt

ちなみに、ed25519 の場合は -b オプションは無視されます
man ssh-keygen 参照)。
実際に生成された鍵を確認すると 256bit 固定のようです。

秘密鍵ファイルが漏れたときの保険として、round 回数 100 にしました。
これで、実際に秘密鍵ファイルを解読するときは1秒くらい待たされます。

あとは相手の ~/.ssh/authorized_keys に自分の id_ed25519.pub
の中身(1行だけ)を追加すれば OK です。

なお、ローカルに複数の鍵ファイルがある場合、
基本的には SSH クライアントは自動選択してくれるらしいですが、
もしダメなときは ed25519 を指定できるみたいです:

1
$ echo 'IdentityFile ~/.ssh/id_ed25519' >> ~/.ssh/config

もし本当に「ed25519 以外は使わない」としたい場合:

1
$ echo 'IdentitiesOnly yes' >> ~/.ssh/config

詳しくは man ssh_config 参照。

ちなみに、GitHub に対して git コマンドを試すと、自動選択してくれました。

今の SSH 鍵の確認

1
$ \ls ~/.ssh/id_*.pub | xargs -n 1 ssh-keygen -l -f

行の先頭が鍵のビット長、行の最後がアルゴリズム名です。

GitHub 疎通確認

https://help.github.com/articles/testing-your-ssh-connection/

1
2
3
4
$ ssh -T -p 22 -i ~/.ssh/id_ed25519 git@github.com
Enter passphrase for key '/home/hoge/.ssh/id_ed25519':
Hi seaoak! You've successfully authenticated, but GitHub does not provide shell access.
$

追記)
Windows の Sshfs Manager (ver 1.5.12.8) は、
新しい秘密鍵ファイル形式に対応していませんでした。
残念。

追記)
WinSCP (ver 5.9.3) は OpenSSH の新しいファイル形式に対応していませんでした。
使おうとすると PuTTY 形式 (.ppk) に変換しようとしてしまいます。
なので、ed25519 が使えるかどうかは未確認。

Ruby めも

Web サーバ H2O の設定には mruby を使うので、
H2O の設定ファイル h2o.conf を生成する自前の YAML トランスレータ(?)も
Ruby で書いてみることにしました。
Ruby 書くのなんて何年ぶりだろう・・・・。

で、ハマったのが、String#match の挙動です。Regexp#match と同じハズ。
https://docs.ruby-lang.org/ja/2.4.0/class/String.html#I_MATCH
https://docs.ruby-lang.org/ja/2.4.0/method/Regexp/i/match.html

第2引数として pos が渡せるのですが、pos0 以外の値を渡した場合、
「文字列先頭にマッチする正規表現」(つまり ^\A)は絶対にマッチしません

1
2
3
$ ruby -e 'p "abc".match(/^./, 1)'
nil
$

ドキュメントに書いておいてほしかったなぁ。

HSTS の導入

独自ドメイン seaoak.jp を独自サーバに移行している中で、
HSTS (HTTP Strict Transport Security) をいう技術を知りました。

もともと全コンテンツを HTTPS 化するつもりだったので、
HSTS も導入したいところです。

せっかくなので、各ブラウザの HSTS Preload List に登録してもらいたい。
そのためには、以下が必要っぽい:

最終的に、h2o.conf に次の1行を追加すればよいと思われます:

1
header.set: "Strict-Transport-Security: max-age=63072000; includeSubDomains; preload"

なお、https://hstspreload.org/ に何回も繰り返し書かれているように、
安易に preload 指定するのは避けたほうがよさそうです。
いったん HSTS Preload List に掲載してしまうと、
HTTPS 化できないサブドメインがどうしても必要になった時に非常に困ります。
https://hstspreload.org/#removal

とりあえず、しばらくは様子見ですね。

Let's Encrypt の導入(root 権限なし)

独自ドメインを全面的に HTTPS 化するべく、
無料で発行してもらえる Let’s Encrypt のサーバ証明書を導入しました。

ドキュメントによるとサーバの root 権限が必要とのことですが、
個人的な趣味としてそれは避けたい。

  • Web サーバを実行するユーザに sudo 権限を与えたくない
  • Web サーバの設定ファイルを自動的に書き換えられるのはイヤ(そもそも H2O は非対応ですが)
  • 証明書ファイル (key file / cert file) はローカルに作成できれば十分

というわけで、なにか手を考えないといけません。

Certbot のドキュメントで、
root 権限を使わない ACME client が紹介されています:

README を読むと letsencrypt-nosudo は root 権限での手作業が必要とのことなので、
全自動化できそうな simp_le を試しました。

まず、各ドメインのドキュメントルートの直下に
.well-known というディレクトリがあり(なければ作り)、
そのディレクトリへの書き込み権限があることが前提です。
また、そのディレクトリ内のファイル/ディレクトリに対して外部から
(Let’s Encrypt のサーバから)
TCP 80 番ポートで HTTP GET できなければなりません。
HTTPS ではないので注意。
全面的に HTTPS 化する場合、すべての HTTP アクセス(80番ポート)を
HTTPS (443番ポート)に 301 リダイレクトすることがあると思いますが、
/.well-known 配下へのアクセスだけはリダイレクトから除外します。
H2O の場合、h2o.conf で次のようにします:

1
2
3
4
5
6
7
8
9
10
11
12
13
hosts:
"example.com:443":
paths:
"/":
file.dir: /path/to/doc-root
"example.com:80":
paths:
"/":
redirect:
url: "https://example.com/"
status: 301
"/.well-known":
file.dir: /path/to/doc-root/.well-known

ちなみに、H2O ではデフォルトで /.well-known 配下がそのまま見えました。
H2O は隠しファイル(名前がドットで始まるもの)を特別扱いしないようです。

さて、ここからは simp_le のインストールの話です。

simp_le の公式ドキュメントでは bootstrap.sh
root 権限 (sudo) で実行するようにと書かれていますが、
中身は apt-get install だけなので、手動でやれば十分です
(ここだけ root 権限が必要ですすみません)。
また、今回は pyenv / pyenv-virtualenv を利用したかったので、
venv.sh も中身を見て手動で実行しました。

python の初期設定については過去記事「Python の導入(root 権限なし)」を参照してください。

まず、bootstrap.sh 相当のことを手動でやる:

1
2
3
4
5
$ sudo apt-get install -y ca-certificates gcc libssl-dev libffi-dev python python-dev
$ cd
$ git clone https://github.com/kuba/simp_le.git
$ cd simp_le
$ pyenv shell 2.7.13

次に、venv.sh 相当のことを手動でやる:

1
2
3
4
5
6
7
8
9
10
11
12
$ pyenv virtualenv --no-site-packages venv-simp_le
$ pyenv virtualenvs
$ pyenv versions
$ pyenv local venv-simp_le
$ pyenv virtualenvs
$ pyenv versions
$ pyenv exec pip list
$ pyenv exec pip install -U setuptools
$ pyenv exec pip install -U pip
$ pyenv exec pip install -U wheel
$ pyenv exec pip install -e .
$ pyenv exec pip list

PATH はすでに通ってるので、設定不要でした。

ヘルプはちゃんと読みましょう:

1
$ simp_le --help

以上で simp_le のインストールは完了です。

続いて、証明書を新規に取得します。

解説記事を読むと
account_key.json をあらかじめ用意しないといけないように思えますが、
不要です。
-f オプションで指定するファイルはすべて simp_le が生成してくれます。
simp_le を最初に実行するディレクトリは空でよい。

1
2
3
4
5
$ cd ~/h2o
$ mkdir letsencrypt
$ cd letsencrypt
$ pyenv local venv-simp_le
$ simp_le -v --email 'foobar@example.com' -f account_key.json -f cert.pem -f chain.pem -f fullchain.pem -f key.pem -d example.com:../doc-root-1 -d www.example.com:../doc-root-2 -d blog.example.com:../doc-root-3

ここで、エラーになってしまいました。

1
2
3
4
5
DeserializationError: Deserialization error: Wrong directory fields

Unhandled error has happened, traceback is above

Debugging tips: -v improves output verbosity. Help is available under --help.

GitHub の Issue#114 に従って --tos_sha256 オプションを追加してみる:
https://github.com/kuba/simp_le/issues/114#issuecomment-236744611

1
$ simp_le -v --tos_sha256 6373439b9f29d67a5cd4d18cbc7f264809342dbf21cb2ba2fc7588df987a6221 --email 'foobar@example.com' -f account_key.json -f cert.pem -f chain.pem -f fullchain.pem -f key.pem -d example.com:../doc-root-1 -d www.example.com:../doc-root-2 -d blog.example.com:../doc-root-3

しかし変わらず。

ここで、GitHub の Issue を追っていると、
Fork して修正してくださったものを見つけました。感謝!!

https://github.com/zenhack/simp_le

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ cd
$ pyenv virtualenv-delete venv-simp_le
$ rm -rf simp_le
$ git clone https://github.com/zenhack/simp_le.git
$ cd simp_le
$ pyenv virtualenv --no-site-packages 2.7.13 venv-simp_le
$ pyenv virtualenvs
$ pyenv versions
$ pyenv local venv-simp_le
$ pyenv virtualenvs
$ pyenv versions
$ pyenv exec pip list
$ pyenv exec pip install -U setuptools
$ pyenv exec pip install -U pip
$ pyenv exec pip install -U wheel
$ pyenv exec pip install -e .
$ pyenv exec pip list
$ cd ~/h2o/letsencrypt
$ ls -a ←中身は `.python-version` のみ
$ simp_le -v --email 'foobar@example.com' -f account_key.json -f cert.pem -f chain.pem -f fullchain.pem -f key.pem -d example.com:../doc-root-1 -d www.example.com:../doc-root-2 -d blog.example.com:../doc-root-3

今度は成功! インタラクティブな問い合わせとか無くて、全自動で完了です。

カレントディレクトリに -f オプションで指定した5個のファイルが生成されています。

1
2
3
4
5
6
7
$ ls -1
account_key.json
cert.pem
chain.pem
fullchain.pem
key.pem
$

あとは h2o.conf に次のように指定してあげて kill -HUP すれば OK。

1
2
3
4
5
listen:
port: 443
ssl:
certificate-file: letsencrypt/fullchain.pem
key-file: letsencrypt/key.pem

ついでに自動更新スクリプトも作成。
解説記事の update_cert.sh を参考にさせていただきました。

update_cert.sh.20170113a.txt

rotatelogs コマンドが無い人は apt-get install -y apache2-utils で入ります。

Certbot のドキュメントで一日2回やることを推奨しているので、crontab を設定:
https://certbot.eff.org/#ubuntuxenial-other

1
2
3
4
$ crontab -l
13 10 * * * /home/foobar/h2o/letsencrypt/update_cert.sh
37 23 * * * /home/foobar/h2o/letsencrypt/update_cert.sh
$

以上、root 権限なしで Let’s Encrypt のサーバ証明書が取得できました。