それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

Arm(aarch64)で mailcow-dockernized を動かした。

Arm(aarch64)で mailcow-dockernized を動かした。

mailcow とは

rspamd/virtual hosting メール / imaps / smtp / WEBメール / ip-ban の必要なものがワンセットで、docker compose だけで簡単にメール環境を作ることができる。

arm 版

Raspiやオラククラウド(A1)でARM64のバイナリを動かせるが、mailcow のdocker 版はx86を前提としているので、自分でビルドして、いくつかの設定を見直す必要がある。

Raspi-ubuntuやオラククラウド(A1)でメールサーバーを作って置こうと思い立って稼働させたのでメモ。色々苦労した

docker は qemu に対応しているので、docker だけでもx86バイナリを動かすことができるが、phpがとにかく遅い。メール配送はバックグラウンドになるで気にならないが、WEB-UIはx86バイナリを動かすとモタつきがきになる。そこでphp/sogo/dovecot をarm64で動かすのが良いと思う。Solr と clamv はメモリ食うのでオフにしてもいいと思うんですけどね。

arm で docker を起動したらエラーになる例。

そのまま起動すると exec format エラーになる。

docker の準備

そこで、aarch64(arm 64)バイナリ版をビルドしてみた。

### Docker の準備

sudo curl -sSL https://get.docker.com/ | CHANNEL=stable sh
sudo systemctl enable --now docker
sudo apt update
sudo apt install docker-compose-plugin
sudo usermod -aG docker $USER


## iptables でポートを開放する
sudo iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 25 -j ACCEPT
sudo iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
sudo iptables-save  | sudo tee /etc/iptables/rules.v4


### ソースコードの準備
git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized
### docker イメージの取得
docker compose pull

ipv6関連を切っていく。

v6関連があるとデバッグが煩雑になるので切っておく。

## mailcow の設定で、v6を切っていく
## 参考資料:https://docs.mailcow.email/post_installation/firststeps-disable_ipv6/
### docker v6 networkで切る
sed -i 's|enable_ipv6: true|enable_ipv6: false|' docker-compose.yml
## ipv6natを切る。
touch docker-compose.override.yml
cat <<EOF | sudo tee docker-compose.override.yml
version: '2.1'
services:
    ipv6nat-mailcow:
      image: bash:latest
      restart: "no"
      entrypoint: ["echo", "ipv6nat disabled in compose.override.yml"]
EOF

### unboundにv6応答をやめさせる
sed -i 's|do-ip6: yes|do-ip6: no|'  data/conf/unbound/unbound.conf
sed -i '/do-ip6/s/$/\n  prefer-ip6: no/g' data/conf/unbound/unbound.conf
sed -i '/ipsecmod-enabled/s/$/\n  local-zone: ip6.arpa. refuse/g' data/conf/unbound/unbound.conf

### postfix にv6利用をやめさせる
cat <<EOF | sudo tee -a data/conf/postfix/extra.cf
smtp_address_preference = ipv4
inet_protocols = ipv4
EOF
### nginx /devecot / php-fpm にv6リッスンをやめさせる
sed -i '\|\[::\]:8081;|d' data/conf/nginx/dynmaps.conf
sed -i '\|::|d' data/conf/nginx/templates/listen*
sed -i 's/,\[::\]//g' data/conf/dovecot/dovecot.conf
sed -i 's/\[::\]://g' data/conf/phpfpm/php-fpm.d/pools.conf
ホスト側でも念のためにv6を切っておいた

docker ホスト側(Oracleインスタンス=docker ホスト) でもv6はオフにしておいた。

cat <<EOF | sudo tee -a /etc/sysctl.conf
net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.lo.disable_ipv6=1
net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.eth0.disable_ipv6=1
EOF

cat <<EOF | sudo tee  /etc/rc.local
#!/bin/bash
# /etc/rc.local

/etc/sysctl.d
/etc/init.d/procps restart

exit 0
EOF

sudo chmod 755 /etc/rc.local
sudo /etc/rc.local

arm(aarch64)用にビルドする。

Arm用バイナリがapt/apk提供されているものは、docker buildだけでいける。

apt で済むもの

apk/apt が提供されているものは、docker build を実行すれば良い。

## ビルド
## sogo と dovecot と rspamd は公式レポジトリを使っている。ためビルドできない
#### debianパッケージを使えば動くと思うが未検証
## aarch64用にビルドする
# sed -i '\|rspamd.com/apt-stable|d' data/Dockerfiles/rspamd/Dockerfile

list=("
  acme
  clamd
  dockerapi
  netfilter
  olefy
  phpfpm
  postfix
  solr
  unbound
  watchdog
")
## aarch64用にビルドし直す 5分くらい
for service in $list; do 
  echo $service
  docker build data/Dockerfiles/$service -t mailcow/$service:aarch64_build
done
## aarch64用にビルドしたものを使う用に書き換え
for service in $list; do 
  echo $service
  grep "mailcow/$service" docker-compose.yml
  sed -i -E "s|mailcow/$service:[0-9.]+|mailcow/$service:aarch64_build|" docker-compose.yml
  grep "mailcow/$service" docker-compose.yml
done
sogo/dovecot/rspamd

sogo/dovecot/rspamd は debian/ubuntu の配布パッケージを使っていない。sogoは sogo.nu のnightly を使っているが、sogo.nuがarmバイナリを未提供

パッケージ mailcow指定 Arm版
sogo packages.sogo.nu ???
dovecot repo.dovecot.org なし
rspamd rspamd.com/apt-stable なし

それぞれ、Debian公式なら存在するので大体は出来る |パッケージ| Debian公式 | aarch64バイナリ | 特記事項 | |:---:|---:|:---:|:---| |sogo | debian/sid | あり | sogo-activesync/aarch64はsid のみ| |dovecot| debian/stable | あり |dovecot-lua がない| |rspamd | debian/stable |あり|sa-rulesが動かない。|

これらについては、インストール後に予期せぬ出来事に遭遇するかもしれないが、場当たり的な対応で動いた。

sogo は id:sogo の home ディレクトリが異なるので対応が必要。

dovecotdovecot-lua が無いが、mailcowがluaを未使用なので問題なさそう。

rspamd は、sa-rule がエラーになって起動しなくなるので、消せば動くが、アチコチで segmentation fault がでて面倒くさいのでarmは諦めて、qemu 経由でx86を動かすことにした。

aarch64で動かないものは、qemu経由で動かす準備する。

aarch64でビルドできない、または、動かすのを諦めるときは、qemu 経由して動かせば良い。ユーザー空間でqemu を動かせるbinfmt-support などを入れて上げるとx86バイナリでもArm64で強引に動かせる。

sudo apt-get install qemu binfmt-support qemu-user-static

これでqemu経由で起動する。

たとえば、次のように、プロセスを見るとqemu-binfmt 経由で起動してるのがわかる。

docker compose exec rspamd-mailcow ps s
root@rspamd:/# ps xf
    PID TTY      STAT   TIME COMMAND
    728 pts/0    Ssl    0:00 /usr/libexec/qemu-binfmt/x86_64-binfmt-P /bin/bash bash
    782 ?        Rl+    0:00  \_ ps xf
      1 ?        Ssl    0:00 /usr/libexec/qemu-binfmt/x86_64-binfmt-P /bin/bash /bin/bash /docker-entrypoint.sh /usr/bin/rspamd -f -u _rspamd -g _rspamd
    779 ?        Sl     0:00 /usr/libexec/qemu-binfmt/x86_64-binfmt-P /bin/sleep sleep 3

既存のボリュームを削除する

もし、起動するバイナリを変えたり、ビルドし直したたら、ボリュームも削除しておく。データ自体はホスト側に書かれるので問題がなさそう。ただしmysql のボリュームにメールデータが保存されるので、mysql を消すと完全に初期化される。

docker compose down  --volumes

初期設定する

./generate_config.sh が初期設定コマンドで、DBパスワードやPostfixオレオレ証明書などを作ってくれる。

./generate_config.sh
Found Docker Compose Plugin (native).
Setting the DOCKER_COMPOSE_VERSION Variable to native
Notice: You´ll have to update this Compose Version via your Package Manager manually!
Press enter to confirm the detected value '[value]' where applicable or enter a custom value.
Mail server hostname (FQDN) - this is not your mail domain, but your mail servers hostname:

起動

mailcow を起動する。

初回起動は、順番に初期化しながらで5分くらいかかる。rspamd が無事に起動したら終了。

docker compose up -d
docker compose logs -f 

失敗したりやり直したときは、docker compose down --volumesでやり直す

起動状況のチェック

docker compose logs watchdog-mailcow -f

Rspamd,Postfix,Sogo,Dovecotが起動してたら最低限は動くはず。

rspamd の起動チェック

docker compose logs -f rspamd-mailcow 次がでてたら、無事に起動しているはず。

skip writing pid in no-fork mode

私は、aarch64版のrspamdを使おうとしたとき、起動後に不安定(segmentation fault)だったので、色々苦労した。rspamd が動かない場合→ qemu で動かした。

aarch64版をビルドして使うとき

sed -i '\|rspamd.com/apt-stable|d' data/Dockerfiles/rspamd/Dockerfile
docker build data/Dockerfiles/rspamd -t mailcow/rspamd:aarch64_build

起動時にのエラーに苦しんだので、このあたりを参考にすると動いた。

https://github.com/mailcow/mailcow-dockerized/issues/3106

#45(main) <sfcohf>; lua; spamassassin.lua:1714: loading SA rules from /etc/rspamd/custom/sa-rules
Segmentation fault (core dumped)

動くには動くが気づかない間に再起動を繰り返すなど動作が不安定だったので、x86で良いかとなった。

ログインする

初期パスワードは admin/moohooで固定です。

メール受信テスト

DNSを設定する。

mail.example.com mx 25 vps.example.com
vps.example.com a 192.168.100.5

ローカル実験の例 data/conf/unbound/unbound.conf

ローカルで実験する場合、DNS(名前解決)を上書きしなくちゃいけない。ローカル配送と外部Submissionを使ってメールを送信する。受信25ポートについては任意にやっておく。

ただしunbound-mailcowroot-hint(ルートネームサーバー)から名前解決をするので、上書き設定や通信設定を data/conf/unbound/unbound.conf に記入する

local-data: 'mail.example.com mx 10 vps.example.com'

または、unboundに外部DNSを参照させる。 我が家では、DNS問い合わせは特定デバイスのみ許可している。なのでmailcow が直接root.hint から名前解決が出来ない。そこで名前解決サーバーを指定した。

data/conf/unbound/unbound.conf

  forward-zone:
    name: "."
    forward-addr: 192.168.100.2

設定したら再起動しておく。

docker compose rm unbound-mailcow  --volumes
docker compose up -d unbound-mailcow

Virtual Domain の設定

設定は、次の場所にある。 mailcow -> right top -> configuration -> mailsetup

ドメインを追加して

ユーザを追加する。

追加したユーザ宛にメールを送る。

curl コマンドでサクッとメールを送る。

TO=test-user@example.com
SMTP_SERVER=xxxx.sakura.ne.jp:587
USER=postmaster@xxxxx.sakura.ne.jp
PASS=xxxxx

echo "To: $TO
From: $USER
Subject: this is a test from 587/starttls

this is a test
using smtps
"  | curl -v \
  --url "smtp://$SMTP_SERVER" \
  --user "$USER:$PASS" \
  --ssl -k \
  --mail-rcpt $TO \
  -T -

受信の確認

Sogo でサクッと見る。

Sogoは再起動しないと、ユーザ作成が反映されないので注意。

IMAPやPOPでアクセスしてもいいけどね・・・

送信の確認

送信の確認は、OP25Bがあって面倒くさいので、割愛。

ローカル配送の場合

mailcow のPostfix設定では、a_user@example.comから b_user@example.com へ配送する場合、毎回 mx を参照してしまう。 これは、mailcow のpostfix設定がローカル配送をする際に、いったんMXを経由する用に設定されているためで、ローカルはなく、すべて name virtual でやってるから。

これはNAT環境やクラウド環境(ElasticIP)などがあるときに、ループバック設定が、とてもめんどくさい。

ローカル配送をやらせる。

同一ドメイン内配送(ローカル配送)をする場合、mailcow で設定しても良いんだけど。 data/conf/unbound/unbound.confで postfix を指定してあげると楽だった。

local-data: 'mail.example.com mx 10 postfix'

レポジトリ

mailcow のarm64 のパッチとビルドをできるように、github にメモを残しておいた

https://github.com/takuya/mailcow-dockerized-aarch64

まとめ

mailcow は arm64 でも qemu 経由で動かせる。ただ、ある程度は aarch64でビルドした方が速くて快適。