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 [2025/11/05 04:34] oemb1905computing:mailserver-trixie [2026/05/31 05:16] (current) oemb1905
Line 10: Line 10:
  
 ------------------------------------------- -------------------------------------------
 +
 +  * [[https://nextcloud.haacksnetworking.org/index.php/s/s6wAL5p7jKHc9Db|Slides]]
 +  * [[https://content.haacksnetworking.org/w/nsMwnJhLnfMrs17W5cAdWg|SeaGL Presentation]]
 +  * [[https://tech.haacksnetworking.org/2025/06/10/your-email-your-rules-self-hosting-simplified/|Blog Post]]
  
 ====== Introduction ====== ====== Introduction ======
 ~~NOTOC~~ ~~NOTOC~~
  
-Contrary to popular belief, it's entirely possible to self-host email servers. Like others, I listened to the propaganda that "it's no longer feasible to self-host email" or "it's too complex and servers won't respect your mail health anyway" or other such explanations. In 2014, while running workshops for students on security and networking, one of my student'parent (a Ruby dev) said he agreed with me and that as far as he knew, postfix was fairly straightforward. From that day forward, I decided to approach self-hosting email servers the same way as I approach self-hosting any instance ([[https://nextcloud.haacksnetworking.org|Nextcloud]], [[https://music.outsidebox.club|Airsonic]], [[https://repo.haacksnetworking.org|Gitlab]], etc.). I decided that it must be entirely possible and that it was merely a question of how. So, from 2014 - 2018, from Wheezy to Buster, I began using my spare hacking time to create my first smtp relay in 2015 and later setup my first proper email server in 2018. As it turns out, it is relatively straight forward to setup a functional base server. Getting the ecosystem to respect your email, however, takes a little tender care. It's entirely doable though: [[https://mail.haacksnetworking.org|My Business Webmail]].+Contrary to popular belief, it's entirely possible to self-host email servers. Like others, I listened to the propaganda that "it's no longer feasible to self-host email" or "it's too complex and servers won't respect your mail health anyway" or other such explanations. In 2014, while running workshops for students on security and networking, one of my student'parents (a Ruby dev) said he agreed with me and that as far as he knew, postfix was fairly straightforward. From that day forward, I decided to approach self-hosting email servers the same way as I approach self-hosting any instance ([[https://nextcloud.haacksnetworking.org|Nextcloud]], [[https://music.outsidebox.club|Airsonic]], [[https://repo.haacksnetworking.org|Gitlab]], etc.). I decided that it must be entirely possible and that it was merely a question of how. So, from 2014 - 2018, from Wheezy to Buster, I began using my spare hacking time to create my first smtp relay in 2015 and later setup my first proper email server in 2018. As it turns out, it is relatively straight forward to setup a functional base server. Getting the ecosystem to respect your email, however, takes a little tender care. It's entirely doable though: [[https://mail.haacksnetworking.org|My Business Webmail]].
  
 I did not migrate my personal emails and/or business infrastructure until 2021. During 2018 - 2021, I would intermittently test, identify and fix failures, breakages, and read up more on DNS records and worked to gain a deeper understanding of the ecosystem. I spent countless hobbyist hours reviewing forums, Stack Exchange, and, of course, Linux Babe. I also shared notes and perspectives with a local colleague and fellow IT/networking professional, [[http://schaeferconsulting.com|Schaefer Consulting]]. I was not in any rush to migrate, and I also wanted to develop a system that balanced complexity with reliability/convenience. After initially developing a [[https://wiki.haacksnetworking.org/doku.php?id=computing:exim4|mail relay recipe]] both under/alongside Schaefer and on my own, I ultimately decided to switch to postfix for incoming/outgoing, or what I call a proper email server (not merely a relay or send-only MTA). This was pure chance, namely, as the first server recipe I got working for IMAP/dovecot was on my postfix VPS not the exim4 VPS, so I simply got motivated to keep fixing it until it all worked. Until that time, circa 2018, I was tinkering back and forth on two different VPSs, one with exim4 and another with postfix, testing different strategies. To this day, I continue to use exim4 for relaying email from hosts behind NAT. For proper email servers, I currently use postfix. In getting everything to work, my goal was to only increase complexity if/when it was required for proper functioning. For this reason, I chose to use simple UNIX users. I did not migrate my personal emails and/or business infrastructure until 2021. During 2018 - 2021, I would intermittently test, identify and fix failures, breakages, and read up more on DNS records and worked to gain a deeper understanding of the ecosystem. I spent countless hobbyist hours reviewing forums, Stack Exchange, and, of course, Linux Babe. I also shared notes and perspectives with a local colleague and fellow IT/networking professional, [[http://schaeferconsulting.com|Schaefer Consulting]]. I was not in any rush to migrate, and I also wanted to develop a system that balanced complexity with reliability/convenience. After initially developing a [[https://wiki.haacksnetworking.org/doku.php?id=computing:exim4|mail relay recipe]] both under/alongside Schaefer and on my own, I ultimately decided to switch to postfix for incoming/outgoing, or what I call a proper email server (not merely a relay or send-only MTA). This was pure chance, namely, as the first server recipe I got working for IMAP/dovecot was on my postfix VPS not the exim4 VPS, so I simply got motivated to keep fixing it until it all worked. Until that time, circa 2018, I was tinkering back and forth on two different VPSs, one with exim4 and another with postfix, testing different strategies. To this day, I continue to use exim4 for relaying email from hosts behind NAT. For proper email servers, I currently use postfix. In getting everything to work, my goal was to only increase complexity if/when it was required for proper functioning. For this reason, I chose to use simple UNIX users.
Line 22: Line 26:
 Results: [[https://www.mail-tester.com/test-8hia4koy2|Mail Tester Results]] Results: [[https://www.mail-tester.com/test-8hia4koy2|Mail Tester Results]]
  
-In my case, the servers I built are on VMs that reside on a [[https://wiki.haacksnetworking.org/doku.php?id=computing:vmserver|custom virtualization stack stack]] that uses virsh and kvm/qemu on a Debian SuperMicro server (Xeon Silvers) that I co-locate at Brown Rice data center. My virtualization stack has roughly 30 VMs at present, with the host boasting over 500 virtual cores and 384GB of RAM. My primary business email server, for haacksnetworking.org, is an 8-core Virtual Machine with 8GB of RAM that resides on that same SuperMicro. Remember, though, as long as your VPS host provides PTR (reverse DNS) access, you can do this on a very basic ($5-$10 per month) VPS. My Taos server is also the proud host of the following services:+In my case, the servers I built are on VMs that reside on a [[https://wiki.haacksnetworking.org/doku.php?id=computing:vmserver|custom virtualization stack]] that uses virsh and kvm/qemu on a Debian SuperMicro server (Xeon Silvers) that I co-locate at Brown Rice data center. My virtualization stack has roughly 30 VMs at present, with the host boasting over 500 virtual cores and 384GB of RAM. My primary business email server, for haacksnetworking.org, is an 8-core Virtual Machine with 8GB of RAM that resides on that same SuperMicro. Remember, though, as long as your VPS host provides PTR (reverse DNS) access, you can do this on a very basic ($5-$10 per month) VPS. My Taos server is also the proud host of the following services:
  
   * **Mastodon**: [[https://gnulinux.social|GNU/Linux Social]]   * **Mastodon**: [[https://gnulinux.social|GNU/Linux Social]]
Line 65: Line 69:
 The first part of the tutorial, i.e., setting up DNS records, is now complete. It's now time to address installation and setup of postfix+dovecot. Do not proceed to this part of the tutorial unless you completed the DNS steps above. Put simply, postfix+dovecot both require proper DNS resolution to work. The only exception to this rule is for our DKIM record, which requires us first configuring the server before we cut the keypair and create the associated TXT record. Other than that, make sure DNS is ready to go before proceeding. Okay, let's ssh into the VM/VPS and do the following: The first part of the tutorial, i.e., setting up DNS records, is now complete. It's now time to address installation and setup of postfix+dovecot. Do not proceed to this part of the tutorial unless you completed the DNS steps above. Put simply, postfix+dovecot both require proper DNS resolution to work. The only exception to this rule is for our DKIM record, which requires us first configuring the server before we cut the keypair and create the associated TXT record. Other than that, make sure DNS is ready to go before proceeding. Okay, let's ssh into the VM/VPS and do the following:
  
-  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 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
  
Line 103: Line 107:
 {{ :computing:postfix7.png?direct&600 |}} {{ :computing:postfix7.png?direct&600 |}}
  
-For the mail name, put haacksnetworking.org or domain.com. Leave most fields at default values; make sure other destinations populated correctly. Do not select All unless you have properly configured records and interfaces for both. Only select and specify what you have records for, otherwise they will fail if they hop to the unsupported protocol. I speak from direct experience. +For the mail name, put ''haacksnetworking.org'' or ''domain.com''. Leave most fields at default values; make sure other destinations populated correctly. Do not select All unless you have properly configured records and interfaces for both. Only select and specify what you have records for, otherwise they will fail if they hop to the unsupported protocol. I speak from direct experience. Now that a basic postfix setup is in place, you can optionally install a firewall. If you choose to do this, I recommend the Uncomplicated Firewall, or ufw. Install it and open up all the ports required by postfix+dovecot and no others.
- +
-Now that a basic postfix setup is in place, you can optionally install a firewall. If you choose to do this, I recommend the Uncomplicated Firewall, or ufw. Install it and open up all the ports required by postfix+dovecot and no others.+
  
   sudo apt install ufw   sudo apt install ufw
Line 165: Line 167:
 #smtpd_tls_security_level=may #smtpd_tls_security_level=may
 #smtp_tls_CApath=/etc/ssl/certs #smtp_tls_CApath=/etc/ssl/certs
-smtp_tls_security_level=may+#smtp_tls_security_level=may
 #smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache #smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
  
Line 171: Line 173:
 smtpd_tls_cert_file=/etc/letsencrypt/live/mail.haacksnetworking.org/fullchain.pem smtpd_tls_cert_file=/etc/letsencrypt/live/mail.haacksnetworking.org/fullchain.pem
 smtpd_tls_key_file=/etc/letsencrypt/live/mail.haacksnetworking.org/privkey.pem smtpd_tls_key_file=/etc/letsencrypt/live/mail.haacksnetworking.org/privkey.pem
-smtpd_tls_security_level=may+smtpd_tls_security_level = may
 smtpd_tls_loglevel = 1 smtpd_tls_loglevel = 1
 smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
Line 187: Line 189:
  
 # F) Primary Block; additional services go below or in dedicated config # F) Primary Block; additional services go below or in dedicated config
-smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination+smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated reject_unauth_destination
 myhostname = mail.haacksnetworking.org myhostname = mail.haacksnetworking.org
 alias_maps = hash:/etc/aliases alias_maps = hash:/etc/aliases
Line 276: Line 278:
 </code> </code>
  
 +If you have IMAP folders with lots of email, consider adjusting the ''imap'' block in ''/etc/dovecot/conf.d/10-master.conf''. Make sure you are not editing ''imap-login'', but rather ''service imap {''. This increases virtual memory and processes for dovecot.
 +
 +<code>
 +service imap {
 +    vsz_limit = 4096M
 +    process_limit = 2048
 +}
 +</code>
 +
 +Similarly, for large IMAP folders, you also want to adjust IMAP's logic to provide 256k (vs. 64k) to each single IMAP command. Additionally, make sure that you raise simultaneous connections from a single IP to 25, 50, or more, so your client can handle more in parallel. Lastly, adjust the idle time notification as well for less latency and snappier results. The default is 2mins, but if this is your server only, you can safely go as low as 15s or 30s. This lowering not only helps Roundcube, but helps Delta Chat and other email clients as well.
 +
 +<code>
 +protocol imap {
 +    imap_max_line_length = 256k
 +    mail_max_userip_connections = 50
 +    imap_idle_notify_interval = 15s
 +}
 +</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''. Please note that if you continue with the optional configurations later in this tutorial, you will integrate these stanzas into other blocks.
  
Line 538: Line 559:
 Download [[https://repo.haacksnetworking.org/haacknet/haackingclub/-/blob/master/configs/mailservers/spamassassin/local.cf?ref_type=heads|local.cf]]:  Download [[https://repo.haacksnetworking.org/haacknet/haackingclub/-/blob/master/configs/mailservers/spamassassin/local.cf?ref_type=heads|local.cf]]: 
  
-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 ''spamassassin --D < example.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 bash>
Line 632: Line 653:
 <$config['db_dsnw'] = 'mysql://roundcube:pass@localhost/roundcube';> <$config['db_dsnw'] = 'mysql://roundcube:pass@localhost/roundcube';>
 <$config['des_key'] = 'rcmail-!24ByteDESkey*Str';? <$config['des_key'] = 'rcmail-!24ByteDESkey*Str';?
-<$config['imap_host'] = 'startls://domain.com:143';>+<$config['imap_host'] = 'ssl://mail.domain.com:993';>
 <$config['smtp_host'] = 'tls://mail.domain.com:587';> <$config['smtp_host'] = 'tls://mail.domain.com:587';>
 <$config['enable_spellcheck'] = true;> <$config['enable_spellcheck'] = true;>
Line 718: Line 739:
   active_path = ~/.dovecot.sieve   active_path = ~/.dovecot.sieve
 } }
 +</code>
 +
 +Lastly, Roundcube is a web gui. So, it is also important that your php handler is optimized and configured with more memory and extra fpm servers. I make the following php adjustments for snappier response time. In ''/etc/php/8.4/fpm/php.ini'', input:
 +
 +<code>
 +memory_limit = 1G
 +max_execution_time = 300
 +max_input_time = 300
 +</code>
 +
 +And, finally, in ''/etc/php/8.4/fpm/pool.d/www.conf'', I adjust the servers to help account for simultaneous connections:
 +
 +<code>
 +pm = dynamic
 +pm.max_children = 200
 +pm.start_servers = 20
 +pm.min_spare_servers = 10
 +pm.max_spare_servers = 20
 +pm.max_requests = 500
 +request_terminate_timeout = 0
 </code> </code>
  
Line 960: Line 1001:
 If your client does not honor autodiscovery and/or you choose to enter manually, use the port recommendations and protocols above. Other options also exist. If your client does not honor autodiscovery and/or you choose to enter manually, use the port recommendations and protocols above. Other options also exist.
  
-====== Part VII - Additional Options ======+====== Part VIII - Additional Options ======
  
 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.
Line 997: Line 1038:
   sudo postmap /etc/postfix/body_checks   sudo postmap /etc/postfix/body_checks
  
-Before, during, and after the creation of this email server tutorial, I've had a need to use messaging/chat apps. I've used them all, whether Signal, Telegram, Nextcloud Talk, and loads of more boutique and experimental platforms. After years of debate with friends and colleagues, a friend suggested [[https://delta.chat/en/download|Delta Chat]], a chat app that - wait for it - uses email servers for chatting. Given my email server was already set up and purring, I gave it a try and I've used it since for family and business conversations, that is, small and trusted audiences. If you get through this tutorial, it'worth giving it a try! Just edit ''/etc/dovecot/conf.d/20-imap.conf'' and ensure the ''imap_idle_notify_interval = 1min'' idle notify interval is 1 or minsFor small use cases, increasing this frequency will harm nothing and improve the snappiness of the Delta Chat experienceEverything else is already perfectly compatible with Delta ChatJust export and save your keys!+Before, during, and after the creation of this email server tutorial, I've had a need to use messaging/chat apps. I've used them all, whether Signal, Telegram, Nextcloud Talk, and loads of more boutique and experimental platforms. After years of debate with friends and colleagues, a friend suggested [[https://delta.chat/en/download|Delta Chat]], a chat app that - wait for it - uses email servers for chatting. Given my email server was already set up and purring, I gave it a try and I've used it since for family and business conversations, that is, small and trusted audiences. All of the settings in this tutorial work perfectly for Delta Chat'classic email server option. The only setting you might want to tinker with if you use the server for Delta Chat is the ''imap_idle_notify_interval'' in ''/etc/dovecot/conf.d/20-imap.conf'' which I covered above. 
 + 
 +-- -- -- -- Miscellaneous Issues -- -- -- -- 
 + 
 +To test sieve's logic and/or to test spamassassin's scoring, download email (.eml) from Roundcube that did not behave as planned. Once you have the email, ''ssh'' into your mail server's simple unix user's mail directory and do the following: 
 + 
 +  su - username 
 +  cd ~/sieve 
 +  spamassassin -t -D < Amazon1.eml  
 +  # this ^^ gives you the headers / spamassassin scores in stdout 
 +  sieve-test -D -e roundcube.sieve Amazon3.eml  
 +  # this ^^ tests your sieve logic to see if the email goes in ham or spam 
 + 
 +In the output that follows, look for something like the below. I put example output for each command above, respectively: 
 + 
 +<code> 
 +Content analysis details:   (16.9 points, 5.0 required) 
 + 
 + pts rule name              description 
 +---- ---------------------- -------------------------------------------------- 
 + 0.8 DKIM_ADSP_ALL          No valid author signature, domain signs all mail 
 + 0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record 
 +-0.0 SPF_PASS               SPF: sender matches SPF record 
 + 0.2 BAYES_999              BODY: Bayes spam probability is 99.9 to 100% 
 +                            [score: 1.0000] 
 + 3.5 BAYES_99               BODY: Bayes spam probability is 99 to 100% 
 +                            [score: 1.0000] 
 + 2.0 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail 
 +                            domains are different 
 + 2.1 HTML_IMAGE_ONLY_12     BODY: HTML: images with 800-1200 bytes of words 
 + 0.0 HTML_EXTRA_CLOSE       BODY: HTML contains far too many close tags 
 + 0.1 MIME_HTML_ONLY         BODY: Message only has text/html MIME parts 
 + 0.0 HTML_MESSAGE           BODY: HTML included in message 
 + 2.0 RDNS_DYNAMIC           Delivered to internal network by host with 
 +                            dynamic-looking rDNS 
 + 0.0 HTML_SHORT_LINK_IMG_2  HTML is very short with a linked image 
 + 3.6 HTML_TAG_BALANCE_CENTER Malformatted HTML 
 + 0.4 HTML_MIME_NO_HTML_TAG  HTML-only message, but there is no HTML tag 
 + 1.0 GOOG_STO_IMG_HTML      Apparently using google content hosting to avoid 
 +                            URIBL 
 + 1.2 DMARC_QUAR             DMARC quarantine policy 
 + 0.0 T_REMOTE_IMAGE         Message contains an external image 
 +</code>
  
-If other quirky issues come up, I'll besure to add them right here!+<code> 
 +sieve-test: Debug: sieve: Commit fileinto action 
 +sieve-test: Debug: sieve: fileinto action: Commit storing into mailbox 'Junk' 
 +sieve-test: Info: sieve: msgid=<20250@psyb.info>: fileinto action: stored mail into mailbox 'Junk' 
 +info: msgid=<20250@psyb.info>: fileinto action: stored mail into mailbox 'Junk'
 +sieve-test: Debug: sieve: Finished finalizing actions (status=ok, keep=none, committed=yes) 
 +</code>   
  
-====== Part VIII - What's next? ======+====== Part IX - What's next? ======
  
 Next Steps Next Steps
Line 1013: Line 1102:
 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]] 2025/11/05 03:41//+ --- //[[alerts@haacksnetworking.org|oemb1905]] 2026/05/31 05:13//
computing/mailserver-trixie.1762317297.txt.gz · Last modified: by oemb1905