mmv

mailserver bootstrap script
git clone git://git.yotsev.xyz/mmv.git
Log | Files | Refs | README | LICENSE

commit 9e89a950e862d05b8cc190f4a4642b393d7e4f72
parent f08dfd3973a23e9aad063be62c350e48baa49350
Author: Petar Yotsev <petar@yotsev.xyz>
Date:   Tue, 14 Dec 2021 10:35:19 +0000

Add multi-domain support & utilities

Diffstat:
MREADME.md | 30++++++++++++++++++++----------
Mfiles/daily.local | 3+--
Afiles/madduser | 31+++++++++++++++++++++++++++++++
Afiles/mdeluser | 34++++++++++++++++++++++++++++++++++
Afiles/mpasswd | 31+++++++++++++++++++++++++++++++
Dfiles/newuser | 12------------
Mfiles/smtpd.conf | 6++++--
Ammv | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsetup.sh | 147-------------------------------------------------------------------------------
9 files changed, 305 insertions(+), 173 deletions(-)

diff --git a/README.md b/README.md @@ -3,10 +3,8 @@ mmv - minimal mailserver virtual mmv is a script for setting up a personal email server on OpenBSD using -virtual users. - -As you might have guessed, there also exists a fork - -[mms](https://git.yotsev.xyz/mms) - that uses system users. +virtual users. It allows one to host email for multiple domains on the +same server. WARNING: The script is still in development and liable to drastic changes with no backwards compatibility. @@ -14,24 +12,36 @@ changes with no backwards compatibility. ## Prerequisites The script automates as much as possible but there is one thing out of -its reach - dns. You'll need a valid A and/or AAAA record for the domain -you're going to use and for a subdomain `mail.domain.tld`. +its reach - DNS. If your email is `user@example.com`, you'll need A/AAAA +records for `mail.example.com`. ## Installation git clone git://git.yotsev.xyz/mmv.git cd mmv - ./setup.sh domain.tld + ./mmv example.com + +If you want to add another domain, simply run the script again: + + ./mmv another-domain.tld ## Post-execution After the script has finished executing successfully, it will have -written dns record that you have to paste into your name server or your +written DNS record that you have to paste into your name server or your registrar's interface. ## Usage After everything is in place, you can use the newly created script -`newuser` to add a user account. +`madduser` to add a user account. You'll be prompted for a password. + + madduser DOMAIN USERNAME + +You can similarly delete users with `mdeluser`. + + mdeluser DOMAIN USERNAME + +And change a password with `mpasswd`. - ./newuser + mpasswd DOMAIN USERNAME diff --git a/files/daily.local b/files/daily.local @@ -1,2 +1 @@ -# renew Let's Encrypt certificate if necessary -acme-client -v <maildom> +acme-client -v <maildom> && reboot diff --git a/files/madduser b/files/madduser @@ -0,0 +1,31 @@ +#!/bin/sh + +[ $# != 2 ] && +echo "Error: Invalid number of arguments" && +echo "Usage: madduser DOMAIN USERNAME" + +domain=$1 +user=$2 + +grep "$domain" /etc/mail/domains > /dev/null || +echo "Error: Invalid domain" && +echo "Info: It should be one of the following:" && +cat /etc/mail/domains && +return 1 + +grep "^$user@$domain" /etc/mail/credentials > /dev/null || +echo "Error: User already exists in /etc/mail/credentials" && return 1 + +grep "^$user@$domain" /etc/mail/virtuals > /dev/null || +echo "Error: User already exists in /etc/mail/virtuals" && return 1 + +echo -n "Password: " +stty -echo +read password +stty echo + +record="$(smtpctl encrypt "$password")" +record="$user@$domain:$record:vmail:2000:2000:/var/vmail/$domain/$user::userdb_mail=maildir:/var/vmail/$domain/$user" +echo "$record" >> /etc/mail/credentials + +echo "$user@$domain: vmail" >> /etc/mail/virtuals diff --git a/files/mdeluser b/files/mdeluser @@ -0,0 +1,34 @@ +#!/bin/sh + +[ $# != 2 ] && +echo "Error: Invalid number of arguments" && +echo "Usage: mdeluser DOMAIN USERNAME" + +domain=$1 +user=$2 + +grep "$domain" /etc/mail/domains > /dev/null || +echo "Error: Invalid domain" && +echo "Info: It should be one of the following:" && +cat /etc/mail/domains && +return 1 + +grep "^$user@" /etc/mail/credentials > /dev/null || +echo "Error: User already exists" && return 1 + +grep "^$user@" /etc/mail/virtuals > /dev/null || +echo "Error: User already exists in /etc/mail/virtuals" && return 1 + +echo -n "Delete records for user \"$user\"? (yes/no): " && +read responce && +[ $responce = "yes" ] && +sed "/$user@$domain/d" /etc/mail/credentials > temp-cred-file && +mv temp-cred-file /etc/mail/credentials && +sed "/$user@$domain/d" /etc/mail/virtuals > temp-virt-file && +mv temp-virt-file /etc/mail/virtuals && + +echo -n "Delete all mail associated with user \"$user\"? (yes/no): " && +read responce && +[ $responce = "yes" ] && +rm -rf /var/vmail/$domain/$user || +return 0 diff --git a/files/mpasswd b/files/mpasswd @@ -0,0 +1,31 @@ +#!/bin/sh + +[ $# != 2 ] && +echo "Error: Invalid number of arguments" && +echo "Usage: mpasswd DOMAIN USERNAME" + +domain=$1 +user=$2 + +grep "$domain" /etc/mail/domains > /dev/null || +echo "Error: Invalid domain" && +echo "Info: It should be one of the following:" && +cat /etc/mail/domains && +return 1 + +grep "^$user@$domain" /etc/mail/credentials > /dev/null && +grep "^$user@$domain" /etc/mail/virtuals > /dev/null || +echo "Error: Invalid username" && +return 1 + +echo -n "Password: " +stty -echo +read password +stty echo + +record="$(smtpctl encrypt "$password")" +record="$user@$domain:$record:vmail:2000:2000:/var/vmail/$domain/$user::userdb_mail=maildir:/var/vmail/$domain/$user" + +sed "s#^$user@$domain.*#$record#g" + +echo "$record" >> /etc/mail/credentials diff --git a/files/newuser b/files/newuser @@ -1,12 +0,0 @@ -#!/bin/sh - -echo -n "Username: " -read -r user -echo -n "Password: " -read -r password - -record="$(smtpctl encrypt "$password")" -record="$user@<domain>:$record:vmail:2000:2000:/var/vmail/<domain>/$user::userdb_mail=maildir:/var/vmail/<domain>/$user" -echo "$record" >> /etc/mail/credentials - -echo "$user@<domain>: vmail" >> /etc/mail/virtuals diff --git a/files/smtpd.conf b/files/smtpd.conf @@ -8,6 +8,7 @@ pki "mail" key "/etc/ssl/private/<maildom>.key" table aliases file:/etc/mail/aliases table credentials passwd:/etc/mail/credentials table virtuals file:/etc/mail/virtuals +table domains file:/etc/mail/domains filter "rspamd" proc-exec "/usr/local/libexec/smtpd/filter-rspamd" @@ -17,11 +18,12 @@ listen on egress port 587 tls-require pki "mail" \ hostname "<maildom>" auth <credentials> filter "rspamd" action "local" mbox alias <aliases> -action "inbound" maildir "/var/vmail/%{dest.domain:lowercase}/%{dest.user:lowercase}" virtual <virtuals> +action "inbound" \ + maildir "/var/vmail/%{dest.domain:lowercase}/%{dest.user:lowercase}/Inbox" virtual <virtuals> action "outbound" relay helo "<domain>" # accept external mail -match from any for domain "<domain>" action "inbound" +match from any for domain <domains> action "inbound" match from local for local action "local" match from local for any action "outbound" match from auth for any action "outbound" diff --git a/mmv b/mmv @@ -0,0 +1,184 @@ +#!/bin/sh + +domain=$1 +maildom="mail.$domain" +firstuse="true" + +replace() { \ +sed "s/<domain>/$domain/g;s/<maildom>/$maildom/g" $1 +} + +success() { \ + echo "\033[1;32m========================================================================" + echo "$@" + echo "========================================================================\033[0m" +} + +failure() { \ + echo "\033[1;31m========================================================================" + echo "$@" + echo "========================================================================\033[0m" +} + +# +# register domain +# + +[ test -f /etc/mail/maindom ] || firstuse="false" + +[ $firstuse = "true" ] && +echo "$domain" >> /etc/mail/maindom + +grep "$domain" /etc/mail/domains > /dev/null || +echo "$domain" >> /etc/mail/domains + +# +# install required software +# + +pkg_add -I opensmtpd-extras opensmtpd-filter-rspamd dovecot \ + dovecot-pigeonhole rspamd-3.0 redis sieve tor && + +success "Installed required software" + +# +# certs +# + +[ $firstuse = "true" ] && + +replace files/acme-client.conf >> /etc/acme-client.conf && + +replace files/httpd.conf >> /etc/httpd.conf && + +rcctl enable httpd && +rcctl restart httpd && + +acme-client -v $maildom && + +replace files/daily.local >> /etc/daily.local && + +success "Created and signed tls certificates (letencrypt)" + +# +# vmail user & authentication +# + +[ $firstuse = "true" ] && + +touch /etc/mail/credentials && +chmod 0440 /etc/mail/credentials && +chown _smtpd:_dovecot /etc/mail/credentials && +useradd -c "Virtual Mail Account" -d /var/vmail -s /sbin/nologin \ + -u 2000 -g =uid -L staff vmail && +mkdir -p /var/vmail && +chown vmail:vmail /var/vmail && + +replace files/virtuals >> /etc/mail/virtuals && + +success "Created vmail user & authentication file" + +# +# smtpd +# + +[ $firstuse = "true" ] && + +replace files/smtpd.conf > /etc/mail/smtpd.conf && + +cp files/madduser /usr/local/bin/ && +cp files/mdeluser /usr/local/bin/ && + +success "Configured OpenSMTPD" + +# +# dovecot +# + +[ $firstuse = "true" ] && + +echo "dovecot:\\ + :openfiles-cur=1024:\\ + :openfiles-max=2048:\\ + :tc=daemon: +" >> /etc/login.conf && + +replace files/local.conf > /etc/dovecot/local.conf && + +sed "s/^ssl_cert/#ssl_cert/;s/^ssl_key/#ssl_key/" \ + /etc/dovecot/conf.d/10-ssl.conf > tempfile && +mv tempfile /etc/dovecot/conf.d/10-ssl.conf && + +# setup training rspamd from email moving in and out of the Junk folder + +mkdir -p /usr/local/lib/dovecot/sieve && +cp files/report-ham.sieve /usr/local/lib/dovecot/sieve && +cp files/report-spam.sieve /usr/local/lib/dovecot/sieve && +sievec /usr/local/lib/dovecot/sieve/report-ham.sieve && +sievec /usr/local/lib/dovecot/sieve/report-spam.sieve && + +cp files/sa-learn-ham.sh /usr/local/lib/dovecot/sieve/ && +cp files/sa-learn-spam.sh /usr/local/lib/dovecot/sieve/ && +chmod 0755 /usr/local/lib/dovecot/sieve/sa-learn-ham.sh && +chmod 0755 /usr/local/lib/dovecot/sieve/sa-learn-spam.sh && + +rcctl enable dovecot && +rcctl start dovecot && + +success "Configured Dovecot" + +# +# rspamd +# + +[ $firstuse = "true" ] && + +mkdir -p /etc/mail/dkim && +openssl genrsa -out /etc/mail/dkim/$domain.key 1024 && +openssl rsa -in /etc/mail/dkim/$domain.key \ + -pubout -out /etc/mail/dkim/public.key && +chmod 0440 /etc/mail/dkim/$domain.key && +chown root:_rspamd /etc/mail/dkim/$domain.key && + +replace files/dkim_signing.conf > /etc/rspamd/local.d/dkim_signing.conf && + +rcctl enable redis rspamd && +rcctl start redis rspamd && +rcctl restart smtpd && + +success "Configured rspamd" + +# +# dns +# + +[ $firstuse = "true" ] && + +pub_key=$(grep -v -e "---" /etc/mail/dkim/public.key | tr -d '\n' ) && +mkdir -p dns && +echo "mail._domainkey.$domain. IN TXT \"v=DKIM1;k=rsa;p=$pub_key\"" > /etc/mail/dns/$domain/dkim && +echo "$domain. IN TXT \"v=spf1 mx -all\"" > /etc/mail/dns/$domain/spf && +echo "_dmarc.$domain. IN TXT +\"v=DMARC1;p=quarantine;pct=100;rua=mailto:postmaster@$domain\"" > /etc/mail/dns/$domain/dmarc && +echo "$domain. IN MX 0 $maildom." > /etc/mail/dns/$domain/mx && +success "Wrote relevant dns records in /etc/mail/dns/$domain/" + +[ $firstuse = "false" ] && + +echo "$domain. IN MX 0 $maildom." > /etc/mail/dns/$domain/mx && +success "Wrote relevant dns records in /etc/mail/dns/$domain/" + +# TODO: does .forward work with virtual users? + +[ $firstuse = "true" ] && + +success \ +"The creation of an admin account is required for this setup! Email to +it can be forwarded to an email address written in: +/var/vmail/$domain/admin/.forward +Please choose a password for the \"admin\" user." && + +madduser $domain admin && +rcctl restart smtpd + +success "Done!" diff --git a/setup.sh b/setup.sh @@ -1,147 +0,0 @@ -#!/bin/sh - -domain=$1 -maildom="mail.$domain" - -replace() { \ -sed "s/<domain>/$domain/g;s/<maildom>/$maildom/g" $1 -} - -success() { \ - echo "\033[1;32m===================================================" - echo "$@" - echo "===================================================\033[0m" -} - -failure() { \ - echo "\033[1;31m===================================================" - echo "$@" - echo "\033[0m===================================================" -} - -# -# install required software -# - -pkg_add opensmtpd-extras opensmtpd-filter-rspamd dovecot dovecot-pigeonhole rspamd redis sieve && - -success "Installed required software" && - -# -# certs -# - -replace files/acme-client.conf >> /etc/acme-client.conf && - -replace files/httpd.conf >> /etc/httpd.conf && - -rcctl enable httpd && -rcctl start httpd && - -acme-client -v $maildom && - -replace files/daily.local >> /etc/daily.local && - -success "Created and signed tls certificates (letencrypt)" && - -# -# vmail user & authentication -# - -touch /etc/mail/credentials && -chmod 0440 /etc/mail/credentials && -chown _smtpd:_dovecot /etc/mail/credentials && -useradd -c "Virtual Mail Account" -d /var/vmail -s /sbin/nologin \ - -u 2000 -g =uid -L staff vmail && -mkdir -p /var/vmail && -chown vmail:vmail /var/vmail && - -replace files/virtuals >> /etc/mail/virtuals && -replace files/newuser > ./newuser && -chmod +x ./newuser && - -success "Created vmail user & authentication file" && - -# -# smtpd -# - -replace files/smtpd.conf > /etc/mail/smtpd.conf && - -success "Configured OpenSMTPD" && - -# -# dovecot -# - -echo "dovecot:\\ - :openfiles-cur=1024:\\ - :openfiles-max=2048:\\ - :tc=daemon: -" >> /etc/login.conf && - -replace files/local.conf > /etc/dovecot/local.conf && - -sed "s/^ssl_cert/#ssl_cert/;s/^ssl_key/#ssl_key/" \ - /etc/dovecot/conf.d/10-ssl.conf > tempfile && -mv tempfile /etc/dovecot/conf.d/10-ssl.conf && - -# setup training rspamd from email moving in and out of the Junk folder - -mkdir -p /usr/local/lib/dovecot/sieve && -cp files/report-ham.sieve /usr/local/lib/dovecot/sieve && -cp files/report-spam.sieve /usr/local/lib/dovecot/sieve && -sievec /usr/local/lib/dovecot/sieve/report-ham.sieve && -sievec /usr/local/lib/dovecot/sieve/report-spam.sieve && - -cp files/sa-learn-ham.sh /usr/local/lib/dovecot/sieve/ && -cp files/sa-learn-spam.sh /usr/local/lib/dovecot/sieve/ && -chmod 0755 /usr/local/lib/dovecot/sieve/sa-learn-ham.sh && -chmod 0755 /usr/local/lib/dovecot/sieve/sa-learn-spam.sh && - -rcctl enable dovecot && -rcctl start dovecot && - -success "Configured Dovecot" && - -# -# rspamd -# - -mkdir -p /etc/mail/dkim && -openssl genrsa -out /etc/mail/dkim/$domain.key 1024 && -openssl rsa -in /etc/mail/dkim/$domain.key \ - -pubout -out /etc/mail/dkim/public.key && -chmod 0440 /etc/mail/dkim/$domain.key && -chown root:_rspamd /etc/mail/dkim/$domain.key && - -replace files/dkim_signing.conf > /etc/rspamd/local.d/dkim_signing.conf && - -rcctl enable redis rspamd && -rcctl start redis rspamd && -rcctl restart smtpd && - -success "Configured rspamd" && - -# -# dns -# - -pub_key=$(grep -v -e "---" /etc/mail/dkim/public.key | tr -d '\n' ) && - -mkdir -p dns && -echo "mail._domainkey.$domain. IN TXT \"v=DKIM1;k=rsa;p=$pub_key\"" > ./dns/dkim-record && -echo "$domain. IN TXT \"v=spf1 mx -all\"" > ./dns/spf-record && -echo "_dmarc.$domain. IN TXT \"v=DMARC1;p=none;pct=100;rua=mailto:postmaster@$domain\"" > ./dns/dmarc-record && - -success "Wrote relevant dns records in ./dns/" && -# TODO: does .forward work with virtual users? -success \ -"The creation of an admin account is required for this setup! Email to -it can be forwarded to an email address written in: -/var/vmail/$domain/admin/.forward -New users can be similarly added by running ./newuser. Please use the -username \"admin\" and a password of your choosing" && - -./newuser && -rcctl restart smtpd