OpenVPN (Tunnelblick) からサーバに接続できなくなったときの対処法

Tunnelblick を使って OpenVPN サーバに接続していましたが、先日 Tunnelblick のアップデートを行ったところ、VPN サーバに接続できなくなってしまいました。

VPN サーバが落ちたのかなと思い、iPhone からアクセスしてみたところ今まで通り問題なく接続することができました。

最初は Tunnelblick のアップデートでバグを踏んでしまったかと思っていたのですが、エラーログを見て調べたところ、どうやら Tunnelblick のバグではなくクライアント端末のネットワークの設定に問題があるということがわかりました。

OpenVPN error: write UDPv4: Can’t assign requested address

この記事を参考に僕が実際に行った解決手順をメモとして残しておきます。

まずはクライアント端末のネットワークインターフェースを確認します。

$ sudo ifconfig

出力された結果の中に en0en1 というのがあるはずなのでそれを確認します。en0, en1status を確認して、active となっている方が現在接続しているネットワークです。statusactive のインターフェースには inet にグローバル IP アドレスが割り振られているのが確認できます。(ちなみにグローバル IP アドレスを調べるには noraworld.net にアクセスします。)

上記参考サイトでは、デフォルトでは en0イーサネットインターフェースで、en1 がワイヤレスインターフェースと書かれていますが、僕の環境では逆だったので ifconfig コマンドで確認したほうが無難です。

statusactive だったほうのインターフェースを切ってルーティングをし直します。

$ sudo ifconfig en0 down
$ sudo route flush
$ sudo ifconfig en0 up

上記コマンドの例では en0 を指定していますが、en1active だった場合は en1 に変えてください。

これでルーティングが再構成されました。ネットワーク(Wi-Fi 等)に再接続されるはずなので、接続されるまで待ちます。

その後、Tunnelblick から VPN 先に接続できれば OK です。お疲れさまでした。

ちなみにこれでもうまくいかない場合は Wi-Fi を切って sudo route flush を実行して Wi-Fi に再接続してから試してみてください。

OpenVPN Connect の Seamless tunnel について

はじめに

OpenVPNを使用してiPhoneVPN接続しているのだが、スリープ中は切れてしまったり、なぜか一日に一回くらいの頻度で勝手にVPNの接続がオフになってしまったりして、どうも安定しないので、調べてみたことの話。

設定の変更方法

iPhoneの"設定"アプリを開き、最初のページを下までスクロールするとインストールしたアプリ一覧が出てくるので、そこから"OpenVPN"を探してタップする。

OpenVPN Connect アプリを開いてもほとんど設定をいじることはできない。そしてこの設定はアプリを開いても何もアナウンスされないので意外と気づきにくい。

Seamless tunnel

iPhoneでのVPN接続がよく切れるので調べていたら、設定の “Seamless tunnel (iOS8+)” という項目をオンにするという解答が多かった。これはデフォルトではオフになっている。Seamless tunnel がよくわからなかったので調べたら海外のこちらのサイトにはこう書かれていた。

For keeping the VPN tunnel active during pause, resume, and reconnect states go to “Settings” → “OpenVPN” and turn on “Seamless tunnel”. Also set “Connection timeout” to “None” value:

“keep active” なのでスリープ中でもずっとVPNに接続している的な意味合いなのだろうと思い、とりあえずオンにしておいた。

オンにしたあとにスリープしたりすると、前と変わらずVPNの接続は切れてしまった。オンにしたときはVPNに接続されていた状態だったので、設定が反映されていなかったのかもしれない。自分の環境ではなぜか一日に一回くらいの頻度でVPNが勝手にオフになる(手動でオンにしないといけない)ので、VPNに再接続した。

VPN接続がオフになった状態から再接続して設定が反映されたのか、スリープしても切れなくなったように感じる。「感じる」というのは、ときどき長くて3時間くらい接続されていてもやっぱり切れてしまったし、一日に一回接続がオフになってしまう現象が解消されたかはまだ未検証なので断言はできない。

この記事を書く直前までは、スリープ中に切れなくなった(ような気がする)ことには気付いておらず、それよりも、Seamless tunnel をオンにしてVPNに再接続したあとに、外出してWi-Fiからモバイル通信(4G, LTE, 3G 等)に切り替わったときにVPNが切れていないことに気付いた。

今まではWi-Fiからモバイル通信、モバイル通信からWi-Fiに切り替わるときにVPNが一時的に切断されてしまっていた。その場合は自動で再接続されるものの、できればずっと接続状態を維持してほしいと思っていた。

そして、Seamless tunnel をオンにしていると、モバイルとWi-Fiの切り替わりのときにVPNが接続されたままになるから、たぶんそういうことなんだろう、という記事をここに書いている途中で、スリープ中でもVPNが切れなくなったように感じはじめた。

ちょっと書こうと思っていたことがずれてしまったけど、これからVPNがオフになったり途中で切れたりしないかどうか検証していきたいと思う。とりあえずモバイルとWi-Fiの切り替わりでVPNの接続状態が維持されることは検証済みなので、オンにしておいて損はないと思う。あと、オンにしたら、VPNを一旦切断して再接続しないと設定が反映されないようなので注意。

それから参考にしたサイトでは、"Connection timeout" を “None” に設定するように紹介されている。デフォルトでは “30 seconds” なのでこちらも変更しておいた。

OpenVPNの構築についてはこちらを参照 OpenVPNのインストールとセットアップからインターネット接続までのガイドブック

認証は通っているのにGitでGitHubリモートリポジトリにアクセスすると Permission denied になる問題の原因

発端

先日、.ssh内の鍵ファイルを整理してたら、git pullが通らなくなりました。

git pullしようとするとこんな感じのエラーが出ます。

Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

直前に鍵ファイルの場所をいじっていたりしたので原因はそれで間違いないなと思っていたのですが、GitHubの認証にも通っているのになんでエラーになるのかな?と数分悩んでしまったのでメモを残したいと思います。

詳細

.ssh/configには以下の設定を追加しています。

Host github
  HostName      github.com
  User          git
  IdentityFile  ~/.ssh/id_rsa

~/.ssh/id_rsa.pubGitHubに登録した状態で

$ ssh github

とすると

Hi noraworld! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.

と表示され、GitHubSSH認証が成功します。

これなら何の問題もないのですが、ぼくはこの前、秘密鍵と公開鍵をまとめるために、defaultというディレクトリを作って、その中にid_rsaid_rsa.pubを保存したので、configの設定を以下のように書き換えました。

Host github
  HostName      github.com
  User          git
  IdentityFile  ~/.ssh/default/id_rsa

この状態でも、認証に使う鍵は同じなので

$ ssh github

とすれば、同じように認証が成功します。

しかし、この状態で、git pullなどすると、認証エラーになってしまいます。

Gitはデフォルトの鍵ファイルを参照する

理由は単純で、Gitは~/.ssh/id_rsaを認証の鍵として使用するからです。ぼくはGitHubで認証が通ったので、GitHubをリモートリポジトリとして設定したリポジトリでGitを使うときにも同じパスを参照してくれるだろうと思っていました。つまり、GitHubの認証に通っていればGitでも同じくSSHでの認証ができるものと思っていました。

しかし、実際には違って、GitHubとの認証では、たしかにconfigに書かれた設定を参照しますが、Gitの諸々のコマンドではデフォルトの鍵(~/.ssh/id_rsa)を参照してしまうので、そこに鍵ファイルがなくてエラーになってしまったというのが原因でした。

なので、解決方法は簡単で、認証に使う鍵を~/.ssh/id_rsaに置いておけばOKです。

とても単純なことですが、ネットでエラーを調べてもこの手の凡ミスを紹介しているサイトは見つからなかったので、同じように悩んでいる人の参考になれば幸いです。

Ghostの設定でURLをHTTPSにするとリダイレクトループが発生する問題の解決法

はじめに

ぼくが愛用しているブログシステムであるGhost。実際に Noraworld Blog でもGhostを利用しています。

Ghostでは、config.jsを編集することで設定をいじることができます。urlという箇所に自分のURLを書いておくと、そのURLでGhostが使えるようになるわけですが、ここのURLにhttps://ではなく、http://と書いておくと、Ghostのブログ内のすべてのリンクがhttp://で表示されます。

リンクがすべてhttp://になっていても、Nginx側でリダイレクトするので結局はhttps://でアクセスされるわけですが、せっかくHTTPSに対応しているのにリンクがすべてhttp://になっちゃうのは気持ちが悪いし、Twitterのシェアもhttp://https://が混在してしまったりしてすっきりしません。

そこで、config.jsurlhttps://にしたいのですが、なぜかhttps://とするとリダイレクトループが発生してしまい、アクセスできないという問題が発生します。その解決法がわからずずっとhttp://のまま利用していたのですが、今日やっとその解決法をネットで見つけたのでメモとして残しておきます。

Nginxの設定を追加

まさにビンゴな答えが紹介されているブログを発見しました。 How to setup HTTPS on your Ghost blog and avoid redirect loop

説明が英語ですが、やっていることはシンプルで、locationディレクティブにproxy_set_headerを一行追加するだけです。

location / {
     proxy_pass        http://localhost:2368;
+    proxy_set_header  X-Forwarded-Proto $scheme;
}

これによってGhostが正しいプロトコルの設定を認識できるようになるらしいです。

追加したら、Nginxを再起動します。

$ sudo nginx -s reload

Nginxを再起動するとリダイレクトループが発生しなくなり、リンクもすべてhttps://で表示されるようになります。

Apacheの場合も上記のサイトで紹介されているので、そちらを参考にしてください。

ちなみにGhostのconfig.jsを編集したあとはNginx同様にGhostを再起動しないと設定が反映されないので忘れずに。

OpenSSL 1.0.2 以降をインストールしてもALPNに対応できないときの対処法

ALPNに対応しているか確認

自分のサイトでALPNが有効かどうかは以下の3つの方法で確認できます。

  1. Chrome拡張機能HTTP/2 and SPDY indicator」を使用する
  2. WebサービスHTTP/2 Test」を使用する
  3. OpenSSLコマンドを実行する

1つめ

拡張機能Chromeにインストールするだけで準備OKです。ALPNが有効であり、かつHTTP/2が有効である場合はこの拡張機能の稲妻アイコンが青くなります(非対応の場合は灰色です)

2つめ

WebサイトにアクセスしてALPN対応かどうか確認したいサイトのURLを入力して「Test」ボタンを押します。"ALPN supported" と出ればALPNに対応していることがわかります。

3つめ

opensslコマンドが使用できるマシンで以下のコマンドを実行します。

$ echo | openssl s_client -alpn h2 -connect example.com:443

example.comの箇所を確認したいURLに置き換えます。コマンドを実行すると色々な情報が出てきますが、ALPNに対応していれば

ALPN protocol: h2

と表示され、対応していなければ

No ALPN negotiated

と表示されます。

参考: NginxでHTTP/2(ALPN対応)

問題

OpenSSLはALPNをサポートしていますが、サポートしているバージョンは OpenSSL 1.0.2 以降です。なので、OpenSSL 1.0.1 などではALPNはサポートされていません。

ところが、OpenSSLのバージョンがALPNに対応していても、なぜかALPN非対応と表示されてしまう問題に直面しました。Webサーバ(Nginx)を再起動してもダメでした。

解決策

ぼくの場合は以下の2つが原因でした。

  1. NginxがALPNに対応したOpenSSLを使用していなかった
  2. サーバ自体を再起動する必要がある

1つめ

NginxやOpenSSLをyumやaptなどのパッケージマネージャで更新した場合は問題ないのですが、自分の場合は、NginxもOpenSSLも、ソースからダウンロードしてビルドしていたので、NginxがビルドしたOpenSSLを参照してくれていなかったのが原因でした。

ソースからビルドしたNginxで、同じくソースからビルドしたOpenSSLを使用するためには、Nginxにインストールでオプションをつけて、もう一度ビルドし直す必要があります。Nginxのソースがあるディレクトリに移動して、以下のコマンドを実行します。

$ ./configure --with-http_ssl_module --with-http_v2_module --with-openssl=ソースからダウンロードしたOpenSSLのディレクトリのパス

OpenSSLは公式サイトからtarball(.tar.gz)をダウンロードして、圧縮ファイルを展開します。その展開したディレクトリをパスとして指定します。Nginxをソースからビルドする方法については以下の記事を参考にしてください。

Nginxでレスポンスヘッダの一部を隠蔽する方法

これでインストールすると、指定したOpenSSLのバージョンを使ってNginxをビルドできます。それを確認するには以下のコマンドを実行します。

$ nginx -V

built with OpenSSL x.x.x DD MM YYYYのように、自分がダウンロードしてきたOpenSSLのバージョン(1.0.2以降)が表示されていればOKです。Apacheの場合はまた違うと思いますので、各自で調べてください。

ビルドが成功したら、Nginxを再起動してください。

$ sudo nginx -s reload

2つめ

これは非常に単純な話なのですが、Nginxを再起動しただけでは、OpenSSLのバージョンを変更してもそれが反映されないみたいです。おそらくOpenSSLを新しいバージョンにしたほうに反映させるコマンドがあるはずですが、自分はそれがわからなかったので、最終手段としてサーバそのものを再起動してしまいました。サーバを再起動するので、再起動後に自動起動するように設定していないデーモンプロセスを再び起動させる手間があってめんどうくさいですが、これが一番確実かと思われます。

サーバを再起動して、もう一度、3つのうちのいづれかの方法でALPN対応か確認するとちゃんと対応していると表示されました!

最新版のOpenSSLのインストール方法についてはこちらをどうぞ OpenSSLをソースからビルドしてNginxで使用する