Postfix in a FreeBSD jail

I recently ran into problems with postfix running inside of a FreeBSD jail. It would constantly report "file too large" errors, and other errors in that vein. Since there appears to be no documentation for FreeBSD "newbies" on fixing this problem, it seems like most people default back to sendmail or exim, rather than using the excellent Postfix MTA on their virtual file systems.

I love postfix, so that is a situation I'd like to change! Here are the directions on how to get postfix working inside a FreeBSD "jail" system.

Well, the basic problem with Postfix in a FreeBSD 4.8 jail is the disconnect in the setrlimit() call in Postfix versus the kernel. You end up with spurious "file too large" errors when sending and receiving messages, which just sucks.

IMPORTANT NOTE: A generous reader left a clarification in a comment below this entry that may be more useful for you. My procedure works fine because you're running "make clean" inside the postfix work directory -- using Postfix's built-in Makefile -- and thus not destroying the source file you're going to edit. However, running "make clean" from the /usr/ports/mail/postfix-current/ directory would blow away your work/ directory, nullifying the effort you're putting into patching :)

1. cd usr/ports/mail/postfix-current

2. Run "make" -- I normally just leave it alone and let Postfix go ahead and build itself. Not a big deal.

3. cd work/postfix-(version)/src/util

4. using your favorite text editor, open "file_limit.c", and go to the SECOND instance of this line:

struct rlimit rlim;

(This is the one followed by "rlim.rlim_cur = rlim.rlim_max = limit;" -- if you don't see that, you're at the wrong one)

5. Paste this line immediately after the "struct rlimit rlim" declaration, then save and exit:

we acquired a lot of knowledge of tuning postfix and it served us very well in the last years. several hundreds of thousand mails a day are no problem. so why change? exim has certain drawbacks i do not like, as it does not generate RFC compliant DSNs when bouncing mails... but that could have changed since then...

I figured out why it works for me. I'm not running "make clean" from /usr/ports/mail/postfix-current/ -- I'm running it from /usr/ports/mail/postfix-current/work/postfix-(version)/ . It's postfix's own "make clean" that I'm running, which won't alter source files like running "make clean" using the port's Makefile.

Either way works satisfactorily, as far as I can tell after rebuilding once again :)

There are several resource allocation calls that don't work in a FreeBSD jail. One day, I'd like to make a complete list of them, but I'm only aware of the ones that have hit me:

Shared memory is unavailable in secure jail implementations. Apparently, you can turn it on but then your jails can end up overwriting one another's memory or something :) Kernel developers appear to be working on this for the FreeBSD 5.X series, but in 4.X, it's not working.

ICMP (Ping & Traceroute) doesn't work from a jail.

You can't make a kvm_open call, which fooses "top". I think there's an alternative mode you can compile certain versions of "top" to that read the process table differently. Curiously, a "ps aux" works just fine, but only shows children of the jailed process, as it is supposed to.

Each jail can only handle one IP address.

With those limitations in mind, jails can still be really useful. This site runs in such a jail on a virtual hosting provider, and I can still do a lot of useful stuff, and it doesn't feel crippled at all 99.99% of the time.

As far as ramifications for Postfix, I think the only problem with lack of setrlimit() is that you could possibly get DOS'd on your Postfix process by someone sending an arbitrarily long message. My solution is ulimit the process to not take more than 50MB of RAM ("ulimit -m 51200"). Then the process handling incoming messages (postfix's "smtpd") would run up hard against that ulimit and bomb out on incoming messages exceeding that threshold. Since SMTPD only starts when postfix's "master" process detects a connection on port 25, it dying off running up against the memory ulimit will just show up as a blip on your syslog with something about "exhausted memory".

The default ulimit for most processes on freebsd is unlimited, so it's probably wise to ulimit any of your network-available daemons you think may grow too large. However, it's rather tedious editing all the init scripts. In order to make Postfix do it, I had to "rm /usr/local/etc/rc.d/postfix.sh", because that was just a symlink to /usr/local/sbin/postfix (an ELF binary), and I then created a shell script that did the ulimit for me and then I named that "postfix.sh". It does the job nicely, and I'm not concerned about the remote possibility of someone crafting a large DOS-oriented message to try to kill my virtual private server.

It works well. It would be nice if postfix's configure script detected setrlimit()'s broken-ness in a FreeBSD jail and automatically ulimit-ted smtpd processes, though.

You may want to check out this page at jvds.com about the same problem. It's solved it for most people; the biggest problem seems to be people making these changes in postfix-current when their currently installed postfix is just /usr/ports/mail/postfix.

In normal operation, Postfix makes a system call to check to see if it can create a file of a certain size. Inside a jail, this call will not succeed as per the very design of jails.
[...]
This patch probably hasn't made it into the port because it completely bypasses a moderately important check.

This description is wrong. The code in question SETS the message file size limit instead of asking for the max available size.

The patch is no less than catastrophic. It allows everyone to completely use up all free queue space in the queue with a single email message.