Background
The thing about FreeBSD jails and VMs is that they’re so easy to set up one tends to end up with many of them, each with its own purpose. Though they don’t have a physical form they’re still full servers, doing all the things servers do unless you configure them not to, and sometimes things can break. If one doesn’t have some way in which to keep tabs on them, such breakage can be subtle and may not become obvious until it is too late. So then, how to monitor a server’s ongoing behaviour? Well, this is a solved problem; FreeBSD, like all Unices, has perfectly good scheduling and logging features built in, and the results of scheduled jobs can trivially be configured to be sent to the server’s root email account. What is not so trivial is how to have such locally-sent mails continue to work whilst also having them forwarded to an account that it outside that server, such as your own personal email account. The main challenges are:
- Configuring the default email utility, sendmail, is witheringly complex, so setting it up to send mail locally and externally is non-trivial;
- The naive optimism of the original SMTP protocol allows one all too easily to arrive at a working but insecure setup that would leave the server open to attack or abuse; and
- Because of (2) many email services treat incoming mail with great suspicion, so it is becoming harder to convince them that your mail is legitimate.
My chosen solution to this conundrum is to leave sendmail doing just the within-server email, and then set up an entirely separate utility (SSMTP) to handle external mail forwarding. Yes, sendmail could do both, but I do not have the time or inclination to work out how to have it perform both within-server and outgoing email in a secure manner, so this is my way to compartmentalize risk. Note that there are many guides out there that will help you set up SSMTP to replace sendmail, but in my experience this breaks within-server email since SSMTP isn’t designed for that use case – it can literally only send mail via SMTP.
Installing SSMTP
pkg install ssmtp
Basic Configuration
Edit /usr/local/etc/ssmtp/ssmtp.conf as follows:
mailhub=<your external SMTP server>:<port used - one of 25, 465 or 587>
Note that this SMTP server is the one which is going to forward your mails, not that of the destination email address. Though it does not necessarily have to match the domain of the destination email address, it is probably more likely to work if they are the same. Various articles suggest that Gmail is not a good bet – they do too much behavioral checking and might not reliably forward your mails.
rewriteDomain=<your local domain name>
In order to improve your chances of having your mail accepted by the chosen forwarder, it is good to have it appear to come from a genuine domain. I use a domain that I set up with dyndns; there are many such free domain forwarder services. Note though that this domain won’t actually be used to route the mail in any way.
FromLineOverride=NO
This is the default value of this setting, but I think it is worth explaining it. The sense is, in my view, backwards. ‘No’ means that the From: line of the incoming mail will not override SSMTP’s ability to rewrite that value. In other words, ‘No’ means that SSMTP is allowed to alter the From: line. We very much want SSMTP to do so in order to improve the apparent validity of the mail; we’ll use the revaliases configuration later on to spoof the From address.
UseTLS=Yes
Presumably you want your SMTP communication with the forwarder to be encrypted?
AuthUser=<your username at the SMTP server>
AuthPass=<your password at the SMTP server>
Obvious. You ought to set the file permissions and flags for this file to be appropriately restrictive since these are clear-text values.
Spoofing the source address
SSMTP allows us to rewrite the From address of mails, as noted above. The mapping is done in the revaliases file, so edit /usr/local/etc/ssmtp/revaliases as follows:
mailnull:<hostname of server>@<value of rewriteDomain set above>
FreeBSD’s periodic utility, which is responsible for scheduled script runs, uses the username mailnull. Since you’re likely to have multiple servers you set up with this configuration, using the hostname of the server is a good way to distinguish between similar mails coming in from different servers. Finally the domain name should match the one set up earlier as rewriteDomain in ssmtp.conf.
Configuring root to forward its email externally
So far so standard; here comes the hack :)
BSD (and no doubt all other Unices) supports a .forward file, stored in each user’s home directory, to be used to forward mail sent to that user elsewhere. I learnt from its manpage that as well as containing literal email addresses, lines enclosed in double quotes will be executed as commands. This means I could insert a line in root’s .forward file in the following format:
"|/usr/local/sbin/ssmtp -F"<server hostname> root" <destination email address>"
Breaking it down, this command pipes each mail sent to root to the ssmtp command, the -F parameter allows me to modify the Sender line so that I know from which server the mail is coming, and sends it to the address specified. Remember that it is probably helpful if the destination address is at the same server you’re using for SSMTP’s mailhub value, though it is not mandatory.
Coda
Since setting this up, I’ve learnt that /etc/mail/aliases also supports the line format described for .forward above, so one could equally insert a line in that file instead, which is arguably a more central configuration file for a server’s email instead of .forward.