diff --git a/mail-aio.sh b/mail-aio.sh index b38504e..c98bbe8 100644 --- a/mail-aio.sh +++ b/mail-aio.sh @@ -9,7 +9,7 @@ hostnamectl | grep -q 'Debian' || exit 1 sshkeys='' # Backup mailservers -backup_mailserver='' +backup_mailserver=() # Exit function function die @@ -39,16 +39,24 @@ do -d | --domain ) if [ ${2} != "" ] then - domain=${2} + domain_url=${2} shift fi ;; + -m | --mail-user ) + if [ ${2} != "" ] + then + mailuser=${2} + shift + fi + ;; -? | -h | --help ) cat </dev/null -echo -e '\n\n\e[1;32mPassword for '${username}'@'${domain}' -p' ${ssh_port}' has been saved\e[0m\n' +echo -e '\n\n\e[1;32mPassword for '${username}'@'${domain_url}' -p' ${ssh_port}' has been saved\e[0m\n' unset userpass userpass2 +# Mail username +if [ -z ${mailuser} ] +then + echo -e '\e[1;34mType in your email username\e[0m' + until [ ${mailuser} ] + do + read -r -p 'Username: ' mailuser + [ ${mailuser} ] || echo -e '\n\e[1;31mUsername cannot be empty, try again\e[0m' + done + echo -e '\n\e[1;32mMail user '${mailuser}'@'${domain_url}' has been saved\e[0m' +fi + +# Mail account password +if [ -z ${mailpass} ] +then + echo -e '\n\e[1;34mCreate a password for your mail account\e[0m' + until [ "${mailpass}" = "${mailpass2}" -a "${mailpass}" ] + do + read -s -r -p 'Mail password: ' mailpass + read -s -r -p $'\nVerify mail password: ' mailpass2 + if [ -z "${mailpass}" ] + then + echo -e '\n\n\e[1;31mPassword field cannot be empty, try again\e[0m' + elif [ "${mailpass}" != "${mailpass2}" ] + then + echo -e '\n\n\e[1;31mPasswords did not match, try again\e[0m' + fi + done + echo -e '\n\n\e[1;32mMail password has been saved\e[0m' +fi + +# Postfixadmin password +if [ -z ${postfixadminpass} ] +then + echo -e '\n\e[1;34mCreate a postfixadmin setup password\e[0m' + until [ "${postfixadminpass}" = "${postfixadminpass2}" -a "${postfixadminpass}" ] + do + read -s -r -p 'Postfixadmin password: ' postfixadminpass + read -s -r -p $'\nVerify Postfixadmin password: ' postfixadminpass2 + if [ -z "${postfixadminpass}" ] + then + echo -e '\n\n\e[1;31mPassword field cannot be empty, try again\e[0m' + elif [ "${postfixadminpass}" != "${postfixadminpass2}" ] + then + echo -e '\n\n\e[1;31mPasswords did not match, try again\e[0m' + fi + done + echo -e '\n\n\e[1;32mPostfixadmin password has been saved\e[0m\n' +fi + +# Static variables +ip_addr=$(wget -q4O- ipv4.icanhazip.com) +subdomain=$(echo ${domain_url} | awk -F . '{print $1}') +domain="$(echo ${domain_url} | awk -F . '{print $2}').$(echo ${domain_url} | awk -F . '{print $3}')" +eff_email=eff@${domain} +roundcubedbpass=$(cat /dev/urandom | tr -d -c 'a-zA-Z0-9' | fold -w 128 | head -n 1) +postfixadmindbpass=$(cat /dev/urandom | tr -d -c 'a-zA-Z0-9' | fold -w 128 | head -n 1) +roundcubepass_strength_drive=$(cat /dev/urandom | tr -d -c 'a-z' | fold -w 8 | head -n 1) + +# Exit if static variable is null +if [ -z ${ip_addr} ] || [ -z ${subdomain} ] || [ -z ${domain} ] || [ -z ${eff_email} ] +then + die 'A static variable is nonexistent' +fi + +# Interaction end echo -e '\e[1;34mUpgrading system...\e[0m' apt remove -y nano exim* &>/dev/null apt update -y || die apt upgrade -y || die apt dist-upgrade -y || die +debconf-set-selections <<< "postfix postfix/mailname string ${domain}" +debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Internet Site'" apt install -y sudo ufw vim fail2ban wget telnet dnsutils rsyslog zram-tools \ - || die 'Apt failed' + composer git acl dbconfig-no-thanks \ + nginx certbot python3-certbot-nginx \ + mariadb-server mariadb-client postfix-mysql dovecot-mysql \ + php php-fpm php-imap php-mbstring php-mysql php-json php-curl php-zip php-xml php-bz2 php-intl php-gmp php-net-ldap3 php-imagick php-common php-gd php-sqlite3 php-cli \ + postfix postfix-pcre \ + dovecot-core dovecot-imapd dovecot-lmtpd \ + postfix-policyd-spf-python opendkim opendkim-tools \ + opendmarc || die 'Apt failed' +apt autoremove -y # cron rsyslog sed -i 's/#cron/cron/' /etc/rsyslog.conf -# ufw firewall +# UFW +# SSH ufw allow ${ssh_port}/tcp >/dev/null +# Mail ports +ufw allow 25/tcp >/dev/null +ufw allow 80,443/tcp >/dev/null +ufw allow 587/tcp >/dev/null +ufw allow 143,993/tcp >/dev/null + yes | ufw enable >/dev/null -systemctl -q enable --now ufw fail2ban +systemctl -q enable --now ufw + +# Check port 25 +echo +if ! grep -q 'Connected to' <<< $(printf 'quit' | telnet -4 gmail-smtp-in.l.google.com 25) +then + echo -e '\n\e[1;31mPort 25 needs to be open for mail server installation to continue, exiting...\e[0m\n' + exit +fi # fail2ban tee /etc/fail2ban/jail.d/sshd.conf >/dev/null <<'SSHD' @@ -159,6 +258,27 @@ do sudo fail2ban-client status $JAIL done ALL-JAILS +tee /etc/fail2ban/jail.d/postfix.local >/dev/null <<'POSTFIX-FLOOD-ATTACK' +[postfix-flood-attack] +enabled = true +bantime = 12h +filter = postfix-flood-attack +action = iptables-multiport[name=postfix, port="http,https,smtp,submission,pop3,pop3s,imap,imaps,sieve", protocol=tcp] +logpath = /var/log/mail.log + +[postfix] +enabled = true +maxretry = 3 +bantime = 12h +filter = postfix +logpath = /var/log/mail.log +POSTFIX-FLOOD-ATTACK +tee /etc/fail2ban/filter.d/postfix-flood-attack.conf >/dev/null <<'POSTFIX-FLOOD-ATTACK' +[Definition] +failregex = lost connection after AUTH from (.*)\[\] +ignoreregex = +POSTFIX-FLOOD-ATTACK +systemctl -q enable --now fail2ban # zram swap echo -e "ALGO=zstd\nPERCENT=60" >>/etc/default/zramswap @@ -167,8 +287,8 @@ echo -e "ALGO=zstd\nPERCENT=60" >>/etc/default/zramswap rm -f /etc/cron.weekly/fstrim &>/dev/null # Hostname and unix users -hostnamectl set-hostname ${domain} -sed -i '/127.0.0.1/ s/$/ '${domain}'/' /etc/hosts +hostnamectl set-hostname ${domain_url} +sed -i '/127.0.0.1/ s/$/ '${domain_url}'/' /etc/hosts adduser ${username} sudo &>/dev/null # SSH settings @@ -189,39 +309,771 @@ unset HISTFILE history -c EOF -if hostname | grep -q "${domain}" && grep -q "${domain}" /etc/hosts + if hostname | grep -q "${domain_url}" && grep -q "${domain_url}" /etc/hosts + then + +# Dovecot +cd ~ +mkdir -p /usr/share/dovecot /usr/share/webapps +touch /usr/share/dovecot/dh.pem + +# PHP +sed -i -e 's/^upload_max_filesize =.*/upload_max_filesize = 0/g' -e 's/^post_max_size =.*/post_max_size = 0/g' -e 's/^memory_limit =.*/memory_limit = 4096M/g' $(find /etc/php -name 'php.ini' | grep fpm) + +# Download Postfixadmin and Roundcube +mkdir -p /usr/share/webapps/{roundcube,postfixadmin} +wget -q4 https://github.com/postfixadmin/postfixadmin/archive/refs/tags/$(wget -q4O- https://api.github.com/repos/postfixadmin/postfixadmin/releases/latest | grep tag_name | awk '{print $2}' | tr -d '"|,').tar.gz -O postfixadmin.tar.gz || die +wget -q4 $(wget -q4O- https://api.github.com/repos/roundcube/roundcubemail/releases/latest | grep 'complete.tar.gz"$' | awk '{print $2}' | tr -d '"|,') -O roundcubemail.tar.gz || die +tar zxf roundcubemail.tar.gz -C /usr/share/webapps/roundcube --strip-components 1 +tar zxf postfixadmin.tar.gz -C /usr/share/webapps/postfixadmin --strip-components 1 +rm *.tar.gz + +# Postfixadmin +echo -e '\n\e[1;34mInstalling Postfixadmin\e[0m' +cd /usr/share/webapps/postfixadmin +# Postfixadmin composer +wget -q4O- https://raw.githubusercontent.com/postfixadmin/postfixadmin/master/install.sh | COMPOSER_ALLOW_SUPERUSER=1 bash - +setfacl -R -m u:www-data:rwx templates_c/ + +# Roundcube +echo -e '\e[1;34mInstalling Roundcube\e[0m' +# Roundcube composer +cd /usr/share/webapps/roundcube +COMPOSER_ALLOW_SUPERUSER=1 composer -n update --no-dev +COMPOSER_ALLOW_SUPERUSER=1 composer -n install --no-dev +chown www-data:www-data temp/ logs/ -R + +# Postwhite +cd /usr/local/bin +git clone --quiet https://github.com/spf-tools/spf-tools.git +git clone --quiet https://github.com/stevejenkins/postwhite.git +cp /usr/local/bin/postwhite/postwhite.conf /etc +cd + +# Install MariaDB +echo -e '\n\e[1;34mInstalling MariaDB\e[0m' +printf '%s\n' "" "n" "y" "${postfixadminpass}" "${postfixadminpass}" "" "" "" "" | mysql_secure_installation &>/dev/null + +# Roundcube database +mysql -u root </dev/null + +# Roundcube password plugin +cp /usr/share/webapps/roundcube/plugins/password/config.inc.php.dist /usr/share/webapps/roundcube/plugins/password/config.inc.php + +sed -i "/^\$config\['password_db_dsn'\]/ s|=.*|= 'mysql://postfixadmin:${postfixadmindbpass}@localhost/postfixadmin';|" /usr/share/webapps/roundcube/plugins/password/config.inc.php +sed -i "/^\$config\['password_query'\]/ s/=.*/= 'UPDATE mailbox SET password=%P,modified=NOW() WHERE username=%u';/" /usr/share/webapps/roundcube/plugins/password/config.inc.php +sed -i "/^\$config\['password_strength_driver'\]/ s/=.*/= '${roundcubepass_strength_drive}';\\ +\$config['password_"${roundcubepass_strength_drive}"_min_score'] = 5;/" /usr/share/webapps/roundcube/plugins/password/config.inc.php +sed -i "/^\$config\['password_algorithm'\]/ s/=.*/= 'dovecot';/" /usr/share/webapps/roundcube/plugins/password/config.inc.php +sed -i "/^\$config\['password_dovecotpw'\]/ s|=.*|= '/usr/bin/doveadm pw -r 5';|" /usr/share/webapps/roundcube/plugins/password/config.inc.php +sed -i "/^\$config\['password_dovecotpw_method'\]/ s/=.*/= 'ARGON2I';/" /usr/share/webapps/roundcube/plugins/password/config.inc.php +sed -i "/^\$config\['password_dovecotpw_with_method'\]/ s/=.*/= true;/" /usr/share/webapps/roundcube/plugins/password/config.inc.php + +rm /usr/share/webapps/roundcube/installer/ -r +chown www-data:www-data /usr/share/webapps/roundcube/plugins/password/config.inc.php +chmod 600 /usr/share/webapps/roundcube/plugins/password/config.inc.php + +# Postfixadmin config setup +# https://git.banananet.work/banananetwork/postfixadmin/raw/commit/864065cd37ef34b6dab915206eea4bd2ac4ebaed/config.inc.php +echo -e '\e[1;34mCreating mail users\e[0m' +echo -e ' '\''postmaster@'${domain}''\'', + '\''eff'\'' => '\''postmaster@'${domain}''\'', + '\''dmarc'\'' => '\''postmaster@'${domain}''\'', +); + +$CONF['\''password_validation'\''] = array( +# # '\''/regular expression/'\'' => '\''$PALANG key (optional: + parameter)'\'', +# '\''/.{5}/'\'' => '\''password_too_short 5'\'', # minimum length 5 characters +# '\''/([a-zA-Z].*){3}/'\'' => '\''password_no_characters 3'\'', # must contain at least 3 characters +# '\''/([0-9].*){2}/'\'' => '\''password_no_digits 2'\'', # must contain at least 2 digits +); + +$CONF['\''fetchmail'\''] = '\''NO'\''; +$CONF['\''show_footer_text'\''] = '\''NO'\''; + +$CONF['\''quota'\''] = '\''YES'\''; +$CONF['\''domain_quota'\''] = '\''YES'\''; +$CONF['\''quota_multiplier'\''] = '\''1024000'\''; +$CONF['\''used_quotas'\''] = '\''YES'\''; +$CONF['\''new_quota_table'\''] = '\''YES'\''; + +$CONF['\''aliases'\''] = '\''0'\''; +$CONF['\''mailboxes'\''] = '\''0'\''; +$CONF['\''maxquota'\''] = '\''0'\''; +$CONF['\''domain_quota_default'\''] = '\''0'\''; +$CONF['\''password_expiration'\''] = '\''NO'\''; + +# Postfixadmin hash +$CONF['\''setup_password'\''] = '\'$(php -r "echo password_hash('${postfixadminpass}', PASSWORD_DEFAULT);")\'';' | tee /usr/share/webapps/postfixadmin/config.local.php >/dev/null + +# Update Postfixadmin databases +# https://git.banananet.work/banananetwork/postfixadmin/raw/commit/864065cd37ef34b6dab915206eea4bd2ac4ebaed/config.inc.php +runuser -u www-data -- php /usr/share/webapps/postfixadmin/public/upgrade.php + +# Create Postfixadmin domain +bash /usr/share/webapps/postfixadmin/scripts/postfixadmin-cli domain add "${domain}" --aliases 0 --mailboxes 0 --maxquota 0 --quota 0 --active --default-aliases -q + +# Create Postfixadmin admin +bash /usr/share/webapps/postfixadmin/scripts/postfixadmin-cli admin add "postmaster@${domain}" --superadmin --active --domains "${domain}" --password "${postfixadminpass}" --password2 "${postfixadminpass}" -q + +# Create Postfixadmin mail users +bash /usr/share/webapps/postfixadmin/scripts/postfixadmin-cli mailbox add "postmaster@${domain}" --active --password "${postfixadminpass}" --password2 "${postfixadminpass}" -q +bash /usr/share/webapps/postfixadmin/scripts/postfixadmin-cli mailbox add "${mailuser}@${domain}" --active --password "${mailpass}" --password2 "${mailpass}" -q + +# Create Postfixadmin mail catch-all alias +bash /usr/share/webapps/postfixadmin/scripts/postfixadmin-cli alias add "*@${domain}" --goto "${mailuser}@${domain}" --active -q + +unset mailuser postfixadminpass postfixadminpass2 mailpass mailpass2 roundcubedbpass roundcubepass_strength_drive +echo + +# Autorestart services +mkdir -p /etc/systemd/system/{dovecot,postfix}.service.d +tee /etc/systemd/system/dovecot.service.d/restart.conf >/dev/null <<'RESTART' +[Service] +Restart=always +RestartSec=5s +RESTART +tee /etc/systemd/system/postfix.service.d/restart.conf >/dev/null <<'RESTART' +[Service] +Restart=on-failure +RestartSec=5s +RESTART +systemctl -q daemon-reload + +# Postfix +# postconf myhostname alias_maps alias_database myorigin mydestination relayhost mynetworks mailbox_size_limit recipient_delimiter inet_interfaces inet_protocols +# cat /etc/mailname +echo -e '\e[1;34mConfiguring Postfix\e[0m' +echo ${domain} | tee /etc/mailname >/dev/null +postconf -e "myhostname = ${subdomain}.${domain}" +postconf -e 'relay_domains = $mydestination' +postconf -e 'smtp_tls_security_level = may' +postconf -e 'smtp_tls_loglevel = 1' +postconf -e 'smtpd_tls_security_level = may' +postconf -e 'smtpd_tls_loglevel = 1' +postconf -e 'mailbox_size_limit = 0' +postconf -e 'message_size_limit = 0' +postconf -e "authorized_submit_users = root,www-data,${USER}" + +postconf -e 'smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache' +postconf -e 'smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache' + +postconf -e 'smtp_tls_note_starttls_offer = yes' +postconf -e 'smtpd_tls_received_header = yes' + +postconf -e 'inet_interfaces = all' +# postconf -e ' inet_interfaces = 127.0.0.1' +postconf -e 'inet_protocols = ipv4' +postconf -e 'smtp_address_preference = ipv4' +postconf -e "mydomain = ${domain}" +postconf -e 'myorigin = $mydomain' +postconf -e 'mydestination = $myhostname, localhost.$mydomain, localhost' + +if [ ${backup_mailserver} ] then - install /dev/stdin /usr/local/bin/mail-server </dev/null + +# master.cf +sed -i 's/smtp .*smtpd/# &/' /etc/postfix/master.cf +sed -i '/#smtp\|#smtpd\|#dnsblog\|#tlsproxy/ s/^#//' /etc/postfix/master.cf + +echo -e '\n# Enable submission +submission inet n - y - - smtpd + -o syslog_name=postfix/submission + -o smtpd_tls_security_level=encrypt + -o smtpd_tls_wrappermode=no + -o smtpd_sasl_auth_enable=yes + -o smtpd_relay_restrictions=permit_sasl_authenticated,reject + -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject + -o smtpd_sasl_type=dovecot + -o smtpd_sasl_path=private/auth + +# SPF Policy +policyd-spf unix - n n - 0 spawn + user=policyd-spf argv=/usr/bin/policyd-spf' | tee -a /etc/postfix/master.cf >/dev/null + +# Deleting Email Headers For Outgoing Emails +echo -e '/^X-Spam-Status:/ IGNORE +/^X-Spam-Checker-Version:/ IGNORE +/^Received:.*/ IGNORE +/^User-Agent:.*/ IGNORE' | tee /etc/postfix/smtp_header_checks >/dev/null + +# Header checks +echo "/free mortgage quote/ DISCARD +/repair your credit/ DISCARD +/lose weight/ DISCARD +/To:.*(gmail.com|yahoo.com|outlook|hotmail.com).*${mailuser}@${domain}/ DISCARD +/To:.*${mailuser}@${domain}.*(gmail.com|yahoo.com|outlook|hotmail.com)/ DISCARD +/Cc:.*(gmail.com|yahoo.com|outlook|hotmail.com).*${mailuser}@${domain}/ DISCARD +/Cc:.*${mailuser}@${domain}.*(gmail.com|yahoo.com|outlook|hotmail.com)/ DISCARD +/To:.*<>/ DISCARD +/From:.*<>/ DISCARD" | tee -a /etc/postfix/header_checks >/dev/null + +# Body checks +echo "/free mortgage quote/ DISCARD +/repair your credit/ DISCARD +/lose weight/ DISCARD" | tee -a /etc/postfix/body_checks >/dev/null + +echo -e "# Permit my own IP addresses +${ip_addr}/32\tpermit" | tee /etc/postfix/postscreen_access.cidr >/dev/null + +# Blocking Email Spam with Postfix +echo -e "${domain} OK" | tee /etc/postfix/{helo_access,rbl_override} >/dev/null + +# Virtual mailboxes +mkdir -p /etc/postfix/sql + +tee /etc/postfix/sql/mysql_virtual_domains_maps.cf >/dev/null </dev/null </dev/null </dev/null </dev/null </dev/null </dev/null +mkdir -p /var/vmail +chown vmail:vmail /var/vmail/ -R + +sed -i 's/#!include auth-sql.conf.ext/!include auth-sql.conf.ext/' /etc/dovecot/conf.d/10-auth.conf +sed -i 's/!include auth-system.conf.ext/#&/' /etc/dovecot/conf.d/10-auth.conf +echo -e '\nauth_debug = yes +auth_debug_passwords = yes' | tee -a /etc/dovecot/conf.d/10-auth.conf >/dev/null + +tee -a /etc/dovecot/dovecot-sql.conf.ext >/dev/null </dev/null + +sed -i 's|^mail_location =.*|mail_location = maildir:~/Maildir\ +'"$(if ! grep -q '^mail_home = /var/vmail/%d/%n/' /etc/dovecot/conf.d/10-mail.conf +then + echo 'mail_home = /var/vmail/%d/%n/' +fi)"'|g' /etc/dovecot/conf.d/10-mail.conf + +sed -i 's|unix_listener lmtp {|unix_listener /var/spool/postfix/private/dovecot-lmtp {\ + mode = 0600\ + user = postfix\ + group = postfix|' /etc/dovecot/conf.d/10-master.conf +sed -i 's|unix_listener auth-userdb {|unix_listener /var/spool/postfix/private/auth {\ + mode = 0660\ + user = postfix\ + group = postfix|' /etc/dovecot/conf.d/10-master.conf +sed -i '/#disable_plaintext_auth/ s/^#//' /etc/dovecot/conf.d/10-auth.conf +sed -i 's/#auth_username_format = %Lu/auth_username_format = %u/' /etc/dovecot/conf.d/10-auth.conf + +sed -i 's/#auth_default_realm.*/auth_default_realm = '${domain}'/' /etc/dovecot/conf.d/10-auth.conf + +sed -i 's/auth_mechanisms = plain/& login/' /etc/dovecot/conf.d/10-auth.conf +sed -i 's/ssl = yes/ssl = required/' /etc/dovecot/conf.d/10-ssl.conf +sed -i 's/#ssl_prefer_server_ciphers = no/ssl_prefer_server_ciphers = yes/' /etc/dovecot/conf.d/10-ssl.conf +sed -i 's/#ssl_min_protocol =.*/ssl_min_protocol = TLSv1.2/' /etc/dovecot/conf.d/10-ssl.conf +echo -e '\nservice stats { + unix_listener stats-reader { + user = www-data + group = www-data + mode = 0660 +} + +unix_listener stats-writer { + user = www-data + group = www-data + mode = 0660 + } +}' | tee -a /etc/dovecot/conf.d/10-master.conf >/dev/null +gpasswd -a www-data dovecot >/dev/null + +# Mailboxes +sed -i 's/namespace inbox {/&\ + # Archive folder\ + mailbox Archive {\ + special_use = \\Archive\ + }/' /etc/dovecot/conf.d/15-mailboxes.conf +sed -i '/Sent Messages/! s/^ mailbox.*{/&\ + auto = subscribe/' /etc/dovecot/conf.d/15-mailboxes.conf +adduser dovecot mail >/dev/null + +systemctl restart dovecot postfix + +# SPF and DKIM +echo -e '\e[1;34mConfiguring SPF and DKIM policies\e[0m' +gpasswd -a postfix opendkim >/dev/null + +grep -q '^Canonicalization.*relaxed/simple$' /etc/opendkim.conf || sed -i 's|.*Canonicalization.*|Canonicalization relaxed/simple|' /etc/opendkim.conf +sed -i '/^#Mode.*sv\|^#SubDomains.*no/ s/^#//' /etc/opendkim.conf +echo -e '\n# Map domains in "from" addresses to keys used to sign messages +KeyTable refile:/etc/opendkim/KeyTable +SigningTable refile:/etc/opendkim/SigningTable + +# Hosts to ignore when verifying signatures +ExternalIgnoreList /etc/opendkim/trusted.hosts + +# A set of internal hosts whose mail should be signed +InternalHosts /etc/opendkim/trusted.hosts' | tee -a /etc/opendkim.conf >/dev/null + +mkdir -p /etc/opendkim/keys +chown -R opendkim:opendkim /etc/opendkim +chmod go-rw /etc/opendkim/keys + +echo "*@${domain} default._domainkey.${domain}" | tee -a /etc/opendkim/SigningTable >/dev/null +echo "default._domainkey.${domain} ${domain}:default:/etc/opendkim/keys/${domain}/default.private" | tee -a /etc/opendkim/KeyTable >/dev/null +echo "127.0.0.1 +localhost + +*.${domain}" | tee -a /etc/opendkim/trusted.hosts >/dev/null + +mkdir -p /etc/opendkim/keys/${domain} +opendkim-genkey -b 2048 -d ${domain} -D /etc/opendkim/keys/${domain} -s default +chown opendkim:opendkim /etc/opendkim/keys/${domain}/default.private +chmod 600 /etc/opendkim/keys/${domain}/default.private + +mkdir -p /var/spool/postfix/opendkim +chown opendkim:postfix /var/spool/postfix/opendkim +sed -i '/^#Socket.*local:\/var\/spool\/postfix\/opendkim\/opendkim.sock/ s/^#//' /etc/opendkim.conf || sed -i 's\^Socket.*local:/run/opendkim/opendkim.sock\Socket local:/var/spool/postfix/opendkim/opendkim.sock\' /etc/opendkim.conf +sed -i 's\^SOCKET=local:$RUNDIR/opendkim.sock\SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"\' /etc/default/opendkim + +# DMARC +echo -e '\e[1;34mConfiguring DMARC\e[0m' +sed -i 's/# AuthservID name/AuthservID OpenDMARC/' /etc/opendmarc.conf +sed -i 's/# TrustedAuthservIDs HOSTNAME/TrustedAuthservIDs '${subdomain}'.'${domain}'/' /etc/opendmarc.conf +sed -i 's/# RejectFailures false/RejectFailures true\ +IgnoreAuthenticatedClients true\ +RequiredHeaders true\ +SPFSelfValidate true/' /etc/opendmarc.conf +sed -i 's|Socket local:/run/opendmarc/opendmarc.sock|Socket local:/var/spool/postfix/opendmarc/opendmarc.sock|' /etc/opendmarc.conf +mkdir -p /var/spool/postfix/opendmarc +chown opendmarc:opendmarc /var/spool/postfix/opendmarc -R +chmod 750 /var/spool/postfix/opendmarc/ -R +adduser postfix opendmarc >/dev/null +echo -e '\nIgnoreHosts /etc/opendmarc/ignore.hosts' | tee -a /etc/opendmarc.conf >/dev/null +mkdir -p /etc/opendmarc +echo '127.0.0.1' | tee -a /etc/opendmarc/ignore.hosts >/dev/null + +# OpenDKIM and OpenDMARC headers +echo -e '\nSoftwareHeader yes' | tee -a /etc/{opendkim,opendmarc}.conf >/dev/null + +systemctl -q restart opendkim postfix opendmarc + +# Roundcube/Nginx +echo -e '\e[1;34mConfiguring Nginx\e[0m' +tee $(find /etc/php/ -type d -name "pool.d")/zz-php-handler.conf >/dev/null </dev/null <<'PROXY' +proxy_set_header Host $http_host; +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +proxy_set_header X-Forwarded-Proto $scheme; +PROXY + +echo -e ' +upstream php-handler { + server unix:/run/php/php-fpm.sock; +} + +server { + server_name '${subdomain}'.'${domain}'; + + index index.php index.html; + + error_log /var/log/nginx/roundcube_error.log; + access_log /var/log/nginx/roundcube_access.log; + + root /usr/share/webapps/roundcube; + + # Postfixadmin + location ^~ /admin/ { + proxy_pass http://127.0.0.1:12000/; + include proxy_params; + } + + # Roundcube + location ~ \.php$ { + try_files $uri =404; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass php-handler; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + } +} + +server { + listen 12000; + root /usr/share/webapps/postfixadmin/public/; + index index.php index.html; + client_max_body_size 0; + + error_log /var/log/nginx/postfixadmin_error.log; + access_log /var/log/nginx/postfixadmin_access.log; + + location / { + try_files $uri $uri/ /index.php; + } + + location ~ ^/(.+\.php)$ { + try_files $uri =404; + fastcgi_pass php-handler; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include /etc/nginx/fastcgi_params; + } +}' | tee /etc/nginx/sites-available/mail.conf >/dev/null +ln -s /etc/nginx/sites-available/mail.conf /etc/nginx/sites-enabled/ + +# Certbot +systemctl -q disable --now apache2.service +systemctl -q reload nginx.service +/etc/init.d/php*-fpm reload + +until certbot --nginx --agree-tos --redirect --hsts --no-eff-email --staple-ocsp -m ${eff_email} -d ${subdomain}.${domain} +do + sleep 10 +done +setfacl -R -m u:www-data:rx /etc/letsencrypt/live/ /etc/letsencrypt/archive/ + +# Postfix +postconf -e "smtpd_tls_key_file = /etc/letsencrypt/live/${subdomain}.${domain}/privkey.pem" +postconf -e "smtpd_tls_cert_file = /etc/letsencrypt/live/${subdomain}.${domain}/fullchain.pem" + +# Dovecot +# sed -i 's|ssl_cert = /dev/null +chmod 600 /etc/dovecot/ssl-keys.conf +echo -e '!include_try ssl-keys.conf' | tee -a /etc/dovecot/dovecot.conf >/dev/null + +# Cron tasks +echo '#!/bin/sh +certbot renew --quiet && systemctl -q reload postfix dovecot nginx +/usr/local/bin/postwhite/postwhite &>/dev/null # Update Postscreen Whitelists' | install /dev/stdin /etc/cron.daily/mailserver +echo '#!/bin/sh +/usr/local/bin/postwhite/scrape_yahoo &>/dev/null # Update Yahoo! IPs for Postscreen Whitelists' | install /dev/stdin /etc/cron.weekly/mailserver +ln -s /usr/share/webapps/roundcube/bin/cleandb.sh /etc/cron.daily/roundcube-cleandb + +# Run postwhite installer +echo -e '\n\e[1;34mInstalling Postwhite\e[0m' +/usr/local/bin/postwhite/postwhite + +# echo -e '\n\e[1;34mRestarting system services...\e[0m' +# /etc/init.d/php*-fpm restart +# systemctl -q restart postfix.service dovecot.service opendkim.service opendmarc.service nginx.service mariadb.service fail2ban.service + +# # Check DKIM key +# while : +# do +# if opendkim-testkey -d ${domain} -s default +# then +# echo -e '\n\e[1;32mDKIM key has been verified!\e[0m' +# break +# fi +# sleep 5 +# done & +# disown + +su ${username} <<"CHANGEUSER" + # SSH + yes | ssh-keygen -t ed25519 -q -f ~/.ssh/id_ed25519 -P "" + echo "${sshkeys}" >~/.ssh/authorized_keys + # Home directory mods + echo -e '\nif [ -f ~/.bash_history ] +then + rm -f ~/.bash_history +fi + +unset HISTFILE +history -c + +# Mail logs +function mail-watch +{ + tail -f /var/log/mail.log +} + +function mail-log +{ + cat /var/log/mail.log +} + +function mail-troubleshoot +{ + systemctl status postfix.service dovecot.service opendkim.service opendmarc.service nginx.service mariadb.service + /etc/init.d/php*-fpm status +} + +function mail-reboot +{ + systemctl -q restart postfix.service dovecot.service opendkim.service opendmarc.service nginx.service mariadb.service + /etc/init.d/php*-fpm restart +} + +function mail-check +{ + if systemctl list-units --state failed | grep -q 'postfix\|dovecot\|opendkim\|opendmarc\|nginx\|mariadb\|php.*-fpm' + then + echo -e '\nErrors found...\n' + systemctl list-units --state failed + else + echo -e '\nAll good!\n' + fi +} + +function mail-test +{ + systemctl stop postfix dovecot + read -n 1 -s -p $'\nPress any key to continue...\n' + systemctl start postfix dovecot && + mail-watch +} + +# SSH pubkey access +function ssh-on +{ + sed -i 's/^PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config.d/10-personal-sshd.conf + systemctl -q restart sshd +} + +function ssh-off +{ + sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config.d/10-personal-sshd.conf + systemctl -q restart sshd +}' >> ~/.bashrc + +install /dev/stdin ~/dhparam >/dev/null <<'dhparam' #!/usr/bin/env bash +echo -# Backup mailservers -backup_mailserver=(${backup_mailserver}) -MAILSERVER + # Create certificates +echo -e '\e[1;34mGenerating DH parameters with openssl\e[0m' +echo -e '\e[3m# a notification will pop up once completed\e[0m' - wget -q4O- https://git.myvelabs.com/lab/linux/raw/branch/master/mail-user.sh >>/usr/local/bin/mail-server +openssl dhparam -out /usr/share/dovecot/dh.pem 4096 && +echo -e '\n\n\e[1;32mOpenssl certificates have successfully been generated!\e[0m' - su ${username} <<"CHANGEUSER" - # SSH - yes | ssh-keygen -t ed25519 -q -f ~/.ssh/id_ed25519 -P "" - echo "${sshkeys}" >~/.ssh/authorized_keys +rm ${0} +dhparam CHANGEUSER - - echo -e '\n\e[1m\t## Run "mail-server" immediately\n\e[0m' - su ${username} - clear + # In your DNS manager, create a TXT record, enter default._domainkey in the name field + echo -e '\e[1;34mUpdate DKIM TXT on DNS registrar and press any key to continue\e[5m...\e[0m' + echo -e '\e[3m# Use default._domainkey in the host field' + echo -e '# Visit https://www.dmarcanalyzer.com/dkim/dkim-checker/ to check manually\e[0m' + cat /etc/opendkim/keys/${domain}/default.txt | sed 's/.*( //' | sed 's/ ).*//' | sed 's/"//g' | sed 's/^[ \t]*//g' | sed ':a;N;$!ba;s/\n//g' + cat <