growiとhackmd(codimd)をhttpsで配信しながらhackmd連携を使う

研究室のwikiとして最近growiを使っている。

growiの構築には公式が出しているdocker-composeを使うのが便利で、研究室のwikiもこれを使って運用している。 さらにgrowiにはhackmdのOSSバージョンであるCodiMDを呼び出して使える機能があり、これも公式のdocker-composeをいい感じに編集することで実現できる。

今まではこれらをdocker-composeでlocalhostの3000番と3100番くらいで動かしておいて、dockerでなくaptで入れたsystemdで動かしているnginxでリバースプロキシしていた。 httpオンリー接続で元気に動かす運用だった。 とはいえ最近のインターネットはhttps通信をしたがるムーブがあるので、growiとhackmdをそれぞれhttpsで動かす方針でやってみた。

httpsでの配信

今回も公式のdocker-composeにある通り、httpsでの設定例を見て構築する。 公式がhttps配信のやり方を書いていて便利。

これはSteveLTN/https-portalのプロジェクトのDocker Imageを利用している。 github.com

https-portalはdocker-composeにドメインとリバースプロキシ先を書いておくと、よしなにLets'Encryptから証明書を持ってきて配置してくれる上にnginxでリバースプロキシしてくれる便利なツール。 READMEとかを見た感じ証明書の更新とかも勝手にやってくれるらしい。良いですね。

というわけでdocker-compose.override.yml に次くらいのものを書いておく

  https-portal:
    image: steveltn/https-portal:1
    ports:
      - '80:80'
      - '443:443'
    links:
      - app:app
    environment:
      DOMAINS: 'growi.cr.ie.u-ryukyu.ac.jp -> http://app:3000, hackmd.cr.ie.u-ryukyu.ac.jp -> http://hackmd:3000'
      STAGE: 'production'
      FORCE_RENEW: 'false'
      WEBSOCKET: 'true'
      CLIENT_MAX_BODY_SIZE: 0
    restart: unless-stopped
    volumes:
      - https-portal_data:/var/lib/https-portal

volumes:
  mariadb_data:
  https-portal_data:

ここまで書いてバシッと起動するとhackmdとgrowiがそれぞれhttpsで配信される。

hackmd連携の対応

とはいえスムーズに進まないのが人生で(?) growiのhackmd連携をしようとすると301のエラーが発生する。

Error: Error: Request failed with status code 301

なんでこうなるかはhttpsではなくhttpのhackmdにcurlするとわかる。

<head><title>301 Moved Permanently</title></head>

SteveLTN/https-portalはデフォルトの設定でhttpにアクセスに来たものを301でhttpsの方に引き渡している。 通常では問題ないのだけれど、growiのhackmd連携はwindow.postMessage を利用して行われている。

つまりwindow.postMessageでhttpアクセスに行ったところ301が出てしまって破滅しているため表示されないということになる。 この問題を回避するには、httpsとhttpを共存させれば良いということになる。

幸いSteveLTN/https-portalはnginxの設定をerbで書けば上書きできるらしいので、301ではなく直接リバースプロキシする様に設定を書き換える。

server {
    listen       80;
    server_name  <%= domain.name %>;


    location / {
              proxy_redirect                      off;
              proxy_set_header Host               $host;
              proxy_set_header X-Real-IP          $remote_addr;
              proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
              proxy_read_timeout          1m;
              proxy_connect_timeout       1m;
              proxy_pass  <%= domain.upstream %>;
    }

    # This helper sets up the path for the ACME server to verify that you own the site
    # Defaults to /.well-known/acme-challenge/
    <%= acme_challenge_location %>
}

ここで設定したドメイン名は <%= domain.name %> で、 リバースプロキシ先は <% domain.upstream > でそれぞれ設定出来る。

これをdocker-compose.override.ymlに以下のように書き加える。

    volumes:
      - https-portal_data:/var/lib/https-portal
      - ./hackmd.cr.ie.u-ryukyu.ac.jp.conf.erb:/var/lib/nginx-conf/hackmd.cr.ie.u-ryukyu.ac.jp.conf.erb:ro

ここまでしてdocker-compose upしなおすといい感じにhackmd連携が使える。めでたしめでたし。