この記事は
opensslのバージョンアップにより、各種アプリケーションが起動できなくなるエラーが起きているようです。
ssl関係はgoogleはじめプラットフォーマーが敏感なせいかサボりにくい部分です…。
'18年後半から現在まで「phpが動かないよー」とか「rubyが動かないよー」という記事がたくさん出ていて、ぶっちゃけ対処法はそれらにも載っているのですが、如何せんスマートな方法を書いている記事がなく。
・他により良い対処法はないのか?
・なぜスマートな方法が見つからないのか?
ということで調べてみました。(phpの名前を出しておいてアレですが、rubyだけです悪しからず。)
この記事の対象
○Macユーザー
△その他Unix系ユーザー
×windowsユーザー
検証環境
Mac OS Mojave 10.14.6 (アップデートをサボっています)
rbenv 1.1.2
ruby 2.6.3
Rails 5.2.3
rubyが動かない現象
事の発端は久々にrailsでバックエンドを作ろうとした時のこと。とりあえずrails -vを打ったところ、やたら長いエラーが発生。もしかしてrails --versionじゃないとダメだったか?と思い、ロングオプションを打つも同じエラー。
仕方がないのでエラーをちゃんと読むとopenssl関係だと分かりました。
運がいいことに、前日postgresqlのバージョンアップでopenssl1.1.0を入れていたので、"openssl1.0.0"の文字からバージョン関係のエラーだと切り分ける事ができました。
ググる
rubyを再インストールして見たら動いたというパターンと、rubyを再インストールすればいいよという記事を見て再インストールしているケースが多数。なるほど最悪rubyを再インストールすればいいと分かりました。
でも明らかに参照先のopensslが違うだけのエラーなので、もうすこし簡単な方法があるはずでは?
間違ったopensslを探しに行っている犯人を探してみる
ruby2.6.3のなかに設定ファイルはないか?
結論→ない
grep -r "(opensslのパス)" .rbenv/versions/2.6.3 してもそれらしい設定ファイルは見つからず。
その代わり、
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/digest/md5.bundle
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/digest/sha2.bundle
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/digest/rmd160.bundle
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/digest/sha1.bundle
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/openssl.bundle
.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/extensions/x86_64-darwin-18/2.6.0-static/puma-3.12.1/puma/puma_http11.bundle
.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/puma-3.12.1/ext/puma_http11/puma_http11.bundle
.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/puma-3.12.1/lib/puma/puma_http11.bundle
がヒット。pumaはgemだけど、後のはどう見てもruby本体のライブラリ、嫌な感じしかしないですね。
もしかして:環境変数
結論→ない
printenvしても一切見つからず。
大抵こういうパターンでも新たに特定の変数名で環境変数を作ってやると解決するパターンがある可能性は高いですが、とりあえず「なくても動いている」=「他の参照元が有効である」ことは確実です。
ということは
rubyをビルドする時にインストール済みのopensslを探しに行ってライブラリに直書きするパターン?
だから再インストールで直るのかー。
rubyが正常に動く状態にする
シンボリックリンクを張る
ln -s libssl.1.1.dylib libssl.1.0.0.dylib
ln -s libcrypto.1.1.dylib libcrypto.1.0.0.dylib
私の環境ではopenssl絡みで参照されるライブラリはlibsslとlibcryptoだけでした。(grepすると分かります。)
おそらく一般的にそうなのではないかと思います。
コマンドの数字の部分は左側が実在のファイルと同じ、右側が最初のエラーで出たopensslのバージョンです。
動いた
まあそうですよね。動くに決まっています。
どのような対応がベストか?
シンボリックリンクを張るだけでうまいこと動いてくれました。
ですが、またopensslのバージョンを変えた場合は同じことの繰り返しです。
それを考えると、どうしても今のrubyを維持したい場合はこの方法でも良いのですが、そうでなければ再インストールでもいいような気がしました。
(追記)そんな甘い話ではなかった
openssl1.0x以下とopenssl1.1xでは起動時にライブラリをロードする方法が違うとのことで、1.0xからバージョンアップした際、openssl.bundleがエラーを吐くことがわかりました。
1.0x以下の環境下でビルドされたrubyはopenssl1.1xの実行に必要なOPENSSL_init_sslを起動できず、
逆にopenssl1.1xに存在しない_SSL_library_initを呼び出そうとするためエラーになる模様。
検証内容
grep -r _SSL_library_init /(path to 2.6.3's)/openssl.bundle
-> match
grep -r OPENSSL_init_ssl /(path to 2.6.3's)/openssl.bundle
-> no match
openssl1.1.0が存在する状態で
rbenv install 2.6.0
rbenv local 2.6.0
元が2.6.3なので、rubyのバージョンは下がっています。ですのでrubyのバージョンが左右する訳ではないはず。
grep -r _SSL_library_init /(path to 2.6.0's)/openssl.bundle
-> no match
grep -r OPENSSL_init_ssl /(path to 2.6.0's)/openssl.bundle
-> match
呼び出し関数名が変わっているのがわかります。
gem install rails
rails new test-app
cd test-app
rails s
-> OK
今度は正常に動いてますね…。
つまり
やっぱり再インストールした方が無難です。