A practically secure mail setup - counter spammers with Linux mail-servers
Who needs this?
Yay, free mails in a sustaining setup!
This is a tutorial on how to practically setup a relatively secure mail-server.
It's supposed to be as minimal as reasonable nowadays, and for a small amount of users (standard root server, max. ~20 mail-users at once). Without a real DB backend. It doesn't scale business-needs, however it's supposed to be extendable.
The reference system this setup works with is a Debian GNU Linux with:
- Maildrop - instead of Procmail for more flexible filter rulesets
- Postfix and Postfix-pcre ~ 2.7
- Courier-IMAP, -imap-ssl, -authlib, -authlib-userdb, pop3-stuff ... ~4.6, courier-base ~ 0.63
- Dspam ~3.6.8
You won't need the exact versions of course. But older versions may lack some features. Use a port system to install these components including their dependencies. Use the port system to update them regularly. That'll save a lot of the compiling and recompiling, patching and extending hassle.
This tutorial-article is also about some background information. That's important for monitoring and troubleshooting aspects of the mail-system.
If you're an experienced administrator, you may want to read another tutorial, that includes database stuff and a separate authentication like LDAP. But if you realize any mistakes or options to optimize this, please notify me at wishi@sandokai.eu. Hopefully I'll get your eMails.
As a side-note I may add that most tutorials covering Mail-server setups on Unix-like operating systems are outdated or very specific. This is supposed to be an approach to generally copy and use. It comes with a reference configuration on GitHub and this documentation.
Postfix - and why Maildrop is necessary
Basically
Postfix transfers mails. It uses SMTP to do that. You send mails to your SMTP server, and it sends them to the recipients SMTP server - which accepts the the eMails.
To retrieve Mails you send, your SMTP server uses port 587 e. g. with TLS, because SMTP is a bare TCP protocol that doesn't wrap any packets with encryption. If you'd authenticate at your server without TLS, you'd need a new password after each login. Which is not manageable of course.
Requirements for Postfix
Postfix needs rules in order to know whether to accept mails or not.
- You don't want to get freaking Spam mails.
- And you don't want your SMTP server to help sending Spam around either.
- Of course you want to secure your Mail-server because many services it provides run with high privileges, processing your (users) information. Mails spools normally hold a bunch of login credentials. So it's not just about your stuff.
Problems
The modular aspect of the eMail system is cumbersome to monitor and maintain. That's the reason for all this background blabla:
- Postfix gets Mail
- -> handles mail to our Dspam AntiSpam Filter. It will just mark spam in the mail-headers.
- -> handles mail to Mailfilter. Marked Spam messages will be sorted into TeX Embedding failed!{data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:TeX Embedding failed!nexthop TeX Embedding failed!recipient
submission inet n - - - - smtpd
-o smtpd_enforce_tls=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
[/geshifilter-code]
First of all we accept incoming eMail via 25 - smtp. You could should eliminate smtpd's -v flag and reactivate a chroot environment later, but for debugging reasons it's very practical like this.Postfix will pipe incoming mails to dspam-retrain, which is runs as a script:
- #339933;"># Get arguments
- #339933;"><em class#339933;">=#ff0000;">"error"#339933;">>TeX Embedding failed#339933;">!</em#339933;">>ARGV#009900;">[#0000dd;">0#009900;">] #339933;">|| die#339933;">; shift#339933;">;
- #339933;"><em class#339933;">=#ff0000;">"error"#339933;">>TeX Embedding failed#339933;">!</em#339933;">>ARGV#009900;">[#0000dd;">0#009900;">] #339933;">|| die#339933;">; shift#339933;">;
- #339933;"><em class#339933;">=#ff0000;">"error"#339933;">>TeX Embedding failed#339933;">!</em#339933;">>ARGV#009900;">[#0000dd;">0#009900;">] #339933;">|| die#339933;">; shift#339933;">;
- #b1b100;">if #009900;">(#339933;"><em class#339933;">=#ff0000;">"error"#339933;">>TeX Embedding failed#339933;">!</em#339933;">>user #339933;">= #339933;"><em class#339933;">=#ff0000;">"error"#339933;">>TeX Embedding failed#339933;">!</em#339933;">>sender #339933;">=~ #339933;">/^#009900;">(\w#339933;">+#009900;">)@#339933;">/#009900;">) #009900;">{
- #339933;"># username is in the sender
- #339933;"><em class#339933;">=#ff0000;">"error"#339933;">>TeX Embedding failed#339933;">!</em#339933;">>#0000dd;">1#339933;">;
- #009900;">} #b1b100;">else #009900;">{
- print #ff0000;">"Can't determine user#000099; font-weight: bold;">\n"#339933;">;
- #009900;">}
- #339933;"># Pull out DSPAM signatures and send them to the dspam program
- #b1b100;">while #009900;">(#339933;"><>#009900;">) #009900;">{
- #b1b100;">if #009900;">(#009900;">(#339933;">! #339933;"><em class#339933;">=#ff0000;">"error"#339933;">>TeX Embedding failed#339933;">!</em#339933;">>subj #339933;">= #339933;"><em class#339933;">=#ff0000;">"error"#339933;">>TeX Embedding failed#339933;">!</em#339933;">>class #339933;">--user #339933;"><em class#339933;">=#ff0000;">"error"#339933;">>TeX Embedding failed#339933;">!</em#339933;">>subj\n#339933;"><em class#339933;">=#ff0000;">"error"#339933;">>TeX Embedding failed#339933;">!</em#339933;">>class #339933;">--user #339933;"><em class#339933;">=#ff0000;">"error"#339933;">>TeX Embedding failed#339933;">!</em#339933;">>subj\n#339933;"><em class#339933;">=#ff0000;">"error"#339933;">>TeX Embedding failed#339933;">!</em#339933;">>#009900;">{recipient#009900;">}
Maildrop is way more sophisticated than Procmail - in my humble opinion. It works very well with Courier. The Mailfilter Syntax has powerful options, as you'll see. You have to include the MDA at this point already.Taking a look at the main.cf again:
- virtual_transport #339933;">= maildrop
- home_mailbox #339933;">= Maildir#339933;">/
Postfix could handle all incoming mail directly into the Maildir. But only without server-sided filtering.Setup Dspam
Dpsam and not spamassasin. The philosophy here is different. Dspam is a statistical approach, and not a collection of wicked Perl scripts (spmassasin 2010 bug). It utilizes ClamAV as an OpenSource AntiVirus engine. You can add custom signatures and stuff, therefore.
On Debian Dspam almost configures automatically. My configuration is at GitHub. You should hardend the configuration if you get Spam, which very much depends on your domain and server location.
Leave Dspam's defaults: the Graham Burton algorithm is more than recommendable. Actions it should perform are defined in the /etc/dspam/dspam.conf, too:
- Preference #ff0000;">"spamAction=tag"
- Preference #ff0000;">"signatureLocation=message" #339933;"># 'message' or 'headers'
- Preference #ff0000;">"showFactors=on"
We just tag Spam.If you take a look at Postfix's master.cf, you'll realize, that I added a Dspam listener on 127.0.0.1:10024.
You see this reflected in the configuration at this point. Dspam accepts mails to process with its client. The server listens on:
- ServerPort #0000dd;">11124
Dspam shouldn't be trained with test-spam. Because - as I mentioned - Spam you receive is depending on your location and domain. And it's not like we'd need an extra amount of spam nowadays. Have it create stats based on your needs.
Greylisting
Installing Greylisting is easy:
- apt#339933;">-get install postgrey
And change the config in main.cf:
- smtpd_recipient_restrictions #339933;">=
- permit_sasl_authenticated#339933;">,
- permit_mynetworks#339933;">,
- reject_unauth_destination#339933;">,
- reject_rbl_client ix.#202020;">dnsbl.#202020;">manitu.#202020;">net#339933;">,
- check_policy_service inet#339933;">:127.0.0.1#339933;">:#0000dd;">60000
This is an extra security setup that is not in my GitHub configs.
Before you deploy that you should have a test-phase and generally it may not be the best solution to use blacklists and Greylisting, because of false-positives.
It's simply your decision.Here's a fitting /ect/default/postgrey:
- #339933;"># postgrey startup options, created for Debian
- #339933;"># you may want to set
- #339933;"># --delay=N how long to greylist, seconds (default: 300)
- #339933;"># --max-age=N delete old entries after N days (default: 35)
- #339933;"># see also the postgrey(8) manpage
- POSTGREY_OPTS#339933;">=#ff0000;">"--inet=127.0.0.1:60000 #000099; font-weight: bold;">\
- --whitelist-clients=/etc/postfix/postgrey_whitelist_clients #000099; font-weight: bold;">\
- --whitelist-recipients=/etc/postfix/postgrey_whitelist_recipients #000099; font-weight: bold;">\
- --greylist-action=451 --delay=420 --max-age=40 \
- #ff0000;"> --lookup-by-subnet --auto-whitelist-clients=10"
- #339933;"># the --greylist-text commandline argument can not be easily passed through
- #339933;"># POSTGREY_OPTS when it contains spaces. So, insert your text here:
- POSTGREY_TEXT#339933;">=#ff0000;">".oO(mmmmaeehh nom nom nom)"
To get some stats:
- sudo mkdir #339933;">/var#339933;">/spool#339933;">/postfix#339933;">/postgrey
- sudo chown mail#339933;">:mail #339933;">/var#339933;">/spool#339933;">/postfix#339933;">/postgrey
And add to the postgrey config:
- #339933;">--user#339933;">=filter #339933;">--group#339933;">=mail
Include Maildrop
Being on mailing-lists requires filters. Set the permission of your ~/.mailfilter accordingly (700). It won't work otherwise. That sucks if you've got no-tech users. On the other hand no-tech users don't use server-sided filters.
The Mailfilter syntax however is pretty keen:
- MD#339933;">=#ff0000;">"/home/wishi/Maildir"
- #339933;"># spam handler
- #b1b100;">if #009900;">(#339933;">/^X#339933;">-Spam#339933;">-Status#339933;">: #339933;">*YES#339933;">/#009900;">)
- to #ff0000;">"Maildir/.Spam"
- #b1b100;">if #009900;">(#339933;">/^X#339933;">-Mailing#339933;">-List#339933;">: #339933;"><debian#339933;">-user@lists.#202020;">debian.#202020;">org#339933;">>/#009900;">)
- to #ff0000;">"<em class="error#ff0000;">">TeX Embedding failed!</em>MD
Many people are more familiar with Procmail. I hate it. This file is not on GitHub. If you want to use Maildrop you have to get familiar with the filters for every-day use.SASALauthd
For this setup the SASLauth daemon handles authentication.
- #339933;"># Should saslauthd run automatically on startup? (default: no)
- START#339933;">=yes
- PWDIR#339933;">=#ff0000;">"/var/spool/postfix/var/run/saslauthd"
- PARAMS#339933;">=#ff0000;">"-m <em class="error#ff0000;">">TeX Embedding failed!</em>{PWDIR}/saslauthd.pid"
- #009900;">[...#009900;">]
- MECHANISMS#339933;">=#ff0000;">"pam"
- #339933;"># Additional options for this mechanism. (default: none)
- #339933;"># See the saslauthd man page for information about mech-specific options.
- #339933;"># MECH_OPTIONS=""
Note that this is very distribution specific and therefore not included into the GitHub configs. There're many ways to compile a sasl authentication daemon. Every distribution chose its own way so the OPTIONS may be relevant to change:
- OPTIONS#339933;">=#ff0000;">"-c -m /var/spool/postfix/var/run/saslauthd"
Another Debian specific line:
dpkg-statoverride --force --update --add root sasl 755 /var/run/saslauthd
- Returns the saslauthd dpkg "state" to its default location.Refences
- The Ubuntu wiki with great links.
- [German] short article about Maildrop and forwards
- [German] another article about Maildrop from the Linuxwiki.
- An older article about a similar setup. Don't use the mentioned blacklits.
- [German] Procmail Kochbuch
- [German] Tuxhausen article
- [German] more Howtos ;)
Host security
Mail-servers need proper host-security. Maybe you have got an internal VPN and you want to firewall non-TLS services? It's a general bad idea to offer plain-text services through the WAN.
Courier runs as root?
Running Courier - as root - so what's with exploitability? Honestly: I don't know how to change this without affecting the whole. Therefore it stays root. For now. That's one of the disadvantages I see having the modular Unix-like mail-setup.
DNS
You want a valid MX record at your domain. Otherwise many hosts will declassify mails from you as Spam. - Whether you host your own primary DNS server or not.
Use your registrar's panel or, if you want, Bind9. Here's an example zonefile:
- #339933;">;
- #339933;">; BIND data file #b1b100;">for crazylazy.#202020;">info
- #339933;">;
- $TTL #0000dd;">604800
- @ IN SOA ns1.#202020;">crazylazy.#202020;">info. #202020;">info.#202020;">crazylazy.#202020;">info. #009900;">(
- #0000dd;">2007011501 #339933;">; Serial
- #0000dd;">7200 #339933;">; Refresh
- #0000dd;">120 #339933;">; Retry
- #0000dd;">2419200 #339933;">; Expire
- #0000dd;">604800#009900;">) #339933;">; Default TTL
- #339933;">;
- #202020;">crazylazy.#202020;">info. #202020;">IN MX #0000dd;">10 mail.#202020;">crazylazy.#202020;">info.
- #202020;">crazylazy.#202020;">info. #202020;">IN A 89.238.75.146
- ns1 IN A 89.238.75.146
- www IN CNAME crazylazy.#202020;">info.
- #202020;">mail IN A 89.238.75.146
- ftp IN CNAME crazylazy.#202020;">info.
- #202020;">crazylazy.#202020;">info. #202020;">IN TXT #ff0000;">"v=spf1 ip4:89.238.75.146 a mx ~all"
- mail IN TXT #ff0000;">"v=spf1 a -all"
You want to reconfigure the Postfix to run in chroot. This has been made default for reasons. Bind9 would like a chroot, too. And yes: I have that stuff running in a chroot ;). Believe it.
Have fun,
wishi

Post new comment