First commit

This commit is contained in:
Myve 2024-12-19 20:27:46 +00:00
commit cd1be5abe2
6 changed files with 423 additions and 0 deletions

181
01-setup.sh Executable file
View file

@ -0,0 +1,181 @@
#!/usr/bin/env bash
# Fill in the following variables
domain= #www.google.com
mailver= #latest/stable
# Exit on any error
set -e
# Check for subdomain
if [ $(echo ${domain} | awk -F . '{print $3}') ]
then
_subdomain=$(echo ${domain} | awk -F . '{print $1}')
_domain="$(echo ${domain} | awk -F . '{print $2}').$(echo ${domain} | awk -F . '{print $3}')"
else
echo "Invalid \${domain} variable, exiting"
exit 1
fi
# Variable check
if [ -z ${domain} ]
then
echo "Missing variable, exiting..."
exit 1
fi
# Certbot
sudo certbot certonly --nginx --non-interactive --agree-tos --no-eff-email \
--staple-ocsp --hsts --no-redirect --renew-hook 'docker exec myvemailbackup postfix reload' \
-m eff@${_domain} -d ${domain}
# Log
[ -d ./data/log/ ] || install --directory ./data/log/
echo | tee ./data/log/{mail,downtime}
# SSL
[ -d ./data/ssl/ ] || install --directory ./data/ssl/
sudo ln -s -f /etc/letsencrypt/live/${domain}/fullchain.pem ./data/ssl/tls.pem
sudo ln -s -f /etc/letsencrypt/live/${domain}/privkey.pem ./data/ssl/tls.key
# Environment file
[ -f ./.env ] || \
cat >./.env <<- gen-env
# Required
# Mail domain
MYVEMAIL_SUBDOMAIN=${_subdomain}
MYVEMAIL_DOMAIN=${_domain}
# Webmail port
MYVEMAIL_PORT=${proxyport}
# Optional
# Version: latest or stable (defaults to latest)
MYVEMAIL_VERSION=${mailver}
# Additional mail domains separated by commas
MYVEMAIL_ADDMX=${_domain}
# Backup mail servers separated by commas
MYVEMAIL_PRIMARYMX=
# Volumes
MYVEMAIL_VOLUME_SSL=
MYVEMAIL_VOLUME_LOG=
gen-env
# Cleanup
rm -r ${0} ./build/ ./README.md -f
# Create a downtime log
echo >./data/log/downtime
# Add postqueue check systemd service
sudo tee /etc/systemd/system/postqueue-check.service >/dev/null <<'POSTQ-SERVICE'
[Unit]
Description=Check postfix mail queue
[Service]
ExecStart=docker exec myvemailbackup postqueue-check
Type=oneshot
[Install]
WantedBy=basic.target
POSTQ-SERVICE
sudo tee /etc/systemd/system/postqueue-check.timer >/dev/null <<'POSTQ-TIMER'
[Unit]
Description=Run postqueue-check every 5 seconds
[Timer]
OnCalendar=*:*:0/5
Persistent=true
[Install]
WantedBy=timers.target
POSTQ-TIMER
sudo systemctl enable --now postqueue-check.timer
# Log downtimes
sudo install /dev/stdin /usr/local/bin/downtime-check >/dev/null <<MAILSERVER
#!/usr/bin/env bash
if ping -q -c 1 -W 15 1.1.1.1 >/dev/null && ping -q -c 1 -W 15 google.com >/dev/null
then
if [[ \$(ssh ${domain} docker container inspect -f '{{.State.Running}}' myvemail) == true ]]
then
exit 0
else
echo "${domain} was inaccessible on \$(date)" >>$(pwd)/data/log/downtime
exit 1
fi
else
exit 1
fi
MAILSERVER
sudo tee /etc/systemd/system/downtime-check.service >/dev/null <<'MAILSERVER-SERVICE'
[Unit]
Description=Log downtimes
[Service]
ExecStart=/usr/local/bin/downtime-check
Type=oneshot
[Install]
WantedBy=basic.target
MAILSERVER-SERVICE
sudo tee /etc/systemd/system/downtime-check.timer >/dev/null <<'MAILSERVER-TIMER'
[Unit]
Description=Run primary mail server check every minute
[Timer]
OnCalendar=*:0/1
Persistent=true
[Install]
WantedBy=timers.target
MAILSERVER-TIMER
sudo tee /etc/systemd/system/downtime-send.service >/dev/null <<'POSTQ-SERVICE'
[Unit]
Description=Send downtime log
[Service]
ExecStart=docker exec myvemailbackup downtime-send
Type=oneshot
[Install]
WantedBy=basic.target
POSTQ-SERVICE
sudo tee /etc/systemd/system/downtime-send.timer >/dev/null <<'POSTQ-TIMER'
[Unit]
Description=Send downtime log monthly
[Timer]
OnCalendar=monthly
AccuracySec=1h
Persistent=true
[Install]
WantedBy=timers.target
POSTQ-TIMER
sudo systemctl enable --now downtime-check.timer downtime-send.timer
# fail2ban postfix
sudo 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 = $(pwd)/data/log/mail
[postfix]
enabled = true
maxretry = 3
bantime = 12h
filter = postfix
logpath = $(pwd)/data/log/mail
POSTFIX-FLOOD-ATTACK
sudo tee /etc/fail2ban/filter.d/postfix-flood-attack.conf >/dev/null <<'POSTFIX-FLOOD-ATTACK'
[Definition]
failregex = lost connection after AUTH from (.*)\[<HOST>\]
ignoreregex =
POSTFIX-FLOOD-ATTACK

43
README.md Normal file
View file

@ -0,0 +1,43 @@
# MyveMail Backup
All-in-one docker container to host your own personal backup mail server, powered by Postfix mail transfer agent. If your primary mail server goes down, emails will be temporarily sent to this backup server, which then returns these emails to the primary as soon as it comes back online.
*Note: ISP must have SMTP Port 25 open.*
## :: Pre-installation
Update your DNS registry to reflect the following records
```
# MX Record
@ 300 IN MX 10 ${subdomain}.${domain}.
# A Record
${subdomain} 300 IN A ${server-ip-address}
```
Example entries:
```
server-ip-address= # Host IPv4 address
subdomain=mail
domain=website.com
```
## :: Installation
Clone this repo and build it locally or pull it on the registry specified in docker-compose.yaml:
```
git clone https://git.myvelabs.com/docker/myvemailbackup.git
```
Supply the variables asked for in 01-setup.sh.
Run **01-setup.sh** to install the Letsencrypt certificates to be used by Postfix. It also generates a functional docker-compose env file.
*Note: The container will fail if this step is skipped.*
Once completed, the container may be brought up:
```
docker compose up --detach
```
## :: Post-installation
Add the backup server's IP address to the primary mail server's Postfix **mynetworks** configuration to properly receive the bounced emails.

28
build/Dockerfile Normal file
View file

@ -0,0 +1,28 @@
# syntax = docker/dockerfile:1
FROM alpine:edge
# LABEL about the custom image
LABEL description="MyveMail Backup"
# Copy required files folders
ADD run/docker-entrypoint /docker-entrypoint/
ADD run/installer.sh /tmp/
# Update Ubuntu Software repository and install requisites
RUN printf '%s\n' 'https://dl-cdn.alpinelinux.org/alpine/latest-stable/main/' \
'https://dl-cdn.alpinelinux.org/alpine/latest-stable/community/' >/etc/apk/repositories \
&& apk update \
&& apk upgrade \
&& apk add --no-cache \
bash bash-completion ncurses \
ca-certificates openssl \
postfix \
# Installer
&& /tmp/installer.sh \
&& rm /tmp/installer.sh
# Expose ports
EXPOSE 25
# Entrypoint hd-wallet-derive script
CMD ["/docker-entrypoint/entrypoint.sh"]

View file

@ -0,0 +1,75 @@
#!/usr/bin/env bash
# Abort if an error is encountered
set -e
# Exit function
trap '[ "${?}" -ne 77 ] || exit 77' ERR
function die
{
local reset="\e[0m"
local red="\e[0m\e[0;31m"
local yellow="\e[0m\e[0;33m"
echo -e "${red}
Error encountered in the following init script:
${yellow}
${@}
${red}
Aborting...
${reset}"
exit 77
}
# Reset
echo | tee /var/log/maillog /etc/postfix/{relaydomains,transportmaps,helo_access,rbl_override}
# Postfix
echo ${MYVEMAIL_DOMAIN} >/etc/mailname
postconf -e "myhostname = ${MYVEMAIL_SUBDOMAIN}.${MYVEMAIL_DOMAIN}"
postconf -e "mydestination = \$myhostname, ${MYVEMAIL_SUBDOMAIN}.${MYVEMAIL_DOMAIN}, localhost, localhost.localdomain, localhost"
postconf -e "mydomain = ${MYVEMAIL_DOMAIN}"
# resolv.conf
[ -d /var/spool/postfix/etc/ ] || mkdir /var/spool/postfix/etc/
cp /etc/resolv.conf /var/spool/postfix/etc/resolv.conf
# Add primary mail servers to mynetworks
if [ ${MYVEMAIL_PRIMARYMX} ]
then
primarymx+=(${MYVEMAIL_PRIMARYMX//,/ })
postconf -e "$(postconf mynetworks)$(printf ' %s/32' ${primarymx[@]})"
fi
# Relay setup
addmx=(${MYVEMAIL_DOMAIN})
addmx+=(${MYVEMAIL_ADDMX//,/ })
printf '%s OK\n' ${addmx[@]} >/etc/postfix/relaydomains
for domain in ${addmx[@]}
do
echo "${domain} smtp:mail.${domain}:25" | tee -a /etc/postfix/transportmaps >/dev/null
echo "${domain} OK" | tee -a /etc/postfix/{helo_access,rbl_override} >/dev/null
done
# Start postfix
postfix start
postmap /etc/postfix/relaydomains /etc/postfix/transportmaps /etc/postfix/helo_access /etc/postfix/rbl_override
postfix reload
# Downtime log
install /dev/stdin /usr/local/bin/downtime <<- downtime
#!/usr/bin/env bash
# Send downtime log to downtime email address
echo "From: ${MYVEMAIL_SUBDOMAIN}@${MYVEMAIL_DOMAIN}
To: downtime@${MYVEMAIL_DOMAIN}
Subject: Monthly downtime log
\$(cat /var/log/downtime)" | sendmail downtime@${MYVEMAIL_DOMAIN}
# Delete log to start anew
echo >/var/log/downtime
downtime
# Monitor log
echo -e "\n\e[1;32mMail service is ready\e[0m\n"
tail -f /var/log/maillog

62
build/run/installer.sh Executable file
View file

@ -0,0 +1,62 @@
#!/usr/bin/env bash
###############
#//
#// Postfix
#//
###############
# Postfix
postconf -e 'myorigin = $mydomain'
postconf -e 'inet_interfaces = all'
postconf -e 'inet_protocols = ipv4'
postconf -e 'smtp_address_preference = ipv4'
postconf -e 'message_size_limit = 0'
postconf -e 'mailbox_size_limit = 0'
# Touch aliases db
newaliases
# Logging
postconf -e "maillog_file = /var/log/maillog"
# Backup mail server specific settings
postconf -e 'maximal_queue_lifetime = 30d'
postconf -e 'minimal_backoff_time = 60s'
postconf -e 'relay_recipient_maps = '
postconf -e "relay_domains = lmdb:/etc/postfix/relaydomains"
postconf -e "transport_maps = lmdb:/etc/postfix/transportmaps"
# Security
postconf -e 'smtpd_tls_security_level = may'
postconf -e 'smtp_tls_security_level = may'
postconf -e 'smtpd_tls_loglevel = 1'
postconf -e 'smtp_tls_verify_cert_match = hostname, nexthop, dot-nexthop'
postconf -e 'smtp_tls_CApath = /etc/ssl/certs'
postconf -e "smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt"
postconf -e 'smtp_tls_loglevel = 1'
openssl rehash /etc/ssl/certs || c_rehash /etc/ssl/certs
[ -d /etc/postfix/ssl/ ] || mkdir -p /etc/postfix/ssl/
postconf -e "smtpd_tls_key_file = /etc/postfix/ssl/tls.key"
postconf -e "smtpd_tls_cert_file = /etc/postfix/ssl/tls.pem"
# # Enforce TLSv1.2 or TLSv1.2
postconf -e "smtpd_tls_protocols = >=TLSv1.2"
# Spam filters (https://www.linuxbabe.com/mail-server/block-email-spam-postfix)
postconf -e "smtpd_sender_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unknown_sender_domain, reject_unknown_reverse_client_hostname, reject_unknown_client_hostname"
postconf -e "smtpd_helo_required = yes"
postconf -e "smtpd_helo_restrictions = permit_mynetworks, permit_sasl_authenticated, check_helo_access lmdb:/etc/postfix/helo_access, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname, reject_unknown_helo_hostname"
postconf -e "smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination"
# Check postqueue every 5 seconds
install /dev/stdin /usr/local/bin/postqueue-check >/dev/null <<'postqueue'
#!/usr/bin/env bash
if postqueue -p | grep -q 'Mail queue is empty'
then
exit 0
else
postqueue -f
fi
postqueue

34
docker-compose.yaml Normal file
View file

@ -0,0 +1,34 @@
services:
myvemailbackup:
image: hub.myvelabs.com/lab/myvemailbackup:${MYVEMAIL_VERSION:-latest}
container_name: myvemailbackup
restart: unless-stopped
# build: .
ports:
- 25:25/tcp
environment:
# Backup mmail domain details
MYVEMAIL_SUBDOMAIN: ${MYVEMAIL_SUBDOMAIN}
MYVEMAIL_DOMAIN: ${MYVEMAIL_DOMAIN}
# Primary mail domain names separated by commas
MYVEMAIL_ADDMX: ${MYVEMAIL_ADDMX}
# Primary mail servers IP addresses separated by commas
MYVEMAIL_PRIMARYMX: ${MYVEMAIL_PRIMARYMX}
volumes:
# Logs
- ${MYVEMAIL_VOLUME_LOG:-./data/log/mail}:/var/log/maillog
- ${MYVEMAIL_VOLUME_LOG:-./data/log/downtime}:/var/log/downtime
# SSL (point to individual files in case symlinks are being used)
- ${MYVEMAIL_VOLUME_SSL:-./data/ssl}/tls.key:/etc/postfix/ssl/tls.key
- ${MYVEMAIL_VOLUME_SSL:-./data/ssl}/tls.pem:/etc/postfix/ssl/tls.pem
networks:
- myvemailbackup
networks:
myvemailbackup:
external: false