はじめに
最近スマートホームにハマってます。家電とかを外から操作できて便利ですよね。うちではSiriで家電を操作したかったので、HomebridgeをRaspberry PiにインストールしてNature remoを操作しています。そこで、HomebridgeのWebUIに家の外からアクセスしたくてNginx ProxyをRaspberry Piにおいてみることにしました。この際せっかくならセキュアにやろうということで、Let's Encryptも導入してみることにします。証明書も自動更新するようにして、管理も楽にする方向でやっていきます。
環境
今回はこんな構成で話を進めていきます。
- Raspberry Pi 3 B+
- Raspbian Stretch
まずRaspbianにDockerを入れて、Docker Composeを使いながらセットアップしていきます。
事前準備
当然のことながらRaspbianのセットアップは済ませておいてください。ここでは記事の範囲を超えるので詳しい説明は省きます。
DockerとDocker Composeのインストール
まず下記コマンドを実行してRaspbianにDockerをインストールします。
$ curl -fsSL https://get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh
続いてDocker Composeもインストールしてしまいましょう。リポジトリから入るバージョンは少し古いのですが、実用上特に問題になることはないはずです。
$ sudo apt install docker-compose
Docker Composeの設定
Raspberry Pi上のDockerでは当然ながら x86_64
向けにビルドされたDockerコンテナを動かすことはできません。そもそものこと、いつも使っているnginx
イメージですら動かないわけです。というわけでRaspberry Pi用にビルドされたイメージを使います。nginx-proxyの代わりにrpi-docker-nginx-proxyを、docker-letsencrypt-nginx-proxy-companionの代わりにrpi-docker-letsencrypt-nginx-proxy-companionをそれぞれ利用します。
docker-compose.yml
ひとまずdocker-compose.yml
全体をお見せして、細かいところを解説していきます。ということでご覧ください。
version: '2'
services:
nginx-proxy:
image: alexanderkrause/rpi-nginx-proxy
restart: always
container_name: nginx-proxy
ports:
- "80:80"
- "443:443"
volumes:
- certs:/etc/nginx/certs:ro
- vhost:/etc/nginx/vhost.d
- nginx_static:/usr/share/nginx/html
- /var/run/docker.sock:/tmp/docker.sock:ro
labels:
com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: ""
nginx-letsencrypt:
image: alexanderkrause/rpi-letsencrypt-nginx-proxy-companion
restart: always
container_name: nginx-letsencrypt
volumes:
- certs:/etc/nginx/certs:rw
- /var/run/docker.sock:/var/run/docker.sock:ro
- vhost:/etc/nginx/vhost.d
- nginx_static:/usr/share/nginx/html
web:
build: ./api-server
restart: always
environment:
VIRTUAL_HOST: "web.example.com"
VIRTUAL_PORT: "80"
LETSENCRYPT_HOST: "web.example.com"
LETSENCRYPT_EMAIL: "webmaster@example.com"
SSL_POLICY: "Mozilla-Modern"
volumes:
certs:
vhost:
nginx_static:
Nginx Proxy
まずはNginx Proxy部分を説明していきます。特徴的なところだけかいつまんでいきましょう。
HTTP/HTTPS通信を外から受けるため、ここだけ80
番と443
番のポートを外側にバインドしておきます。
証明書などの各種ファイルを読み書きするため、3つほどボリュームをマウントしておきます。ただし証明書が入っているcerts
ボリュームは、こちら側のコンテナからは安全のため読み込み専用にしておきます。また、docker.sock
はproxy対象のコンテナが建ったときに勝手に設定を追加してもらうために読み込み専用でマウントしておきましょう。ここで利用するボリュームはvolumes
セクションに定義しておくことを忘れないでください。
最後にlabels
を設定します。これはLet's Encryptを自動取得するコンテナ側からこのコンテナを識別するために使います。ちょっと記法が見慣れない感じなのですが、キーにラベル名を、値に空文字列を設定することで有効化されます。
services:
nginx-proxy:
image: alexanderkrause/rpi-nginx-proxy
restart: always
container_name: nginx-proxy
ports:
- "80:80"
- "443:443"
volumes:
- certs:/etc/nginx/certs:ro
- vhost:/etc/nginx/vhost.d
- nginx_static:/usr/share/nginx/html
- /var/run/docker.sock:/tmp/docker.sock:ro
labels:
com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: ""
volumes:
certs:
vhost:
nginx_static:
Let's Encrypt
Let's Encrypt側のコンテナもかいつまんで説明していきましょう。
こちらも同じようなボリュームをマウントしていますが、certs
だけは書き込む必要があるのでrw
を指定しています。ここだけ注意してください。
nginx-letsencrypt:
image: alexanderkrause/rpi-letsencrypt-nginx-proxy-companion
restart: always
container_name: nginx-letsencrypt
volumes:
- certs:/etc/nginx/certs:rw
- vhost:/etc/nginx/vhost.d
- nginx_static:/usr/share/nginx/html
- /var/run/docker.sock:/var/run/docker.sock:ro
プロキシされるコンテナ
プロキシされるWebサービスはあくまでサンプルなのでここは各自の環境に置き換えてほしいのですが、ざっくりと解説していきます。ポイントとなるのは5つの環境変数です。VIRTUAL_*
としているのがNginx Proxy用の環境変数で、それ以外がLet's Encrypt用の環境変数です。
VIRTUAL_HOST
にはこのコンテナに割り当てたいドメインを指定します。事前にお使いのドメインに対してサブドメインを生やしておいて、DNSを設定しておいてください。VIRTUAL_PORT
にはポートフォワーディング先のポート番号を記入します。ここでは仮に80
としましたが、例えば5000
番ポートで動いているアプリがある場合はそのように変更することを忘れないでください。
LETSENCRYPT_HOST
にはTLS証明書を発行する対象となるドメインを指定します。通常はVIRTUAL_HOST
と同じで良いでしょう。LETSENCRYPT_EMAIL
に各種確認メールを送信する先のメールアドレスを指定するのも忘れないでください。SSL_POLICY
にはどのようなTLSプリセットを用いるかを指定できます。デフォルトはMozilla-Intermediate
に設定されていますが、今回はMozilla-Modern
に設定することでTLSv1.2の利用を強制し、よりセキュアにしています。ただし古い環境からは接続できなくなりますので注意してください。
web:
build: ./api-server
restart: always
environment:
VIRTUAL_HOST: "web.example.com"
VIRTUAL_PORT: "80"
LETSENCRYPT_HOST: "web.example.com"
LETSENCRYPT_EMAIL: "webmaster@example.com"
SSL_POLICY: "Mozilla-Modern"
起動
あとはコンテナ群を起動すれば自動的に証明書を取得して繋がるように設定してくれます。
$ sudo docker-compose up -d
おわりに
Raspberry Pi用にフォークされた便利コンテナを使うことで、ちょっとDocker Composeの設定を書くだけでLet's Encryptを使ったプロキシの設定ができてしまいました。x86_64環境と全く同じとまではいきませんが、それなりに簡単に構築できたかと思います。また、自動的に証明書の更新もかけてくれるのでコンテナが起動してさえいれば更新忘れなどもありません。
皆さんもぜひRaspberry Piでお手軽なHTTPS環境を構築して、誤家庭の充実に役立ててください!