LukeSmithxyz / emailwiz

Script that installs/configures a Dovecot, Postfix, Spam Assassin, OpenDKIM Debian web server
GNU General Public License v3.0
1.72k stars 274 forks source link

Multiple domains (w/ SSL Cert & DKIM for each) #283

Open tavo-wasd-gh opened 1 year ago

tavo-wasd-gh commented 1 year ago

Steps:

Note:

Run emailwiz.sh

Set it up normally for your first domain, check that it works fine. Then continue with the next step

Generate new certificate

Not totally necessary for mail to "just work" but it will help, in this case I specified --standalone but do use --nginx or --apache instead, if your email service depends on one of those, if not sure, leave it as standalone. This is the line from the script:

certbot -d "$maildomain" certonly --standalone --register-unsafely-without-email --agree-tos

Note: Redirect at least your mail subdomain from your OTHER domain(s). Later on you'll have to also add other records for emails to work! See DNS Records step.

Dovecot

Dovecot is easier, you should be good by just adding these lines to /etc/dovecot/dovecot.conf Note: Remember to actually generate the keys with certbot, like in the "Generate new certificate" step below. Note: Uses TLS SNI, according to Dovecot's docs, it is tested in clients:

# mail.domain.org
local_name mail.domain.org {
    ssl_cert = </etc/letsencrypt/live/mail.domain.org/fullchain.pem
    ssl_key = </etc/letsencrypt/live/mail.domain.org/privkey.pem
}

# mail.otherdomain.org
local_name mail.otherdomain.org {
    ssl_cert = </etc/letsencrypt/live/mail.otherdomain.org/fullchain.pem
    ssl_key = </etc/letsencrypt/live/mail.otherdomain.org/privkey.pem
}

Create vmail map for the certificates

Add these entries in the vmail map to specify the certificate for each domain you need. You have to add them also for your already configred domain. This file is in /etc/postfix/vmail_ssl.map

mail.domain.org /etc/letsencrypt/live/mail.domain.org/privkey.pem /etc/letsencrypt/live/mail.domain.org/fullchain.pem
mail.otherdomain.org /etc/letsencrypt/live/mail.otherdomain.org/privkey.pem /etc/letsencrypt/live/mail.otherdomain.org/fullchain.pem

Generate a new DKIM key

Technically this is not necessary either since you can use the same key as your main domain, generated by emailwiz. However, some email clients and/or recipients might complain. Note: These lines are totally ripped off from the emailwiz script, I didn't come up with this I just found it useful to share the steps to reproduce my setup for multiple domains. Note: Obviously use your second domain name, first one is already generated.

mkdir -p "/etc/postfix/dkim/$domain"
opendkim-genkey -D "/etc/postfix/dkim/$domain" -d "$domain" -s "$subdom"
chgrp -R opendkim /etc/postfix/dkim/*
chmod -R g+r /etc/postfix/dkim/*

Add DKIM key to keytable

This file is in /etc/postfix/dkim/keytable The first one should already be filled out.

    mail._domainkey.domain.org domain.org:mail:/etc/postfix/dkim/domain.org/mail.private
 +  mail._domainkey.otherdomain.org otherdomain.org:mail:/etc/postfix/dkim/otherdomain.org/mail.private

Add entry in signing table

This file is in /etc/postfix/dkim/signingtable Again, first one should already be there.

    *@domain.org mail._domainkey.domain.org
 +  *@otherdomain.org mail._domainkey.otherdomain.org

Make sure both signing and keytable paths are present in /etc/opendkim.conf, like this:

KeyTable file:/etc/postfix/dkim/keytable
SigningTable refile:/etc/postfix/dkim/signingtable

Virtual alias

Add your desired email address, followed by the user the mail should be sent to. As stated before, you will need to do this for existing and new users. This file is in /etc/postfix/virtual

exampleuser@domain.org exampleuser
eggsample@domain.org eggsample
otheruser@otherdomain.org otheruser
yetanother@otherdomain.org yetanother

Tell postfix about it

Add these lines at the end of your postfix configuration. This file is in /etc/postfix/main.cf

virtual_alias_domains = otherdomain.org
virtual_alias_maps = hash:/etc/postfix/virtual

# provide the map to be used when SNI support is enabled
tls_server_sni_maps = hash:/etc/postfix/vmail_ssl.map

Apply and restart

Run these to apply the new configs and restart the services.

Note (edit): I had some issues when NOT using the -F option in postmap -F /etc/postfix/vmail_ssl.map, it references files, so make sure to use it.

postmap /etc/postfix/virtual
postmap -F /etc/postfix/vmail_ssl.map
systemctl restart postfix
systemctl restart dovecot
systemctl restart opendkim

DNS Records

In your second domain's panel, point the mail subdomain to the VPS, as usual, then add the same DNS records in dns_emailwizard, but do swap the domain name, for example:

domain.org        TXT     v=spf1 mx a:mail.domain.org -all

Would be

otherdomain.org        TXT     v=spf1 mx a:mail.otherdomain.org -all

Also, the output of the following commands is the TXT record for the new DKIM key (generated in the "Generate a new DKIM key" step).

pval="$(tr -d '\n' <"/etc/postfix/dkim/$domain/$subdom.txt" | sed "s/k=rsa.* \"p=/k=rsa; p=/;s/\"\s*\"//;s/\"\s*).*//" | grep -o 'p=.*')"
echo "$subdom._domainkey.$domain   TXT     v=DKIM1; k=rsa; $pval"

For new accounts

References:

Dovecot SSL configuration - TLS SNI Support Set up certs for multiple domains in Postfix and Dovecot

Notes & edits

Note: I had an issue with thunderbird where it could not verify server configuration. Checking systemctl status dovecot, it was a login issue even though I'm not trying to log in. I just clicked "done" when adding new email account without checking for server configuration and it works just fine.

Note (edit 2023-07-20): I noticed when using Thunderbird, for whatever reason it grabs OTHER domain names if you have multiple subdomains, for example, Thunderbird would get turn.example.org's cert instead of the appropriate mail.example.org. I noticed this because I was getting flagged mail when sending to corporate or institutions mail, BUT when using claws-mail (based, lightweight, simple client), it would actually get the mail.example.org cert. I don't know how to fix this since I'm not a Thunderbird user and I couldn't find any obvious way to do it. But note that it might happen :)

Note: (edit 2023-07-21): Gmail will complain about PTR records: "Gmail does not accept messages from IPs with missing PTR records." This is expected since you have (ideally) only one reverse DNS record for IPv4 (A) and IPv6 (AAAA), which is probably for your main domain. According to what I looked up online you COULD have multiple reverse DNS addresses but people say it might be worse than having one or even none. I don't exactly know the implications of this approach because I'm no expert, but receiving mail should work just fine.

suonpaa commented 1 year ago

Thanks, good advice.

One question, though. What is the purpose of hostname mail.otherdomain.org?

I ha multiple domains (example1.fi, example2 and example3), but only one A (and AAAA) record for mail server itself. MX record in example2.fi and example3.fi point to mx.example1.fi.

I am a bit baffled on what I should use as subdomain i.e. selector in example2.fi and example3.fi in this case. I ended up substituting mail with "default" and everything seems to be working.

(Also in SPF-record just "mx" instead of "mx a=example2.org" should work, right?)

ewof commented 1 year ago

what about dmarc for otherdomain

suonpaa commented 1 year ago

My current configuration with two domains it something along these lines.

Domains: domain.example otherdomain.example

Mail server: mail.domain.example

DNS zonefiles:

domain.example

@       IN   MX   10   mail
_dmarc      IN   TXT   "v=DMARC1; p=none; rua=mailto:dmarc@domain.example; fo=1"

otherdomain.example

@       IN  MX  10  mail.domain.example.
_dmarc      IN  TXT "v=DMARC1; p=none; rua=mailto:dmarc@otherdomain.example; fo=1"
ewof commented 1 year ago

@LukeSmithxyz it'd be nice if u could do all of this with the script, it works but it's kinda tedious

adamzea commented 1 year ago

@LukeSmithxyz it'd be nice if u could do all of this with the script, it works but it's kinda tedious

Or maybe this could be turned into a separate script file like "emailwiz-add-domain.sh", that way it can be run additional times whenever you want to add support for another domain? In other words, run emailwiz-add-domain.sh to add otherdomain1.org, then run it again to add otherdomain2.org, etc. Maybe an "emailwiz-add-user.sh" script could request the email address and password of a new user and then do the "Add unix user as explained in the main emailwiz documentation, Add new entry in /etc/postfix/virtual, postmap /etc/postfix/virtual && systemctl restart postfix" part.

adamzea commented 1 year ago

I'm not very good at this, but here's my attempt to make a separate script for adding domains and a separate script for adding users. I haven't tested yet as I'm afraid of breaking my server and haven't set up a test server yet. I think a couple other modifications to the main script will be necessary to support the 1st domain as well. emailwiz_add-user.sh.txt emailwiz-add-domain.sh.txt

EDIT: I don't know about adding virtual domains to main.cf. Not sure how to do that properly from a script. Below is probably only going to work for the 2nd domain, but not a 3rd.

sudo tee -a /etc/postfix/main.cf <<EOF virtual_alias_domains = ${domain} EOF

suonpaa commented 11 months ago

After editing /etc/postfix/virtual you should run postmap to update the lookup table, which is /etc/postfix/virtual.db.

Updated adduser -script:

#!/bin/bash

echo "Enter username:"
read username

useradd -m -G mail $username

echo "Enter password:"
passwd $username

echo "Enter email address:"
read email

echo "$email $username" >> /etc/postfix/virtual
/usr/sbin/postmap /etc/postfix/virtual
adamzea commented 10 months ago

I tried to make a fork that has extra scripts for adding domains and adding users for a multi-domain server: https://github.com/adamzea/emailwiz I'm trying to test it, but having some DNS issues with email clients still connecting to the old server. (I'm not very good at this!)

ewof commented 9 months ago

im using this and it works fine with thunderbird and apple mail but trying to use it with mutt wizard doesn't work, if i use a vanilla muttrc (like the one in lukes 4 year old video) it works but i am prompted saying that the certificate doesn't match the hostname. (i am trying to add an email on the first domain but it's giving a certificate of the second domain i added)

edit: this might help, im about to try it https://unix.stackexchange.com/questions/592341/mutt-smtp-certificate-hostname-does-not-match

edit fixed with this: https://serverfault.com/questions/1032855/postfix-not-using-ssl-certificate

ewof commented 9 months ago

also to fix dovecot returning the wrong certificates it should be

# mail.domain.org
ssl_cert = </etc/letsencrypt/live/mail.domain.org/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.domain.org/privkey.pem

# mail.otherdomain.org
local_name mail.otherdomain.org {
    ssl_cert = </etc/letsencrypt/live/mail.otherdomain.org/fullchain.pem
    ssl_key = </etc/letsencrypt/live/mail.otherdomain.org/privkey.pem
}
programmer-ke commented 9 months ago

I was also looking for a way to support multiple domains via emailwiz about a year ago, and ended up working on a new script from scratch (ansible, not bash).

I just came back to point this out in-case someone needs an out-of-the-box solution: https://github.com/programmer-ke/replatform/

adamzea commented 2 months ago

Have you renewed Letsencrypt certificates since then? It looks like Postfix doesn't get the new certificates even after a reload, restart, and reboot of the server. It looks like postmap -F /etc/postfix/vmail_ssl.map and systemctl restart postfix && systemctl restart dovecot && systemctl restart opendkim has to be run with every LetsEncrypt renewal.

On mine, I added a Certbot deploy hook file that should hopefully fix it using this script:

# Add deploy hook for certbot renewals to apply to Postfix 
# Create the reload-postfix.sh file
echo '#!/bin/bash' > /etc/letsencrypt/renewal-hooks/deploy/reload-postfix.sh
echo '' >> /etc/letsencrypt/renewal-hooks/deploy/reload-postfix.sh
# Add the desired commands
echo 'postmap -F /etc/postfix/vmail_ssl.map' >> /etc/letsencrypt/renewal-hooks/deploy/reload-postfix.sh
echo 'systemctl restart postfix && systemctl restart dovecot && systemctl restart opendkim' >> /etc/letsencrypt/renewal-hooks/deploy/reload-postfix.sh
# Make the script executable
chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-postfix.sh

echo "Script 'reload-postfix.sh' has been created and configured."

I also added that to my emailwiz-add-domain.sh file here: https://github.com/adamzea/emailwiz/blob/master/emailwiz-add-domain.sh