アキレスと亀

一日一歩。一日一膳。光合成で生きていきたいお気持ちが強い。

Growi+PostfixをDockerで構築

背景

久々にWikiを構築する機会があったので、お気に入りのGrowiを使用して構築することにした。
手軽に使用できるSMTPサーバがないため、メールサーバ込みで構築する必要がある。
運用面を考えて全てコンテナで構築したいが、公式のdocker-composeではメールサーバまでカバーしていない。
また、最小限の認証機能付きDocker imageも見つからない。 上記の理由から自分で構築したが、意外と試行錯誤したため共有。

構築手順

growi-docker-composeのダウンロード

公式のGithubから、docker-composeをダウンロード。

$ git clone https://github.com/weseek/growi-docker-compose.git growi

Postfixの構築

Postfixコンテナ用ディレクトリの作成。

$ cd growi
$ mkdir postfix
$ mkdir postfix/conf

postfix/Dockerfileの作成。Alpine Linuxで作成する。

FROM alpine:latest

RUN apk add --update --no-cache postfix cyrus-sasl bash

ADD conf/main.cf /etc/postfix/main.cf
ADD conf/smtpd.conf /usr/lib/sasl2/smtpd.conf
ADD entrypoint.sh /entrypoint.sh

CMD /entrypoint.sh

postfix/conf/main.cfの作成。

mynetworks = 127.0.0.0/8
maillog_file = /dev/stdout
myhostname =  # This will be overwritten in entrypoint.sh
smtp_relay_restrictions = permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes

postfix/conf/smtpd.confの作成。今回は、sasldbプラグインを利用し、ファイルでパスワードを作成する。(参考サイト)
mech_listの行は、多分PLAIN LOGINだけで大丈夫。

pwcheck_method: auxprop
auxprop_plugin: sasldb
mech_list: PLAIN LOGIN CRAM-MD5 DIGEST-MD5 NTLM

postfix/entrypointの作成。

#!/bin/bash

# SASL Settings
if [ ! -f /etc/sasl2/sasldb2 ]; then
  mkdir /etc/sasl2
  echo $smtp_pw | saslpasswd2 -p -c -f /etc/sasl2/sasldb2 -u $ mail_domain $smtp_user
  chown postfix:postfix /etc/sasl2/sasldb2
fi

# Execute newaliases
postconf -e myhostname=$mail_domain
newaliases

# Start postfix
postfix start-fg

docker-compose.ymlの編集

以下の通り編集。

version: '3'

services:
  app:
    build:
      context: .
      dockerfile: ./Dockerfile
    ports:
      - 3000:3000    # localhost only by default
    links:
      - mongo:mongo
      - elasticsearch:elasticsearch
    depends_on:
      - mongo
      - elasticsearch
    environment:
      - MONGO_URI=mongodb://mongo:27017/growi
      - ELASTICSEARCH_URI=http://elasticsearch:9200/growi
      - PASSWORD_SEED=changeme
      - FILE_UPLOAD=mongodb   # activate this line if you use MongoDB GridFS rather than AWS
      - MATHJAX=1             # activate this line if you want to use MathJax
      
    entrypoint: "dockerize
                  -wait tcp://mongo:27017
                  -wait tcp://elasticsearch:9200
                  -timeout 60s
                  /docker-entrypoint.sh"
    command: ["yarn migrate && node -r dotenv-flow/config --expose_gc dist/server/app.js"]

    restart: unless-stopped
    volumes:
      - growi_data:/data

  mongo:
    image: mongo:4.4
    restart: unless-stopped
    volumes:
      - mongo_configdb:/data/configdb
      - mongo_db:/data/db

  elasticsearch:
    build:
      context: ./elasticsearch
      dockerfile: ./Dockerfile
    environment:
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms256m -Xmx256m"  # increase amount if you have enough memory
      - LOG4J_FORMAT_MSG_NO_LOOKUPS=true # CVE-2021-44228 mitigation for Elasticsearch <= 6.8.20/7.16.0
    ulimits:
      memlock:
        soft: -1
        hard: -1
    restart: unless-stopped
    volumes:
      - es_data:/usr/share/elasticsearch/data
      - ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml

  postfix:
    build:
      context: ./postfix
      dockerfile: ./Dockerfile
    environment:
      - mail_domain=server.example.com
      - smtp_user=test
      - smtp_pw=testpass
    ports:
      - 127.0.0.1:25:25
    restart: unless-stopped

volumes:
  growi_data:
  mongo_configdb:
  mongo_db:
  es_data:

構築・テスト

コンテナ構築

$ docker-compose build
$ docker-compose up -d

ブラウザからアクセス。http://localhost:3000
管理者アカウント作成。
設定 > アプリ設定 > メール設定から、以下を設定する。

  • Fromアドレス: 任意(ドメインは、$mail_domainのサーバ名を抜いたものにする。)
  • 送信方法: SMTP
  • ホスト: postfix
  • ポート: 25
  • ユーザ: test
  • パスワード: testpw

SASLのデバッグ方法

Growiのメールテストがうまく動かない場合は、以下のようにデバッグする。

@Postfixコンテナ
docker-compose logs -f postfixpostfixのログを監視。

@Growiコンテナ
apt update && apt install telnettelnetをインストール。
telnet postfix 25postfixコンテナに接続。
以下のような感じで、認証が通るか確認。

220 server.example.com ESMTP Postfix
EHLO client.example.com  # 入力する
250-server.example.com
250-PIPELINING
250-SIZE 10240000
250-ETRN
250-AUTH DIGEST-MD5 PLAIN CRAM-MD5
250 8BITMIME
AUTH PLAIN dGVzdAB0ZXN0AHRlc3RwYXNz  # 入力する。
235 Authentication successful

AUTH PLAINの後の文字は、"{認証ユーザ名}¥0{認証ユーザ名}¥0{認証パスワード}"をbase64エンコードした文字。
¥0はNULL文字。
test/testpassの場合は、dGVzdAB0ZXN0AHRlc3RwYXNzとなる。
認証が通らない場合には、postfixコンテナ側のlogを見ながらググる