Help us understand the problem. What is going on with this article?

Raspberry PiでLet's EncryptなNginx Proxyを作ろう

はじめに

最近スマートホームにハマってます。家電とかを外から操作できて便利ですよね。うちでは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全体をお見せして、細かいところを解説していきます。ということでご覧ください。

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を自動取得するコンテナ側からこのコンテナを識別するために使います。ちょっと記法が見慣れない感じなのですが、キーにラベル名を、値に空文字列を設定することで有効化されます。

nginx-proxy部分
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を指定しています。ここだけ注意してください。

Let'sEncrypt部分
  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サービス部分
  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環境を構築して、誤家庭の充実に役立ててください!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした