Nextcloud with Apache2(http2) + PostgreSQL on Docker

【[当研究室のシステム](https://qiita.com/NeK/items/70f994b271b0c1a48590)】
# 概要
Docker起動したらNextcloud動くようにしたもの．「[apache2(http2) on Docker]」をベースにしたもの．


## 準備
細かな設定はそれぞれのページに沿うものとする．

* [apache2(http2) on Docker]
* [php-fpm on Docker]
* [PostgreSQL on Docker]

### Apache2にインストールするモジュール等
公式の[Installation on Linux -Prerequisites for manual installation](https://docs.nextcloud.com/server/latest/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation)眺めて，入っていないものをインストール．
自分は，LDAP, PostgreSQLを使用しているので，関係しているものを入れている．

### パラメータについて
phpのパラメータはphp-fpmのDockerfileで，Nextcloudのパラメータはマウントしている`/srv/nfs4/apache2/www/nextcloud/config/config.php`を直接編集し，設定している．
基本的には公式の値を使用しているが，自分の環境に合わせて変更した部分も少しある．

# 設定
## データベース関係
nextcloudで使用するデータベース用のユーザ・テーブル作成．
[PostgreSQL on Docker]の場合，データベースの動いているPC上で作業．
例だとコンテナ名は`pgsql_db`，ユーザ名は`nextcloud`，パスワードは`pass`，データベース名は`nextcloud_db`．適宜変えましょう(特にパスワード)．

```bash
$ docker container exec --user postgres -it <データベースのコンテナ名> bash
$ psql
postgres=# CREATE USER <ユーザ名> WITH PASSWORD '<パスワード>';
postgres=# CREATE DATABASE <データベース名> WITH OWNER <ユーザ名>;
```

```bash:例
$ docker container exec --user postgres -it pgsql_db bash
$ psql
postgres=# CREATE USER nextcloud WITH PASSWORD 'pass';
postgres=# CREATE DATABASE nextcloud_db WITH OWNER nextcloud;
```

以後はこの例を使用する．

## Apache2関係
Apache2で使用するNextcloud用のconf作成．
[apache2(http2) on Docker]の場合，`~/Docker/www/sites-available/`に作成．

```conf:~/Docker/www/sites-available/nextcloud.conf
Alias /nextcloud "/var/www/nextcloud/"

<Directory /var/www/nextcloud/>
  Require all granted
  AllowOverride All
  Options FollowSymLinks MultiViews

  <IfModule mod_dav.c>
    Dav off
  </IfModule>
</Directory>
```

## Docker関係
[apache2(http2) on Docker]の`Dockerfile`を以下のように編集・更新．

```Dockerfile:~/Docker/www/Dockerfile
FROM ubuntu:22.04

RUN set -x && \
    apt update && apt upgrade -y && \
    DEBIAN_FRONTEND=noninteractive apt install -y \
       apache2 \
       locales && \
    locale-gen ja_JP.UTF-8

ENV TZ=Asia/Tokyo LANG=ja_JP.UTF-8 LANGUAGE=ja_JP:ja

COPY ./conf /etc/apache2/conf
COPY ./sites-available /etc/apache2/sites-available

ARG HOSTNAME=www # ホスト名として名前を適宜設定(ここではwww)

# 以下ではdefault.confもdefault-ssl.confも使用する設定
RUN echo ServerName $HOSTNAME > /etc/apache2/conf-available/fqdn.conf && \
    /usr/sbin/a2enconf fqdn && \
    /usr/sbin/a2dismod php8.1 && \
    /usr/sbin/a2dismod mpm_prefork && \
    /usr/sbin/a2enmod mpm_event && \
    /usr/sbin/a2enmod proxy_fcgi && \
    /usr/sbin/a2enmod setenvif && \
    /usr/sbin/a2enmod http2 && \
    /usr/sbin/a2dissite 000-default && \
    /usr/sbin/a2ensite default-ssl && \
    /usr/sbin/a2enmod ssl && \
    /usr/sbin/a2enmod authnz_ldap && \
    /usr/sbin/a2ensite moodle && \
    /usr/sbin/a2enmod rewrite && \
    /usr/sbin/a2ensite nextcloud && \
    /usr/sbin/a2enmod headers

EXPOSE 80
EXPOSE 443

CMD ["apachectl","-D","FOREGROUND"]
```

`memory_limit >= post_max_size >= upload_max_filesize`である．
で，Nextcloudの場合，大きなファイルは分割してアップロード，その後に内部で結合，らしい．のである程度で良さそう．
ただし下記参考にあるようにパラメータの調整は必要そう．
参考:[【techblog】Nextcloud での大容量ファイルの取り扱い](https://nextcloud.stylez.co.jp/blog/techblog/nextcloud-handling-large-file.html)

ちなみに`max_execution_time = 3600`はNextcloudの`filelocking.ttl`のデフォルト値に合わせただけ．

[php-fpm on Docker]の`Dockerfile`を以下のように編集・更新．

```Dockerfile:~/Docker/php-fpm/Dockerfile
FROM php:8.1.18-fpm-bullseye

RUN set -x && \
    apt update && apt upgrade -y && \
    DEBIAN_FRONTEND=noninteractive apt install -y \
       ffmpeg && \
    curl -sSLf \
        -o /usr/local/bin/install-php-extensions \
        https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions && \
    chmod +x /usr/local/bin/install-php-extensions && \
    install-php-extensions apcu bcmath bz2 curl gd gmp exif imagick imap intl ldap mbstring opcache pdo pdo_pgsql pgsql smbclient sysvsem xml zip

ENV TZ=Asia/Tokyo

# Use the default production configuration
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" && \
    sed -i 's/memory_limit = 128M/memory_limit = -1/' "$PHP_INI_DIR/php.ini" && \
    sed -i 's/post_max_size = 8M/post_max_size = 20480M/' "$PHP_INI_DIR/php.ini" && \
    sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 20480M/' "$PHP_INI_DIR/php.ini" && \
    sed -i 's/max_execution_time = 30/max_execution_time = 600/' "$PHP_INI_DIR/php.ini" && \
    sed -i 's/;max_input_vars = 1000/max_input_vars = 5000/' "$PHP_INI_DIR/php.ini" && \
    echo "apc.enable_cli=1" >> "$PHP_INI_DIR/php.ini" && \
    echo "opcache.enable = 1" >> "$PHP_INI_DIR/conf.d/docker-php-ext-opcache.ini" && \
    echo "opcache.enable_cli = 1" >> "$PHP_INI_DIR/conf.d/docker-php-ext-opcache.ini" && \
    echo "opcache.interned_strings_buffer = 16" >> "$PHP_INI_DIR/conf.d/docker-php-ext-opcache.ini" && \
    echo "opcache.max_accelerated_files = 10000" >> "$PHP_INI_DIR/conf.d/docker-php-ext-opcache.ini" && \
    echo "opcache.memory_consumption = 256" >> "$PHP_INI_DIR/conf.d/docker-php-ext-opcache.ini" && \
    echo "opcache.save_comments = 1" >> "$PHP_INI_DIR/conf.d/docker-php-ext-opcache.ini" && \
    echo "opcache.revalidate_freq = 600" >> "$PHP_INI_DIR/conf.d/docker-php-ext-opcache.ini" && \
    echo "opcache.jit = 1255" >> "$PHP_INI_DIR/conf.d/docker-php-ext-opcache.ini" && \
    echo "opcache.jit_buffer_size = 256M" >> "$PHP_INI_DIR/conf.d/docker-php-ext-opcache.ini" && \
    cp /usr/local/etc/php-fpm.d/www.conf /usr/local/etc/php-fpm.d/zzz-www.conf && \
    sed -i 's!pm.max_children = 5!pm.max_children = 10!' /usr/local/etc/php-fpm.d/zzz-www.conf && \
    sed -i 's!listen = 127.0.0.1:9000!listen = /var/run/php-fpm/php-fpm.sock!' /usr/local/etc/php-fpm.d/zzz-www.conf && \
    sed -i 's!;listen.owner = www-data!listen.owner = www-data!' /usr/local/etc/php-fpm.d/zzz-www.conf && \
    sed -i 's!;listen.mode = 0660!listen.mode = 0660!' /usr/local/etc/php-fpm.d/zzz-www.conf
```

docker-compose.ymlは[apache2(http2) on Docker]のものをそのまま使用．

```yml:~/Docker/docker-compose.yml
version: '3.9'

services:
  www:
    build: ./www
    image: nek/www:latest
    container_name: www
    hostname: www
    ports:
      - 443:443
    restart: always
    depends_on:
      - php-fpm
    volumes:
      - www_data:/var/www
      - socket:/var/run/php-fpm

  php-fpm:
    build: ./php-fpm
    image: nek/php-fpm:latest
    container_name: php-fpm
    hostname: php-fpm
    restart: always
    volumes:
      - www_data:/var/www
      - socket:/var/run/php-fpm
      - /etc/group:/etc/group:ro
      - /etc/passwd:/etc/passwd:ro

volumes:
  socket:
  www_data:
    driver_opts:
      type: nfs
      o: "port=2049,addr=192.168.0.2,rw,nfsvers=4"
      device: ":/apache2/www"
```

## Nextcloud
### 本体のDL・展開
1. [公式](https://nextcloud.com/install/)のcommunity projectsのGet Zip fileから`latest.zip`を取得．
1. /var/www/nextcloudに展開
    1. [Apache2 on Docker]ではnfs4で提供されている`/apache/www`を利用しているので，もととなる`/apache/www/nextcloud`に展開．
    1. 所有権を`www-data`に設定
       ```bash
       cd '/apache/www/の場所'
       chown -R www-data:www-data nextcloud
       ```
### ビルド&起動

```bash
cd ~/Docker
docker compose up -d --build
```

エラーがなければブラウザ経由(`https://<自分のサイト名>/nextcloud/`や`https://<IPアドレス>/nextcloud/`など)でアクセスできる．

### Nextcloudのインストール
ブラウザ経由でアクセスすると，設定を行うためのページが出てくる．
管理者用のユーザ名・パスワードはここで設定する．
その他のものは設定した値(データ置き場:/var/www/nextcloud/data，データベースアクセスのためのユーザ名:nextcloud，そのパスワード:pass，データベース名:nextcloud_dbやデータベースの名前・IPアドレスなど)を入力する．
ちょっと時間がかかるが，正しく終わると次に進む．
入力間違えちゃって訳が分からなくなったら，`nextcloud/config/config.php`を消してもう一回すればよい．

自分の環境では，`https://nextcloud/index.php/core/apps/recommended`にジャンプして「読み込めないよ」と出た．しかし，`https://`と`nextcloud/index.php/...`の間に自分のサイト名を入れたら無事に次の画面に進んだ．

# 運用
基本的にネットに沢山の情報があるので適当に調べつつ設定．
以下は，特に自分用の忘備録．

## cronについて
定期的に回したいものなどぼちぼちある．
特に管理者でログインし設定する**バックグラウンドジョブ**では`Cron(推奨)`に設定した上でシステムのcronにより`nextcloud/cron.php`を5分ごとに実行する必要がある．
一方でdockerでcronまわすのはちょっと面倒っぽい．
よってホストPCのcronでdocker内の処理を定期的に実行する．`nextcloud/cron.php`の例だと以下のようになる．

```:ホストの/etc/cron.d/nextcloud
*/5 * * * * root docker container exec --user www-data php-fpm /usr/local/bin/php -f /var/www/nextcloud/cron.php
```

## 新規ユーザのデフォルトフォルダ・ファイル類
nextcloudインストールディレクトリの`core/skelton/`に新規ユーザ用のフォルダ・ファイルが配置されている．これをいじると良い．


[apache2(http2) on Docker]:https://qiita.com/NeK/items/22d5849da05cca717a76
[PostgreSQL on Docker]:https://qiita.com/NeK/items/15d7dbe20d1ace57ffb8
[php-fpm on Docker]:https://qiita.com/NeK/items/8b539a81a3d9af005471