Dockerを使って、ownCloudをセットアップしてみた。 運用編

#はじめに
前回、[Dockerを使って、ownCloudをセットアップしてみた。 Nginx編](http://qiita.com/takanemu/items/0b813408bd3cc9f74922)では、Nginx,ownCloud,PostgreSQLの3つのコンテナを使って、ownCloud環境を作成しました。
今回は、運用するのに必要な情報を調べてみました。

##カスタマイズ
多くの場合、ownCloudをそのまま使うのではなく、会社のロゴを入れたりブランディングするのでは、ないでしょうか？
ownCloudは、カスタマイズする方法が公式に用意されておりバージョンアップしたら上書きされてしまうなどの問題を気にせずカスタマイズが行えます。
参考：[ownCloudのカスタマイズ方法](https://thinkit.co.jp/article/9773)

owncloudコンテナの中から```/var/www/html/themes/example```ディレクトリを抜き取りカスタマイズします。
具体的なカスタマイズ方法は、参考サイトを参照してください。
会社ロゴと色を弄るだけでもだいぶ見栄えが変わります。
カスタマイズしたテーマサンプルのディレクトリ名称をMyThemeへ変更しtarに固めてからDockerイメージをビルドします。
ビルドが成功したらDocker Hubへプッシュします。(ここはお好みで)

```:config.php
<?php
$CONFIG = array (
  'theme' => 'MyTheme',  
);
```

```:Dockerfile
FROM owncloud:fpm
COPY config.php /var/www/html/config/config.php
ADD ./MyTheme.tar.gz /var/www/html/themes/
MAINTAINER yyyy@xxxx.jp
```

```:bash
$ docker login
$ docker build -t takanemu/owncloud .
$ docker push takanemu/owncloud
```

##データバックアップ
dockerを勉強してみて面白いと思ったのは、データコンテナです。
dockerのコンテナは、仮想環境なので当然データについても仮想環境の内部に閉じています。
volumesオプションを付加することで、コンテナが削除されてもデータが消えないように永続化できるのですが
ホストOSと共有化されたデータファイルをホストOS側からバックアップするのだろうと思っていました。
しかし、一手間かけて、データコンテナに集約するというのが、docker界の流儀のようです。
データコンテナというのは、プロセスを持たない共有ディレクトリだけをマウントするコンテナのことで、busyboxという組み込み向けlinuxの簡易コマンドラインツールのイメージを使います。
busyboxでないと駄目な訳ではなくコマンドラインツールが使える最も小さなコンテナイメージということです。
volumes_fromオプションを使い共有化されているowncloudとpostgresのディレクトリをマウントします。
busyboxは、プロセスを持っていないので、そのままではコンテナとして起動しません。
commandオプションで、シェルを立ち上げてプロセスの代わりにします。
バックアップ用のコンテナ操作ファイルは別(backup.yml)になっています。

```:docker-compose.yml
# postgres
postgres:
    image: postgres
    container_name: postgres
    volumes:
        - "~/data/postgres:/var/lib/postgresql/data"
    environment:
        POSTGRES_PASSWORD: supersecretpassword
# owncloud
owncloud:
    image: owncloud:fpm
    container_name: owncloud
    links:
        - postgres
    volumes:
        - "~/data/owncloud/apps:/var/www/html/apps"
        - "~/data/owncloud/config:/var/www/html/config"
        - "~/data/owncloud/data:/var/www/html/data"
# nginx
nginx:
    image: raulr/nginx-owncloud
    container_name: nginx
    links:
        - owncloud
    volumes_from:
        - owncloud
    ports:
        - "80:80"
```
実行します。

```:bash
$ docker-compose up -d
```

```:backup.yml
# data
dataonly:
    image: busybox
    container_name: dataonly
    command: /bin/sh
    tty: true
    volumes_from:
        - owncloud:ro
        - postgres:ro
```
バックアップをしてみます。
dataonlyコンテナが起動している状態で、exportを実行すれば、バックアップファイルが作成されます。

```:bash
$ docker-compose -f backup.yml up -d
$ docker export dataonly | gzip -c > backup.tar.gz
$ docker-compose -f backup.yml stop
```
##証明書設定
###証明書の購入
最近は、無料の証明書もあるので、そちらを利用しようかと思ったのですが、会社のインフラなので、EV証明書を購入するように上司から指示がありサイバートラストさんのEV Multi-Domainという証明書を購入することにしました。
社内手続きで証明書購入まで時間は掛かりましたが、アドレスバーに社名が表示されるとそれっぽく見えますね。
個人ではなかなか、買えないお値段のブツなので、良い勉強になりました。
途中ドメイン絡みで私のミスが発覚して、サポートに問合せしたのですが、レスポンス良く対応して貰えて助かりました。
サーバー証明書の購入から設定まで、完全な初心者だったのですが、落ち着いてドキュメントを読み込んでいけば、問題無く設定できると思います。（何度か心が折れそうになりましたけど）
###中間CA証明書のダウンロード
サーバー証明書と中間CA証明書は、発行のお知らせメールに載っているURLからダウンロードします。クロスルート証明書は、必要ないみたいなので無視します。
###証明書と中間CA証明書を合体
証明書ファイルと中間CA証明書を連結します。

```:bash
$ cat サーバー証明書 中間CA証明書 > 連結したファイル
```
###鍵ファイルにパスワードを埋め込み
証明書屋さんの説明書通りに、鍵ファイルを作ると鍵にはパスフレーズが設定されます。
ですが、パスフレーズの設定されている鍵ファイルを使用するとNginxの起動時に、パスフレーズの入力が要求されてしまいます。
コンテナの中のNginxに、どうやって入力させるのか悩んだのですが、どうやら鍵ファイルに、パスフレーズを埋め込む事ができるみたいです。

```:bash
$ cp server.key server.key.org
$ openssl rsa -in server.key.org -out server.key
[パスフレーズ入力]
```
###コンテナへ証明書と鍵ファイルをコピー
コンテナ内へ入りフォルダを作成してからdockerコマンドで、ファイルをコピーします。

```:bash
$ sudo docker exec -it nginx /bin/bash
$ mkdir /etc/nginx/ssl_certs
$ sudo docker cp ./sslkey/certs.pem nginx:/etc/nginx/ssl_certs/certs.pem
$ sudo docker cp ./sslkey/server.key nginx:/etc/nginx/ssl_certs/server.key
```
###設定ファイルの書き換え
コンテナ内には、vimが入っていませんので、ホストへコピーしてから書き戻します。

```:bash
$ sudo docker cp nginx:/etc/nginx/conf.d/default.conf ./sslkey/default.conf 
$ vi ./sslkey/default.conf
$ sudo docker cp ./sslkey/default.conf nginx:/etc/nginx/conf.d/default.conf
```
設定ファイルの修正は、HTTPをHTTPSへリダイレクトするのと証明書の設定とセキュリティ対策を少しだけ修正しています。（ほぼ追記です）

```:default.conf
upstream php-handler {
  server owncloud:9000;
}

server {
    listen 80;
    server_name [FQDN];
    return 301 https://$server_name$request_uri;
}

server {
  listen 443 ssl;
  server_name [FQDN];

  ssl_certificate     /etc/nginx/ssl_certs/certs.pem;
  ssl_certificate_key /etc/nginx/ssl_certs/server.key;

  # Add headers to serve security related headers
  add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
  add_header X-Content-Type-Options nosniff;
  add_header X-Frame-Options "SAMEORIGIN";
  add_header X-XSS-Protection "1; mode=block";
  add_header X-Robots-Tag none;
  add_header "X-Download-Options" "noopen";
  add_header "X-Permitted-Cross-Domain-Policies" "none";

  # Path to the root of your installation
  root /var/www/html;
  # set max upload size
  client_max_body_size 10G;
  fastcgi_buffers 64 4K;

  # Disable gzip to avoid the removal of the ETag header
  gzip off;

  index index.php;
  error_page 403 /core/templates/403.php;
  error_page 404 /core/templates/404.php;

  rewrite ^/.well-known/carddav /remote.php/carddav/ permanent;
  rewrite ^/.well-known/caldav /remote.php/caldav/ permanent;

  location = /robots.txt {
    allow all;
    log_not_found off;
    access_log off;
  }

  location ~ ^/(build|tests|config|lib|3rdparty|templates|data)/ {
    deny all;
  }

  location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
    deny all;
  }

  location / {

    rewrite ^/remote/(.*) /remote.php last;

    rewrite ^(/core/doc/[^\/]+/)$ $1/index.html;

    try_files $uri $uri/ /index.php;
  }

  location ~ \.php(?:$|/) {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param modHeadersAvailable true; #Avoid sending the security headers twice
    fastcgi_param HTTPS on;
    fastcgi_pass php-handler;
    fastcgi_intercept_errors on;
  }

  # Adding the cache control header for js and css files
  # Make sure it is BELOW the location ~ \.php(?:$|/) { block
  location ~* \.(?:css|js)$ {
    add_header Cache-Control "public, max-age=7200";
    # Add headers to serve security related headers
    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Robots-Tag none;
    # Don't log access to assets
    access_log off;
  }

  # Don't log access to other assets
  location ~* \.(?:jpg|jpeg|gif|bmp|ico|png|swf)$ {
    access_log off;
  }
}
```
###設定ファイルの確認
コンテナの中で、configtestを行って、設定ファイルをチェックします。

```:bash
$ sudo docker exec -it nginx /bin/bash
# /etc/init.d/nginx configtest
```
###証明書のチェック
クライアントのbashで、証明書のチェックを行います。

```:bash
$openssl s_client -connect [FQDN]:443 -showcerts << EOF
> HEAD / HTTP/1.0
> EOF
```
```Verify return code: 0 (ok)```と出力されれば、問題なく配置されています。
エラーの場合には、エラー内容が出力されるので、ググりましょう。