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)バイナリ版をビルドしてみた。
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
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 compose pull
ipv6関連を切っていく。
v6関連があるとデバッグが煩雑になるので切っておく。
sed -i 's|enable_ipv6: true|enable_ipv6: false|' docker-compose.yml
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
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
cat <<EOF | sudo tee -a data/conf/postfix/extra.cf
smtp_address_preference = ipv4
inet_protocols = ipv4
EOF
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 を実行すれば良い。
list=("
acme
clamd
dockerapi
netfilter
olefy
phpfpm
postfix
solr
unbound
watchdog
")
for service in $list; do
echo $service
docker build data/Dockerfiles/$service -t mailcow/$service:aarch64_build
done
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 は debian/ubuntu の配布パッケージを使っていない。sogoは sogo.nu のnightly を使っているが、sogo.nuがarmバイナリを未提供
それぞれ、Debian公式なら存在するので大体は出来る
|パッケージ| Debian公式 | aarch64バイナリ | 特記事項 |
|:---:|---:|:---:|:---|
|sogo | debian/sid | あり | sogo-activesync/aarch64はsid のみ|
|dovecot| debian/stable | あり |dovecot-lua がない|
|rspamd | debian/stable |あり|sa-rulesが動かない。|
これらについては、インストール後に予期せぬ出来事に遭遇するかもしれないが、場当たり的な対応で動いた。
sogo は id:sogo の home ディレクトリが異なるので対応が必要。
dovecot は dovecot-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-mailcow
が root-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でビルドした方が速くて快適。