#!/bin/bash # Run as root: # sudo ./install.sh [maildomain.com] INSTALLDIR=`pwd` if [[ $EUID -ne 0 ]]; then echo "This script must be run as root" 1>&2 exit 1 fi HOSTNAME="$1" WILDDUCK_COMMIT="6b9c2dbabb09d18335217e26635a6cb46a79754d" ZONEMTA_COMMIT="560094b82300e3aa550a0029e9b41ce61ea66367" WEBMAIL_COMMIT="be67abbad78c0f912394e0aaaf699629477e3985" if [[ $EUID -ne 0 ]]; then echo "This script must be run as root" 1>&2 exit 1 fi # stop on first error set -e export DEBIAN_FRONTEND=noninteractive useradd wildduck # mongo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6 echo "deb [ arch=amd64,arm64 ] http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list # node curl -sL https://deb.nodesource.com/setup_8.x | bash - apt-get update apt-get -q -y install mongodb-org pwgen nodejs git ufw build-essential libssl-dev dnsutils python software-properties-common nginx lsb-release wget systemctl enable mongod.service # redis apt-add-repository -y ppa:chris-lea/redis-server # rspamd CODENAME=`lsb_release -c -s` wget -O- https://rspamd.com/apt-stable/gpg.key | apt-key add - echo "deb http://rspamd.com/apt-stable/ $CODENAME main" > /etc/apt/sources.list.d/rspamd.list echo "deb-src http://rspamd.com/apt-stable/ $CODENAME main" >> /etc/apt/sources.list.d/rspamd.list apt-get update apt-get -q -y install redis-server clamav clamav-daemon apt-get -q -y --no-install-recommends install rspamd apt-get clean if [ -z "$HOSTNAME" ] then PUBLIC_IP=`curl -s https://api.ipify.org` if [ ! -z "$PUBLIC_IP" ]; then HOSTNAME=`dig +short -x $PUBLIC_IP | sed 's/\.$//'` HOSTNAME="${HOSTNAME:-$PUBLIC_IP}" fi HOSTNAME="${HOSTNAME:-`hostname`}" fi node -v redis-server -v mongod --version echo "HOSTNAME: $HOSTNAME" ####### WILD DUCK ####### cd /var/opt git clone --bare git://github.com/nodemailer/wildduck.git mkdir /opt/wildduck git --git-dir=/var/opt/wildduck.git --work-tree=/opt/wildduck checkout "$WILDDUCK_COMMIT" cp -r /opt/wildduck/config /etc/wildduck mv /etc/wildduck/default.toml /etc/wildduck/wildduck.toml sed -i -e "s/999/99/g;s/localhost/$HOSTNAME/g" /etc/wildduck/imap.toml sed -i -e "s/999/99/g;s/localhost/$HOSTNAME/g" /etc/wildduck/pop3.toml echo "enabled=true port=24 disableSTARTTLS=true" > /etc/wildduck/lmtp.toml echo "user=\"wildduck\" group=\"wildduck\" emailDomain=\"$HOSTNAME\"" | cat - /etc/wildduck/wildduck.toml > temp && mv temp /etc/wildduck/wildduck.toml echo '[[spamHeader]] key="X-Rspamd-Bar" value="^\\+{6}" target="\\Junk"' >> /etc/wildduck/spamheaders.toml sed -i -e "s/localhost:3000/$HOSTNAME/g;s/localhost/$HOSTNAME/g;s/2587/587/g" /etc/wildduck/wildduck.toml cd /opt/wildduck sudo npm install --production chown -R wildduck:wildduck /var/opt/wildduck.git chown -R wildduck:wildduck /opt/wildduck echo '[Unit] Description=Wild Duck Mail Server Conflicts=cyrus.service dovecot.service After=mongod.service redis.service [Service] Environment="NODE_ENV=production" WorkingDirectory=/opt/wildduck ExecStart=/usr/bin/node server.js --config="/etc/wildduck/wildduck.toml" ExecReload=/bin/kill -HUP $MAINPID Type=simple Restart=always [Install] WantedBy=multi-user.target' > /etc/systemd/system/wildduck.service systemctl enable wildduck.service ####### HARAKA ####### cd sudo npm install --unsafe-perm -g Haraka haraka -i /opt/haraka cd /opt/haraka sudo npm install --save haraka-plugin-wildduck haraka-plugin-rspamd Haraka mv config/plugins config/pluginbs.bak echo "26214400" > config/databytes echo "$HOSTNAME" > config/me echo "spf ## ClamAV is disabled by default. Make sure freshclam has updated all ## virus definitions and clamav-daemon has successfully started before ## enabling it. #clamd rspamd tls dkim_verify queue/lmtp wildduck" > config/plugins echo "key=/etc/wildduck/certs/privkey.pem cert=/etc/wildduck/certs/fullchain.pem" > config/tls.ini echo "host=127.0.0.1 port=24" > config/lmtp.ini echo 'host = localhost port = 11333 add_headers = always [dkim] enabled = true [header] bar = X-Rspamd-Bar report = X-Rspamd-Report score = X-Rspamd-Score spam = X-Rspamd-Spam [check] authenticated=true private_ip=true [reject] spam = false [soft_reject] enabled = true [rmilter_headers] enabled = true [spambar] positive = + negative = - neutral = /' > config/rspamd.ini echo 'clamd_socket = /var/run/clamav/clamd.ctl [reject] virus=true error=false' > config/clamd.ini echo '--- accounts: maxStorage: 1024 redis: "redis://127.0.0.1:6379/3" mongo: url: "mongodb://127.0.0.1:27017/wildduck" srs: secret: "supersecret" attachments: type: "gridstore" bucket: "attachments" decodeBase64: true log: authlogExpireDays: 30' > config/wildduck.yaml echo '[Unit] Description=Haraka MX Server After=mongod.service redis.service [Service] Environment="NODE_ENV=production" WorkingDirectory=/opt/haraka ExecStart=/usr/bin/node ./node_modules/.bin/haraka -c . Type=simple Restart=always [Install] WantedBy=multi-user.target' > /etc/systemd/system/haraka.service echo 'user=wildduck group=wildduck' >> config/smtp.ini chown -R wildduck:wildduck /opt/haraka systemctl enable haraka.service #### ZoneMTA #### cd /var/opt git clone --bare git://github.com/zone-eu/zone-mta-template.git zone-mta.git mkdir /opt/zone-mta git --git-dir=/var/opt/zone-mta.git --work-tree=/opt/zone-mta checkout "$ZONEMTA_COMMIT" cp -r /opt/zone-mta/config /etc/zone-mta sed -i -e 's/port=2525/port=587/g;s/host="127.0.0.1"/host="0.0.0.0"/g;s/authentication=false/authentication=true/g' /etc/zone-mta/interfaces/feeder.toml echo '# @include "../wildduck/dbs.toml"' > /etc/zone-mta/dbs-production.toml echo 'user="wildduck" group="wildduck"' | cat - /etc/zone-mta/zonemta.toml > temp && mv temp /etc/zone-mta/zonemta.toml echo "[[default]] address=\"0.0.0.0\" name=\"$HOSTNAME\"" > /etc/zone-mta/pools.toml echo "[\"modules/zonemta-wildduck\"] enabled=[\"receiver\", \"sender\"] # which interfaces this plugin applies to interfaces=[\"feeder\"] # optional hostname to be used in headers # defaults to os.hostname() hostname=\"$HOSTNAME\" # How long to keep auth records in log authlogExpireDays=30 # SRS settings for forwarded emails # Handle rewriting of forwarded emails forwardedSRS=true # SRS secret value. Must be the same as in the MX side secret=\"secret value\" # SRS domain, must resolve back to MX rewriteDomain=\"$HOSTNAME\" # Delivery settings for local messages # do not set these values if you do not want to use local delivery # Use LMTP instead of SMTP localLmtp=true localMxPort=24 # SMTP/LMTP server for local delivery [[\"modules/zonemta-wildduck\".localMx]] priority=0 # hostname is for logging only, IP is actually used exchange=\"$HOSTNAME\" A=[\"127.0.0.1\"] AAAA=[] # Interface to be used for local delivery # Make sure that it can connect to the localMX IP [\"modules/zonemta-wildduck\".localZoneAddress] address=\"127.0.0.1\" name=\"$HOSTNAME\"" > /etc/zone-mta/plugins/wildduck.toml sed -i -e "s/test/wildduck/g;s/example.com/$HOSTNAME/g;s/signTransportDomain=true/signTransportDomain=false/g;" /etc/zone-mta/plugins/dkim.toml cd /opt/zone-mta/keys openssl genrsa -out "$HOSTNAME-dkim.pem" 2048 chmod 400 "$HOSTNAME-dkim.pem" openssl rsa -in "$HOSTNAME-dkim.pem" -out "$HOSTNAME-dkim.cert" -pubout DNS_ADDRESS="v=DKIM1;p=$(grep -v -e '^-' $HOSTNAME-dkim.cert | tr -d "\n")" cd /opt/zone-mta sudo npm install zonemta-wildduck --save sudo npm install --production chown -R wildduck:wildduck /var/opt/zone-mta.git chown -R wildduck:wildduck /opt/zone-mta echo '[Unit] Description=Zone Mail Transport Agent Conflicts=sendmail.service exim.service postfix.service After=mongod.service redis.service [Service] Environment="NODE_ENV=production" WorkingDirectory=/opt/zone-mta ExecStart=/usr/bin/node index.js --config="/etc/zone-mta/zonemta.toml" ExecReload=/bin/kill -HUP $MAINPID Type=simple Restart=always [Install] WantedBy=multi-user.target' > /etc/systemd/system/zone-mta.service systemctl enable zone-mta.service #### WWW #### cd /var/opt git clone --bare git://github.com/nodemailer/wildduck-webmail.git mkdir /opt/wildduck-webmail git --git-dir=/var/opt/wildduck-webmail.git --work-tree=/opt/wildduck-webmail checkout "$WEBMAIL_COMMIT" cp /opt/wildduck-webmail/config/default.toml /etc/wildduck/wildduck-webmail.toml sed -i -e "s/localhost/$HOSTNAME/g;s/999/99/g;s/2587/587/g" /etc/wildduck/wildduck-webmail.toml cd /opt/wildduck-webmail sudo npm install --production chown -R wildduck:wildduck /var/opt/wildduck-webmail.git chown -R wildduck:wildduck /opt/wildduck-webmail echo '[Unit] Description=Wildduck Webmail After=wildduck.service [Service] Environment="NODE_ENV=production" WorkingDirectory=/opt/wildduck-webmail ExecStart=/usr/bin/node server.js --config="/etc/wildduck/wildduck-webmail.toml" ExecReload=/bin/kill -HUP $MAINPID Type=simple Restart=always [Install] WantedBy=multi-user.target' > /etc/systemd/system/wildduck-webmail.service systemctl enable wildduck-webmail.service #### NGINX #### # Create initial certs. These will be overwritten later by Let's Encrypt certs mkdir /etc/wildduck/certs cd /etc/wildduck/certs openssl req -subj "/CN=$HOSTNAME/O=My Company Name LTD./C=US" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout privkey.pem -out fullchain.pem chown -R wildduck:wildduck /etc/wildduck/certs chmod 0700 /etc/wildduck/certs/privkey.pem # Setup domain without SSL at first, otherwise acme.sh will fail echo "server { listen 80; server_name $HOSTNAME; ssl_certificate /etc/wildduck/certs/fullchain.pem; ssl_certificate_key /etc/wildduck/certs/privkey.pem; location / { proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header HOST \$http_host; proxy_set_header X-NginX-Proxy true; proxy_pass http://127.0.0.1:3000; proxy_redirect off; } }" > "/etc/nginx/sites-available/$HOSTNAME" ln -s "/etc/nginx/sites-available/$HOSTNAME" "/etc/nginx/sites-enabled/$HOSTNAME" systemctl reload nginx #### UFW #### ufw allow 22/tcp ufw allow 80/tcp ufw allow 443/tcp ufw allow 25/tcp ufw allow 587/tcp ufw allow 993/tcp ufw --force enable #### SSL CERTS #### curl https://get.acme.sh | sh echo 'cert="/etc/wildduck/certs/fullchain.pem" key="/etc/wildduck/certs/privkey.pem"' > /etc/wildduck/tls.toml sed -i -e "s/key=/#key=/g;s/cert=/#cert=/g" /etc/zone-mta/interfaces/feeder.toml echo '# @include "../../wildduck/tls.toml"' >> /etc/zone-mta/interfaces/feeder.toml # vanity script as first run should not restart anything echo '#!/bin/bash echo "OK"' > /usr/local/bin/reload-services.sh chmod +x /usr/local/bin/reload-services.sh /root/.acme.sh/acme.sh --issue --nginx \ -d "$HOSTNAME" \ --key-file /etc/wildduck/certs/privkey.pem \ --fullchain-file /etc/wildduck/certs/fullchain.pem \ --reloadcmd "/usr/local/bin/reload-services.sh" \ --force || echo "Warning: Failed to generate certificates, using self-signed certs" # Update site config, make sure ssl is enabled echo "server { listen 80; server_name $HOSTNAME; return 301 https://\$server_name\$request_uri; } server { listen 443 ssl http2; server_name $HOSTNAME; ssl_certificate /etc/wildduck/certs/fullchain.pem; ssl_certificate_key /etc/wildduck/certs/privkey.pem; location / { proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header HOST \$http_host; proxy_set_header X-NginX-Proxy true; proxy_pass http://127.0.0.1:3000; proxy_redirect off; } }" > "/etc/nginx/sites-available/$HOSTNAME" systemctl reload nginx # update reload script for future updates echo '#!/bin/bash /bin/systemctl reload nginx /bin/systemctl reload wildduck /bin/systemctl restart zone-mta /bin/systemctl restart haraka /bin/systemctl restart wildduck-webmail' > /usr/local/bin/reload-services.sh chmod +x /usr/local/bin/reload-services.sh ### start services #### systemctl start mongod systemctl start wildduck systemctl start haraka systemctl start zone-mta systemctl start wildduck-webmail systemctl reload nginx cd "$INSTALLDIR" echo "NAMESERVER SETUP ================ MX -- Add this MX record to the $HOSTNAME DNS zone: $HOSTNAME. IN MX 5 $HOSTNAME. SPF --- Add this TXT record to the $HOSTNAME DNS zone: $HOSTNAME. IN TXT \"v=spf1 a ~all\" DKIM ---- Add this TXT record to the $HOSTNAME DNS zone: wildduck._domainkey.$HOSTNAME. IN TXT \"$DNS_ADDRESS\" PTR --- Make sure that your public IP has a PTR record set to $HOSTNAME. If your hosting provider does not allow you to set PTR records but has assigned their own hostname, then edit /etc/zone-mta/pools.toml and replace the hostname $HOSTNAME with the actual hostname of this server. (this text is also stored to $INSTALLDIR/$HOSTNAME-nameserver.txt)" > "$INSTALLDIR/$HOSTNAME-nameserver.txt" echo "" cat "$INSTALLDIR/$HOSTNAME-nameserver.txt" echo "" echo "All done, open https://$HOSTNAME/ in your browser"