pipが動作しないエラーの解決

#環境
 - Mac OS X 10.11.6 (El Capitan)
 - Python 3.5.1
 - pip 9.0.1
 - 今日の日付 2018-07-18 (案外重要)

#経緯

twitterのbotが作りたくて、tweepyかtwythonをpipでインストールしようとしました。

```
$ pip install tweepy
```

すると、以下のエラーが発生

```
Collecting tweepy
  Could not fetch URL https://pypi.python.org/simple/tweepy/: There was a problem confirming the ssl certificate: [SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:645) - skipping
  Could not find a version that satisfies the requirement tweepy (from versions: )
No matching distribution found for tweepy
```

#解決策(?)その1

検索してみると、下記のコマンドを使ってpipをアップグレードするといい、という情報が見つかりました。

```
curl https://bootstrap.pypa.io/get-pip.py | python3
```

参考：
https://github.com/pypa/pip/issues/5236

その通りやってみると…

```
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 1603k  100 1603k    0     0  2151k      0 --:--:-- --:--:-- --:--:-- 2149k
Collecting pip
  Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLError('certificate verify failed, error code: 5',),)': /simple/pip/
  Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLError('certificate verify failed, error code: 5',),)': /simple/pip/
  Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLError('certificate verify failed, error code: 5',),)': /simple/pip/
  Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLError('certificate verify failed, error code: 5',),)': /simple/pip/
  Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLError('certificate verify failed, error code: 5',),)': /simple/pip/
  Could not fetch URL https://pypi.org/simple/pip/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host='pypi.org', port=443): Max retries exceeded with url: /simple/pip/ (Caused by SSLError(SSLError('certificate verify failed, error code: 5',),)) - skipping
  Could not find a version that satisfies the requirement pip (from versions: )
No matching distribution found for pip
Could not fetch URL https://pypi.org/simple/pip/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host='pypi.org', port=443): Max retries exceeded with url: /simple/pip/ (Caused by SSLError(SSLError('certificate verify failed, error code: 5',),)) - skipping
```

うまくいきません。

##原因

エラーの中心は`certificate verify failed`ですね。「証明書の検証に失敗」です。

調べてみると、どうやら、パッケージをインストールする先方のURLが変更になり、pip側が「そんなURLは知らないぞ！信用出来ないんじゃないのか？？」と疑って、エラーを出している、ということっぽいです。多分。ちゃんとわかってなくてすみません。

参考：
https://github.com/pypa/pip/issues/5288
https://packaging.python.org/guides/migrating-to-pypi-org/
↑2個目のURLが公式アナウンスです。

#解決策(?)その2

次の参考URLに書いてあるように、新しいURLについて「このURLは信用していいよ〜」という情報をpipに教えてあげましょう。

参考：
https://stackoverflow.com/questions/25981703/pip-install-fails-with-connection-error-ssl-certificate-verify-failed-certi

`pypi.org`と`files.pythonhosted.org`を信用するように指示すれば良いようです。

でも、この方法ではうまくいきませんでした。
```
pip install --trusted-host pypi.org --trusted-host files.pythonhosted.org <package_name>
```

そもそもpipをアップグレードする必要があるので、先に使いたいコマンドは`curl`なんですよね。`pip`ではなく。

しかし

```
curl https://bootstrap.pypa.io/get-pip.py | python3
```

の中でどうやら`pip`が使われてるらしく、ここでは`--trusted-host`の指定をしていないので、結局同じエラーがでる。

ということで、同じ参考URLにあったもう一つの方法を使います。

`pip.conf`という設定ファイルを作って、そこに「このURLは信用していいよ」という内容を記述します。(Windowsの場合は`pip.ini`)



#結論

結局、下記のようにしてうまくいきました。

##pip.confの作成(Windowsの場合はpip.ini)

まず、`pip.conf`を所定の場所に作り、下記の記述をします。

```~/.pip/pip.conf
[global]
trusted-host = pypi.python.org
               pypi.org
               files.pythonhosted.org
```

これで、これらのURLは信用され、これらのURLからパッケージをダウンロードしてくれるようになります。

`pip.conf`を置く場所については下記を参考に。

参考：
https://stackoverflow.com/questions/45337029/pip-conf-not-paying-attention-to-trusted-host

##pipのアップグレード

```
curl https://bootstrap.pypa.io/get-pip.py | python3
```

これを実行します。`pip`が`10.0.1`にアップグレードされます。

##パッケージのインストール

ようやくここまで来ましたが、これが当初やりたかったやつです。本来、これだけでできるはずなんだよなあ。

僕の場合は`tweepy`をインストールしました。

```
pip install tweepy
```

以上です。


#追記(2018-07-19)VPSサーバーでもpipを動かす

#VPSサーバーの環境

- CentOS Linux release 7.0.1406 (Core) 
- curl 7.29.0 (x86_64-redhat-linux-gnu) libcurl/7.29.0 NSS/3.15.4 zlib/1.2.7 libidn/1.28 libssh2/1.4.3
- Python 3.6.2
- pip 9.0.1


#経緯

僕の場合tweepyはVPSサーバー上で動いてくれないと意味がないので、VPSサーバーにも上記の方法でインストールしようとした所、

```
curl https://bootstrap.pypa.io/get-pip.py | python3.6
```

を実行した時点で、ローカルの時とは異なるエラーが発生。

(コマンドの最後がpython3ではなくpython3.6になっているのは、僕のVPS環境でpython3を呼び出すコマンドが`python3.6`になっているからです。)

```
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
curl: (35) Peer reports incompatible or unsupported protocol version.
```

調べてみると、どうも、Curlのバージョンが古いのが原因のようです。

参考：
https://stackoverflow.com/questions/43975973/how-to-fix-error-failed-to-download-on-rbenv-install

--verboseオプションをつけて

```
curl --verbose https://bootstrap.pypa.io/get-pip.py | python3.6
```

を実行してみると、以下のような詳細が出ました。

```
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* About to connect() to bootstrap.pypa.io port 443 (#0)
*   Trying 2a04:4e42:11::175...
* Connected to bootstrap.pypa.io (2a04:4e42:11::175) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* NSS error -12190 (SSL_ERROR_PROTOCOL_VERSION_ALERT)
* Peer reports incompatible or unsupported protocol version.
* Error in TLS handshake, trying SSLv3...
> GET /get-pip.py HTTP/1.1
> User-Agent: curl/7.29.0
> Host: bootstrap.pypa.io
> Accept: */*
> 
* Connection died, retrying a fresh connect
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
* Closing connection 0
* Issue another request to this URL: 'https://bootstrap.pypa.io/get-pip.py'
* About to connect() to bootstrap.pypa.io port 443 (#1)
*   Trying 2a04:4e42:11::175...
* Connected to bootstrap.pypa.io (2a04:4e42:11::175) port 443 (#1)
* TLS disabled due to previous handshake failure
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* NSS error -12286 (SSL_ERROR_NO_CYPHER_OVERLAP)
* Cannot communicate securely with peer: no common encryption algorithm(s).
* Closing connection 1
curl: (35) Peer reports incompatible or unsupported protocol version.
```

TLSのハンドシェイクプロトコルでエラーが発生し、NSS error として報告されています。

(ハンドシェイクプロトコルでは、やりとりする2者が両方とも使える暗号化プロトコルを選ぶのですが、そこで合致するプロトコルがなかったということらしい。)

ということで、参考URLにある方法をそのまま使って、NSS error を解決します。

#解決策(?)1

##NSSのアップデート

ルート権限で以下を実行します。

```
yum update nss nss-util nspr
```

……結果から言うと、何も解決しませんでした。なんなんだ。

#解決策(?)2

参考：
https://support.plesk.com/hc/en-us/articles/214029229-How-to-update-cURL-to-the-latest-version-on-a-Plesk-server

こちらのサイトにある方法を試します。

```
yum update curl.x86_64
```

を実行した後に、curlのバージョンを確認。

```
curl 7.29.0 (x86_64-redhat-linux-gnu) libcurl/7.29.0 NSS/3.34 zlib/1.2.7 libidn/1.28 libssh2/1.4.3
```

はい。変わってませんね。7.29のままです。

NSSのバージョンが3.15.4から3.34に上がってますが、NSSをupdateしたからなのか、今curlのupdateをしたからなのか、今となってはわからなくなってしまった。

どっちにしても、問題は解決していない。

#解決策(?)3

下記3サイトに、ほぼ同じ方法が解決策が書いてあるので、実行してみます。

参考：
https://support.plesk.com/hc/en-us/articles/214029229-How-to-update-cURL-to-the-latest-version-on-a-Plesk-server
https://serverfault.com/questions/321321/upgrade-curl-to-latest-on-centos
https://stackoverflow.com/questions/28495444/how-to-upgrade-php-curl-to-version-7-36-0

`/etc/yum.repos.d/city-fan.repo`というファイルを作り、中身を次のようにします。

```/etc/yum.repos.d/city-fan.repo
[CityFan]
name=City Fan Repo
baseurl=http://www.city-fan.org/ftp/contrib/yum-repo/rhel$releasever/$basearch/
enabled=1
gpgcheck=0
```
そしたら次を実行します。

```
yum clean all
yum install curl
```

すると………


次のエラーが出ます！！！！

```
Loaded plugins: fastestmirror
CityFan                                                                                                                                   | 2.9 kB  00:00:00     
base                                                                                                                                      | 3.6 kB  00:00:00     
epel/x86_64/metalink                                                                                                                      | 6.6 kB  00:00:00     
epel                                                                                                                                      | 3.2 kB  00:00:00     
extras                                                                                                                                    | 3.4 kB  00:00:00     
Could not retrieve mirrorlist https://mirrors.iuscommunity.org/mirrorlist?repo=ius-centos7&arch=x86_64&protocol=http error was
14: curl#60 - "Peer's Certificate issuer is not recognized."


 One of the configured repositories failed (Unknown),
 and yum doesn't have enough cached data to continue. At this point the only
 safe thing yum can do is fail. There are a few ways to work "fix" this:

     1. Contact the upstream for the repository and get them to fix the problem.

     2. Reconfigure the baseurl/etc. for the repository, to point to a working
        upstream. This is most often useful if you are using a newer
        distribution release than is supported by the repository (and the
        packages for the previous distribution release still work).

     3. Disable the repository, so yum won't use it by default. Yum will then
        just ignore the repository until you permanently enable it again or use
        --enablerepo for temporary usage:

            yum-config-manager --disable <repoid>

     4. Configure the failing repository to be skipped, if it is unavailable.
        Note that yum will try to contact the repo. when it runs most commands,
        so will have to try and fail each time (and thus. yum will be be much
        slower). If it is a very temporary problem though, this is often a nice
        compromise:

            yum-config-manager --save --setopt=<repoid>.skip_if_unavailable=true

Cannot find a valid baseurl for repo: ius/x86_64
```


はい。


何にもうまくいかないな……。。。。。


#結論(curlのアップデートを諦める)

curlのアップデートを諦めます。

要は、pythonプログラムである https://bootstrap.pypa.io/get-pip.py を実行すればいいわけなので、これを直接ローカルにダウンロードして、scpでサーバーにアップロードします。

で、普通にpythonプログラムとして実行

```
python3.6 get-pip.py
```

これでVPSサーバー上でもpipを10.0.1に更新できました。

そのまま`pip install tweepy`も問題なく済みました。


curlのアップデートがうまくいかなかった理由がわかる方がいらっしゃいましたら、どうか教えてください。