Apache2 on Docker

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

Apache上でPukiwiki, Moodle, Nextcloudなど動かすのに細々といじりたいので自分で作成．
そんなに効率的ではないが，自分にとって楽な方法．

## 前提

* とりあえずApache2が動作するまでのもの
* ディレクトリなどはubuntuのaptでインストールしたもの準拠
* SSL/TLS接続のための`server.crt`と`server.key`は取得済
* sites-availableはマウントではなくDockerfileの中でCOPY
    * site-availableの中を増やすとビルドし直しで手間
    * しかし全site-available/以下の対象をビルドのみで起動
        * Dockerfileに全部任せられて楽かも？
* ubuntu:22.04がベース
    * alpineとかの方がいいのかもしれないが，自分が慣れているから
* 説明のためにディレクトリ構成は以下のとおり
    * ~/Docker/www/
        * www用のDockerfileなど置くところ
    * nfs4によるデータ領域のマウント
        * /var/www/以下のデータはデータサーバ(192.168.0.2)に置くことを考える．
            * べつにローカルにおいても良いんだけど
        * データサーバはnfs4で公開している
            * 名前は`/apache2/www`

# 設定
## 準備

conf用のディレクトリの作成

```bash
$ mkdir -p ~/Docker/www/sites-available/
```

### 通常:80ポート使用
デフォルトで`000-default.conf`がある．
それをそのまま使用しても良いが，~~なんか気に食わない~~動作確認のために`default.conf`の名前で使用する．

#### `default.conf`の作成

`ServerAdmin`および`ServerName`(FQDN)は自分のものに合わせて設定しましょう．
```conf:~/Docker/www/sites-available/default.conf
<VirtualHost *:80>
     ServerAdmin webmaster@localhost
     ServerName my.domain.name.co.jp
     DocumentRoot /var/www/html

     ErrorLog ${APACHE_LOG_DIR}/error.log
     CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
```

### SSL/TLS接続の場合: 443ポート使用
中間CA証明書の名前はとりあえず`nii-hogehogehoge.cer`とする．

#### `default-ssl.conf`の作成

`ServerAdmin`および`ServerName`(FQDN)は自分のものに合わせて設定しましょう．
```conf:~/Docker/www/sites-available/default-ssl.conf
<IfModule mod_ssl.c>
        <VirtualHost _default_:443>
                ServerAdmin webmaster@localhost
                ServerName my.domain.name.co.jp
                DocumentRoot /var/www/html

                ErrorLog ${APACHE_LOG_DIR}/error.log
                CustomLog ${APACHE_LOG_DIR}/access.log combined

                SSLEngine on

                SSLCertificateFile      /etc/apache2/conf/ssl.crt/server.crt
                SSLCertificateKeyFile /etc/apache2/conf/ssl.key/server.key
                SSLCertificateChainFile /etc/apache2/conf/ssl.crt/nii-hogehogehoge.cer

                <FilesMatch "\.(cgi|shtml|phtml|php)$">
                                SSLOptions +StdEnvVars
                </FilesMatch>
                <Directory /usr/lib/cgi-bin>
                                SSLOptions +StdEnvVars
                </Directory>
        </VirtualHost>
</IfModule>
```

`server.crt`, `server.key`, `nii-hogehogehoge.cer`は`~/Docker/www/conf/`以下に入れておく．

## 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/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

EXPOSE 80
EXPOSE 443

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

### とりあえずビルド
`イメージ名`と`タグ名`は適宜設定する．例えば`nek/www:latest`とか．

```bash
docker image build -t <イメージ名:タグ名> .
```

### `docker-compose.yml`の作成

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

services:
  www:
    build: .
    image: nek/www:latest
    container_name: www
    hostname: www
    ports:
      - 80:80
      - 443:443
    restart: always
    volumes:
      - www_data:/var/www

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

# 運用
* 起動
   ```bash
   docker compose up -d
   ```
* 終了
   ```bash
   docker compose down
   ```
* サイトを増やした場合(sites-available/*.confの追加)，再度ビルド．
    * confファイルの追加とともに，`Dockerfile`中で`/usr/sbin/a2ensite ...`をして有効にすること

## 注意
### sites-available/*.confの「編集」のみの場合
既に追加し，a2ensiteしているconfファイルを編集した場合，そのままビルドしても編集は有効にならない．
なぜなら`Dockerfile`自体が更新されているわけではないので，confファイルがDockerの中のイメージに反映されず古いままとなる．

対策としては色々あるけど，とりあえず`docker image build --no-cache -t <イメージ名:タグ名> .`とやっておけば間違いない．時間かかるけど．