This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
computing:mailserver [2025/04/03 19:07] – oemb1905 | computing:mailserver [2025/04/23 20:55] (current) – oemb1905 | ||
---|---|---|---|
Line 11: | Line 11: | ||
------------------------------------------- | ------------------------------------------- | ||
- | This tutorial is for users of Debian GNU/Linux who want to set up a proper email server.. This tutorial assumes you know how to set up A, AAAA, SPF, DKIM, DMARC, MX, and PTR records. Set an A record for example.org and mail.example.org. If you don't know how, then learn up, and do not proceed. //Thanks to LinuxBabe for a great jumping off point//. | + | This tutorial is for users of Debian GNU/Linux who want to set up a proper email server.. This tutorial assumes you know how to set up A, AAAA, SPF, DKIM, DMARC, MX, and PTR records. Set an A record for example.org and mail.example.org. If you don't know how, then learn up, and do not proceed. //Thanks to LinuxBabe for a great jumping off point// |
- | | + | |
+ | 127.0.0.1 mail.example.org localhost | ||
- | Edit the second line and add a line to the bottom similar to: | + | Install postfix and mailutils |
- | + | ||
- | < | + | |
- | < | + | |
- | + | ||
- | Install postfix and mailutils | + | |
- | + | ||
- | | + | |
- | <Internet Site> | + | |
- | <example.org> | + | |
Install firewall, open common ports for front facing website, and for imap/smtp: | Install firewall, open common ports for front facing website, and for imap/smtp: | ||
Line 30: | Line 22: | ||
sudo apt install ufw | sudo apt install ufw | ||
sudo ufw allow 22/tcp | sudo ufw allow 22/tcp | ||
- | sudo ufw allow 53/tcp | ||
sudo ufw allow 25/tcp | sudo ufw allow 25/tcp | ||
sudo ufw allow 587/tcp | sudo ufw allow 587/tcp | ||
sudo ufw allow 143/tcp | sudo ufw allow 143/tcp | ||
+ | sudo ufw allow 465/tcp | ||
sudo ufw allow 993/tcp | sudo ufw allow 993/tcp | ||
sudo ufw allow 80 | sudo ufw allow 80 | ||
Line 42: | Line 34: | ||
sudo postconf -e message_size_limit=52428800 | sudo postconf -e message_size_limit=52428800 | ||
- | Set hostname and aliases | + | Set hostname and aliases |
- | + | ||
- | | + | |
- | + | ||
- | Make sure that the hostname, origin, destination, | + | |
| | ||
myhostname = mail.example.com | myhostname = mail.example.com | ||
Line 121: | Line 109: | ||
smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 | smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 | ||
- | Now, we can install dovecot and configure | + | Now, let' |
- | sudo apt install dovecot-core dovecot-imapd | + | |
- | | + | smtpd_sasl_auth_enable = yes |
- | < | + | smtpd_sasl_type = dovecot |
- | sudo nano / | + | smtpd_sasl_path = private/ |
- | < | + | smtpd_sasl_security_options = noanonymous |
- | sudo adduser dovecot mail | + | |
- | + | Now, we can install dovecot and configure it to use IMAP and lmtp. Install the packages with '' | |
- | We will now configure dovecot to use lmtp and in so doing use spam sieve and other modules: | + | |
- | sudo apt install dovecot-lmtpd | ||
- | sudo nano / | ||
< | < | ||
- | Now, we need to edit '' | + | After that, open '' |
+ | |||
+ | < | ||
+ | |||
+ | Let' | ||
+ | |||
+ | sudo adduser dovecot mail | ||
+ | sudo adduser username mail | ||
+ | |||
+ | Now we can configure dovecot over at '' | ||
service lmtp { | service lmtp { | ||
Line 146: | Line 140: | ||
} | } | ||
- | Similarly, we need to edit postfix for lmtp: | + | Similarly, we need to edit postfix for lmtp as well with '' |
- | | + | mailbox_transport = lmtp: |
- | <mailbox_transport = lmtp: | + | smtputf8_enable = no |
- | | + | |
- | Next, let's configure dovecot authorization: | + | Next, let's configure dovecot authorization |
- | | + | disable_plaintext_auth = yes |
- | <disable_plaintext_auth = yes> | + | auth_username_format = %n |
- | | + | auth_mechanisms = plain login |
- | | + | |
| | ||
- | Now, configure SSL/TLS encryption in dovecot: | + | Now, configure SSL/TLS encryption in dovecot |
- | | + | ssl = required |
- | <ssl = required> | + | ssl_cert = </ |
- | | + | ssl_key = </ |
- | | + | ssl_prefer_server_ciphers = yes |
- | | + | ssl_min_protocol = TLSv1.2 |
- | | + | |
| | ||
- | SASL configuration | + | Set up the SASL listener |
service auth { | service auth { | ||
Line 183: | Line 174: | ||
openssl s_client -starttls smtp -connect mail.example.com: | openssl s_client -starttls smtp -connect mail.example.com: | ||
| | ||
- | Now it is time to setup an spf policy agent so that the incoming email that is received checks for validity of spf records. **Do not confuse this with creating an spf TXT record for your outgoing email.** | + | Now it is time to setup an spf policy agent so that the incoming email that is received checks for validity of spf records. **Do not confuse this with creating an spf TXT record for your outgoing email.** |
+ | |||
+ | policyd-spf | ||
+ | user=policyd-spf argv=/ | ||
+ | |||
+ | After that, let's set up '' | ||
- | | + | policyd-spf_time_limit = 3600 |
- | sudo nano / | + | smtpd_recipient_restrictions = |
- | < | + | |
- | < | + | |
- | sudo nano / | + | |
- | <policyd-spf_time_limit = 3600> | + | |
- | | + | |
- | <permit_mynetworks, | + | |
- | <permit_sasl_authenticated, | + | |
- | <reject_unauth_destination, | + | |
- | <check_policy_service unix: | + | |
- | Now, it is time to set up DKIM on your server. After creating the DKIM record/key on your server, you will need to create a corresponding TXT record for it to establish that anything over smtp with that signature is, in fact, you/your server. | + | Now, it is time to set up DKIM on your server. After creating the DKIM record/key on your server, you will need to create a corresponding TXT record for it to establish that anything over smtp with that signature is, in fact, you/your server. |
- | | + | Canonicalization |
- | sudo adduser postfix opendkim | + | Mode sv |
- | sudo nano / | + | SubDomains |
- | <Canonicalization | + | Nameservers |
- | | + | KeyTable |
- | | + | SigningTable |
- | | + | ExternalIgnoreList |
- | | + | InternalHosts |
- | | + | |
- | | + | |
- | | + | |
Now that the configuration for DKIM is ready, let's create the keys and content for the locations specified above: | Now that the configuration for DKIM is ready, let's create the keys and content for the locations specified above: | ||
Line 216: | Line 204: | ||
sudo chown -R opendkim: | sudo chown -R opendkim: | ||
sudo chmod 711 / | sudo chmod 711 / | ||
- | sudo nano / | + | |
- | | + | Once all the directories and key locations are created, let's open the signing table with '' |
- | | + | |
- | sudo nano / | + | |
- | | + | |
- | sudo nano / | + | |
- | | + | Now that the signing table is setup, we need to edit the key table with '' |
+ | |||
+ | default._domainkey.example.com | ||
+ | |||
+ | The trusted hosts is next, over in '' | ||
+ | |||
+ | 127.0.0.1 | ||
+ | localhost | ||
+ | .domain.com | ||
+ | |||
+ | We now need to cut the DKIM keys (and make sure to add TXT records on your DNS host later) as follows: | ||
+ | | ||
sudo mkdir / | sudo mkdir / | ||
sudo opendkim-genkey -b 2048 -d example.com -D / | sudo opendkim-genkey -b 2048 -d example.com -D / | ||
Line 228: | Line 227: | ||
sudo chmod 600 / | sudo chmod 600 / | ||
- | It's now time to create | + | To get the information you need for the DNS record, you can run '' |
sudo opendkim-testkey -d example.com -s default -vvv | sudo opendkim-testkey -d example.com -s default -vvv | ||
| | ||
- | Note that that output will display "key not secure" | + | Note that that output will display "key not secure" |
sudo mkdir / | sudo mkdir / | ||
sudo chown opendkim: | sudo chown opendkim: | ||
sudo nano / | sudo nano / | ||
- | | + | |
- | | + | In the dkim config file, enter: |
- | | + | |
- | sudo nano /etc/postfix/main.cf | + | |
- | < | + | |
- | < | + | After establishing the socket directory and location, let's configure our dkim defaults in '' |
- | < | + | |
- | < | + | |
- | It's now a good time to test your email quality with [[https://mail-tester.com|Mail Tester]] to see if you got a 10/10 score. When upgrading | + | SOCKET=" |
- | | + | Lastly, we need to configure postfix to be able to use opendkim in '' |
- | | + | |
- | < | + | |
- | < | + | |
- | < | + | |
- | < | + | non_smtpd_milters = $smtpd_milters |
- | < | + | |
- | < | + | |
- | < | + | |
- | < | + | |
- | + | ||
- | To set up email header and/or body checks to prevent spam: | + | |
- | | + | In addition to spf and dkim policies, it's also best practice to have a dmarc policy. Let's install opendmarc with '' |
- | | + | |
- | | + | |
- | | + | |
+ | RejectFailures true | ||
+ | IgnoreAuthenticatedClients true | ||
+ | RequireHeaders true | ||
+ | SPFSelfValidate true | ||
+ | Socket local:/var/spool/postfix/opendmarc/ | ||
| | ||
- | You will then need to configure the files with whatever strings you expect spam headers or bodies to have, and either reject them and/or discard them. You will also need to rebuild the indexes. You may optionally | + | The opendmarc socket also needs its directory created, similar |
- | sudo apt install opendmarc | ||
- | <no to db configure> | ||
- | sudo nano / | ||
- | < | ||
- | < | ||
- | < | ||
- | < | ||
- | < | ||
- | <Socket local:/ | ||
- | sudo mkdir -p / | ||
sudo chown opendmarc: | sudo chown opendmarc: | ||
sudo chmod 750 / | sudo chmod 750 / | ||
Line 283: | Line 269: | ||
sudo systemctl restart opendmarc | sudo systemctl restart opendmarc | ||
| | ||
- | Now, configure postfix to work with openDMARC. | + | Now, we need to configure postfix to work with openDMARC. |
- | | + | milter_default_action = accept |
- | <milter_default_action = accept> | + | milter_protocol = 6 |
- | | + | smtpd_milters = local: |
- | | + | non_smtpd_milters = $smtpd_milters |
- | | + | |
- | sudo systemctl restart postfix | + | |
- | + | ||
- | This about covers everything. The only missing part is how to get past picky microsoft users and/or automate or simplify account creation. Okay, to view and/or delete messages from postfix mailq: | + | |
- | mailq | + | It' |
- | postcat -q E900C4780073 | + | |
- | postsuper -d E900C4780073 | + | |
- | postsuper -d ALL | + | |
- | + | ||
- | If you have issues, it' | + | |
- | + | ||
- | dig txt +short _dmarc.jonathanhaack.com | + | |
- | dig txt +short _dmarc.haacksnetworking.org | + | |
- | dig default._domainkey.jonathanhaack.com txt | + | |
- | dig default._domainkey.haacksnetworking.org txt | + | |
- | dig txt +short jonathanhaack.com | + | |
- | dig txt +short haacksnetworking.org | + | |
- | dig -x 8.28.86.130 +short | + | |
- | dig -x 8.28.86.125 +short | + | |
- | sudo opendkim-testkey -d jonathanhaack.com -s default -vvv | + | |
- | sudo opendkim-testkey -d haacksnetworking.org -s default -vvv | + | |
- | + | ||
- | Also, please note that the above applies to clients connecting to the domain. If you intend to also host websites/ | + | |
- | + | ||
- | echo "Hi, I am testing the subdomain email health." | + | |
- | + | ||
- | It' | + | |
- | + | ||
- | | + | |
- | + | ||
- | An example block: | + | |
mailbox Drafts { | mailbox Drafts { | ||
- | auto = create | + | |
special_use = \Drafts | special_use = \Drafts | ||
} | } | ||
- | Simply add the '' | + | Since I use lmtp, which is case-sensitive, |
virtual_alias_maps = regexp:/ | virtual_alias_maps = regexp:/ | ||
| | ||
- | From there, you can configure aliases one by one or with regex. For example, I could either do all combinations of oemb (line 1-2, etc.), or the regex for all of them (line 3): | + | After you enter that block, let's open the file '' |
- | /^OEMB1905/ | + | /^[Jj][Oo][Nn][Aa][Tt][Hh][Aa][Nn]@haacksnetworking.org/ |
- | / | + | /^[Ww][Ee][Bb][Mm][Aa][Ss][Tt][Ee][Rr]@haacksnetworking.org/ |
- | /^[Oo][Ee][Mm][Bb]1905/ oemb1905 | + | |
+ | It's super important to include the domain above after the regex or all emails you send to that begin with your user name will wind up in that user's inbox. When finished configuring, | ||
+ | |||
+ | smtpd_sender_restrictions = | ||
+ | permit_mynetworks, | ||
+ | permit_sasl_authenticated, | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | reject_sender_login_mismatch | ||
+ | permit | ||
+ | |||
+ | Personally, I disable most of the above rejects by design. I include them here more for others' | ||
+ | |||
+ | header_checks = pcre:/ | ||
+ | body_checks = pcre:/ | ||
| | ||
- | When finished configuring, run '' | + | In these locations, '' |
- | | + | |
- | | + | /free mortgage quote/ |
- | Set to: | + | Once they are to your liking, make sure to compile them with '' |
protocols = imap lmtp sieve | protocols = imap lmtp sieve | ||
- | | ||
- | Then, open | ||
- | |||
- | sudo nano / | ||
- | Set to: | + | In '' |
protocol lda { | protocol lda { | ||
Line 356: | Line 324: | ||
} | } | ||
| | ||
- | Finally, | + | Let's also adjust the lmtp agent in '' |
- | + | ||
- | | + | |
- | + | ||
- | Which should be: | + | |
protocol lmtp { | protocol lmtp { | ||
mail_plugins = quota sieve | mail_plugins = quota sieve | ||
} | } | ||
- | | ||
- | Once that's done, let's enable regular expression checking of headers and the email body within postfix. I personally don't use these, but I keep them active just in case. | ||
- | |||
- | sudo apt install postfix-pcre | ||
- | sudo nano / | ||
- | < | ||
- | < | ||
- | | ||
- | This enables regular expression checking on headers and in the email body. You can enter REJECT or DISCARD as follows: | ||
- | |||
- | sudo nano / | ||
- | </free mortgage quote/ | ||
- | sudo nano / | ||
- | </free mortgage quote/ | ||
- | sudo postmap / | ||
- | sudo postmap / | ||
- | Now it's time to setup spamassassin. | + | Now it's time to setup spamassassin |
- | | + | |
- | | + | |
- | | + | smtpd_milters = local: |
- | sudo nano / | + | non_smtpd_milters = $smtpd_milters |
- | <smtpd_milters = local: | + | |
| | ||
- | The milter line above depends on one' | + | It' |
- | | + | |
- | | + | # |
+ | | ||
+ | #Reject emails with spamassassin scores | ||
+ | OPTIONS=" | ||
| | ||
- | If you prefer to reject | + | Again, I do not use the reject |
- | | + | |
- | OPTIONS=" | + | |
| | ||
- | Now that dovecot' | + | The sieve_before |
- | + | ||
- | sudo nano /etc/dovecot/conf.d/ | + | |
- | < | + | |
- | + | ||
- | Open the sieve rule with '' | + | |
require " | require " | ||
Line 417: | Line 361: | ||
sudo sievec / | sudo sievec / | ||
- | |||
- | [DO NOT DO THIS] Now we can alert postfix to check our spamassassin policy on our behalf. In the ''/ | ||
- | |||
- | < | ||
| | ||
- | [DO NOT DO THIS] And over in ''/ | + | This rule does one thing. It checks whether spam assassin identified the message as spam, and if so, it uses dovecot to file it in Junk. This means your spam assassin scores and config are what drive the success rate of this sieve rule. It's also important to note that this rule is global, and impacts all user names on the mail server. It's a good approach for the most heinous spam, leaving more customized rules to roundcube' |
- | | + | |
- | | + | #adjust score below to your use-case |
+ | required_score 5.0 | ||
+ | # | ||
+ | report_safe 0 | ||
+ | add_header all Spam-Flag _YESNO_ | ||
+ | | ||
+ | add_header all Report _REPORT_ | ||
+ | add_header all Level _STARS_ | ||
+ | add_header all Status " | ||
+ | add_header all Checker-Version " | ||
+ | #legacy/deprecated header config | ||
+ | # | ||
- | We can now configure | + | I included some header options, which can help with debugging. Also, I disable safe reporting and Subject rewriting because they alter the original email, which I think is overkill. In order to activate all that spam assassin can do, we need to have our own recursive DNS resolver, required by RBL services. Let's use the DNS server unbound and install it as follows '' |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | + | | |
- | Before we enter the custom scores and white and black lists, let's install and enable unbound, so that spam-assassin can query the RBLs. RBLs do not allow upstream DNS queries, thus we are required to run our own recursive resolver here. Take care not to expose this publicly. I prefer unbound, but one can also use bind9 or others. Specify the DNS in the '' | + | score DKIM_ADSP_NXDOMAIN |
+ | score FORGED_GMAIL_RCVD | ||
+ | score FREEMAIL_FORGED_FROMDOMAIN | ||
+ | score HEADER_FROM_DIFFERENT_DOMAINS | ||
+ | score FREEMAIL_FROM | ||
+ | score ACCT_PHISHING | ||
+ | score AD_PREFS | ||
+ | score ADMAIL | ||
+ | score ADMITS_SPAM | ||
+ | score CONFIRMED_FORGED | ||
+ | score FROM_PAYPAL_SPOOF | ||
+ | score SPF_SOFTFAIL | ||
+ | score SPF_FAIL | ||
+ | whitelist_from *@statefarm.com | ||
+ | blacklist_from *@email.freethinkerdaily.com | ||
- | sudo apt install unbound | + | Additionally, |
- | sudo nano / | + | |
- | < | + | |
- | <score MISSING_FROM | + | |
- | <score MISSING_DATE | + | |
- | <score MISSING_HEADERS | + | |
- | <score PDS_FROM_2_EMAILS | + | |
- | <score FREEMAIL_FORGED_REPLYTO | + | |
- | <score DKIM_ADSP_NXDOMAIN | + | |
- | <score FORGED_GMAIL_RCVD | + | |
- | <score FREEMAIL_FORGED_FROMDOMAIN | + | |
- | <score HEADER_FROM_DIFFERENT_DOMAINS | + | |
- | <score FREEMAIL_FROM | + | |
- | <score ACCT_PHISHING | + | |
- | <score AD_PREFS | + | |
- | <score ADMAIL | + | |
- | <score ADMITS_SPAM | + | |
- | <score CONFIRMED_FORGED | + | |
- | <score FROM_PAYPAL_SPOOF | + | |
- | <score SPF_SOFTFAIL | + | |
- | <score SPF_FAIL | + | |
- | < | + | |
- | < | + | |
- | Additionally, | + | require [" |
+ | # rule: | ||
+ | | ||
+ | header :contains " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ] | ||
+ | ) { | ||
+ | keep; | ||
+ | stop; | ||
+ | } | ||
+ | # rule: | ||
+ | if anyof ( | ||
+ | header :contains " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | ] | ||
+ | ) { | ||
+ | fileinto " | ||
+ | stop; | ||
+ | } | ||
+ | # rule: | ||
+ | if anyof ( | ||
+ | header :contains " | ||
+ | header :contains " | ||
+ | header :contains " | ||
+ | ) { | ||
+ | fileinto " | ||
+ | stop; | ||
+ | } | ||
- | | + | These rules are processed sequentially. Monitor the Junk folder periodically and refine whitelists as needed. If something escapes, like a full health dirty marketing scam, adjust your blacklist. That's all there is to it. Now that spam controls are setup, we need to setup some auditing tools to monitor how well our server is doing these tasks. For postfix, that tool is pflogsumm. Let's install it with '' |
- | | + | |
| | ||
- | Disable the ''/ | + | Disable the ''/ |
- | + | ||
- | | + | |
- | + | ||
- | In that file, enter the following: | + | |
/ | / | ||
Line 481: | Line 450: | ||
} | } | ||
- | Once that's done, let's create script and cronjob to send us daily reports: | + | Once that's done, let's create script and cronjob to send us daily reports |
- | + | ||
- | | + | |
- | + | ||
- | In that script, enter something like this: | + | |
#!/bin/sh | #!/bin/sh | ||
- | #/ | + | #/ |
gunzip / | gunzip / | ||
/ | / | ||
Line 502: | Line 467: | ||
30 12 * * * /bin/bash / | 30 12 * * * /bin/bash / | ||
| | ||
- | In extreme cases, directly block problem domains in postfix | + | You can also use the '' |
- | sudo adduser username mail | + | ------------------------------------------- |
| | ||
The SASL module packages should be brought in as dependencies of postfix and/or dovecot. However, on upgrades, etc., they might be removed during dependency resolution. If you get "no sasl" report on your logs suddenly, despite everything working prior, use: | The SASL module packages should be brought in as dependencies of postfix and/or dovecot. However, on upgrades, etc., they might be removed during dependency resolution. If you get "no sasl" report on your logs suddenly, despite everything working prior, use: | ||
sudo apt-get install libsasl2-modules | sudo apt-get install libsasl2-modules | ||
+ | | ||
+ | If/when things are going wrong, turn on your detailed debugging logs and study them: | ||
+ | |||
+ | nano / | ||
+ | < | ||
+ | | ||
+ | To check record health after you set your DNS records, you can do the following: | ||
+ | | ||
+ | dig txt +short _dmarc.jonathanhaack.com | ||
+ | dig txt +short _dmarc.haacksnetworking.org | ||
+ | dig default._domainkey.jonathanhaack.com txt | ||
+ | dig default._domainkey.haacksnetworking.org txt | ||
+ | dig txt +short jonathanhaack.com | ||
+ | dig txt +short haacksnetworking.org | ||
+ | dig -x 8.28.86.130 +short | ||
+ | dig -x 8.28.86.125 +short | ||
+ | sudo opendkim-testkey -d jonathanhaack.com -s default -vvv | ||
+ | sudo opendkim-testkey -d haacksnetworking.org -s default -vvv | ||
+ | | ||
+ | You should test email health with the CLI and/or use a service like [[https:// | ||
+ | |||
+ | echo "Hi, I am testing the subdomain email health." | ||
+ | | ||
+ | Postfix has its own CLI control tools, such as but not exclusive to viewing email, deleting email, etc.: | ||
+ | |||
+ | mailq | ||
+ | postcat -q E900C4780073 | ||
+ | postsuper -d E900C4780073 | ||
+ | postsuper -d ALL | ||
+ | | ||
+ | These tools prove helpful if/when emails get stuck, etc. | ||
- | --- // | + | --- // |