Docker で Crowi version 1.6.1 を建てました（nginx-proxy + letsencrypt-companion）

> 注意：バックエンド初心者です。間違いがあったらごめんなさい。ですが僕の環境では動作確認済みで、サーバー運用に慣れている友達に教わりながら建てたので致命的なミスは無いはずです。初心者だからこその視点で詳しく書いたつもりです。
>
> あとこのようなまとまったエントリーを書くのが初めてなので、不手際があれば教えていただきたいです。すぐに修正致します。よろしくお願い致しますm(_ _)m

Docker を使ってプライベートで使うための Crowi サーバーを建てました。有り難いことに先駆者の方々がたくさんいらっしゃり関連記事はたくさんあります。ただそれらの記事で扱っている Crowi のバージョンが古いもので、僕が使いたいver1.6以降を使っているものがありませんでした。

なのでこの記事では、Crowi 1.6.1を建てる事をメインで書きつつ、多くの部分は参照リンクを貼りつつ、一から十までざっくりと説明できたらなと思います。
また最後に、Crowi以外にもサービスを建ててたときに、「こうすればよかったかも」って事をメモとして残しておきます。その部分に関しては動作確認できていないです。
**Crowi ユーザ増えたら嬉しい！**

はじめに、キーワードとかメモとか

- ConoHa VPS
- Proxy（nginx-proxy）
- SSL認証（letsencrypt-nginx-proxy-compaion）
- basic 認証はなし（crowi側の設定で、認証ありにすると動作が完全でなくなりました。必要ないしまぁいいかと。）
- 全ての作業は root ユーザでやってます。

## Crowi について

Markdown で書ける wiki！Pukiwiki, Dokuwiki, MDwikiを経てここにたどり着きました。
良さは他の方々のページを参照してください。

- [Crowi](http://site.crowi.wiki/)
- [Markdownで書けるWiki - Crowi - Qiita](http://qiita.com/nullsnet/items/a6e69e44087339127b35)
- [自宅用WikiとしてCrowiを利用する - 日々の作業メモ](http://jimaoka.hatenablog.jp/entry/crowi-install)

## なぜ Crowi 1.6.1 なのか。

ver 1.6以降、画像以外のファイルの添付が出来るようになったからです。
個人 wiki なので、書類とかもアップロードしたいんです。

（mermaid が対応するようになったらバージョンあげたいですね。）

## VPSを借りてから各種設定

自分は ConoHa VPSを借りてます。設定まではこちらを参考にさせてもらいました。

[ConohaにVPSを設置して、SSHログイン、ポート番号変更、rootログイン禁止までを30分で！ - Qiita](http://qiita.com/ongaeshi/items/bb17ebfbd4d22057c8fd#ssh%E3%81%AE%E3%83%9D%E3%83%BC%E3%83%88%E7%95%AA%E5%8F%B7%E3%82%92%E5%A4%89%E6%9B%B4)

ただ、上の記事は「SSHのポート番号を変更」で iptables を使っているので、Centos7 らしく firewalld を使います。

[CentOS7のfirewalldでsshのポート番号を変更する方法 - Qiita](http://qiita.com/DQNEO/items/5780d81b2e0af4cc1544)

[RHEL/CentOS7ではiptablesではなくfirewalld - Qiita](http://qiita.com/sak_2/items/fe996c518e8075214b49#%E3%82%BE%E3%83%BC%E3%83%B3%E3%81%AB%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B)

この各種設定が終わったら、yum のアップデートしときましょう。時間かかります。

```
yum update
```

## Docker ＋ docker-compose をインストール

最近、Docker が Docke CE(Community Edition) と Docker EE(Enterprise Edition) に別れたみたいで初心者は戸惑います。最新の情報を英語で確保ししつつ、以下のページを参照

[Docker Community Edition for CentOS - Docker Store](https://store.docker.com/editions/community/docker-ce-server-centos)

[CentOS7にdockerをインストール - Qiita](http://qiita.com/maimai-swap/items/00590b96888330aa54f1) このページは、docker ce でインストールの説明してくれてます！

そして、docker-compose のインストール。

[Docker Compose のインストール — Docker-docs-ja 1.13.RC ドキュメント](http://docs.docker.jp/compose/install.html)

この記事ではDocker、docker-composeの使用法などについては触れません。生半可な知識で説明してもわかりづらいでしょうし。

> ちなみに、はじめdocker-composeを使わずに建てようとしていました。ProxyをNginx単体で動作させようと頑張りましたが挫折し、途中でnginx-proxyを使うためにdocker-composeで立て直しました。

## Nginx-proxy と Let's encrypt companion

> Proxyいらないよって人は飛ばしても大丈夫です。ただ environment の設定やコンテナのポートを空けるようにするのとかが変わってくるので、このエントリーでは対応できないです。一応 crowi 1.6.1 に対応させて、port8080 で空ける docker image は [yusanish/crowi - Docker Hub](https://hub.docker.com/r/yusanish/crowi/) において置きました。

Crowi を早く建てたいところですが、VPSの上に立てているためGlobal IPは大変貴重みたいですね。ドメインを取得して、Proxy を使います！ポイントは以下の２つのコンテナです。

- jwilder/nginx-proxy
- jrcs/letsencrypt-nginx-proxy-companion

２つのコンテナが最高で、proxy ぱっとやってくれるし、自動でSSL認証の評価を『A+』にしてくれるし、はじめに建てようとしたときから使うべきでした。使おうとしなかったおかげで色々学べたことはありますが、あくまでも Crowi を使うことが目的です！

**ポイント**

- 推奨される方法である nginx, docker-gen, letsencrypt-nginx-proxy-companion の３つのコンテナを使いました。
- crowiもdocker-composeで立ち上げるため、コンテナネットワークを先に作成してます。

以下のリンクを参考にさせてもらいました。ただbasic認証をしないのでhtpasswdの部分とは省略しました。

- [Docker × Nginx × Let'sEncrypt | 俺の考えた最強のサーバー構築方法！ | Hackers Log](https://hackerslog.net/post/labs/docker-letsencrypt-on-docker-and-nginx/)
- [nginx-proxy, docker-gen という便利ツール – 1Q77](https://blog.1q77.com/2016/02/nginx-proxy-and-docker-gen/)
- [dockerでマルチなWeb環境を整えるのに便利なnginx-proxyの覚え書き – Aistear Web Laboratory](https://a-lab.biz/1111)

日本語の記事での十分かもしれませんが上の日本語の記事を読んだ後に、以下の letsencrpt-companion 公開先のReadmeを参照してやるといいかもです。『Separate Containers (recommended method)』ってやつです。僕はこれを見ながら、docker-compose.yamlにまとめました。

[JrCs/docker-letsencrypt-nginx-proxy-companion: LetsEncrypt companion container for nginx-proxy](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion)

３つのコンテナを一度に起動させるために、僕が使った docker-compose を貼っておきます。nginx-gen は entrypoint で実行します（command ではうまくいかなかった）。

下の docker-compose.yaml を`docker create network proxy`のあとに`docker-compose up -d`でproxyサーバの出来上がり。

> 自分は利用するイメージを全て手動でpullしてから起動してますが、それも自動でやる方法もあるんですね。[docker-compose コマンドまとめ - Qiita](http://qiita.com/aild_arch_bfmv/items/d47caf37b79e855af95f)
>
> それと docker-composeで指定している volume も手動で作ってました。見てもらえば分かるんですが、基本root以下に色々おいてます。それが良いことかどうかはわかりません…。

```(yaml):docker-compose.yaml
version: '2'

services:
  nginx:
    image: nginx
    container_name: nginx
    ports:
      - 80:80
      - 443:443
    volumes:
      - /etc/nginx/conf.d
      - /etc/nginx/vhost.d
      - /usr/share/nginx/html
      - /root/docker/nginx-proxy/certs:/etc/nginx/certs:ro
    labels:
      com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: "true"

  nginx-gen:
    image: jwilder/docker-gen
    container_name: nginx-gen
    volumes_from:
      - nginx
    volumes:
      - /root/docker/nginx-proxy/docker-gen/nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro
      - /var/run/docker.sock:/tmp/docker.sock:ro
    entrypoint: /usr/local/bin/docker-gen -notify-sighup nginx -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf

  letsencrypt-nginx-proxy-companion:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: letsencrypt-nginx-proxy-companion
    privileged: true
    volumes_from:
      - nginx
    volumes:
      - /root/docker/nginx-proxy/certs:/etc/nginx/certs:rw
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      - NGINX_DOCKER_GEN_CONTAINER=nginx-gen

networks:
  default:
    external:
      name: proxy
```

ここでは詳しいことを書きませんが、後にcrowiを起動した時に、certファイルが作成された場所に鍵が作成されたかどうがを確認することで、うまく動かなかったときにどこが問題とかわかってきます。

## Crowi

Proxy が立ったので、後は Crowi を建てます！

[bakudankun/crowi - Docker Hub](https://hub.docker.com/r/bakudankun/crowi/) を参考に、ver1.6.1に対応させる為のDockerfileを用意しました[yusanish/crowi - Docker Hub](https://hub.docker.com/r/yusanish/crowi/)。

> 初めてMITライセンスのコードを利用して、こういった形で公開することになりました。ここでも、bakudankunさんに感謝申し上げます。

`docker pull yusanish/crowi` で image を持ってきてください。

**ここで注意ですが**、Dockerhubに書いてあるdocker-composeはこのエントリー用では無いです。
**もう一つ注意として**、redis, mongoDB, elasticsearch の version指定。最新のものを使おうとするとうまく動かなかったです。

`docker-entrypoint.sh`を手元に持ってきた後、以下のdocker-compose.yamlを使ってください。

```
version: '2'                                        
                                                    
services:                                           
  crowi:                                            
    image: crowi-yusanish                           
    container_name: crowi                           
    links:                                          
      - mongo:db                                    
      - redis:redis                                 
      - elasticsearch:es                            
    expose:                                         
      - 3000                                        
    volumes:                                        
      - "~/crowi/data:/data"                        
    environment:                                    
      VIRTUAL_HOST: <your domain>            
      LETSENCRYPT_HOST: <your domain>
      LETSENCRYPT_EMAIL: <your mail（僕はgmailを使いました）>
                                                    
  mongo:                                            
    image: mongo:3                                  
    container_name: crowi-mongo                     
                                                    
  redis:                                            
    image: redis:3.0-alpine                         
    container_name: crowi-redis                     
                                                    
  elasticsearch:                                    
    image: elasticsearch:2-alpine                   
    container_name: crowi-elasticsearch             
    entrypoint:                                     
      - bash                                        
      - -c                                          
      - >-                                          
        bin/plugin list | grep -q analysis-kuromoji 
        || bin/plugin install analysis-kuromoji     
        && exec /docker-entrypoint.sh $$0 $$@       
    command: elasticsearch                          
                                                    
networks:                                           
  default:                                          
    external:                                       
      name: proxy                                   
```

そして、`docker-compe up -d`！

ちょっと待てば（僕の環境では１分くらい？）、指定したドメインの鍵ファイルが、先程指定した`/root/docker/nginx-proxy/certs`にできていることが確認でき、そして指定したドメインにアクセスすれば、crowi の 初回起動画面に入れると思います！

`docker ps`をするとこんな感じで動いていませんか？

```
CONTAINER ID        IMAGE                                    COMMAND                  CREATED             STATUS              PORTS                                      NAMES
000000000000        yusanish/crowi                           "/entrypoint.sh np..."   2 days ago          Up 1 minutes         3000/tcp                                   crowi
000000000000        mongo:3                                  "docker-entrypoint..."   2 days ago          Up 1 minutes         27017/tcp                                  crowi-mongo
000000000000        redis:3.0-alpine                         "docker-entrypoint..."   2 days ago          Up 1 minutes         6379/tcp                                   crowi-redis
000000000000        elasticsearch:2-alpine                   "bash -c 'bin/plug..."   2 days ago          Up 1 minutes         9200/tcp, 9300/tcp                         crowi-elasticsearch
000000000000        jrcs/letsencrypt-nginx-proxy-companion   "/bin/bash /app/en..."   2 days ago          Up 1 minutes                                                    nginx-proxy-letsencrypt-companion
000000000000        jwilder/docker-gen                       "/usr/local/bin/do..."   2 days ago          Up 1 minutes                                                    nginx-gen
000000000000        nginx                                    "nginx -g 'daemon ..."   2 days ago          Up 1 minutes         0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   nginx
```

## バックアップとリストア

### mongoDB

バックアップ

新しくmongoDBコンテナを建てて、mongodumpでリモート先からデータを持ってきてます。`chmod u+x`で権限を与えないと動かないです。

```
# docker run --rm --net=proxy --link mongo-crowi:mongo-crowi -v ~/crowi/mongodump:/dump:rw mongo /bin/bash -c "chmod u+x /dump && mongodump --host mongo-crowi --port 27017 -d crowi --out=/dump"
```

そして圧縮保存はこんな感じ。コンテナに渡した`/crowi/data/config`と`/crowi/data/uploads`も一緒に圧縮しちゃってます。

```
tar -cf ~/backups/crowi/20170516.tar -C ~ crowi
```

リストア

crowi を止めて、`/crowi/data`の中身を入れ替えて、データベースも元に戻す。

```
# cd /root/docker/crowi/
# docker-compose stop
# docker start mongo-crowi
# docker run --rm --net=proxy --link mongo-crowi:mongo-crowi -v ~/crowi/mongodump:/dump:rw mongo /bin/bash -c "chmod u+x /dump && mongorestore --host mongo-crowi"
# docker stop mongo-crowi
# docker-compose start
```

こんなところでしょうか！後はバックアップをご自身のお好きなようにcronで組めばよいと思います。
申し訳ありませんが、サーバーサイド、Docker初心者なので、質問にお答えするのは難しいと思います。
今回は、建てたナレッジを共有したくてエントリー書きました。
次はmastdonとgitlabを建てたいけど、Railsアプリ重いと聞くし悩みどころですね。

## 後日談

### ブラウザのCookieのせいで502 Bad Gatewayに何度も泣かされた。

ヘッダータイトルどおりで、うまく動かない理由がはじめの方はわからず、やっていくうちに履歴の性ということがわかりました。プライベートウィンドウで動作確認すれば問題ありません。

### busybox コンテナ

データの永続化についあまり考えれておらず、こういったものもあるんだなとあとで知りました。