Nginxをリバースプロキシとして使ってるところにLet'sEncryptしようとしたらはまった話

CentOS7.2に[Kallithea](https://kallithea-scm.org)を立てていて、外からはNginxをリバースプロキシにして、HTTP:80でアクセスしています。
気づいたら[Let's Encrypt](https://letsencrypt.org/)がパブリックベータになっていたので、これを機にHTTPSでアクセスできるようにしよう！
と思ったらなんかはまったのでメモがてら書いときます。

なお、Nginxは1.9.9、Kallitheaは0.3を使用しています。
そしてSSL通信の設定自体はここでは省いてます。
あとドメイン名はサンプルです。

# Let's Encrypt
[公式サイト https://letsencrypt.org/](https://letsencrypt.org/)
[日本語サイト https://letsencrypt.jp/](https://letsencrypt.jp/)
TLSやHTTPS通信の普及を目指すべく、SSL/TLSサーバ証明書を無料で発行している団体。
詳細はここでは省略。

# 今までの設定
## Nginxの設定
```nginx:kallithea.conf
server {
    listen 80;
    server_name kallithea.example.com;

    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Real-IP $remote_addr;

    location / {
        proxy_pass http://127.0.0.1:5000;
    }
}
```

普通です。`kallithea.example.com`にアクセスが来たら、内部で動いてるKallitheaにパスするだけです。
プロセスはユーザ`nginx`、グループ`nginx`で動いています。

## Kallitheaの設定
`/opt/kallithea/kallithea.sys`にKallithea本体、`/opt/kallithea/repos`にリポジトリを置いてます。
プロセスはユーザ`kallithea`で実行しており、`/opt/kallithea`以下は全部`kallithea`が所有者になっています。suid、sgidビットは特につけてません。

# 何も考えずに普通に実行
クライアントを普通に持ってきて、普通に打っただけ。

```console-session:console
# git clone git://github.com/letsencrypt/letsencrypt
# cd letsencrypt
# ./letsencrypt-auto --help
# ./letsencrypt-auto certonly --webroot -w /opt/kallithea -d kallithea.example.com
```

結果は404 Not Foundだったぞダメーって言われました。
Let's Encryptの大まかな流れは、
1. `-w`で指定したパスにACME-Challengeの認証ファイルを作成。
2. Let's Encryptのサーバから、自サーバに対して認証ファイルのGETリクエストを送信。

2の時のリクエストURLは、http://kallithea.example.com/.well-known/acme-challenge/hogehoge みたいなURLになります。
Nginxで受けてKallitheaへリクエストを送信するのですが、KallitheaはこんなURLは当然用意してないので404が帰るのも当然でしたね。

# ちゃんとルートディレクトリを用意
ならばルートディレクトリを用意してあげませんとね、というわけで用意しました。

```console-session:console
$ mkdir /opt/kallithea/home
```

```nginx:kallithea.conf
    location / {
        proxy_pass http://127.0.0.1:5000;
    }

    # 以下を追記
    location ^~ /.well-known/acme-challenge/ {
        root /opt/kallithea/home;
    }
```

Nginxをrestart後、Let's Encryptクライアントを実行します。

```console:console
# ./letsencrypt-auto certonly --webroot -w /opt/kallithea/home -d kallithea.example.com
```

結果は、今度は403 Forbiddenが返ってきてダメってなりました。
どうやらNginxを動かしているユーザと、ルートディレクトリの所有者が違うと、Nginxは403を返すようです。この辺細かく検証したわけじゃないので実は違うとかだったらごめんなさい。
→ 参考にさせていただきました。
* [403 forbidden errorをどうにかしたいときに必要なこと - by shigemk2](http://www.shigemk2.com/entry/20131101/1383300760)

# 今度こそルートディレクトリを用意
ACME-Challenge用のディレクトリを作成し、所有者もNginx実行ユーザにしました。

```console:console
# mkdir /opt/acme
# chown nginx.nginx /opt/acme
```

```nginx:kallithea.conf
    location ^~ /.well-known/acme-challenge/ {
        root /opt/acme;
    }
```

そしてLet's Encryptクライアントを実行。

```console:console
# ./letsencrypt-auto certonly --webroot -w /opt/acme -d kallithea.example.com
Updating letsencrypt and virtual environment dependencies......
Requesting root privileges to run with virtualenv: /root/.local/share/letsencrypt/bin/letsencrypt certonly -w /opt/acme -d kallithea.example.com

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/kallithea.example.com/fullchain.pem. Your cert will
   expire on 2016-05-01. To obtain a new version of the certificate in
   the future, simply run Let's Encrypt again.
 - If you like Let's Encrypt, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
```

できました。

ただこれがスマートな方法なのかどうかはわからない…。