TL; DR
古い OpenSSL が使われるのが原因です。Python ビルド時に新しい OpenSSL を指定すれば解決します。
$ pyenv uninstall 3.6.5 $ CPPFLAGS="-I/usr/local/ssl/include" LDFLAGS="-L/usr/local/ssl/lib" pyenv install 3.6.5
経緯
さくらのレンタルサーバーはプラン スタンダード以上で SSH が使えるので、pyenv を入れたり pip を入れたりできます。pyenv を使って Python の他のバージョンをインストールするときに注意しないといけないのが、さくらでは Python 導入時のビルドで古い OpenSSL が使われてしまうことです。これの影響で pip したときに次のような SSL のエラーを吐きます。
$ pip install bcrypt Collecting bcrypt Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLError(1, '[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:833)'),)': /simple/bcrypt/ Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLError(1, '[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:833)'),)': /simple/bcrypt/ Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLError(1, '[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:833)'),)': /simple/bcrypt/ Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLError(1, '[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:833)'),)': /simple/bcrypt/ Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLError(1, '[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:833)'),)': /simple/bcrypt/ Could not fetch URL https://pypi.python.org/simple/bcrypt/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host='pypi.python.org', port=443): Max retries exceeded with url: /simple/bcrypt/ (Caused by SSLError(SSLError(1, '[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:833)'),)) - skipping Could not find a version that satisfies the requirement bcrypt (from versions: ) No matching distribution found for bcrypt
OpenSSL のバージョンが古いのかな?とバージョンを確認しても最新版です。
$ openssl version OpenSSL 1.0.2o 27 Mar 2018
ですが pyenv install 3.6.5 した Python 上で確認してみると
$ python Python 3.6.5 (default, Jun 26 2018, 10:35:21) [GCC 4.2.1 20070831 patched [FreeBSD]] on freebsd9 Type "help", "copyright", "credits" or "license" for more information. >>> import ssl >>> ssl.OPENSSL_VERSION 'OpenSSL 0.9.8zf 19 Mar 2015'
思いっきり 0.9.8zf と出ていますね。「Python - さくらレンタルサーバーでpip installができません(123028)|teratail」によると、普通にビルドすると最新版の OpenSSL ではなくて、古い方の OpenSSL をリンクしてしまうとのこと。
さくらレンタルサーバでは普通にpythonをbuildすると古いopensslにつながってしまうようです。
/usr/local/sslに新しいのが入ってるみたいなので、./configure CPPFLAGS="-I/usr/local/ssl/include" LDFLAGS="-L/usr/local/ssl/lib"でpythonを作るとよさそうです。
ということで一旦インストールした Python を uninstall して、OpenSSL のパスを指定して再度インストールし直します。
$ pyenv uninstall 3.6.5 $ CPPFLAGS="-I/usr/local/ssl/include" LDFLAGS="-L/usr/local/ssl/lib" pyenv install 3.6.5 Downloading Python-3.6.5.tgz... -> https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tgz Installing Python-3.6.5... Installed Python-3.6.5 to /home/USERNAME/.pyenv/versions/3.6.5
無事インストールできたようなので、OpenSSL のバージョンを確認してみます。
$ python Python 3.6.5 (default, Jun 26 2018, 10:35:21) [GCC 4.2.1 20070831 patched [FreeBSD]] on freebsd9 Type "help", "copyright", "credits" or "license" for more information. >>> import ssl >>> ssl.OPENSSL_VERSION 'OpenSSL 1.0.2o 27 Mar 2018'
大丈夫そうですね。pip の更新を兼ねて pip を試してみます。
$ pip install -U pip Collecting pip Downloading https://files.pythonhosted.org/packages/0f/74/ecd13431bcc456ed390b44c8a6e917c1820365cbebcb6a8974d1cd045ab4/pip-10.0.1-py2.py3-none-any.whl (1.3MB) 100% |################################| 1.3MB 890kB/s Installing collected packages: pip Found existing installation: pip 9.0.3 Uninstalling pip-9.0.3: Successfully uninstalled pip-9.0.3 Successfully installed pip-10.0.1
ばっちり動きました。
ですが……今回の目的だった bcrypt のインストールは、libffi がなくて結局できず。py-bcrypt なら pip 一発なのでソースコードを py-bcrypt に書き替えた方が早そう。ちょっと不完全燃焼です。