Nextcloud with Apache2 + PostgreSQL on Docker

【[当研究室のシステム](https://qiita.com/NeK/items/70f994b271b0c1a48590)】

【変更履歴】
2023/04/10:php.iniの`memory_limit`, `post_max_size`, `upload_max_filesize`変更．

# 概要
Docker起動したらNextcloud動くようにしたもの．
Apache2のDockerの中にNextcloudを設定．Apache2で動かしているメインのページは`/var/www/html`などに別にあり，Nextcloudはサブディレクトリで動かす(Nextcloud専用にしない)．
PostgreSQLのDockerは他のPC上にあるものとするが，同じPC上に構築する場合も同様．

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

* [Apache2 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-ldap`，`php-pgsql`をインストールし，`a2enmod authnz_ldap`している．

### パラメータについて
phpのパラメータはApache2の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 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 on Docker]の`Dockerfile`を以下のように編集・更新．
[Apache2 on Docker]の`docker-compose.yml`はそのまま使用．

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

RUN set -x && \
    apt update && apt upgrade -y && \
    DEBIAN_FRONTEND=noninteractive apt install -y \
       apache2 \
       ffmpeg \
       libmagickcore-6.q16-6-extra \
       locales \
       php \
       php-apcu \
       php-bcmath \
       php-bz2 \
       php-curl \
       php-gd \
       php-gmp \
       php-imagick \
       php-imap \
       php-intl \
       php-ldap \
       php-mbstring \
       php-pgsql \
       php-smbclient \
       php-xml \
       php-zip && \
    locale-gen ja_JP.UTF-8

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

ARG HOSTNAME=www

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

RUN echo ServerName $HOSTNAME > /etc/apache2/conf-available/fqdn.conf && \
    /usr/sbin/a2enconf fqdn && \
    /usr/sbin/a2dissite 000-default && \
    /usr/sbin/a2ensite default && \
    /usr/sbin/a2ensite default-ssl && \
    /usr/sbin/a2enmod ssl && \
    /usr/sbin/a2enmod authnz_ldap && \
    /usr/sbin/a2enmod rewrite && \
    /usr/sbin/a2ensite nextcloud && \
    /usr/sbin/a2enmod headers && \
    sed -i 's/memory_limit = 128M/memory_limit = -1/' /etc/php/8.1/apache2/php.ini && \
    sed -i 's/memory_limit = 128M/memory_limit = -1/' /etc/php/8.1/cli/php.ini && \
    sed -i 's/post_max_size = 8M/post_max_size = 128M/' /etc/php/8.1/apache2/php.ini && \
    sed -i 's/post_max_size = 8M/post_max_size = 128M/' /etc/php/8.1/cli/php.ini && \
    sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 128M/' /etc/php/8.1/apache2/php.ini && \
    sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 128M/' /etc/php/8.1/cli/php.ini && \
    sed -i 's/max_execution_time = 30/max_execution_time = 3600/' /etc/php/8.1/apache2/php.ini && \
    sed -i 's/max_execution_time = 30/max_execution_time = 3600/' /etc/php/8.1/cli/php.ini && \
    sed -i 's/;max_input_vars = 1000/max_input_vars = 5000/' /etc/php/8.1/apache2/php.ini && \
    sed -i 's/;max_input_vars = 1000/max_input_vars = 5000/' /etc/php/8.1/cli/php.ini && \
    echo "opcache.enable = 1" >> /etc/php/8.1/mods-available/opcache.ini && \
    echo "opcache.enable_cli = 1" >> /etc/php/8.1/mods-available/opcache.ini && \
    echo "opcache.interned_strings_buffer = 16" >> /etc/php/8.1/mods-available/opcache.ini && \
    echo "opcache.max_accelerated_files = 10000" >> /etc/php/8.1/mods-available/opcache.ini && \
    echo "opcache.memory_consumption = 256" >> /etc/php/8.1/mods-available/opcache.ini && \
    echo "opcache.save_comments = 1" >> /etc/php/8.1/mods-available/opcache.ini && \
    echo "opcache.revalidate_freq = 1" >> /etc/php/8.1/mods-available/opcache.ini && \
    echo "opcache.jit = 1255" >> /etc/php/8.1/mods-available/opcache.ini && \
    echo "opcache.jit_buffer_size = 256M" >> /etc/php/8.1/mods-available/opcache.ini && \
    echo "apc.enable_cli=1" >> /etc/php/8.1/apache2/php.ini && \
    echo "apc.enable_cli=1" >> /etc/php/8.1/cli/php.ini

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`のデフォルト値に合わせただけ．

## 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
       ```
### Dockerイメージの作成・起動
`~/Docker/www`で作業．
イメージ名・タグ名はご自由に．

```bash
docker image build -t nek/www:latest . && docker compose up -d
```

エラーがなければブラウザ経由(`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 www /usr/bin/php -f /var/www/nextcloud/cron.php
```

[Apache2 on Docker]:https://qiita.com/NeK/items/51bbee008f11f0c62e0e
[PostgreSQL on Docker]:https://qiita.com/NeK/items/15d7dbe20d1ace57ffb8