27. メーリングリストサーバ構築 – sympa [さくらのVPS/CentOS7]

・ 構築の前に

  1. メールサーバの構築が 11. メールサーバ構築(5) – nginx/php-fpm [さくらのVPS/CentOS7]
    まで完了していること
  2. メーリングリスト用にサブドメインを一つ用意すること
  3. メーリングリストから送信されるシステムメールは SPF, DKIM, DMARC, ARC に対応
  4. メーリングリストから送信される投稿メールは SPF,ARC に対応し、DKIM, DMARCは自メールドメインからの投稿メールのみ対応する

・sympa のインストール

#-- 変数に必要な値を代入
DOMAIN=masdon.life
MLDOMAIN=ml.${DOMAIN}
LISTMASTER=admin@${DOMAIN}
URL=https://${DOMAIN}/sympa

#-- sympa のリポジトリ設定とsympaのインストール(副作用でnginxもインストールされてしまう)
curl -o /etc/yum.repos.d/sympa-ja.org.rhel.repo http://sympa-ja.org/download/rhel/sympa-ja.org.rhel.repo
yum install -y sympa sympa-nginx

#-- nginx の起動スクリプトの修正
sed -i -e 's#/usr/sbin/nginx#/usr/local/nginx/sbin/nginx#' \
       -e '/^PIDFile/a ExecStartPre=/usr/local/bin/ipv6upchk.sh nginx' /usr/lib/systemd/system/nginx.service

systemctl daemon-reload
systemctl enable nginx

#-- nginx と sympa-nginx を update しないように変更
echo "exclude=nginx*,sympa-nginx" >> /etc/yum.conf

#-- sympa の database を作成
mysql -e "CREATE DATABASE sympa CHARACTER SET utf8;"
#-- database の password は お好みで
mysql -e "GRANT ALL PRIVILEGES ON sympa.* TO 'sympa'@'localhost' IDENTIFIED BY 'sympass';"
mysql -e "FLUSH PRIVILEGES;"

#-- sympa の設定
cp -p /etc/sympa/sympa.conf{,.org}

sed -i -e "/^#domain/a domain ${MLDOMAIN}" \
       -e "/^#listmaster/a listmaster ${LISTMASTER}" \
       -e "/^#lang/a lang ja" \
       -e "/^#db_type/a db_type MySQL" \
       -e "/^#db_name/a db_name sympa" \
       -e "/^#db_host/a db_host 127.0.0.1" \
       -e "/^#db_user/a db_user sympa" \
       -e "/^#db_passwd/a db_passwd sympass" \
       -e "/^#wwsympa_url/a wwsympa_url ${URL}" /etc/sympa/sympa.conf

#- sympa の設定の確認(何も表示されなければOK)
sympa.pl --health_check

#- 定期的に postfix の設定を更新するスクリプトを作成
cat <<'_EOL_'> /usr/local/bin/create_sympa_regex.sh
#!/bin/bash

if [ $# -ne 1 ]
then
  echo "usage: $0 <sympa-domain>"
  exit 1
fi

DOMAIN=$1
SYMPA1=/etc/sympa/aliases.sympa.postfix
SYMPA2=/var/lib/sympa/sympa_aliases
REGEX=/etc/postfix-inbound/symparcptcheck.regexp
TMP=/tmp/symparcptcheck.regexp

# 2分以内にメーリングリストの更新があったらpostfixに反映する
LIMIT=120

if [ $(($(stat --format=%Y ${SYMPA1}) + ${LIMIT})) -ge $(date +%s) ] || [ $(($(stat --format=%Y ${SYMPA2}) + ${LIMIT})) -ge $(date +%s) ]
then
  /usr/bin/cp /dev/null ${TMP}
  for x in $(awk -F: '!/^#/{print $1}' ${SYMPA1} ${SYMPA2})
  do
      echo "/^${x}@${DOMAIN}/ OK" >> ${TMP}
  done
  /usr/bin/mv -f ${TMP} ${REGEX}
  systemctl reload postfix
fi

exit 0
_EOL_

chmod 755 /usr/local/bin/create_sympa_regex.sh

#- alias 関連ファイルのパーミション設定やデータ更新
chown sympa /etc/sympa/aliases.sympa.postfix.db
chown sympa /var/lib/sympa
postalias /var/lib/sympa/sympa_aliases

sed -i -e "s/\S*@my.domain.org/admin@${DOMAIN}/" -e "s/postmaster/admin@${DOMAIN}/" /etc/sympa/aliases.sympa.postfix
postalias /etc/sympa/aliases.sympa.postfix

#- postfix 用の宛先存在確認ルールを作成(上記コマンド実行後、2分以内に実行すること)
/usr/local/bin/create_sympa_regex.sh ${MLDOMAIN}

#- sympaでメーリングリストが追加された場合にpostfixに設定を反映するためのcron
echo "* * * * * root /usr/local/bin/create_sympa_regex.sh ${MLDOMAIN} >/dev/null 2>&1" >> /etc/cron.d/${DOMAIN}-cron

#-- nginx に設定追加
rm -f /etc/nginx/conf.d/sympa.conf
cat <<'_EOL_'> /etc/nginx/conf.d/https.d/sympa.conf
    location /sympa {
        include       /etc/nginx/fastcgi_params;
        fastcgi_pass  unix:/var/run/sympa/wwsympa.socket;

        # If you changed wwsympa_url in sympa.conf, change this regex too!
        fastcgi_split_path_info ^(/sympa)(.*)$;
        fastcgi_param SCRIPT_FILENAME /usr/libexec/sympa/wwsympa.fcgi;
        fastcgi_param PATH_INFO $fastcgi_path_info;

    }

    location /static-sympa/css {
        alias /var/lib/sympa/css;
    }
    location /static-sympa/pictures {
        alias /var/lib/sympa/pictures;
    }
    location /static-sympa {
        alias /usr/share/sympa/static_content;
    }
_EOL_

systemctl restart nginx

#-- sympa 起動
systemctl enable sympa wwsympa
systemctl start sympa wwsympa

#-- postfix の設定
#- メールを受け付ける対象にml用ドメインを追加
cat <<_EOF_>> /etc/postfix-inbound/relay_domains
${MLDOMAIN}
_EOF_

#- ml用ドメインはローカルに配送する(alias を適用する)設定を追加
cat <<_EOF_>> /etc/postfix-inbound/transport
${MLDOMAIN} local:
_EOF_

postmap /etc/postfix-inbound/transport

#- alias を sympa のファイルを参照するように変更、宛先チェックなどの設定も変更
postconf -c /etc/postfix-inbound -e alias_maps=hash:/etc/sympa/aliases.sympa.postfix,hash:/var/lib/sympa/sympa_aliases
postconf -c /etc/postfix-inbound -e alias_database=/etc/sympa/aliases.sympa.postfix,hash:/var/lib/sympa/sympa_aliases
postconf -c /etc/postfix-inbound -e smtpd_recipient_restrictions="check_recipient_access ldap:/etc/postfix-inbound/ldaprcptcheck.cf check_recipient_access regexp:/etc/postfix-inbound/symparcptcheck.regexp reject"
postconf -c /etc/postfix-inbound -e transport_maps="ldap:/etc/postfix-inbound/ldaptransport.cf hash:/etc/postfix-inbound/transport"

systemctl restart postfix

#-- rspamd の設定

#- envelope from が ml用ドメインの場合、SPAM判定のScoreを10下げる(これを実施しないと送信時にX-Spam: Yes が追加される)
cat <<_EOF_> /etc/rspamd/local.d/multimap.conf
WHITELIST_SENDER_DOMAIN {
  type = "from";
  filter = "email:domain";
  map = "/etc/rspamd/local.d/whitelist_sender_domain.map";
  score = -10.0
}
_EOF_

cat <<_EOF_>/etc/rspamd/local.d/whitelist_sender_domain.map
${MLDOMAIN}
_EOF_

#- DKIM と ARC の署名設定を追加する(詳しくはrspamdの構築設定手順を参照)
rspamadm dkim_keygen -d ${MLDOMAIN} -s default -b 2048
#-- 秘密鍵を記述
vi /etc/rspamd/local.d/keys/default.${MLDOMAIN}.key
chmod 600 /etc/rspamd/local.d/keys/default.${MLDOMAIN}.key
chown _rspamd. /etc/rspamd/local.d/keys/default.${MLDOMAIN}.key

#- ml用ドメインの設定を追加する
vi /etc/rspamd/local.d/dkim_signing.conf
vi /etc/rspamd/local.d/arc.conf

#- dkim署名するヘッダーを下記に変更する
vi /etc/rspamd/local.d/dkim_signing.conf
sign_headers = '(o)from:(o)date:(o)message-id:(o)to:(o)cc:(o)mime-version:(o)content-type:(o)content-transfer-encoding:resent-to:resent-cc:resent-from:resent-sender:resent-message-id:(o)in-reply-to:(o)references:list-id:list-owner:list-unsubscribe:list-subscribe:list-post';

#- arc署名するヘッダーを下記に変更する
vi /etc/rspamd/local.d/arc.conf
sign_headers = "(o)from:(o)sender:(o)reply-to:(o)date:(o)message-id:(o)to:(o)cc:(o)mime-version:(o)content-type:(o)content-transfer-encoding:resent-to:resent-cc:resent-from:resent-sender:resent-message-id:(o)in-reply-to:(o)references:list-id:list-owner:list-unsubscribe:list-subscribe:list-post:dkim-signature";

#- rspamd 再起動
systemctl restart rspamd

#-- nsd の設定
IPV4=$(ip addr show eth0 | awk '/inet /{print $2}' | awk -F\/ '{print $1}')
IPV6=$(ip addr show eth0 | awk '/inet6 /&&/global/{print $2}' | awk -F\/ '{print $1}')

cat <<_EOL_>>/etc/nsd/zone/${DOMAIN}.zone
ml                      IN      MX 100  ${DOMAIN}.
ml                      IN      TXT     "v=spf1 +ip4:${IPV4} +ip6:${IPV6} -all"
_dmarc.ml               IN      TXT     "v=DMARC1; p=none; rua=mailto:root@${DOMAIN}"
_adsp._domainkey.ml     IN      TXT     "dkim=discardable"
default._domainkey.ml   IN      TXT     ( "v=DKIM1; k=rsa; "
                                        "p=共通鍵を記述"
                                        ) ;
_EOL_

systemctl restart nsd

・初期パスワードの作成

  • https://masdon.life/sympa/firstpasswd で 管理者ユーザのパスワードを作成する

14. LDAP管理サーバ構築 – phpldapadmin [さくらのVPS/CentOS7]

・phpldapadmin の用途

  1. LDAPのレコード管理

・phpldapadmin のインストール

#-- 変数に必要な値を代入
HTTPS_DOCROOT=/var/www/html/https_root

#-- phpldapadmin本家は php7.x に対応していない為、 fork されたものを clone する
git clone https://github.com/breisig/phpLDAPadmin.git ~/work/git/phpldapadmin

cp -pr ~/work/git/phpldapadmin ${HTTPS_DOCROOT}/phpldapadmin
cp -p ${HTTPS_DOCROOT}/phpldapadmin/config/config.php{.example,}
chown -R nginx. ${HTTPS_DOCROOT}/phpldapadmin

#-- 複数ドメインがある場合は、カンマ区切りで追加する
sed -i -e "301i \$servers->setValue('server','base',array('dc=masdon,dc=life'));" ${HTTPS_DOCROOT}/phpldapadmin/config/config.php

#-- 使用しないテンプレートを移動
mkdir ${HTTPS_DOCROOT}/phpldapadmin/templates/creation_backup
for x in courierMailAccount.xml courierMailAlias.xml mozillaOrgPerson.xml sambaDomain.xml sambaGroupMapping.xml sambaMachine.xml sambaSamAccount.xml
do
  mv ${HTTPS_DOCROOT}/phpldapadmin/templates/creation/${x} ${HTTPS_DOCROOT}/phpldapadmin/templates/creation_backup
done

ログインユーザは RootDN

13. Webメールサーバ構築 – roundcube/rainloop [さくらのVPS/CentOS7]

・roundcubeの用途

  1. Webメール
  2. アカウントのパスワード変更
  3. メールのフォルダ振り分け/転送の設定

・roundcubeのインストール

#-- 変数に必要な値を代入
DOMAIN=masdon.life
HTTPS_DOCROOT=/var/www/html/https_root

#-- 1.3系の最新版を入手
git clone https://github.com/roundcube/roundcubemail.git ~/work/git/roundcubemail
cd ~/work/git/roundcubemail
VERSION=$(git for-each-ref --sort=-taggerdate --format='%(tag)' refs/tags | grep -m 1 "1\.3\.")
git checkout ${VERSION}
cp -pr ../roundcubemail ${HTTPS_DOCROOT}/roundcubemail-${VERSION}
ln -s ${HTTPS_DOCROOT}/roundcubemail-${VERSION} ${HTTPS_DOCROOT}/roundcube

#-- roundcube の DB を作成
mysql -e "create database roundcubemail character set utf8 collate utf8_bin;"
#-- database の password は お好みで
mysql -e "grant all on roundcubemail.* to roundcube@localhost identified by 'roundcube';"
mysql -e "FLUSH PRIVILEGES;"
mysql roundcubemail < ${HTTPS_DOCROOT}/roundcube/SQL/mysql.initial.sql

#-- 必要なPHPのライブラリをインストール
yum install -y php73-php-{pdo,xml,pear,mbstring,intl,pecl-imagick,gd,mysqlnd,pspell,pecl-zip}
yum install -y php-pear-Mail-mimeDecode php-kolab-net-ldap3 php-pear-Net-IDNA2 php-pear-Auth-SASL php-pear-Net-SMTP php-pear-Net-Sieve

#-- php-fpm の再起動
systemctl restart php73-php-fpm

#-- roundcube の設定
cat <<'_EOF_'> ${HTTPS_DOCROOT}/roundcube/config/config.inc.php
<?php
$config['db_dsnw'] = 'mysql://roundcube:roundcube@localhost/roundcubemail';
$config['default_host'] = array('_DOMAIN_');
$config['default_port'] = 993;
$config['smtp_server'] = '_DOMAIN_';
$config['smtp_port'] = 465;
$config['smtp_user'] = '%u';
$config['smtp_pass'] = '%p';
$config['support_url'] = '';
$config['product_name'] = 'Roundcube Webmail';
$config['des_key'] = 'rcmail-!24ByteDESkey*Str';
$config['plugins'] = array('managesieve', 'password', 'archive', 'zipdownload');
$config['managesieve_host'] = 'localhost';
$config['spellcheck_engine'] = 'pspell';
$config['skin'] = 'larry';
_EOF_

sed -i "s#_DOMAIN_#ssl://${DOMAIN}#" ${HTTPS_DOCROOT}/roundcube/config/config.inc.php

cp -p ${HTTPS_DOCROOT}/roundcube/plugins/managesieve/config.inc.php{.dist,}
sed -i -e "s/managesieve_vacation'] = 0/managesieve_vacation'] = 1/" ${HTTPS_DOCROOT}/roundcube/plugins/managesieve/config.inc.php

cp -p ${HTTPS_DOCROOT}/roundcube/plugins/password/config.inc.php{.dist,}

sed -i -e "s/'sql'/'ldap'/" \
       -e "s/'ou=people,dc=example,dc=com'/''/" \
       -e "s/'dc=exemple,dc=com'/''/" \
       -e "s/'uid=%login,ou=people,dc=exemple,dc=com'/'uid=%name,ou=People,%dc'/" \
       -e "s/'(uid=%login)'/'(uid=%name,ou=People,%dc)'/" ${HTTPS_DOCROOT}/roundcube/plugins/password/config.inc.php

chown -R nginx. ${HTTPS_DOCROOT}/roundcubemail-${VERSION}
cd ${HTTPS_DOCROOT}/roundcube/bin
./install-jsdeps.sh

mv ${HTTPS_DOCROOT}/roundcube/installer ${HTTPS_DOCROOT}/roundcube/_installer

・rainloop のインストール

#-- 変数に必要な値を代入
DOMAIN=masdon.life
HTTPS_DOCROOT=/var/www/html/https_root

#-- rainloop のインストール
mkdir -p ${HTTPS_DOCROOT}/rainloop
cd ${HTTPS_DOCROOT}/rainloop
curl -sL https://repository.rainloop.net/installer.php | php
chown -R nginx. ${HTTPS_DOCROOT}/rainloop
curl -s https://${DOMAIN}/rainloop/

#-- rainloop の設定
for x in $(ldapsearch -x mailroutingaddress | awk -F@ '/^mailRoutingAddress/{print $2}' | sort | uniq)
do
cat <<_EOL_> ${HTTPS_DOCROOT}/rainloop/data/_data_/_default_/domains/${x}.ini
imap_host = "${DOMAIN}"
imap_port = 993
imap_secure = "SSL"
imap_short_login = Off
sieve_use = Off
sieve_allow_raw = Off
sieve_host = ""
sieve_port = 4190
sieve_secure = "None"
smtp_host = "${DOMAIN}"
smtp_port = 465
smtp_secure = "SSL"
smtp_short_login = Off
smtp_auth = On
smtp_php_mail = Off
_EOL_
  chown nginx. ${HTTPS_DOCROOT}/rainloop/data/_data_/_default_/domains/${x}.ini
done

sed -i 's/$/,gmail.com/' ${HTTPS_DOCROOT}/rainloop/data/_data_/_default_/domains/disabled

cat <<_EOL_> /etc/nginx/conf.d/https.d/rainloop.conf
  location ^~ /rainloop/data {
    deny all;
  }
_EOL_

#-- nginx の再起動
systemctl reload nginx

admin アカウントのパスワードはデフォルトのため、直ぐに変更すること
https://masdon.life/rainloop/?ADMIN
user: admin , pass: 12345

12. メールサーバ構築(6) – Thunderbird の Autoconfig [さくらのVPS/CentOS7]

・thunderbird autoconfig の用途

  1. Thunderbird へのメールアカウント追加時にメールアドレスとパスワードのみでSMTP/IMAP設定を完了させる設定

・xmlを作成

#-- 変数に必要な値を代入
DOMAIN=masdon.life

#-- https://masdon.life/.well-known/autoconfig/mail/config-v1.1.xml を作成
mkdir -p /var/www/html/https_root/.well-known/autoconfig/mail
chown -R nginx. /var/www/html/https_root/.well-known
cat <<'_EOL_'>/var/www/html/https_root/.well-known/autoconfig/mail/config-v1.1.xml
<?xml version="1.0"?>
<clientConfig version="1.1">
    <emailProvider id="sakuravps">
      <domain>_DOMAIN_</domain>
      <displayName>_DOMAIN_</displayName>
      <displayShortName>_DOMAIN_</displayShortName>
      <incomingServer type="imap">
         <username>%EMAILADDRESS%</username>
         <hostname>_DOMAIN_</hostname>
         <port>993</port>
         <socketType>SSL</socketType>
         <authentication>password-cleartext</authentication>
      </incomingServer>
      <incomingServer type="pop3">
         <username>%EMAILADDRESS%</username>
         <hostname>_DOMAIN_</hostname>
         <port>995</port>
         <socketType>SSL</socketType>
         <authentication>password-cleartext</authentication>
         <pop3>
            <leaveMessagesOnServer>true</leaveMessagesOnServer>
            <downloadOnBiff>true</downloadOnBiff>
            <daysToLeaveMessagesOnServer>14</daysToLeaveMessagesOnServer>
         </pop3>
      </incomingServer>
      <outgoingServer type="smtp">
         <username>%EMAILADDRESS%</username>
         <hostname>_DOMAIN_</hostname>
         <port>465</port>
         <socketType>SSL</socketType>
         <authentication>password-cleartext</authentication>
      </outgoingServer>
    </emailProvider>
    <clientConfigUpdate url="http://_DOMAIN_/mail/config-v1.1.xml" />
</clientConfig>
_EOL_

sed -i "s/_DOMAIN_/${DOMAIN}/g" /var/www/html/https_root/.well-known/autoconfig/mail/config-v1.1.xml

11. メールサーバ構築(5) – nginx/php-fpm [さくらのVPS/CentOS7]

・nginxの用途

  1. メールプロキシーサーバ(SMTP-Submission/SMTPS/POPS/IMAPS)
  2. メール認証サーバ(HTTP)
  3. Webサーバ(HTTPS)

・nginx のインストール

#-- 変数に必要な値を代入
DOMAIN=masdon.life
VERSION=1.17.0
IPV4=$(ip addr show eth0 | awk '/inet /{print $2}' | sed 's#/.*##')
IPV6=$(ip addr show eth0 | awk '/inet6 /&&/global/{print $2}' | sed 's#/.*##')

#-- nginx ユーザ/グループの作成と起動スクリプトを用意する為、OS標準の nginx をインストールしてアンインストール
yum install -y nginx
cp -p /usr/lib/systemd/system/nginx.service /var/tmp
yum remove -y nginx

#-- ldapに登録したメールアカウントで basic 認証ができるように nginx-auth-ldap をダウンロード
mkdir ~/work/git
git clone https://github.com/kvspb/nginx-auth-ldap.git ~/work/git/nginx-auth-ldap

#-- nginx の source のダウンロード (TLS1.3 に対応するため、source からインストールする)
cd ~/work/src
curl -L -O https://nginx.org/download/nginx-${VERSION}.tar.gz
tar xvzf nginx-${VERSION}.tar.gz && cd nginx-${VERSION}

#- build
./configure \
--prefix=/usr/local/nginx-${VERSION} \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_stub_status_module \
--with-mail \
--with-mail_ssl_module \
--with-file-aio \
--with-cc-opt=-O2 \
--with-http_v2_module \
--add-module=../../git/nginx-auth-ldap \
--with-openssl=../openssl-1.1.1d \
--with-openssl-opt=enable-tls1_3 \
--with-stream \
--with-stream_ssl_module
make
make install
ln -s nginx-${VERSION} /usr/local/nginx
/usr/bin/cp -pf conf/* /etc/nginx/

mkdir /var/lib/nginx
chown nginx. /var/lib/nginx

#-- nginx の起動設定を修正
mv /var/tmp/nginx.service /usr/lib/systemd/system/nginx.service
sed -i -e 's#/usr/sbin/nginx#/usr/local/nginx/sbin/nginx#' \
       -e '/^PIDFile/a ExecStartPre=/usr/local/bin/ipv6upchk.sh nginx' /usr/lib/systemd/system/nginx.service

・php7.3とphp-fpm のインストール

#-- remi レポジトリの追加
rpm -Uvh https://rpms.remirepo.net/enterprise/remi-release-7.rpm

#-- php-fpm のインストール
yum install -y php73-php php73-php-{fpm,ldap,devel}

#-- php-fpm の設定
cp -p /etc/opt/remi/php73/php-fpm.d/www.conf{,.org}

sed -i "s/apache/nginx/" /etc/opt/remi/php73/php-fpm.d/www.conf
chown nginx /var/opt/remi/php73/log/php-fpm
chgrp nginx /var/opt/remi/php73/lib/php/*

cp -p /etc/opt/remi/php73/php.ini{,.org}

sed -i -e "s/^max_execution_time = 30/max_execution_time = 300/" \
       -e "s/^max_input_time = 60/max_input_time = 300/" \
       -e "s/^post_max_size = 8M/post_max_size = 20M/" \
       -e "s/^upload_max_filesize = 2M/upload_max_filesize = 20M/" \
       -e "s/^;date.timezone =/date.timezone = 'Asia\/Tokyo'/" /etc/opt/remi/php73/php.ini

ln -s php73 /usr/bin/php
ln -s /var/opt/remi/php73/log/php-fpm /var/log/php-fpm

#-- php を update した場合、permission が apache になるのでその対策
cat <<_EOL_>> /etc/cron.d/${DOMAIN}-cron
* * * * * root chown nginx /var/opt/remi/php73/log/php-fpm >/dev/null 2>&1
* * * * * root chgrp nginx /var/opt/remi/php73/lib/php/{opcache,session,wsdlcache} >/dev/null 2>&1
_EOL_

・nginxの設定

#-- nginx mail proxy サーバの設定
cat <<_EOL_> /etc/nginx/mail.conf
mail {
  auth_http  127.0.0.1/nginx_mail_proxy/ldap_authentication.php ;
  proxy on;
  proxy_pass_error_message on;
  include /etc/nginx/default.d/${DOMAIN}_ssl.conf;
  ssl_session_cache shared:MAIL:10m;
  smtp_capabilities PIPELINING 8BITMIME "SIZE 20480000";
  pop3_capabilities TOP USER UIDL;
  imap_capabilities IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=LOGIN;
  smtp_auth login plain;

  server {
    listen     ${IPV4}:587;
    listen     [${IPV6}]:587;
    protocol   smtp;
    starttls   on;
    xclient    on;
    resolver   127.0.0.1;
    auth_http_header PORT 587;
  }
  server {
    listen     ${IPV4}:465 ssl;
    listen     [${IPV6}]:465 ssl;
    protocol   smtp;
    xclient    on;
    resolver   127.0.0.1;
    auth_http_header PORT 465;
  }
#  server {
#    listen     ${IPV4}:110;
#    listen     [${IPV6}]:110;
#    protocol   pop3;
#    starttls   on;
#    auth_http_header PORT 110;
#  }
  server {
    listen     ${IPV4}:995 ssl;
    listen     [${IPV6}]:995 ssl;
    protocol   pop3;
    auth_http_header PORT 995;
  }
#  server {
#    listen     ${IPV4}:143;
#    listen     [${IPV6}]:143;
#    protocol   imap;
#    starttls   on;
#    auth_http_header PORT 143;
#  }
  server {
    listen     ${IPV4}:993 ssl;
    listen     [${IPV6}]:993 ssl;
    protocol   imap;
    auth_http_header PORT 993;
  }
}
_EOL_

cp -p /etc/nginx/nginx.conf{,.org}

#-- nginx.conf の作成
cat <<'_EOL_'> /etc/nginx/nginx.conf
user  nginx;
worker_processes  2;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    limit_req_zone $binary_remote_addr zone=limit_req_by_ip:10m rate=1r/m;
    limit_req_log_level error;
    limit_req_status 503;

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/default.d/ldap.conf;
    include /etc/nginx/conf.d/*.conf;

    client_max_body_size 10485760; # 10MB
}
include /etc/nginx/mail.conf;
_EOL_

#-- basic認証でldapを参照する設定
cat <<_EOL_> /etc/nginx/default.d/ldap.conf
auth_ldap_cache_enabled on;
auth_ldap_cache_expiration_time 600000;
auth_ldap_cache_size 100;

ldap_server ldap1 {
    url ldap://127.0.0.1/?mailroutingaddress?sub?(objectClass=*);
    satisfy any;
}
_EOL_

#-- TLSの設定
cat <<_EOL_> /etc/nginx/default.d/masdon.life_ssl.conf
ssl_protocols TLSv1.2 TLSv1.3 ;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH;
ssl_ecdh_curve prime256v1;
ssl_prefer_server_ciphers on;
ssl_session_timeout  5m;
ssl_certificate /etc/letsencrypt/live/masdon.life/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/masdon.life/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/masdon.life/chain.pem;
resolver          127.0.0.1 8.8.8.8 valid=300s;
resolver_timeout  10s;
_EOL_

#-- 127.0.0.1:80 は nginx mail proxy の認証で使用
#-- global は TLS証明書の更新時に使用
cat <<_EOL_> /etc/nginx/conf.d/http.conf
server {
  listen 127.0.0.1:80;
  server_name ${DOMAIN};
  index index.html, index.php;
  access_log /var/log/nginx/access_auth.log main;
  error_log  /var/log/nginx/error_auth.log  error;
  root /var/www/html/http_root;
  server_tokens off;
  charset     utf-8;

  location ~ \.php\$ {
    allow 127.0.0.1;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
    include fastcgi_params;
    deny all;
  }

  error_page 500 502 503 504 /50x.html;
    location = /50x.html {
  }
}

server {
  listen     ${IPV4}:80;
  listen     [${IPV6}]:80;
  server_name _;
  index index.html, index.php;
  access_log /var/log/nginx/access.log main;
  error_log  /var/log/nginx/error.log  error;
  root /var/www/html/http_root;
  server_tokens off;
  charset     utf-8;

  location ^~ /.well-known/acme-challenge/ {}
  location ^~ /mail/ {}
  location /nginx_mail_proxy/ { deny all; }

  error_page 500 502 503 504 /50x.html;
    location = /50x.html {
  }
}
_EOL_

mkdir -p /var/www/html/http{,s}_root /var/log/nginx /var/cache/nginx/client_temp /etc/nginx/conf.d/https.d
cp -p /usr/local/nginx-${VERSION}/html/50x.html /var/www/html/http_root/
cp -p /usr/local/nginx-${VERSION}/html/50x.html /var/www/html/https_root/
chown -R nginx. /var/www/html/ /var/log/nginx /var/cache/nginx/client_temp

cat <<'_EOL_'> /etc/nginx/conf.d/https.conf
server {
  listen 443 ssl http2 default_server;
  listen [::]:443 ssl http2 default_server;
  server_name masdon.life;
  include /etc/nginx/default.d/masdon.life_ssl.conf;
  index index.html, index.php;
  access_log /var/log/nginx/access_ssl.log main;
  error_log  /var/log/nginx/error_ssl.log  error;
  root /var/www/html/https_root;
  server_tokens off;
  charset     utf-8;

  #-- for roundcube attache file
  client_max_body_size 20m;

  ssl_session_cache shared:WEB:10m;
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
  ssl_stapling on ;
  ssl_stapling_verify on ;

  include /etc/nginx/conf.d/https.d/*.conf;

  location ~ \.php$ {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
    include fastcgi_params;
  }
}
_EOL_

・メールプロキシー認証スクリプトの作成

mkdir -p /var/www/html/http_root/nginx_mail_proxy

cat <<'_EOL_'> /var/www/html/http_root/nginx_mail_proxy/ldap_authentication.php
<?php

error_reporting(0);

// write syslog
function _writelog($message) {
  openlog("nginx-mail-proxy", LOG_PID, LOG_MAIL);
  syslog(LOG_INFO,"$message") ;
  closelog();
}

// ldap authentication
function _ldapauth($server,$port,$dn,$passwd) {
  $conn = ldap_connect($server, $port);
  if ($conn) {
    ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3);
    $bind = ldap_bind($conn, $dn, $passwd);
    if ($bind) {
      ldap_close($conn);
      return True;
    } else {
      ldap_close($conn);
      return False;
    }
  } else {
    return False;
  }
}

function _mail_proxy($server,$port,$base,$filter,$attribute,$proxyport) {
  $message = "" ;
  $proxyhost = _ldapsearch($server,$port,$base,$filter,$attribute);

  if ( $proxyhost === '' ) {
    // proxyhost is not found
    $message = "proxy=failure" ;
    header('Content-type: text/html');
    header('Auth-Status: Invalid login') ;
  } else {
    // proxyhost is found
    $proxyip = gethostbyname($proxyhost);

    $message = sprintf('proxy=%s:%s', $proxyhost, $proxyport );
    header('Content-type: text/html');
    header('Auth-Status: OK') ;
    header("Auth-Server: $proxyip") ;
    header("Auth-Port: $proxyport") ;
  }
  return $message ;
}

// ldap search
function _ldapsearch($server,$port,$base,$filter,$attribute) {

  $conn = ldap_connect($server, $port);
  if ($conn) {
    ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3);
    $sresult = ldap_search($conn, $base, $filter, array($attribute));
    $info = ldap_get_entries($conn, $sresult);
    if ( $info[0][$attribute][0] != "" ) {
      return $info[0][$attribute][0];
    }
  }
  return "" ;
}

// set $env from nginx
$env['meth']    = getenv('HTTP_AUTH_METHOD');
$env['user']    = getenv('HTTP_AUTH_USER');
$env['passwd']  = getenv('HTTP_AUTH_PASS');
$env['salt']    = getenv('HTTP_AUTH_SALT');
$env['proto']   = getenv('HTTP_AUTH_PROTOCOL');
$env['attempt'] = getenv('HTTP_AUTH_LOGIN_ATTEMPT');
$env['client']  = getenv('HTTP_CLIENT_IP');
$env['host']    = getenv('HTTP_CLIENT_HOST');
$env['port']    = getenv('HTTP_PORT');
$env['helo']    = getenv('HTTP_AUTH_SMTP_HELO');
$env['from']    = getenv('HTTP_AUTH_SMTP_FROM');
$env['to']      = getenv('HTTP_AUTH_SMTP_TO');

$log = "" ;

// protocol port map
$portmap = array(
  "smtp" => 25,
  "pop3" => 110,
  "imap" => 143,
);

// port searvice name map
$protomap = array(
  "995" => "pops",
  "993" => "imaps",
  "110" => "pop",
  "143" => "imap",
  "587" => "smtp",
  "465" => "smtps",
);

// ldap setting
$ldap = array(
  "host" => "127.0.0.1",
  "port" => 389,
  "basedn" => "",
  "filter" => "(mailRoutingAddress=" . $env['user'] . ")",
  "attribute" => "mailhost",
  "dn" => "",
  "passwd" => "",
);

// split uid and domain
$spmra = preg_split('/\@/', $env['user']) ;

// make dn
foreach (preg_split("/\./", $spmra[1]) as $value) {
        $ldap['dn'] = $ldap['dn'] . 'dc=' . $value . ',' ;
}
$tmpdn = preg_split('/,$/',$ldap['dn']);
$ldap['dn'] = 'uid=' . $spmra[0] . ',ou=People,' . $tmpdn[0];

// set search attribute
if ( $env['proto'] === 'smtp' ) {
  $ldap['attribute'] = 'sendmailmtahost' ;
}

// set log
$log = sprintf('meth=%s, user=%s, client=%s, proto=%s', $env['meth'], $env['user'], $env['client'], $protomap[$env['port']]);

// set password
$ldap['passwd'] = urldecode($env['passwd']) ;

// ldap authentication
if ( _ldapauth($ldap['host'],$ldap['port'],$ldap['dn'],$ldap['passwd'])) {
  // authentication successful
  $log = sprintf ('auth=successful, %s', $log) ;
  $proxyport = $portmap[$env['proto']];
  $result = _mail_proxy($ldap['host'],$ldap['port'],$ldap['basedn'],$ldap['filter'],$ldap['attribute'],$proxyport);
  $log = sprintf ('%s, %s', $log,$result) ;
} else {
  // authentication failure
  $log = sprintf('auth=failure, %s, passwd=%s', $log, $ldap['passwd']);
  // $log = sprintf('auth=failure, %s', $log);
  header('Content-type: text/html');
  header('Auth-Status: Invalid login') ;
}

_writelog($log);
exit;
?>
_EOL_

・nginxとphp-fpmの起動

#-- php-fpm の起動
systemctl daemon-reload
systemctl enable nginx php73-php-fpm
systemctl start nginx php73-php-fpm

#-- firewall の解放
firewall-cmd --permanent --add-port={25,587,465,993,995,443}/tcp
firewall-cmd --reload

10. メールサーバ構築(4) – postfix [さくらのVPS/CentOS7]

・postfixの用途

  1. SMTPサーバ(OUTBOUND/INBOUND)
  2. STARTTLS の TLS1.3 対応

・postfix のインストール

#-- 変数に必要な値を代入
DOMAIN=masdon.life
VERSION=3.4.5
RSPAMD_SERVER=127.0.0.1
RSPAMD_PORT=11332
IPV4=$(ip addr show eth0 | awk '/inet /{print $2}' | sed 's#/.*##')
IPV6=$(ip addr show eth0 | awk '/inet6 /&&/global/{print $2}' | sed 's#/.*##')
OUTBOUND_MTA_SERVER=127.0.0.1
LDAP_SERVER=127.0.0.1
XAUTH_HOST=127.0.0.1
LMTP_PORT=24

#-- 既存の起動スクリプトのバックアップ後、OS標準の postfix, sendmail をアンインストール
grep -v ExecStartPre= /usr/lib/systemd/system/postfix.service > /var/tmp/postfix.service
yum remove -y postfix sendmail

#-- 必要なパッケージインストール
yum install -y {cyrus-sasl,openldap,pcre,libdb}-devel

#-- source ファイルのダウンロード
cd ~/work/src
curl -O http://www.ftp.saix.net/MTA/postfix/official/postfix-${VERSION}.tar.gz
tar xvzf postfix-${VERSION}.tar.gz && cd postfix-${VERSION}

#-- postfix の build (buildオプションはcentos7のpostfixのbuildオプションを真似たつもり)
CCARGS="-Wmissing-prototypes -Wformat -Wno-comment -fPIC \
-DHAS_LDAP -DLDAP_DEPRECATED=1 -DHAS_PCRE -I/usr/include/pcre \
-DHAS_MYSQL -I/usr/include/mysql -DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
-I/usr/include/sasl -DUSE_TLS -I/usr/local/openssl-1.1.1d/include \
-DDEF_CONFIG_DIR=\\\"/etc/postfix\\\""

AUXLIBS="-lldap -llber -lpcre -L/usr/lib64/mysql -lmysqlclient \
-lm -L/usr/lib64/sasl2 -lsasl2 -L/usr/local/openssl-1.1.1d/lib -lssl \
-lcrypto  -pie -Wl,-z,relro,-z,now"

make -f Makefile.init makefiles CCARGS="${CCARGS}" AUXLIBS="${AUXLIBS}"
make
make install
#-- ディレクトリ設定などは全て default を選択

#-- postfix の起動
mv /var/tmp/postfix.service /usr/lib/systemd/system/
systemctl enable postfix
systemctl start postfix

・postfix の設定

#-- postmulti で inbound/outbound で設定を分ける
postmulti -e init
postmulti -I postfix-inbound -e create

postconf -c /etc/postfix -e inet_interfaces=${OUTBOUND_MTA_SERVER}
postconf -c /etc/postfix -e inet_protocols=all
postconf -c /etc/postfix -e smtpd_milters=inet:${RSPAMD_SERVER}:${RSPAMD_PORT}
postconf -c /etc/postfix -e non_smtpd_milters=inet:${RSPAMD_SERVER}:${RSPAMD_PORT}
postconf -c /etc/postfix -e smtpd_authorized_xclient_hosts=${XAUTH_HOST}
postconf -c /etc/postfix -e smtpd_sasl_auth_enable=yes
postconf -c /etc/postfix -e smtpd_sender_restrictions=reject_sender_login_mismatch
postconf -c /etc/postfix -e smtpd_sender_login_maps=ldap:/etc/postfix/ldapsendercheck.cf
postconf -c /etc/postfix -e alias_maps=hash:/etc/aliases

postconf -c /etc/postfix-inbound -e inet_interfaces=${IPV4},${IPV6}
postconf -c /etc/postfix-inbound -e inet_protocols=all
postconf -c /etc/postfix-inbound -e myhostname=${DOMAIN}
postconf -c /etc/postfix-inbound -e recipient_delimiter=+
postconf -c /etc/postfix-inbound -e smtpd_milters=inet:${RSPAMD_SERVER}:${RSPAMD_PORT}
postconf -c /etc/postfix-inbound -e smtpd_helo_restrictions=reject_invalid_hostname
postconf -c /etc/postfix-inbound -e transport_maps=ldap:/etc/postfix-inbound/ldaptransport.cf
postconf -c /etc/postfix-inbound -e virtual_alias_maps=ldap:/etc/postfix-inbound/ldapvirtualalias.cf
postconf -c /etc/postfix-inbound -e relay_domains=/etc/postfix-inbound/relay_domains
postconf -c /etc/postfix-inbound -e authorized_submit_users=static:anyone
postconf -c /etc/postfix-inbound -e alias_maps=hash:/etc/aliases
postconf -c /etc/postfix-inbound -X master_service_disable

#-- postconf が面倒になったので、、、
cat <<_EOL_>> /etc/postfix-inbound/main.cf
smtpd_recipient_restrictions =
    check_recipient_access ldap:/etc/postfix-inbound/ldaprcptcheck.cf
    reject
_EOL_

for cf in /etc/postfix/main.cf /etc/postfix-inbound/main.cf
do
cat <<_EOL_>> ${cf}
milter_default_action = tempfail
milter_protocol = 6
smtpd_junk_command_limit = 20
smtpd_helo_required = yes
smtpd_hard_error_limit = 5
message_size_limit = 20480000
milter_command_timeout=15s
milter_content_timeout=20s
# anvil_rate_time_unit = 60s
# smtpd_recipient_limit = 50
# smtpd_client_connection_count_limit = 15
# smtpd_client_message_rate_limit = 100
# smtpd_client_recipient_rate_limit = 200
# smtpd_client_connection_rate_limit = 100
disable_vrfy_command = yes
smtpd_discard_ehlo_keywords = dsn, enhancedstatuscodes, etrn
lmtp_host_lookup = native
smtp_host_lookup = native
_EOL_
done

cat <<_EOL_>/etc/postfix-inbound/ldaprcptcheck.cf
server_host = ${LDAP_SERVER}
bind = no
version = 3
scope = sub
timeout = 15
query_filter = (&(objectClass=inetLocalMailRecipient)(mailLocalAddress=%s))
result_attribute = mailRoutingAddress
result_format = OK
_EOL_

cat <<_EOL_>/etc/postfix-inbound/ldaptransport.cf
server_host = ${LDAP_SERVER}
bind = no
version = 3
scope = sub
timeout = 15
query_filter = (&(objectClass=inetLocalMailRecipient)(mailLocalAddress=%s))
result_attribute = mailHost
result_format = lmtp:[%s]:${LMTP_PORT}
_EOL_

cp /etc/postfix-inbound/ldaprcptcheck.cf /etc/postfix-inbound/ldapvirtualalias.cf
sed -i 's/result_format = OK/result_format = %s/' /etc/postfix-inbound/ldapvirtualalias.cf

cat <<_EOL_>/etc/postfix/ldapsendercheck.cf
server_host = ${LDAP_SERVER}
bind = no
version = 3
scope = sub
timeout = 15
query_filter = (&(objectClass=inetLocalMailRecipient)(mailRoutingAddress=%s))
result_attribute = mailRoutingAddress
result_format = %s
_EOL_

#-- マルチドメインの場合は、ドメインを全て記述する
cat <<_EOL_>/etc/postfix-inbound/relay_domains
${DOMAIN}
_EOL_

#-- TLS関連設定
cat <<_EOL_>> /etc/postfix-inbound/main.cf
smtp_tls_CAfile = /etc/pki/tls/certs/ca-bundle.crt
smtp_tls_cert_file = /etc/letsencrypt/live/${DOMAIN}/fullchain.pem
smtp_tls_key_file  = /etc/letsencrypt/live/${DOMAIN}/privkey.pem
smtp_tls_loglevel = 1
smtp_tls_security_level = may
smtp_use_tls =yes
smtpd_tls_CAfile = /etc/pki/tls/certs/ca-bundle.crt
smtpd_tls_ask_ccert = yes
smtpd_tls_cert_file = /etc/letsencrypt/live/${DOMAIN}/fullchain.pem
smtpd_tls_key_file  = /etc/letsencrypt/live/${DOMAIN}/privkey.pem
smtpd_tls_ciphers = high
smtpd_tls_loglevel = 1
smtpd_tls_mandatory_ciphers = high
smtpd_tls_mandatory_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1
smtpd_tls_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_database = btree:/var/lib/postfix-inbound/smtpd_tls_session_cache
smtpd_use_tls = yes
tls_high_cipherlist  = EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
tls_preempt_cipherlist = yes
tls_random_source = dev:/dev/urandom
tls_ssl_options = NO_RENEGOTIATION
_EOL_

cat <<_EOL_>> /etc/postfix/main.cf
smtp_tls_CAfile = /etc/pki/tls/certs/ca-bundle.crt
smtp_tls_cert_file = /etc/letsencrypt/live/${DOMAIN}/fullchain.pem
smtp_tls_key_file  = /etc/letsencrypt/live/${DOMAIN}/privkey.pem
smtp_tls_loglevel = 1
smtp_tls_security_level = may
smtp_use_tls =yes
tls_high_cipherlist  = EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
tls_preempt_cipherlist = yes
tls_random_source = dev:/dev/urandom
_EOL_

#-- postfix 再起動
systemctl restart postfix

postmulti -i postfix-inbound -e enable
postmulti -i postfix-inbound -p start

09. DBサーバ構築 – mysql [さくらのVPS/CentOS7]

・mysql の用途

  1. postfix のコンパイルにmysqlのライブラリが必要
  2. 各Webアプリ(Roundcube、Tiny Tiny RSS、NextCloud、Wordpressなど)
  3. Mattermost (日本語全文検索を簡単に有効にする為、postgresqlではなくmysql 5.7 を選択)

・mysql 5.7 のインストール

#-- mysql の root パスワードを設定
PASSWORD=********

#-- 関連リポジトリの追加
yum remove -y mysql-community-release
yum install -y https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
yum install -y https://packages.groonga.org/centos/groonga-release-1.3.0-1.noarch.rpm

#-- mroonga は mattermost での日本語検索で必要(mattermostをインストールしないなら必要なし)
yum install -y mysql57-community-mroonga mysql-community-devel

#-- mysql の設定
cp -p /etc/my.cnf{,.org}
cat <<_EOL_>> /etc/my.cnf

character-set-server = utf8mb4
innodb_large_prefix = ON
innodb_file_format = Barracuda
innodb_file_format_max = Barracuda
#validate_password_length=7
#validate_password_policy=LOW

#[mysql]
#default-character-set = utf8mb4
_EOL_

#-- mysqld の起動
systemctl enable mysqld
systemctl start mysqld

#-- .my.cnf の作成
TMPPASS="$(awk '/temporary password/{print $NF}' /var/log/mysqld.log)"

cat <<_EOL_> /root/.my.cnf
[client]
host     = localhost
user     = root
password = "${TMPPASS}"
socket   = /var/lib/mysql/mysql.sock
_EOL_

chmod 600 /root/.my.cnf
export HOME=/root

#-- パスワードポリシーの緩和
mysql --connect-expired-password -e "SET GLOBAL validate_password_policy=LOW;" ;
mysql --connect-expired-password -e "SET GLOBAL validate_password_length=7;"

mysqladmin -u root -p${TMPPASS} password "${PASSWORD}"
sed -i "s/^password.*/password = ${PASSWORD}/" ~/.my.cnf

mysql -e "SET GLOBAL validate_password_policy=LOW;" ;
mysql -e "SET GLOBAL validate_password_length=7;"

sed -i 's/^#validate/validate/' /etc/my.cnf

・ これ以降、mysql の update には下記のコマンドを実行する

yum update -y mysql-community-server mysql-community-client
yum reinstall -y mysql57-community-mroonga

08. openssl-1.1.1d(TLS1.3対応) [さくらのVPS/CentOS7]

・openssl-1.1.1d の用途

  1. postfix の TLS1.3 対応
  2. nginx の TLS1.3 対応

・openssl-1.1.1d のインストール

#-- 変数に必要な値を代入
VERSION=1.1.1d

#-- 作業ディレクトリの作成
mkdir -p ~/work/src
cd ~/work/src

#-- build に必要なパッケージのインストール
yum -y install perl-core zlib-devel

#-- source のダウンロード
curl -O -L https://www.openssl.org/source/openssl-${VERSION}.tar.gz
tar xvzf openssl-${VERSION}.tar.gz && cd openssl-${VERSION}

#-- build と install
./config --prefix=/usr/local/openssl-${VERSION} shared zlib
make
make install

#-- ライブラリパスに追加
ln -s openssl-${VERSION} /usr/local/openssl
echo /usr/local/openssl/lib >> /etc/ld.so.conf.d/openssl.conf
ldconfig

06. メールサーバ構築(2) – clamav [さくらのVPS/CentOS7]

・clamav-milter の用途

  1. 送信/受信メールのウィルススキャン (rspamd+calmav)
#-- 変数に必要な値を代入
DOMAIN=masdon.life

#-- clamav-milter のインストール
yum install -y clamav clamav-server-systemd clamav-update

#- Virus Database の更新
freshclam

#- clamd の設定
mkdir /var/log/clamd
chown clamscan /var/log/clamd

cp -p /etc/clamd.d/scan.conf{,.org}

cat <<_EOL_>/etc/clamd.d/scan.conf
LogFile /var/log/clamd/clamd.log
LogFileMaxSize 0
LogTime yes
LogSyslog yes
PidFile /var/run/clamd.scan/clamd.pid
TemporaryDirectory /var/tmp
DatabaseDirectory /var/lib/clamav
LocalSocket /var/run/clamd.scan/clamd.sock
FixStaleSocket yes
MaxConnectionQueueLength 30
MaxThreads 50
ReadTimeout 300
User clamscan
ScanPE yes
ScanELF yes
ScanOLE2 yes
ScanMail yes
ScanArchive yes
ArchiveBlockEncrypted no
_EOL_

#-- clamd の起動
systemctl enable clamd@scan 

#-- 2019/10/15の時点で私のテスト環境で clamd の起動に 約5分かかり、systemd の timeout (90秒)で起動に失敗する。タイムアウトを 5分に変更する
grep ^TimeoutSec /lib/systemd/system/clamd@.service >/dev/null || echo "TimeoutSec = 5min" >> /lib/systemd/system/clamd@.service
systemctl daemon-reload

systemctl start clamd@scan 

07. メールサーバ構築(3) – rspamd [さくらのVPS/CentOS7]

・rspamd の用途

  1. メール送信/転送時に DKIM/ARC署名
  2. メール受信時に SPF/DKIM/DMARC/ARC認証
  3. メール受信時に Virus/Spam Check (採点結果をヘッダーに追加)

・rspamd のインストール

#-- rspamd.com の repository を登録
curl https://rspamd.com/rpm-stable/centos-7/rspamd.repo > /etc/yum.repos.d/rspamd.repo
rpm --import https://rspamd.com/rpm-stable/gpg.key

#-- rspamd と redis のインストール
yum install -y rspamd redis

mkdir /etc/rspamd/local.d/keys/

#-- rspamd の設定
cat <<'_EOL_'> /etc/rspamd/local.d/options.inc
filters = "chartable,dkim,spf,surbl,regexp,fuzzy_check";
check_all_filters = true;
_EOL_

cat <<'_EOL_'> /etc/rspamd/local.d/milter_headers.conf
use = ["x-spamd-result","x-rspamd-server","x-rspamd-queue-id","authentication-results","x-spam-level","x-virus"];
#use = ["authentication-results"];
authenticated_headers = ["authentication-results"];
_EOL_

cat <<'_EOL_'> /etc/rspamd/local.d/redis.conf
servers = "127.0.0.1";
_EOL_

cat <<'_EOL_'> /etc/rspamd/local.d/actions.conf
reject = null;
add_header = 2.0 ;
greylist = null;
_EOL_

cat <<'_EOL_'> /etc/rspamd/local.d/greylist.conf
enabled = false
_EOL_

cat <<'_EOL_'> /etc/rspamd/local.d/phishing.conf
openphish_enabled = true;
phishtank_enabled = true;
_EOL_

cat <<_EOL_> /etc/rspamd/local.d/antivirus.conf
clamav {
  action  = "reject";
  type    = "clamav";
  servers = "/var/run/clamd.scan/clamd.sock";
  symbol = "CLAM_VIRUS";
  patterns {
    #symbol_name = "pattern";
    JUST_EICAR = "^Eicar-Test-Signature$";
  }
}
_EOL_

#-- clamd.sock にアクセスできるように group に追加
usermod -aG clamscan _rspamd
usermod -aG virusgroup _rspamd

cat <<'_EOL_'> /etc/rspamd/local.d/url_reputation.conf
enabled = true;

# Key prefix for redis - default "Ur."
key_prefix = "Ur.";

# Symbols to insert - defaults as shown
symbols {
  white = "URL_REPUTATION_WHITE";
  black = "URL_REPUTATION_BLACK";
  grey = "URL_REPUTATION_GREY";
  neutral = "URL_REPUTATION_NEUTRAL";
}

# DKIM/DMARC/SPF allow symbols - defaults as shown
foreign_symbols {
  dmarc = "DMARC_POLICY_ALLOW";
  dkim = "R_DKIM_ALLOW";
  spf = "R_SPF_ALLOW";
}

# SURBL metatags to ignore - default as shown
ignore_surbl = ["URIBL_BLOCKED", "DBL_PROHIBIT", "SURBL_BLOCKED"];

# Amount of samples required for scoring - default 5
threshold = 5;

#Maximum number of TLDs to update reputation on (default 1)
update_limit = 1;

# Maximum number of TLDs to query reputation on (default 100)
query_limit = 100;

# If true, try to find most 'relevant' URL (default true)
relevance = true;
_EOL_

#-- redisに書き込むデータ行数などの設定 10000以上が推奨
cat <<_EOL_> /etc/rspamd/local.d/history_redis.conf
servers         = 127.0.0.1:6379;
key_prefix      = "rs_history";
nrows           = 10000;
compress        = true;
subject_privacy = false;
_EOL_

#-- 拡張子の spam スコアを設定
cat <<_EOL_> /etc/rspamd/local.d/mime_types.conf
bad_extensions = {
    ace = 4,
    arj = 4,
    bat = 2,
    cab = 3,
    com = 2,
    exe = 1,
    jar = 2,
    lnk = 4,
    scr = 4,
};
bad_archive_extensions = {
    pptx = 0.1,
    docx = 0.1,
    xlsx = 0.1,
    pdf  = 0.1,
    jar  = 3,
    js   = 0.5,
    vbs  = 4,
};
archive_extensions = {
    zip = 1,
    arj = 1,
    rar = 1,
    ace = 1,
    7z  = 1,
    cab = 1,
};
_EOL_

#-- ホワイトリストの設定
cat <<'_EOL_'>/etc/rspamd/local.d/multimap.conf
WHITELIST_SENDER_DOMAIN {
  type = "from";
  map = "/etc/rspamd/local.d/whitelist_sender_domain.map";
  filter = "email:domain";
  score = -10.0
}
WHITELIST_IP {
  type = "ip";
  map = "/etc/rspamd/local.d/whitelist_ip.map";
  score = -10.0
}
_EOL_

#-- 変数に必要な値を代入
DOMAIN=masdon.life
IPV4=$(ip addr show eth0 | awk '/inet /{print $2}' | sed 's#/.*##')
IPV6=$(ip addr show eth0 | awk '/inet6 /&&/global/{print $2}' | sed 's#/.*##')

cat <<_EOL_>/etc/rspamd/local.d/whitelist_sender_domain.map
$DOMAIN
_EOL_

#-- これを設定しないとUser Unknown 時の MAILER DAEMONがSPAM扱いになってしまう。
cat <<_EOL_>/etc/rspamd/local.d/whitelist_ip.map
${IPV4}
${IPV6}
_EOL_

・DKIMで使用する秘密鍵と共通鍵の作成

#-- 変数に必要な値を代入
DOMAIN=masdon.life

#-- 鍵の生成
rspamadm dkim_keygen -d ${DOMAIN} -s default -b 2048
-----BEGIN PRIVATE KEY-----
....
....
....
....
-----END PRIVATE KEY-----
default._domainkey IN TXT ( "v=DKIM1; k=rsa; "
  "p=...."
  "...."
) ;

#-- 秘密鍵の登録 ----BEGIN〜 行から ----END〜 行までをファイルに記述する
vi /etc/rspamd/local.d/keys/default.${DOMAIN}.key
chmod 600 /etc/rspamd/local.d/keys/default.${DOMAIN}.key
chown _rspamd. /etc/rspamd/local.d/keys/default.${DOMAIN}.key

#-- 共通鍵の登録 default._domainkey〜 から ) ; 行までをゾーンファイルに記述し、シリアルを更新し nsd を再起動する
vi /etc/nsd/zone/${DOMAIN}.zone
systemctl restart nsd

#-- dkimの署名の設定
cat <<'_EOL_'> /etc/rspamd/local.d/dkim_signing.conf
# メーリングリストや転送の対応
allow_hdrfrom_mismatch = true;
sign_local = true;

# subdomain の sign 対応
use_esld = false;
try_fallback = false;

# sign 対象のヘッダー
sign_headers = '(o)from:(o)sender:(o)reply-to:(o)subject:(o)date:(o)message-id:(o)to:(o)cc:(o)mime-version:(o)content-type:(o)content-transfer-encoding:resent-to:resent-cc:resent-from:resent-sender:resent-message-id:(o)in-reply-to:(o)references:list-id:list-owner:list-unsubscribe:list-subscribe:list-post';

domain {
  masdon.life {
    # Private key path
    path = "/etc/rspamd/local.d/keys/$selector.$domain.key";
    # Selector
    selector = "default";
  }
}
_EOL_

#-- arc署名の設定
cat <<'_EOL_'> /etc/rspamd/local.d/arc.conf
# メーリングリストや転送の対応
allow_hdrfrom_mismatch = true;
sign_local = true;
use_domain = "envelope";

# subdomain の sign 対応
use_esld = false;
try_fallback = false;

sign_headers = "(o)from:(o)sender:(o)reply-to:(o)subject:(o)date:(o)message-id:(o)to:(o)cc:(o)mime-version:(o)content-type:(o)content-transfer-encoding:resent-to:resent-cc:resent-from:resent-sender:resent-message-id:(o)in-reply-to:(o)references:list-id:list-owner:list-unsubscribe:list-subscribe:list-post:dkim-signature";

domain {
  masdon.life {
    # Private key path
    path = "/etc/rspamd/local.d/keys/$selector.$domain.key";
    # Selector
    selector = "default";
  }
}
_EOL_

・Web interface のパスワード設定

#-- Web interface のパスワードを生成
PASSWORD=$(rspamadm pw -p ********)

cat <<_EOL_> /etc/rspamd/local.d/worker-controller.inc
password        = "${PASSWORD}";
enable_password = "${PASSWORD}";
_EOL_

・rspamd, redis 起動

systemctl enable rspamd redis
systemctl start rspamd redis

・Web interface用の nginx の設定ファイルを用意

mkdir -p /etc/nginx/conf.d/https.d
cat <<'_EOL_' > /etc/nginx/conf.d/https.d/rspamd.conf
  location ^~ /rspamd {
    location /rspamd/ {
      proxy_pass       http://localhost:11334/;
      proxy_set_header Host      $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
  }
_EOL_