From cce9257146bf7daf046d50d1450765bf2f51997e Mon Sep 17 00:00:00 2001 From: Ludovic Pouzenc Date: Wed, 2 Jan 2019 21:53:56 +0100 Subject: Initial import, d9-mail-family-fr.sh d9-mail-family-fr.sh should ends up with a working mail server, real-world testing has to be done. --- d9-mail-family-fr.sh | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 551 insertions(+) create mode 100644 d9-mail-family-fr.sh (limited to 'd9-mail-family-fr.sh') diff --git a/d9-mail-family-fr.sh b/d9-mail-family-fr.sh new file mode 100644 index 0000000..fff61ec --- /dev/null +++ b/d9-mail-family-fr.sh @@ -0,0 +1,551 @@ +#!/bin/bash +# This file is part of Take It Easy Linux. + +# Take It Easy Linux is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# Take It Easy Linux is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with Take It Easy Linux. If not, see . + +# Copyright © 2019 Ludovic Pouzenc + +# Fonctions utilitaires pour tracer, installer, télécharger, configurer +t() { + echo -n "[ ] ${BASH_LINENO[0]} $*" + out=$($* 2>&1) + if [ $? -eq 0 ] + then echo -e "\r[\e[32m OK \e[0m]" + else echo -e "\r[\e[1m\e[31mFAILED\e[0m]" + echo "$out" + fi +} +inst() { + touch /tmp/installed + if grep -q -- "$*" /tmp/installed + then echo 'Already installed' + else t apt-get install --quiet --yes $* && echo $* >> /tmp/installed + fi +} +get() { + filename=$1 + baseurl=$2 + if [ -f /tmp/$filename ] + then echo 'Already downloaded' + else t wget -O /tmp/$filename $baseurl/$filename + fi +} +link() { + target=$1 + linkpath=$2 + [ -L $linkpath ] || ln -sf $target $linkpath +} +confwrite() { + file=$1 + [ -s $file ] && cp -a $file $file.tmp + cat > $file + if [ -f $file.tmp ] + then if diff -q $file $file.tmp + then rm $file.tmp + else mv $file.tmp $file.orig + fi + fi +} +confset() { + file=$1 + conf_keyword=$2 + conf_valuematch=$3 + conf_newvalue=$4 + sed --in-place -e 's#^\(\s*\)\#\?\(\s*'$conf_keyword'\s*[ =]\+\s*\)'$conf_valuematch'\(.*\)$#\1\2'$conf_newvalue'\3#' $file +} +confenable() { + file=$1 + conf_keyword=$2 + sed --in-place -e 's#^\(\s*\)\#\?\(\s*'$conf_keyword'\s*[ =]\+\s*'$conf_valuematch'.*\)$#\1\2#' $file +} +confappend() { + file=$1 + shift + line=$* + grep -q -- "$line" $file || echo $line >> $file +} + +# Paramètres détéectés et utilisés par la suite du script +set -x +host=$(hostname) +domain=$(dnsdomainname) +lang=${LANG%.*} +set +x +echo 'Saisissez un mot de passe admin pour le webmail et rspamd ou ctrl+C pour annuler' +read -rsp 'Password: ' adminpass +echo + +# Ajout des dépôts nécessaires et les clés GPG pour valider les paquets reçus +t confwrite /etc/apt/sources.list.d/backports.list <<"EOT" +deb http://ftp.debian.org/debian stretch-backports main +EOT +t confwrite /etc/apt/sources.list.d/rspamd.list <<"EOT" +deb [arch=amd64] http://rspamd.com/apt-stable/ stretch main +EOT +t get gpg.key https://rspamd.com/apt-stable +t apt-key add /tmp/gpg.key + +# Prise en compte des nouveaux dépots +t apt update + +# Préremplissage des questions posées à l'installation de certains paquets +t debconf-set-selections <<"EOT" +exim4-config exim4/dc_eximconfig_configtype select internet site; mail is sent and received directly using SMTP +exim4-config exim4/use_split_config boolean true +EOT + +# Installation des paquets nécessaires +# Obtention de certificat TLS gratuits +t inst -t stretch-backports python-certbot-apache +# Redis utilisé par rainloop et rspamd (et la version 3 buggue avec rspam, "127.0.0.1: connection refusée") +t inst -t stretch-backports redis-server +# Programmes pour traiter et stocker les mails +t inst dovecot-lmtpd dovecot-imapd dovecot-sieve dovecot-managesieved exim4-daemon-heavy rspamd clamav-daemon +# Prérequis webmail RainLoop +t inst libapache2-mod-php php-curl php-iconv php-sqlite3 php-xml unzip +# Système, sécurité, monitoring +t inst apachetop fail2ban munin-node liblwp-useragent-determined-perl + +read -t10 -p 'Installation de paquets terminée, configuration dans 10 secondes (ctrl+C pour annuler)' garbage +echo + +# Configuration munin-node +rm /etc/munin/plugins/ntp_kernel_* 2>/dev/null +t link /usr/share/munin/plugins/netstat /etc/munin/plugins/ +t link /usr/share/munin/plugins/apache_accesses /etc/munin/plugins/ +t link /usr/share/munin/plugins/apache_processes /etc/munin/plugins/ +t link /usr/share/munin/plugins/apache_volume /etc/munin/plugins/ +t service munin-node restart + +# Configuration redis (base de données mémoire simple pour webmail et rspamd) +t confset /etc/redis/redis.conf maxmemory '' 500mb +t confset /etc/redis/redis.conf maxmemory-policy 'noeviction' volatile-ttl +t confwrite /etc/sysctl.d/50-redis-overcommit_memory.conf <<"EOT" +vm.overcommit_memory = 1 +EOT +echo 1 > /proc/sys/vm/overcommit_memory +t service redis-server restart + +# Configuration apache2 (serveur web) +t confset /etc/apache2/mods-enabled/mpm_prefork.conf MaxRequestWorkers '[0-9]\+' 20 + +t confwrite /etc/apache2/sites-available/000-default.conf < + ServerAdmin postmaster@$domain + DocumentRoot /var/www/html + ErrorLog /var/log/apache2/error.log + CustomLog /var/log/apache2/access.log combined + + # Gère les redirections depuis http vers https sur le nom canonique + + RewriteEngine on + RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/ + RewriteRule ^/(.*) https://$host.$domain/\$1 [L,R=301] + + + # Accepte les requêtes challenge LetsEncrypt + + Options None + AllowOverride None + Require all granted + + + # Ne pas publier les données du webmail (si mod_rewrite n'est pas actif) + + Options None + AllowOverride None + Require all denied + + + +EOT +t confwrite /etc/apache2/sites-available/default-ssl.conf < + + ServerAdmin postmaster@$domain + ServerName $host.$domain + DocumentRoot /var/www/html + + ErrorLog /var/log/apache2/error.log + CustomLog /var/log/apache2/access.log combined + + + Options None + AllowOverride None + Require all granted + + + # Ne pas publier les données du webmail + + Options None + AllowOverride None + Require all denied + + + # Renvoi par défaut sur le webmail et (spam,rspamd) -> rspamd/ + + RewriteEngine on + RewriteRule ^/$ https://$host.$domain/webmail/ [L,R=302] + RewriteRule ^/spam$ https://$host.$domain/rspamd/ [L,R=302] + RewriteRule ^/rspamd$ https://$host.$domain/rspamd/ [L,R=302] + + + # Exposer l'interface de rspamd en https + + ProxyPass /rspamd/ http://127.0.0.1:11334/ + ProxyPassReverse /rspamd/ http://127.0.0.1:11334/ + ProxyRequests Off + + + # Paramètres TLS de LetsEncrypt + Include /etc/letsencrypt/options-ssl-apache.conf + SSLCertificateFile /etc/letsencrypt/live/$domain/fullchain.pem + SSLCertificateKeyFile /etc/letsencrypt/live/$domain/privkey.pem + + +EOT + +t a2enmod proxy_http rewrite ssl +t a2ensite default-ssl +t confset /etc/php/7.0/apache2/php.ini upload_max_filesize '[0-9M]\+' 26M +t confset /etc/php/7.0/apache2/php.ini post_max_size '[0-9M]\+' 30M + +# Pré-configuration certificats TLS (initialement : auto-signés, mais prêt pour LetsEncrypt) +t mkdir -p /etc/letsencrypt/live/$domain/ +t cp -a /usr/lib/python3/dist-packages/certbot_apache/options-ssl-apache.conf /etc/letsencrypt/ +t link /etc/ssl/certs/ssl-cert-snakeoil.pem /etc/letsencrypt/live/$domain/fullchain.pem +t link /etc/ssl/private/ssl-cert-snakeoil.key /etc/letsencrypt/live/$domain/privkey.pem + +t service apache2 restart + +# Déploiement webmail RainLoop +t get rainloop-community-latest.zip https://www.rainloop.net/repository/webmail +t mkdir -p /var/www/html/webmail +t unzip -qnd /var/www/html/webmail /tmp/rainloop-community-latest.zip +t chown -R root: /var/www/html/webmail +t mkdir -p /var/www/html/webmail/data/_data_/_default_/logs/fail2ban/ +t touch /var/www/html/webmail/data/_data_/_default_/logs/fail2ban/auth-empty.txt + +# Configuration webmail Rainloop +t php -- "$domain" "$lang" "$adminpass" "(autoconfig webmail)" <<"EOT" +Set('webmail', 'title', 'Webmail ' . $argv[1]); +$oConfig->Set('webmail', 'language', $argv[2]); +$oConfig->Set('webmail', 'attachment_size_limit', 25); +$oConfig->Set('contacts', 'enable', 'On'); +$oConfig->SetPassword($argv[3]); +$oConfig->Set('login', 'default_domain', $argv[1]); +$oConfig->Set('logs', 'enable', 'On'); +$oConfig->Set('logs', 'write_on_error_only', 'On'); +$oConfig->Set('logs', 'filename', 'syslog'); +$oConfig->Set('logs', 'auth_logging', 'On'); +$oConfig->Set('cache', 'fast_cache_driver', 'redis'); +echo 'Config ' . ( $oConfig->Save() ? 'Saved' : 'Error') . "\n"; +?> +EOT +t confwrite /var/www/html/webmail/data/_data_/_default_/domains/$domain.ini < user=.* host=.* port=.*$ +ignoreregex = +EOT + +t confwrite /etc/fail2ban/jail.local <<"EOT" +[rainloop] +enabled = true +banaction = iptables-multiport +filter = rainloop +port = http,https +logpath = /var/www/html/webmail/data/_data_/_default_/logs/fail2ban/auth-*.txt +maxretry = 5 +findtime = 1500 +bantime = 900 +EOT + +t service fail2ban restart + +# Configuration Dovecot (serveur IMAP de consultation mail, filtres sieve) +t confset /etc/dovecot/dovecot.conf verbose_proctitle '[a-z]\+' yes +t confset /etc/dovecot/conf.d/10-auth.conf disable_plaintext_auth '[a-z]\+' yes +t confset /etc/dovecot/conf.d/10-auth.conf auth_username_format '[%A-Za-z]\+' '%Ln' +t confenable /etc/dovecot/conf.d/10-logging.conf mail_log_events '\S\+' +t confenable /etc/dovecot/conf.d/10-logging.conf mail_log_fields '\S\+' +t confset /etc/dovecot/conf.d/10-mail.conf mail_location '\S\+' 'mdbox:~/mail' +t confset /etc/dovecot/conf.d/10-ssl.conf ssl 'no' required +t confset /etc/dovecot/conf.d/10-ssl.conf ssl_cert '[a-z/<.]\+' " {$max_received_linelength}{998}} + .endif + + # Deny unless the address list headers are syntactically correct. + # + # If you enable this, you might reject legitimate mail. + .ifdef CHECK_DATA_VERIFY_HEADER_SYNTAX + deny + message = Message headers fail syntax check + !acl = acl_local_deny_exceptions + !verify = header_syntax + .endif + + + # require that there is a verifiable sender address in at least + # one of the "Sender:", "Reply-To:", or "From:" header lines. + .ifdef CHECK_DATA_VERIFY_HEADER_SENDER + deny + message = No verifiable sender address in message headers + !acl = acl_local_deny_exceptions + !verify = header_sender + .endif + + + # Deny if the message contains malware. Before enabling this check, you + # must install a virus scanner and set the av_scanner option in the + # main configuration. + # + # exim4-daemon-heavy must be used for this section to work. + # + # deny + # malware = * + # message = This message was detected as possible malware ($malware_name). + + # Actually scan message agaist spam (and malware trough rspamd) + warn + logwrite = spam-check: starting + spam = Debian-exim:true + logwrite = spam-check: ending + + # Defer message if spam scanner is not available + defer + condition = ${if eq{$spam_action}{}} + message = Please try again later, spam scanner unavailable + + # FROM https://rspamd.com/doc/integration.html + + # use greylisting available in rspamd v1.3+ + defer message = Please try again later + condition = ${if eq{$spam_action}{soft reject}} + + # Reject message that have high-probability to be spam + deny message = Message classified as spam + condition = ${if eq{$spam_action}{reject}} + + # Remove foreign headers + warn + remove_header = x-spam-bar : x-spam-score : x-spam-report : x-spam-status + + # add spam-score and spam-report header when "add header" action is recommended by rspamd + warn + condition = ${if eq{$spam_action}{add header}} + add_header = X-Spam-Score: $spam_score ($spam_bar) + add_header = X-Spam-Report: $spam_report + + # add x-spam-status header if message is not ham + warn + ! condition = ${if match{$spam_action}{^no action\$|^greylist\$}} + add_header = X-Spam-Status: Yes + + # This hook allows you to hook in your own ACLs without having to + # modify this file. If you do it like we suggest, you'll end up with + # a small performance penalty since there is an additional file being + # accessed. This doesn't happen if you leave the macro unset. + .ifdef CHECK_DATA_LOCAL_ACL_FILE + .include CHECK_DATA_LOCAL_ACL_FILE + .endif + + + # accept otherwise + accept +EOT +t confwrite /etc/exim4/conf.d/auth/50_dovecot_auth <<"EOT" +dovecot_authplain: + driver = dovecot + public_name = PLAIN + server_advertise_condition = ${if def:tls_cipher} + server_socket = /var/run/dovecot/auth-client + server_set_id = $auth1 +EOT +t confwrite /etc/exim4/conf.d/transport/50_dovecot_lmtp <<"EOT" +dovecot_lmtp: + driver = lmtp + socket = /var/run/dovecot/lmtp + #maximum number of deliveries per batch, default 1 + batch_max = 200 + #allow suffixes/prefixes (default unset) + rcpt_include_affixes +EOT + +t confset /etc/exim4/conf.d/main/02_exim4-config_options spamd_address '\S\+\s[0-9]\+' MAIN_SPAMD_ADDRESS +t service exim4 restart + +# Afficher un texte explicatif en fin d'exécution +iface=$(ip -o r | sed -ne 's/^default .* dev \(\S\+\).*$/\1/p') +ip=$(ip -o a s dev $iface | sed -ne 's/^.*inet \([0-9.]\+\).*/\1/p') +cat < +URL mises en place : +https://$host.$domain/webmail/ +https://$host.$domain/webmail/?admin +https://$host.$domain/rspamd/ +Il est possible d'utiliser l'IP aussi (si le DNS n'est pas configuré) +https://$ip/webmail/ +EOT -- cgit v1.2.3