User Tools

Site Tools


computing:mailserver-trixie

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
computing:mailserver-trixie [2026/07/31 15:40] oemb1905computing:mailserver-trixie [2026/08/31 00:07] (current) oemb1905
Line 70: Line 70:
  
   sudo apt update && sudo apt upgrade -y   sudo apt update && sudo apt upgrade -y
-  sudo apt install mailutils postfix ufw fail2ban nginx apache2 php8.4-fpm php8.4-mysql php8.4-curl php8.4-gd php8.4-mbstring php8.4-xml php8.4-zip dovecot-core dovecot-imapd dovecot-lmtpd+  sudo apt install mailutils postfix ufw fail2ban apache2 php8.4-fpm php8.4-mysql php8.4-curl php8.4-gd php8.4-mbstring php8.4-xml php8.4-zip dovecot-core dovecot-imapd dovecot-lmtpd
  
 It's also important that that the host knows how to identify itself properly. Let's open it up ''/etc/hosts'' and make it is setup correctly. It's also important that that the host knows how to identify itself properly. Let's open it up ''/etc/hosts'' and make it is setup correctly.
  
-<code bash>+<code>
 127.0.0.1 localhost 127.0.0.1 localhost
 127.0.1.1 mail.haacksnetworking.org haacksnetworking 127.0.1.1 mail.haacksnetworking.org haacksnetworking
Line 131: Line 131:
 Make sure to create ''vhost-mail.conf'' and enable it with ''a2ensite'' for the ''mail.haacksnetworking.org'' or ''mail.domain.com'' and run the same ''certbot'' command again for Let's Encrypt to create a cert for this subdomain as well. You need to specify and create a different webroot for ''ServerName'', ''ServerAdmin'', and ''DocumentRoot'' this subdomain, just like the parent domain. Don't run the certbot commands on both domains together as it might interpret that command as being wildcards and/or nested certificates (e.g., multi-site WordPress). When you installed postfix, it automatically populated the global config file over in ''/etc/postfix/main.cf'' with the specified choices. It's now time to configure individual services for postfix (smtpd, submission, etc.), so open up ''/etc/postfix/master.cf'' and add these blocks where appropriate. You can view an actual config of mine in the link below this block. Make sure to create ''vhost-mail.conf'' and enable it with ''a2ensite'' for the ''mail.haacksnetworking.org'' or ''mail.domain.com'' and run the same ''certbot'' command again for Let's Encrypt to create a cert for this subdomain as well. You need to specify and create a different webroot for ''ServerName'', ''ServerAdmin'', and ''DocumentRoot'' this subdomain, just like the parent domain. Don't run the certbot commands on both domains together as it might interpret that command as being wildcards and/or nested certificates (e.g., multi-site WordPress). When you installed postfix, it automatically populated the global config file over in ''/etc/postfix/main.cf'' with the specified choices. It's now time to configure individual services for postfix (smtpd, submission, etc.), so open up ''/etc/postfix/master.cf'' and add these blocks where appropriate. You can view an actual config of mine in the link below this block.
  
-<code bash>+<code>
 submission inet n - y - - smtpd submission inet n - y - - smtpd
   -o syslog_name=postfix/submission   -o syslog_name=postfix/submission
Line 155: Line 155:
 The changes above add service definitions and configurations for smtps (465) and submission (587), both of which handle mail submission, or the sending of email. Examples of these configurations can be found in ''/usr/share/doc/postfix/examples/''. Submission is the newer protocol, but I retain smtps for compatibility with older clients. Once that's done, it's time to edit ''/etc/postfix/main.cf'' to account for the TLS certificate we just cut with Let's Encrypt a few steps earlier. We can additionally specify for postfix to use auth mechanisms that leverage this cert and are consistent with the services setup in master.cf. Let's open ''/etc/postfix/main.cf'' and review/add/edit the following: The changes above add service definitions and configurations for smtps (465) and submission (587), both of which handle mail submission, or the sending of email. Examples of these configurations can be found in ''/usr/share/doc/postfix/examples/''. Submission is the newer protocol, but I retain smtps for compatibility with older clients. Once that's done, it's time to edit ''/etc/postfix/main.cf'' to account for the TLS certificate we just cut with Let's Encrypt a few steps earlier. We can additionally specify for postfix to use auth mechanisms that leverage this cert and are consistent with the services setup in master.cf. Let's open ''/etc/postfix/main.cf'' and review/add/edit the following:
  
-<code bash>+<code>
 # A) Leave the following upper-block defaults # A) Leave the following upper-block defaults
 smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU) smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
Line 202: Line 202:
 inet_protocols = all inet_protocols = all
 message_size_limit = 52428800 message_size_limit = 52428800
 +cyrus_sasl_config_path = /etc/postfix/sasl #now default since early 2026
 </code> </code>
  
Line 212: Line 213:
 In order for dovecot to work, we need to specify which protocols we allow, the mail directory location, ensure that dovecot is a member of the mail group, and enable lmtp the for delivery agent. Lmtp is a local delivery agent and hands off processed incoming emails to the storage directories without requiring external authentication. This ensures everything is delivered locally, or within the hardened host. Larger distributed email systems require smtp for network hand offs between servers, but that's not required or helpful for mail server self-hosters. Open up ''/etc/dovecot/dovecot.conf'' and specify the protocols. It is also required to specfify the storage and config versions (updated for Trixie): In order for dovecot to work, we need to specify which protocols we allow, the mail directory location, ensure that dovecot is a member of the mail group, and enable lmtp the for delivery agent. Lmtp is a local delivery agent and hands off processed incoming emails to the storage directories without requiring external authentication. This ensures everything is delivered locally, or within the hardened host. Larger distributed email systems require smtp for network hand offs between servers, but that's not required or helpful for mail server self-hosters. Open up ''/etc/dovecot/dovecot.conf'' and specify the protocols. It is also required to specfify the storage and config versions (updated for Trixie):
  
-<code bash>+<code>
 protocols = imap lmtp protocols = imap lmtp
 dovecot_storage_version = 2.4.1 dovecot_storage_version = 2.4.1
Line 225: Line 226:
  
  
-<code bash>+<code>
 mail_driver = maildir mail_driver = maildir
 mail_path = ~/Maildir mail_path = ~/Maildir
Line 239: Line 240:
 It is required that lmtp be configured for use with dovecot. To do that, edit ''/etc/dovecot/conf.d/10-master.conf'': It is required that lmtp be configured for use with dovecot. To do that, edit ''/etc/dovecot/conf.d/10-master.conf'':
  
-<code bash>+<code>
 service lmtp { service lmtp {
   unix_listener /var/spool/postfix/private/dovecot-lmtp {   unix_listener /var/spool/postfix/private/dovecot-lmtp {
Line 251: Line 252:
 Postfix also needs to know the delivery agent that's being used, otherwise it won't know what service to which it should send incoming email. In short, lmtp hands off emails from postfix's mail queue to dovecot's mail storage. This is done via a socket, so that needs to be configured in the main postfix configuration. Open up ''/etc/postfix/main.cf'' and define the socket as follows. It is recommended that you also disable UTF-8 support in headers and addresses so that legacy mail servers can handle emails from your server. Postfix also needs to know the delivery agent that's being used, otherwise it won't know what service to which it should send incoming email. In short, lmtp hands off emails from postfix's mail queue to dovecot's mail storage. This is done via a socket, so that needs to be configured in the main postfix configuration. Open up ''/etc/postfix/main.cf'' and define the socket as follows. It is recommended that you also disable UTF-8 support in headers and addresses so that legacy mail servers can handle emails from your server.
  
-<code bash>+<code>
 mailbox_transport = lmtp:unix:private/dovecot-lmtp mailbox_transport = lmtp:unix:private/dovecot-lmtp
 smtputf8_enable = no smtputf8_enable = no
Line 265: Line 266:
 Now, let's enforce ssl so that the plain and login mechanisms above are wrapped - end to end - in TLS handshakes. It is also important to explicitly define the least secure and/or oldest TLS handshake your server will permit. Additionally, make sure that you comment out ssl_prefer_server_ciphers and/or anything like ''ssl_server_dh'' file, both of which are now deprecated. To do this, open up ''/etc/dovecot/conf.d/10-ssl.conf'' and edit the following parameters (updated for Trixie): Now, let's enforce ssl so that the plain and login mechanisms above are wrapped - end to end - in TLS handshakes. It is also important to explicitly define the least secure and/or oldest TLS handshake your server will permit. Additionally, make sure that you comment out ssl_prefer_server_ciphers and/or anything like ''ssl_server_dh'' file, both of which are now deprecated. To do this, open up ''/etc/dovecot/conf.d/10-ssl.conf'' and edit the following parameters (updated for Trixie):
  
-<code bash>+<code>
 ssl = required ssl = required
 ssl_server_cert_file = /etc/letsencrypt/live/mail.yourdomain.com/fullchain.pem ssl_server_cert_file = /etc/letsencrypt/live/mail.yourdomain.com/fullchain.pem
Line 274: Line 275:
 Add SASL listener in ''/etc/dovecot/conf.d/10-master.conf'' so that postfix can query dovecot and this socket for user credentials for incoming email. Combined with the configuration ''smtpd_sasl_path=private/auth'' in ''main.cf'', this also allows postfix to authenticate smtp requests. In all cases, dovecot leverages the UNIX users for credentials. Add SASL listener in ''/etc/dovecot/conf.d/10-master.conf'' so that postfix can query dovecot and this socket for user credentials for incoming email. Combined with the configuration ''smtpd_sasl_path=private/auth'' in ''main.cf'', this also allows postfix to authenticate smtp requests. In all cases, dovecot leverages the UNIX users for credentials.
  
-<code bash>+<code>
 service auth { service auth {
   unix_listener /var/spool/postfix/private/auth {   unix_listener /var/spool/postfix/private/auth {
Line 303: Line 304:
 </code> </code>
    
-Lastly, before testing, make sure that you only authorize your mynetworks and properly authenticated users. Failing to do this will mean your server could potentially be used for public relay. This block rejects any unauthenticated senders (besides localhost) and requires senders to be authenticated (or to be localhost) while only permitting incoming email directed to ''@haacksnetworking.org'' or ''@domain.com''Please note that if you continue with the optional configurations later in this tutorial, you will integrate these stanzas into other blocks.+Lastly, before testing, make sure that you only authorize your mynetworks and properly authenticated users. Failing to do this will mean your server could potentially be used for public relay. This block rejects any unauthenticated senders (besides localhost) and requires senders to be authenticated (or to be localhost) while only permitting incoming email directed to ''@haacksnetworking.org'' or ''@domain.com''These blocks will be added later in the tutorial, but/and I bring them up now to emphasize that you should close off the public relay.
  
-<code bash>+<code>
 smtpd_sender_restrictions = permit_mynetworks, permit_sasl_authenticated, permit smtpd_sender_restrictions = permit_mynetworks, permit_sasl_authenticated, permit
 smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
Line 312: Line 313:
 At this time, the bare minimum requirements are in place for sending and receiving email. You can either fire up Thunderbird and field test it all, or use swaks, ncat, telnet, or openssl to test the TLS handshakes. Here's the ones I use in addition to field testing with Thunderbird: At this time, the bare minimum requirements are in place for sending and receiving email. You can either fire up Thunderbird and field test it all, or use swaks, ncat, telnet, or openssl to test the TLS handshakes. Here's the ones I use in addition to field testing with Thunderbird:
  
-<code bash>+<code>
 openssl s_client -connect mail.yourdomain.com:465 openssl s_client -connect mail.yourdomain.com:465
 openssl s_client -connect mail.yourdomain.com:587 openssl s_client -connect mail.yourdomain.com:587
Line 342: Line 343:
 After that, open up ''/etc/postfix/main.cf'' and put the spf policy together with postfix's recipient restrictions. The reason I organize the block this way is because it makes logical sense to group together the criteria under which email is received, whether because it is postfix's general policy and/or your SPF policy. After that, open up ''/etc/postfix/main.cf'' and put the spf policy together with postfix's recipient restrictions. The reason I organize the block this way is because it makes logical sense to group together the criteria under which email is received, whether because it is postfix's general policy and/or your SPF policy.
  
-<code bash+<code> 
-#spf incoming policy and recipient restrictions\ +#spf incoming policy and recipient restrictions 
-policyd-spf_time_limit = 3600\+policyd-spf_time_limit = 3600
 smtpd_recipient_restrictions =  smtpd_recipient_restrictions = 
     permit_mynetworks,      permit_mynetworks, 
Line 393: Line 394:
 Once that's done, it's time to open ''/etc/opendkim.conf'' and setup the configuration for the server's keypair: Once that's done, it's time to open ''/etc/opendkim.conf'' and setup the configuration for the server's keypair:
  
-<code bash>+<code>
 Canonicalization relaxed/simple Canonicalization relaxed/simple
 Mode sv Mode sv
Line 410: Line 411:
 sudo chown -R opendkim:opendkim /etc/opendkim sudo chown -R opendkim:opendkim /etc/opendkim
 sudo chmod 711 /etc/opendkim/keys sudo chmod 711 /etc/opendkim/keys
-sudo mkdir /etc/opendkim/keys/yourdomain.com 
-sudo opendkim-genkey -b 2048 -d yourdomain.com -D /etc/opendkim/keys/yourdomain.com -s default -v 
-sudo chown opendkim:opendkim /etc/opendkim/keys/yourdomain.com/default.private 
-sudo chmod 600 /etc/opendkim/keys/yourdomain.com/default.private 
 </code> </code>
  
 After creating the keys, edit the signing table so that outgoing emails can verify against the keypair. Open up ''/etc/opendkim/signing.table'' and add: After creating the keys, edit the signing table so that outgoing emails can verify against the keypair. Open up ''/etc/opendkim/signing.table'' and add:
  
-<code bash+<code> 
-'*@yourdomain.com default._domainkey.yourdomain.com' +*@yourdomain.com default._domainkey.yourdomain.com 
-'*@*.yourdomain.com default._domainkey.yourdomain.com'+*@*.yourdomain.com default._domainkey.yourdomain.com
 </code> </code>
  
Line 427: Line 424:
   default._domainkey.yourdomain.com yourdomain.com:default:/etc/opendkim/keys/yourdomain.com/default.private   default._domainkey.yourdomain.com yourdomain.com:default:/etc/opendkim/keys/yourdomain.com/default.private
  
-Lastly, instruct you server to trust only localhost and your domain. Open up /etc/opendkim/trusted.hosts and enter:+Lastly, instruct you server to trust only localhost and your domain. Open up ''/etc/opendkim/trusted.hosts'' and enter:
  
-<code bash>+<code>
 127.0.0.1\ 127.0.0.1\
 localhost\ localhost\
Line 435: Line 432:
 </code> </code>
  
-Use the built-in tool to test your DKIM keypair:+Now, cut the keys:
  
-  sudo opendkim-testkey -d yourdomain.com -s default -vvv+  sudo mkdir /etc/opendkim/keys/example.com 
 +  sudo opendkim-genkey -b 2048 -d example.com -D /etc/opendkim/keys/example.com -s default -
 +  sudo chown opendkim:opendkim /etc/opendkim/keys/example.com/default.private 
 +  sudo chmod 600 /etc/opendkim/keys/example.com/default.private
  
 It's now time to build your last DNS record. To do that, you need your public key you created above. To view that on the CLI, run the cat command below. You then take that output to your DNS host of choice, and create a TXT record containing this value. In the subdomain field, you enter your selector, i.e., default._domainkey and in the target, you enter the output of the command below. It's now time to build your last DNS record. To do that, you need your public key you created above. To view that on the CLI, run the cat command below. You then take that output to your DNS host of choice, and create a TXT record containing this value. In the subdomain field, you enter your selector, i.e., default._domainkey and in the target, you enter the output of the command below.
  
   sudo cat /etc/opendkim/keys/yourdomain.com/default.txt   sudo cat /etc/opendkim/keys/yourdomain.com/default.txt
 +
 +Once your DNS record for DKIM is created, use the built-in tool to test the record:
 +
 +  sudo opendkim-testkey -d yourdomain.com -s default -vvv
  
 Okay, now that your keypair for smtp has been created and DNS updated, it's a good time to create the server's DKIM policy. First, you need to give postfix access to opendkim's tooling: Okay, now that your keypair for smtp has been created and DNS updated, it's a good time to create the server's DKIM policy. First, you need to give postfix access to opendkim's tooling:
Line 458: Line 462:
 Now that the server's DKIM policy is configured, it's required to let postfix know of the policy, where the socket is, and how to leverage the policy (reject/accept). Please note that the other policies will add to and/or expand this block, notably the smtpd_milters stanza, which will expand with each additional policy and associated socket that gets added. Open up the main postfix configuration in ''/etc/postfix/main.cf'' and enter the following: Now that the server's DKIM policy is configured, it's required to let postfix know of the policy, where the socket is, and how to leverage the policy (reject/accept). Please note that the other policies will add to and/or expand this block, notably the smtpd_milters stanza, which will expand with each additional policy and associated socket that gets added. Open up the main postfix configuration in ''/etc/postfix/main.cf'' and enter the following:
  
-<code bash>+<code>
 milter_default_action = accept milter_default_action = accept
 milter_protocol = 6 milter_protocol = 6
Line 465: Line 469:
 </code> </code>
  
-The most important line is the uppermost line, which specifies that email should not be rejected as a result of leveraging the policy. Again, this ensures that spam assassin has what it needs to help users sort and organize email, without the possibility of phantom rejections, prohibiting email from having ever arrived in your inbox. After your DKIM keypair and DKIM policy are setup, you can setup a DMARC policy as well. Install the policy with sudo apt install opendmarc. After it installs, open up ''/etc/opendmarc.conf'' and enter the following:+The most important line is the uppermost line, which specifies that email should not be rejected as a result of leveraging the policy. Again, this ensures that spam assassin has what it needs to help users sort and organize email, without the possibility of phantom rejections, prohibiting email from having ever arrived in your inbox. After your DKIM keypair and DKIM policy are setup, you can setup a DMARC policy as well. Install the policy with ''sudo apt install opendmarc''. After it installs, open up ''/etc/opendmarc.conf'' and enter the following:
  
-<code bash>+<code>
 AuthservID OpenDMARC AuthservID OpenDMARC
 TrustedAuthservIDs mail.yourdomain.com TrustedAuthservIDs mail.yourdomain.com
Line 479: Line 483:
 Similarly to the DKIM policy, we need to give postfix permissions to the DMARC tooling and socket. It's also required to add opendmarc to the postfix group: Similarly to the DKIM policy, we need to give postfix permissions to the DMARC tooling and socket. It's also required to add opendmarc to the postfix group:
  
-<code bash>+<code>
 sudo mkdir -p /var/spool/postfix/opendmarc sudo mkdir -p /var/spool/postfix/opendmarc
 sudo chown opendmarc:opendmarc /var/spool/postfix/opendmarc -R sudo chown opendmarc:opendmarc /var/spool/postfix/opendmarc -R
Line 489: Line 493:
 Similarly to SPF and DKIM, it's essential to define the policy in the main postfix configuration file. Open up ''/etc/postfix/main.cf'' and add a block for dmarc. Expand the ''smtpd_milters'' section to include DMARC's socket. Note again how I specify accept so as to ensure proper logging for spam assassin without any possibility of phantom rejections, or email lost at the gates. Similarly to SPF and DKIM, it's essential to define the policy in the main postfix configuration file. Open up ''/etc/postfix/main.cf'' and add a block for dmarc. Expand the ''smtpd_milters'' section to include DMARC's socket. Note again how I specify accept so as to ensure proper logging for spam assassin without any possibility of phantom rejections, or email lost at the gates.
  
-<code bash>+<code>
 #dmarc policy #dmarc policy
 milter_default_action = accept milter_default_action = accept
Line 507: Line 511:
 First, let's add sieve to the local delivery agent over in /etc/dovecot/conf.d/15-lda.conf. This is essential for any time you are manually testing and/or processing emails on the shell, which will utilize the LDA instead of LMTP. This ensures that the local delivery agent is sieve-ready. Head over to ''/etc/dovecot/conf.d/15-lda.conf'' and edit the block: First, let's add sieve to the local delivery agent over in /etc/dovecot/conf.d/15-lda.conf. This is essential for any time you are manually testing and/or processing emails on the shell, which will utilize the LDA instead of LMTP. This ensures that the local delivery agent is sieve-ready. Head over to ''/etc/dovecot/conf.d/15-lda.conf'' and edit the block:
  
-<code bash>+<code>
 protocol lda { protocol lda {
   mail_plugins = $mail_plugins sieve   mail_plugins = $mail_plugins sieve
Line 515: Line 519:
 It is also imperative that LMTP be configured for using sieve as well. Head over to ''/etc/dovecot/conf.d/20-lmtp.conf'' and edit the block: It is also imperative that LMTP be configured for using sieve as well. Head over to ''/etc/dovecot/conf.d/20-lmtp.conf'' and edit the block:
  
-<code bash>+<code>
 protocol lmtp { protocol lmtp {
   mail_plugins = quota sieve   mail_plugins = quota sieve
Line 523: Line 527:
 As with any service, it's essential to configure postfix to use it. So, head to ''/etc/postfix/main.cf'' and add the spam assassin socket to the primary milter. Just as with DKIM and DMARC, you are expanding the existing smtpd_milters clause, not making redundant and/or duplicate stanzas. Head over to ''/etc/postfix/main.cf'' and edit the policy block we created above for DKIM, DMARC, and now spam assassin. As with any service, it's essential to configure postfix to use it. So, head to ''/etc/postfix/main.cf'' and add the spam assassin socket to the primary milter. Just as with DKIM and DMARC, you are expanding the existing smtpd_milters clause, not making redundant and/or duplicate stanzas. Head over to ''/etc/postfix/main.cf'' and edit the policy block we created above for DKIM, DMARC, and now spam assassin.
  
-<code bash>+<code>
 milter_default_action = accept milter_default_action = accept
 milter_protocol = 6 milter_protocol = 6
Line 543: Line 547:
 Sieve is already enabled in dovecot and postfix. That was done up above. Now, the tutorial is discussing how to leverage the sieve syntax or language to get desired user results for incoming email. The most basic way to do this is by setting up a global, or server-wide rule, that filters emails before dovecot, via lmtp, delivers the emails to their final destination. This is done by spam assassin adding custom fields and scoring to incoming email headers. The sieve plugin assesses these headers and then makes the correct determination for the final destination, which dovecot, via lmtp, carries out. In summary, spam assassin does the ranking and header-adding, sieve assesses the spam assassin scores and uses the global sieve rule to make determinations for all users, and finally dovecot+limtp handles the mail delivery. To create a global config for all users in this way, head over to ''/etc/dovecot/conf.d/90-sieve.conf'' and then add/uncomment this line: Sieve is already enabled in dovecot and postfix. That was done up above. Now, the tutorial is discussing how to leverage the sieve syntax or language to get desired user results for incoming email. The most basic way to do this is by setting up a global, or server-wide rule, that filters emails before dovecot, via lmtp, delivers the emails to their final destination. This is done by spam assassin adding custom fields and scoring to incoming email headers. The sieve plugin assesses these headers and then makes the correct determination for the final destination, which dovecot, via lmtp, carries out. In summary, spam assassin does the ranking and header-adding, sieve assesses the spam assassin scores and uses the global sieve rule to make determinations for all users, and finally dovecot+limtp handles the mail delivery. To create a global config for all users in this way, head over to ''/etc/dovecot/conf.d/90-sieve.conf'' and then add/uncomment this line:
  
-  sieve_before = /var/mail/SpamToJunk.sieve+<code> 
 +#sieve_before = /var/mail/SpamToJunk.sieve #old bookworm way and early Trixie
  
-Now, create the file that you just referenced above in ''/var/mail/SpamToJunk.sieve'' and enter the following:+#modern trixie way 
 +sieve_script SpamToJunk { 
 +  type = before 
 +  path = /var/mail/SpamToJunk.sieve 
 +
 +</code>
  
-<code bash>+Now, create the file that you just referenced above in ''/var/mail/SpamToJunk.sieve'' and enter the following and/or any sieve rules you would like. 
 + 
 +<code>
 require "fileinto"; require "fileinto";
 if header :contains "X-Spam-Flag" "YES" { if header :contains "X-Spam-Flag" "YES" {
Line 557: Line 569:
 Load the rule by issuing the ''sudo sievec /var/mail/SpamToJunk.sieve'' command. I would also recommend restarting postfix, dovecot, and spam assassin. Now, the header called X-Spam-Flag is populated with either a Yes or No response by the spam assassin service. Spam assassin determines the yes/no score based on the scoring rules specified in the configuration file. There are many other options and far more complex rules one can establish than this basic example. This is just to get folks started. Here's an example set of rules from the ''/etc/spamassassin/local.cf'' main configuration file: Load the rule by issuing the ''sudo sievec /var/mail/SpamToJunk.sieve'' command. I would also recommend restarting postfix, dovecot, and spam assassin. Now, the header called X-Spam-Flag is populated with either a Yes or No response by the spam assassin service. Spam assassin determines the yes/no score based on the scoring rules specified in the configuration file. There are many other options and far more complex rules one can establish than this basic example. This is just to get folks started. Here's an example set of rules from the ''/etc/spamassassin/local.cf'' main configuration file:
  
-<code bash>+<code>
 report_contact webmaster@yourdomain.com report_contact webmaster@yourdomain.com
 required_score 5.0 required_score 5.0
 report_safe 0 report_safe 0
-ifplugin Mail::SpamAssassin::Plugin::Shortcircuitendif # Mail::SpamAssassin::Plugin::Shortcircuit+ifplugin Mail::SpamAssassin::Plugin::Shortcircuit 
 +endif Mail::SpamAssassin::Plugin::Shortcircuit
 # uncomment the line below once unbound is working (optional) # uncomment the line below once unbound is working (optional)
 # dns_server 127.0.0.1score MISSING_FROM 5.0 # dns_server 127.0.0.1score MISSING_FROM 5.0
Line 589: Line 602:
 This basic configuration shows you where to place the rules/scoring, etc. The names above are referred to technically as symbolic headers and I found the examples above by searching documentation and/or forum hunting. I also spent time reviewing the rules for accuracy and testing with ''sudo -u username sieve-test -C -D -t - /home/username/sieve/roundcube.sieve ./spam-message.eml'' regularly until assassing scored emails properly. It takes time to perfec this, so keep it permissive for starters. Make sure to check logs regularly for errors/clues using ''journalctl -u spamass-milter -u postfix -u dovecot -u opendkim -u opendmarc''. This will help you track what is and is not working for spam assassin and for you, and to thereby adjust/alter/remove scores or change points to fit your use-case and preferences. The whitelist and blacklist options can be scaled as needed and are self-explanatory. This setup is very elegant and helpful for single user email servers and/or tight-knit and close groups of family/people. As more users are needed, the ability of a one-sizefits-all rule to meet everyone's individual needs becomes more and more difficult. For this reason, I chose to install Roundcube in order to leverage the filters feature in the webgui to more easily manage spam rules. Here's how to install Roundcube and use it to manage sieve. This basic configuration shows you where to place the rules/scoring, etc. The names above are referred to technically as symbolic headers and I found the examples above by searching documentation and/or forum hunting. I also spent time reviewing the rules for accuracy and testing with ''sudo -u username sieve-test -C -D -t - /home/username/sieve/roundcube.sieve ./spam-message.eml'' regularly until assassing scored emails properly. It takes time to perfec this, so keep it permissive for starters. Make sure to check logs regularly for errors/clues using ''journalctl -u spamass-milter -u postfix -u dovecot -u opendkim -u opendmarc''. This will help you track what is and is not working for spam assassin and for you, and to thereby adjust/alter/remove scores or change points to fit your use-case and preferences. The whitelist and blacklist options can be scaled as needed and are self-explanatory. This setup is very elegant and helpful for single user email servers and/or tight-knit and close groups of family/people. As more users are needed, the ability of a one-sizefits-all rule to meet everyone's individual needs becomes more and more difficult. For this reason, I chose to install Roundcube in order to leverage the filters feature in the webgui to more easily manage spam rules. Here's how to install Roundcube and use it to manage sieve.
  
-<code bash>+<code>
 cd /var/www cd /var/www
 wget https://github.com/roundcube/roundcubemail/releases/download/1.6.1/roundcubemail-1.6.1-complete.tar.gz wget https://github.com/roundcube/roundcubemail/releases/download/1.6.1/roundcubemail-1.6.1-complete.tar.gz
Line 602: Line 615:
 Obviously, go check the git repo and make sure to download the latest stable version. Roundcube requires a database, so let's set that up: Obviously, go check the git repo and make sure to download the latest stable version. Roundcube requires a database, so let's set that up:
  
-<code bash>+<code>
 sudo mysql -u root sudo mysql -u root
 CREATE DATABASE roundcube DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; CREATE DATABASE roundcube DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
Line 617: Line 630:
 Earlier in the tutorial, you were instructed to setup a vhost for ''mail.haacksnetworking.org'' / ''mail.domain.com''. You already created vhost-mail.conf for the purposes of having an associated A record and website destination, which is helpful for complete validation of email's record health. Now, you are going leverage this certificate for the purpose of encrypting the apache2 front-end, or reverse proxy. Apache receives the public requests, and then the new vhost config, which enables the reverse proxy, forwards those requests upstream to the roundcube service. First, replace ''vhost-mail.conf'' with something like the following: Earlier in the tutorial, you were instructed to setup a vhost for ''mail.haacksnetworking.org'' / ''mail.domain.com''. You already created vhost-mail.conf for the purposes of having an associated A record and website destination, which is helpful for complete validation of email's record health. Now, you are going leverage this certificate for the purpose of encrypting the apache2 front-end, or reverse proxy. Apache receives the public requests, and then the new vhost config, which enables the reverse proxy, forwards those requests upstream to the roundcube service. First, replace ''vhost-mail.conf'' with something like the following:
  
-<code bash>+<code>
 <VirtualHost *:80> <VirtualHost *:80>
       ServerName mail.domain.com       ServerName mail.domain.com
       ServerAdmin email@email.com       ServerAdmin email@email.com
-      DocumentRoot /var/www/roundcube/+      DocumentRoot /var/www/roundcube/ #add public_html for latest RC
       ErrorLog ${APACHE_LOG_DIR}/roundcube_error.log       ErrorLog ${APACHE_LOG_DIR}/roundcube_error.log
       CustomLog ${APACHE_LOG_DIR}/roundcube_access.log combined       CustomLog ${APACHE_LOG_DIR}/roundcube_access.log combined
Line 645: Line 658:
 After that's done, edit the vhost-mail-le.conf file with something like the following: After that's done, edit the vhost-mail-le.conf file with something like the following:
  
-<code bash>+<code>
 <IfModule mod_ssl.c> <IfModule mod_ssl.c>
 <VirtualHost *:443> <VirtualHost *:443>
       ServerName mail.domain.com       ServerName mail.domain.com
       ServerAdmin email@email.com       ServerAdmin email@email.com
-      DocumentRoot /var/www/roundcube/+      DocumentRoot /var/www/roundcube/  #add public_html for latest RC
       ErrorLog ${APACHE_LOG_DIR}/roundcube_error.log       ErrorLog ${APACHE_LOG_DIR}/roundcube_error.log
       CustomLog ${APACHE_LOG_DIR}/roundcube_access.log combined       CustomLog ${APACHE_LOG_DIR}/roundcube_access.log combined
Line 674: Line 687:
 Since the certificate was already created, these configs can just be dropped in to the http vhost and https vhost, respectively. These two vhosts were created earlier by you (http) and subsequently by Let's Encrypt (https). It's now time to connect Roundcube to the database that was created earlier: Since the certificate was already created, these configs can just be dropped in to the http vhost and https vhost, respectively. These two vhosts were created earlier by you (http) and subsequently by Let's Encrypt (https). It's now time to connect Roundcube to the database that was created earlier:
  
-<code bash>+<code>
 cd /var/www/roundcube/config/ cd /var/www/roundcube/config/
 sudo cp config.inc.php.sample config.inc.php sudo cp config.inc.php.sample config.inc.php
Line 688: Line 701:
 In addition to configuring the database and renaming the sample config, it's imperative to edit the plugins block at the end of the primary configuration as well. Add and/or replace the bottom plugin block as follows: In addition to configuring the database and renaming the sample config, it's imperative to edit the plugins block at the end of the primary configuration as well. Add and/or replace the bottom plugin block as follows:
  
-<code bash>+<code>
 $config['plugins'] = [ $config['plugins'] = [
   'archive',   'archive',
Line 698: Line 711:
   'debug_logger',   'debug_logger',
   'emoticons',   'emoticons',
-  'enigma',+  // 'enigma', //
   'filesystem_attachments',   'filesystem_attachments',
   'help',   'help',
Line 727: Line 740:
 At this point, you should be able to log in to mail.haacksnetworking.org / mail.domain.com using a common web browser and your credentials. Your user name is the UNIX user name, i.e., only the handle without the domain. So, my user name is jonathan, for example ... and without haacksnetworking.org at the end. Your password is whatever you adduser yourusername specified when creating your simple UNIX user. At this point, you want to open your web browser and login. Head to the Filters section under Settings. Click the cog at the top and select Edit Filter Set. In the block to the right, replace the contents with the following: At this point, you should be able to log in to mail.haacksnetworking.org / mail.domain.com using a common web browser and your credentials. Your user name is the UNIX user name, i.e., only the handle without the domain. So, my user name is jonathan, for example ... and without haacksnetworking.org at the end. Your password is whatever you adduser yourusername specified when creating your simple UNIX user. At this point, you want to open your web browser and login. Head to the Filters section under Settings. Click the cog at the top and select Edit Filter Set. In the block to the right, replace the contents with the following:
  
-<code bash>+<code>
 require ["fileinto"]; require ["fileinto"];
 # rule:[whitelist] # rule:[whitelist]
Line 755: Line 768:
 As you can see in the asset above, you now have access to refined sieve rules for each user. Once I decided that I needed or wanted user-level spam controls, it no longer made sense for me to manage this exclusively on the CLI. For this reason, I added Roundcube and began managing spam for email accounts individually. When Trixie came out, Dovecot's sieve implementation needed a bit of fine-tuning. First, head to ''/etc/dovecot/conf.d/90-sieve.conf'' and change the block as follows: As you can see in the asset above, you now have access to refined sieve rules for each user. Once I decided that I needed or wanted user-level spam controls, it no longer made sense for me to manage this exclusively on the CLI. For this reason, I added Roundcube and began managing spam for email accounts individually. When Trixie came out, Dovecot's sieve implementation needed a bit of fine-tuning. First, head to ''/etc/dovecot/conf.d/90-sieve.conf'' and change the block as follows:
  
-<code bash>+<code>
 # Comment out the old block: # Comment out the old block:
 #plugin {  #plugin { 
Line 791: Line 804:
 ====== Part V - Setting up pflogsumm ====== ====== Part V - Setting up pflogsumm ======
  
-It's important to be able to monitor how your setup is performing and what is or is not working correctly. No better way to do that than to get some analytics emailed to you each day. To do that, let's install pflogsumm and use rsyslog for logging. Install the packages sudo apt install pflogsumm rsyslog and then create the log rotation rule over in ''/etc/logrotate.d/postfix-log'' and enter the following:+It's important to be able to monitor how your setup is performing and what is or is not working correctly. No better way to do that than to get some analytics emailed to you each day. To do that, let's install pflogsumm and use rsyslog for logging. Install the packages ''sudo apt install pflogsumm'' rsyslog and then create the log rotation rule over in ''/etc/logrotate.d/postfix-log'' and enter the following:
  
-<code bash>+<code>
 /var/log/mail.log { /var/log/mail.log {
   missingok   missingok
Line 806: Line 819:
 You need to make sure to comment out or remove #mail.log from ''/etc/logrotate.d/rsyslog''. This is done so as to replace the default rotation. Now, I will create a script to run pflogsumm on the archives. Create ''/usr/local/bin/pflog-run.sh'' or something similar and enter the following: You need to make sure to comment out or remove #mail.log from ''/etc/logrotate.d/rsyslog''. This is done so as to replace the default rotation. Now, I will create a script to run pflogsumm on the archives. Create ''/usr/local/bin/pflog-run.sh'' or something similar and enter the following:
  
-<code bash>+<code>
 #!/bin/sh #!/bin/sh
 #/usr/sbin/logrotate -f /etc/logrotate.d/postfix-log #/usr/sbin/logrotate -f /etc/logrotate.d/postfix-log
Line 831: Line 844:
 Some of the spam assassin tooling that uses RBL will not work unless you use your own recursive DNS instead of, for example, ''8.8.8.8''. It should also be noted that using your own DNS is better from both a speed and privacy perspective, so setting this up kills two birds with one proverbial stone. I have a separate tutorial about this on my blog and it has an associated wiki entry as well. As you review these tutorials, please remember that unbound can be used for both LAN and WAN settings. For this tutorial, an email server, one would use the WAN configuration. Here's a concise recap of how to set that up, which you will do directly on the email server. First, let's install unbound sudo apt install unbound, by far the most hassle free way to do recursive DNS. Once it is up and running, it's time to put a WAN-based config in place in ''/etc/unbound/unbound.conf''. In that file, add the following: Some of the spam assassin tooling that uses RBL will not work unless you use your own recursive DNS instead of, for example, ''8.8.8.8''. It should also be noted that using your own DNS is better from both a speed and privacy perspective, so setting this up kills two birds with one proverbial stone. I have a separate tutorial about this on my blog and it has an associated wiki entry as well. As you review these tutorials, please remember that unbound can be used for both LAN and WAN settings. For this tutorial, an email server, one would use the WAN configuration. Here's a concise recap of how to set that up, which you will do directly on the email server. First, let's install unbound sudo apt install unbound, by far the most hassle free way to do recursive DNS. Once it is up and running, it's time to put a WAN-based config in place in ''/etc/unbound/unbound.conf''. In that file, add the following:
  
-<code bash>+<code>
 server: server:
   # Bind to localhost only   # Bind to localhost only
Line 910: Line 923:
 Next, open up ''/etc/logrotate.d/unbound'' and enter the rotation logic: Next, open up ''/etc/logrotate.d/unbound'' and enter the rotation logic:
  
-<code bash>+<code>
 /var/log/unbound/unbound.log { /var/log/unbound/unbound.log {
 daily daily
Line 924: Line 937:
 Next, disable systemd's resolver: Next, disable systemd's resolver:
  
-<code bash>+<code>
 systemctl disable --now unbound-resolvconf.service systemctl disable --now unbound-resolvconf.service
 sed -Ei 's/^unbound_conf=/#unbound_conf=/' /etc/resolvconf.conf sed -Ei 's/^unbound_conf=/#unbound_conf=/' /etc/resolvconf.conf
Line 974: Line 987:
 In the .xml file, put the following, adjusting for ''domain.com'': In the .xml file, put the following, adjusting for ''domain.com'':
  
-<code bash>+<code>
 <?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
 <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006"> <Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
Line 1033: Line 1046:
 The options below are results of small things that came up while using my own server over the last 5 years or so. First, I noticed that clients would not set up the standard directories and it turns out you need to tell dovevot to do that over in ''/etc/dovecot/conf.d/15-mailboxes.conf'' by enabling the ''auto = create'' in the folder blocks for which you desire auto-population. The options below are results of small things that came up while using my own server over the last 5 years or so. First, I noticed that clients would not set up the standard directories and it turns out you need to tell dovevot to do that over in ''/etc/dovecot/conf.d/15-mailboxes.conf'' by enabling the ''auto = create'' in the folder blocks for which you desire auto-population.
  
-<code bash>+<code>
 mailbox Drafts { mailbox Drafts {
   auto = create   auto = create
Line 1050: Line 1063:
  
 Once you edited the file, load the changes with sudo postmap /etc/postfix/virtual_alias. Once you edited the file, load the changes with sudo postmap /etc/postfix/virtual_alias.
-Another thing I researched when reviewing Linux Babe's tutorial, but ultimately rejected doing was body and header inspection. To do that, install postfix's regular expression tooling with sudo apt install postfix-pcre and then edit the main configuration ''/etc/postfix/main.cf'' and enter the following stanzas:+Another thing I researched when reviewing Linux Babe's tutorial, but ultimately rejected doing was body and header inspection. To do that, install postfix's regular expression tooling with ''sudo apt install postfix-pcre'' and then edit the main configuration ''/etc/postfix/main.cf'' and enter the following stanzas:
  
   header_checks = pcre:/etc/postfix/header_checks   header_checks = pcre:/etc/postfix/header_checks
Line 1130: Line 1143:
 I rewrote the mail server tutorial for the presentation [[https://tech.haacksnetworking.org/2025/06/10/your-email-your-rules-self-hosting-simplified/|Your Email, Your Rules: Self-Hosting Simplified]]. The SeaGL presentation can be found [[https://pretalx.seagl.org/2025/talk/VLM7AS/|on their calendar]]. I rewrote the mail server tutorial for the presentation [[https://tech.haacksnetworking.org/2025/06/10/your-email-your-rules-self-hosting-simplified/|Your Email, Your Rules: Self-Hosting Simplified]]. The SeaGL presentation can be found [[https://pretalx.seagl.org/2025/talk/VLM7AS/|on their calendar]].
  
- --- //[[alerts@haacksnetworking.org|oemb1905]] 2026/07/28 19:51//+ --- //[[alerts@haacksnetworking.org|oemb1905]] 2026/08/31 00:07//
computing/mailserver-trixie.1785512400.txt.gz · Last modified: by oemb1905