0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

mailman3 で発信用MLサーバを docker compose で構築

Last updated at Posted at 2025-02-22

目的

ML管理したいが、そのためにメールサーバを設定するのはセキュリティとか色々と考慮する必要があり大変。
リレー先メールサーバさえ転送を受け付けてくれれば、発信専門のMLを構築できそう。

ということで、コンテナでサクッと発信専門のMLサーバ構築したので以下にその手順を示す。

注意事項

リレー先メールサーバが転送を受け付けてくれる前提であり、メールサーバ側の設定については関与しない。
発信専門であるため、発信元メアドに送信しても no such address となる。

docker compose 設定

docker-mailman/docker-compose.yaml を参考に設定。

変更点は以下:

  • mailman設定関連をローカルフォルダに置くよう /opt/mailman → . に変更
  • mailman-web アクセス用の webサーバとして nginx を設定
  • nginx 以外は expose しないよう設定
  • MTA用の postfix を設定
  • postfix の転送信頼アドレスとして mynetwork に各サービスが属するよう IPアドレス空間(172.18.0.0/24)を設定
  • SMTP_HOST に postfix サービスを指定

docker-compose.yaml

services:
  mailman-core:
    image: maxking/mailman-core:0.4 # Use a specific version tag (tag latest is not published)
    container_name: mailman-core
    hostname: mailman-core
    restart: unless-stopped
    volumes:
    - ./core:/opt/mailman/
    # - /opt/mailman/core:/opt/mailman/
    stop_grace_period: 30s
    links:
    - database:database
    depends_on:
      database:
        condition: service_healthy
    environment:
    - DATABASE_URL=${DATABASE_URL:-postgresql://mailman:mailmanpass@database/mailmandb}
    - DATABASE_TYPE=${DATABASE_TYPE:-postgres}
    - DATABASE_CLASS=${DATABASE_CLASS:-mailman.database.postgresql.PostgreSQLDatabase}
    - HYPERKITTY_API_KEY=${HYPERKITTY_API_KEY:-someapikey}
    - MTA=${MTA:-postfix}
    #- MM_HOSTNAME=${MM_HOSTNAME:-}
    - SMTP_HOST=${SMTP_HOST:-postfix}
    - SMTP_PORT=${SMTP_PORT:-25}
    - SMTP_HOST_USER=${SMTP_HOST_USER:-}
    - SMTP_HOST_PASSWORD=${SMTP_HOST_PASSWORD:-}
    - SMTP_SECURE_MODE=${SMTP_SECURE_MODE:-smtp}
    - SMTP_VERIFY_HOSTNAME=${SMTP_VERIFY_HOSTNAME:-true}
    - SMTP_VERIFY_CERT=${SMTP_VERIFY_CERT:-true}
    # ports:
    # - "127.0.0.1:8001:8001" # API
    # - "127.0.0.1:8024:8024" # LMTP - incoming emails
    networks:
     - net_mailman

  mailman-web:
    image: maxking/mailman-web:0.4 # Use a specific version tag (tag latest is not published)
    container_name: mailman-web
    hostname: mailman-web
    restart: unless-stopped
    depends_on:
      database:
        condition: service_healthy
    links:
    - mailman-core:mailman-core
    - database:database
    volumes:
    - ./web:/opt/mailman-web-data
    # - /opt/mailman/web:/opt/mailman-web-data
    environment:
    - DATABASE_TYPE=${DATABASE_TYPE:-postgres}
    - DATABASE_URL=${DATABASE_URL:-postgresql://mailman:mailmanpass@database/mailmandb}
    - HYPERKITTY_API_KEY=${HYPERKITTY_API_KEY:-someapikey}
    - SECRET_KEY=${SECRET_KEY:-}
    - SERVE_FROM_DOMAIN=${SERVE_FROM_DOMAIN:-example.com}
    - MAILMAN_ADMIN_USER=${MAILMAN_ADMIN_USER:-admin}
    - MAILMAN_ADMIN_EMAIL=${MAILMAN_ADMIN_EMAIL:-admin@example.com}
    - SMTP_HOST=${SMTP_HOST:-postfix}
    # ports:
    # - "127.0.0.1:8000:8000" # HTTP
    # - "127.0.0.1:8080:8080" # uwsgi
    networks:
     - net_mailman

  database:
    environment:
    - POSTGRES_DB=mailmandb
    - POSTGRES_USER=mailman
    - POSTGRES_PASSWORD=mailmanpass
    image: postgres:12-alpine
    volumes:
    - ./database:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready --dbname mailmandb --username mailman"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
     - net_mailman

  postfix:
    build: ./postfix
    hostname: postfix
    container_name: postfix
    environment:
    - MAIL_DOMAIN=${MAIL_DOMAIN:-example.com}
    volumes:
    - ./postfix/main.cf:/etc/postfix/main.cf
    - ./core/var/data/:/opt/mailman/core/var/data/
    networks:
     - net_mailman

  nginx:
    image: nginx:latest
    ports:
    - ${SERVICE_PORT:-80}:80
    volumes:
    - ./nginx/conf.d:/etc/nginx/conf.d
    - ./web:/opt/mailman-web-data
    depends_on:
    - mailman-web
    networks:
     - net_mailman

networks:
  net_mailman:
    driver: bridge
    ipam:
      driver: default
      config:
      - subnet: 172.18.0.0/24

.env 設定例

SECRET_KEY=適当に設定

SERVE_FROM_DOMAIN=適当なドメイン名

## SMTPホスト検証をしたくないとき
SMTP_VERIFY_HOSTNAME=false
SMTP_VERIFY_CERT=false

## 管理者アカウント設定
MAILMAN_ADMIN_USER=管理者アカウント
MAILMAN_ADMIN_EMAIL=管理者メアド

mailman-web設定

CSRF検証を無効にするとき

管理者メアドの検証の際に django で mailman-web 稼働サーバのCSRF検証を行おうとするため、これを無効化する。
具体的には、 settings_local.py にて CSRF モジュールを外すよう settings.py 設定を上書きする。
デフォルトの MIDDLEWARE 設定は https://github.com/maxking/docker-mailman/blob/main/web/mailman-web/settings.py を見ればわかる。

./web/settings_local.py:

MIDDLEWARE = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'allauth.account.middleware.AccountMiddleware',
    'django_mailman3.middleware.TimezoneMiddleware',
    'postorius.middleware.PostoriusMiddleware',
)

ALLOWED_HOSTS 設定

Mailman-webのREADME には ALLOWED_HOSTS の設定のためにドメイン名(example.com)を SERVE_FROM_DOMAIN に設定するとあるが、実際はそのまま環境変数を設定しているため効かない。

正しくは ".ドメイン名" とすることでワイルドカードが効くようになる。

refs: DjangoのALLOWED_HOSTSの仕様

設定は上記と同じく settings_local.py に追加設定。

web/settings_local.py:

ALLOWED_HOSTS = [
    '.localhost', '127.0.0.1',
    'mailman-web',
    '.適当なドメイン',
]

MTA(postfix) の設定

コンテナ作成

作り方は Dockerコンテナ内で、Postfixを使ってメール送受信を行う を参考。

postfix/Dockerfile:

FROM ubuntu:22.04

RUN apt-get update && apt-get install -y \
    postfix \
    # iputils-ping iproute2 net-tools dnsutils \
    && rm -rf /var/lib/apt/lists/*

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

CMD ["/entrypoint.sh"]

postfix/entrypoint.sh:

#!/bin/sh

## postfix の DNS 参照は resolv.conf でなく postfix 用の resolv.conf を参照するため、サービス実行前にコピー
## refs: https://zenn.dev/flyingbarbarian/articles/5bb1d38b1ada40
cp /etc/resolv.conf /var/spool/postfix/etc/resolv.conf

#postfix start-fg
postfix start

### ログ監視をフォアグラウンド実行してサービス実行を継続
tail -F /var/log/maillog

postfix/main.cf:

postfixコンテナを一旦起動し、デフォルト設定をコピーして編集するとよい。

$ docker build . -t postfix
$ docker run -d --rm --name postfix postfix
$ docker cp postfix:/etc/postfix/main.cf .

デフォルト設定から以下を編集。
docker-compose で指定したネットワークアドレスを mynetworks に指定する。
これを設定しないと mailman-web や mailman-core からのメール転送を受け付けてくれない。

myhostname = postfix
mydomain = 適当なドメイン
mydestination = $myhostname, localhost.$mydomain, localhost

## メールのリレー先
relayhost = [転送先メールサーバ]

## docker composeサービス内のメール転送を受け付けるよう IP範囲を設定
mynetworks = 127.0.0.0/8 172.18.0.0/24

## ログをファイル出力
maillog_file = /var/log/maillog

## for mailman
# Support the default VERP delimiter.
recipient_delimiter = +
unknown_local_recipient_reject_code = 550
owner_request_special = no

transport_maps =
    regexp:/opt/mailman/core/var/data/postfix_lmtp
local_recipient_maps =
    regexp:/opt/mailman/core/var/data/postfix_lmtp
relay_domains =
    regexp:/opt/mailman/core/var/data/postfix_domains

この状態で docker compose サービス内からメール送信できるようになる。

例えば mailman-web サービスから以下のように送信。

mailman-web# python
>>> from smtplib import SMTP
>>> smtp = SMTP('postfix')
>>> smtp.sendmail('from_addr@mailman-web', '適当なメアド', 'test message')

mailman-core 設定

postfix に設定するファイルを仮出力しておく。

$ mkdir -p core/var/data
$ touch ./core/var/data/postfix_lmtp
$ touch ./core/var/data/postfix_domains

nginx設定

nginx/conf.d/default.conf

proxy_pass で設定するか、 uwsgi_pass で設定するかはどちらでもよい。

server {
    listen  [::]:80;
    server_name  ML管理用webサーバ;

    location /static {
        alias /opt/mailman-web-data/static;
        autoindex off;
    }

    location / {
		  proxy_pass http://mailman-web:8000 ;
          # uwsgi_pass mailman-web:8080;
		  include uwsgi_params;
		  uwsgi_read_timeout 300;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

mailman-web の転送先アドレス設定

上記設定までで各サービスは動くが、パスワードリセット時のアドレスが
https://mailman-web:8000/accounts/password/reset/key/xxxxxxxxxx/
のようになり、
https://ML管理用サーバ/accounts/password/reset/key/xxxxxxxxxx/
に書き換えないとパスワードリセットができない。

これでは不便のため、nginx設定を以下のように書き換える。

nginx/conf.d/default.conf

server {
  location / {
    proxy_set_header Host $server_name:$server_port;
  }

サービス起動

docker compose up するだけ。

$ docker compose up -d

これでサーバアドレスにアクセスして以下のような mailman3 画面が表示されればOK。

image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?