summaryrefslogtreecommitdiff
path: root/d9-mail-family-fr.sh
diff options
context:
space:
mode:
Diffstat (limited to 'd9-mail-family-fr.sh')
-rw-r--r--d9-mail-family-fr.sh551
1 files changed, 551 insertions, 0 deletions
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 <https://www.gnu.org/licenses/>.
+
+# Copyright © 2019 Ludovic Pouzenc <ludovic@pouzenc.fr>
+
+# 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 '<bytes>' 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 <<EOT
+<VirtualHost *:80>
+ 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
+ <IfModule mod_rewrite.c>
+ RewriteEngine on
+ RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
+ RewriteRule ^/(.*) https://$host.$domain/\$1 [L,R=301]
+ </IfModule>
+
+ # Accepte les requêtes challenge LetsEncrypt
+ <Directory /var/www/html/.well-known/acme-challenge>
+ Options None
+ AllowOverride None
+ Require all granted
+ </Directory>
+
+ # Ne pas publier les données du webmail (si mod_rewrite n'est pas actif)
+ <Directory /var/www/html/webmail/data>
+ Options None
+ AllowOverride None
+ Require all denied
+ </Directory>
+
+</VirtualHost>
+EOT
+t confwrite /etc/apache2/sites-available/default-ssl.conf <<EOT
+<IfModule mod_ssl.c>
+<VirtualHost _default_:443>
+ ServerAdmin postmaster@$domain
+ ServerName $host.$domain
+ DocumentRoot /var/www/html
+
+ ErrorLog /var/log/apache2/error.log
+ CustomLog /var/log/apache2/access.log combined
+
+ <Directory /var/www/html>
+ Options None
+ AllowOverride None
+ Require all granted
+ </Directory>
+
+ # Ne pas publier les données du webmail
+ <Directory /var/www/html/webmail/data>
+ Options None
+ AllowOverride None
+ Require all denied
+ </Directory>
+
+ # Renvoi par défaut sur le webmail et (spam,rspamd) -> rspamd/
+ <IfModule mod_rewrite.c>
+ 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]
+ </IfModule>
+
+ # Exposer l'interface de rspamd en https
+ <IfModule mod_proxy_http.c>
+ ProxyPass /rspamd/ http://127.0.0.1:11334/
+ ProxyPassReverse /rspamd/ http://127.0.0.1:11334/
+ ProxyRequests Off
+ </IfModule>
+
+ # 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
+</VirtualHost>
+</IfModule>
+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"
+<?php
+$_ENV['RAINLOOP_INCLUDE_AS_API'] = true;
+include '/var/www/html/webmail/index.php';
+$oConfig = \RainLoop\Api::Config();
+$oConfig->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 <<EOT
+imap_host = "localhost"
+imap_port = 143
+imap_secure = "TLS"
+imap_short_login = Off
+sieve_use = On
+sieve_allow_raw = Off
+sieve_host = "localhost"
+sieve_port = 4190
+sieve_secure = "TLS"
+smtp_host = "localhost"
+smtp_port = 587
+smtp_secure = "TLS"
+smtp_short_login = Off
+smtp_auth = On
+smtp_php_mail = Off
+white_list = ""
+EOT
+t chown -R www-data: /var/www/html/webmail/data
+t chmod -R o= /var/www/html/webmail/data
+
+t confwrite /etc/cron.daily/rainloop-auth-log-purge.sh <<"EOT"
+#!/bin/sh
+find /var/www/html/webmail/data/_data_/_default_/logs/fail2ban/ -type f -mtime +365 -print0 | xargs -r0 rm
+EOT
+chmod +x /etc/cron.daily/rainloop-auth-log-purge.sh
+
+t link /var/www/html/webmail/data/_data_/_default_/logs/fail2ban/ /var/log/rainloop-fail2ban
+t link /var/www/html/webmail/data/_data_/_default_/ /etc/rainloop
+
+# Configuration fail2ban (auto-bannir les IP qui essayent des mots de passes sur le webmail)
+t confwrite /etc/fail2ban/filter.d/rainloop.conf <<"EOT"
+[Definition]
+failregex = : Auth failed: ip=<HOST> 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/<.]\+' "</etc/letsencrypt/live/$domain/fullchain.pem"
+t confset /etc/dovecot/conf.d/10-ssl.conf ssl_key '[a-z/<.]\+' "</etc/letsencrypt/live/$domain/privkey.pem"
+t confwrite /etc/dovecot/conf.d/10-master.local.conf <<"EOT"
+service auth {
+ unix_listener auth-client {
+ mode = 0660
+ group = Debian-exim
+ }
+}
+EOT
+t confwrite /etc/dovecot/conf.d/20-lmtp.conf <<"EOT"
+protocol lmtp {
+ mail_plugins = $mail_plugins sieve
+}
+EOT
+t confwrite /etc/dovecot/conf.d/20-managesieve.conf <<"EOT"
+protocols = $protocols sieve
+service managesieve-login {
+ inet_listener sieve {
+ }
+}
+service managesieve {
+ process_limit = 16
+}
+protocol sieve {
+}
+EOT
+t confset /etc/dovecot/conf.d/90-sieve.conf sieve_before '\S\+' /etc/dovecot/sieve-global/before.d
+mkdir -p /etc/dovecot/sieve-global/before.d
+t confwrite /etc/dovecot/sieve-global/before.d/spam-into-junk.sieve <<"EOT"
+require ["fileinto"];
+
+if header :is "X-Spam" "Yes" {
+ fileinto "Junk";
+ stop;
+}
+EOT
+t sievec /etc/dovecot/sieve-global/before.d/spam-into-junk.sieve
+t service dovecot restart
+
+# Configuration rspamd (anti-spam qui appelle l'antivirus ClamAV)
+t confwrite /etc/rspamd/local.d/redis.conf <<"EOT"
+write_servers = "localhost";
+read_servers = "localhost";
+EOT
+t confwrite /etc/rspamd/local.d/classifier-bayes.conf <<"EOT"
+backend = "redis";
+new_schema = true;
+expire = 8640000;
+autolearn = true
+EOT
+t confwrite /etc/rspamd/local.d/antivirus.conf <<"EOT"
+clamav {
+servers = "/var/run/clamav/clamd.ctl";
+}
+EOT
+t confwrite /etc/rspamd/local.d/worker-controller.inc <<EOT
+password = "$(rspamadm pw -p $adminpass | grep '^\$')";
+EOT
+t service clamav-daemon restart
+t service rspamd restart
+
+# Configuration exim4 (serveur de mail, MTA, connecté à dovecot et rspamd)
+t confwrite /etc/exim4/exim4.conf.template <<"EOT"
+# This file is NOT used by exim because of :
+# dc_use_split_config='true' (in update-exim4.conf.conf)
+#
+# See conf.d folder
+# use "update-exim4.conf" command before "service exim4 reload"
+EOT
+t confappend /etc/default/exim4 "SMTPLISTENEROPTIONS='-oX 25:587 -oP /run/exim4/exim.pid'"
+t adduser Debian-exim ssl-cert
+
+t confwrite /etc/exim4/local_macros.conf <<EOT
+# acl/30_exim4-config_check_rcpt
+CHECK_RCPT_VERIFY_SENDER = yes
+
+# acl/40_exim4-config_check_data
+CHECK_DATA_VERIFY_HEADER_SYNTAX = yes
+CHECK_DATA_VERIFY_HEADER_SENDER = yes
+
+# main/02_exim4-config_options
+MESSAGE_SIZE_LIMIT = 25M
+MAIN_HARDCODE_PRIMARY_HOSTNAME=$domain
+MAIN_SPAMD_ADDRESS = 127.0.0.1 11333 variant=rspamd
+
+# main/03_exim4-config_tlsoptions
+MAIN_TLS_ENABLE = yes
+MAIN_TLS_CERTIFICATE = /etc/letsencrypt/live/$domain/fullchain.pem
+MAIN_TLS_PRIVATEKEY = /etc/letsencrypt/live/$domain/privkey.pem
+
+# router/900_exim4-config_local_user
+LOCAL_DELIVERY = dovecot_lmtp
+EOT
+t link /etc/exim4/local_macros.conf /etc/exim4/conf.d/main/00_local_macros
+t confwrite /etc/exim4/conf.d/acl/40_exim4-config_check_data <<"EOT"
+### acl/40_exim4-config_check_data
+#################################
+
+# This ACL is used after the contents of a message have been received. This
+# is the ACL in which you can test a message's headers or body, and in
+# particular, this is where you can invoke external virus or spam scanners.
+
+acl_check_data:
+
+ # Deny if the message contains an overlong line. Per the standards
+ # we should never receive one such via SMTP.
+ #
+ .ifndef IGNORE_SMTP_LINE_LENGTH_LIMIT
+ deny message = maximum allowed line length is 998 octets, \
+ got $max_received_linelength
+ condition = ${if > {$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 <<EOT
+Le script a terminé son exécution. Tout devrait être en "OK", sinon, voir le numéro de ligne indiqué dans le script.
+(Pour remonter dans le terminal, utiliser Shift + PageUp)
+Les certificats TLS sont prévus avec LetsEncrypt mais n'est pas lancé par ce script.
+Pré-requis : le serveur soit joignable depuis internet avec son DNS public (celui retourné par hostname --fqdn).
+Pour obtenir les certificats, lancer :
+# certbot --apache certonly
+Pour ajouter des utilisateurs / boites mails utilisez :
+adduser <login>
+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