1 - Postfix LMTP support ======================== LMTP stands for Local Mail Transfer Protocol, and is detailed in RFC2033. Postfix uses this protocol to communicate with the final delivery agent, which may run on the local host or a remote host. This protocol opens up interesting possibilities: one Postfix front end machine can drive multiple mailbox back end machines over LMTP. As the mail load increases, you add more Postfix front end systems and more LMTP mailbox back end systems. This is the model that Wietse had in mind when he began drafting the design for Postfix - a scalable architecture that allows you to keep adding SMTP servers and mailbox servers painlessly. Such a distributed architecture needs glue to keep things together. You can use a networked database (LDAP or mysql) to share the user database among the front end and back end systems. Use a replicated database so that no machine becomes a single point of failure for the entire mail infrastructure. Or you can use rsync when files are small and/or when information does not change often. Postfix LMTP support is based on a modified version of the Postfix SMTP client. The initial version was by Philip A. Prindeville of Mirapoint, Inc., USA. This code was modified further by Amos Gouaux of University of Texas at Dallas, Richardson, USA, who also revised much of the documentation. Wietse Venema reduced the code to its present shape. 2 - Overview ============ Most of the examples in this document involve the CMU Cyrus IMAP/POP server, available from: http://asg.web.cmu.edu/cyrus/ While certainly not the only application that could make use of LMTP, it tends to be the most discussed. These examples are based on Cyrus 2.1.5. The 2.x branch of Cyrus places greater emphasis on LMTP delivery than the previous releases. Those using older releases of Cyrus can find a discussion in the appendix of this document. There are a variety of ways LMTP delivery can be configured in Postfix. The two basic flavors are delivery over UNIX-domain sockets and delivery over TCP sockets. o Connections from the Postfix LMTP client over UNIX-domain sockets allow you to deliver to non-Postfix LMTP servers running on the same machine. o Connections from the Postfix LMTP client over TCP sockets allow you to deliver to non-Postfix LMTP servers across a local network. Note: the above is not to be confused with the UNIX-domain sockets that Postfix uses internally to speak its own protocols with the Postfix LMTP client. The precise syntax for UNIX-domain and TCP connection endpoints is given in the lmtp(8) manual page. Examples are also given in the text below. Both socket flavors can be specified in either the Postfix main.cf file (see section 5) or in a Postfix transport map (section 6). What is the best approach for you depends upon the arrangement of your servers. 3 - LMTP over UNIX-domain sockets ================================= Use this to deliver mail from the Postfix LMTP client to an LMTP server that is running on the same system. A UNIX-domain socket is specified as the socket type ("unix") and a name in the local file system: unix:/path/name The "/path/name" part should be the name of a socket created by the LMTP server on the local machine. See the specific examples later in this document. NOTE: If you run the Postfix LMTP client chrooted, the interpretation of the /path/name is relative to the Postfix queue directory (typically, /var/spool/postfix). By default, the Postfix LMTP client does not run chrooted. With LMTP delivery to the local machine there is no good reason to run the Postfix LMTP client chrooted. 4 - LMTP over TCP sockets ========================= Use this to deliver mail from the Postfix LMTP client to an LMTP server that is running on the same system or on a different system. A TCP destination is specified as the socket type ("inet"), the destination hostname and the TCP port: inet:hostname:port The "inet:" part can be omitted, as it is the default socket type. The destination port can be omitted as well. Currently the default TCP port number for this type of connection is 24, but this can be customized in the /etc/services file. Specific examples are given later in this document. NOTE: With connections over TCP sockets, Cyrus 2.0.x LMTP server implementations insisted on SASL-style authentication. This meant that Postfix had to be built with SASL support (see SASL_README). While newer Cyrus releases offer an option to turn off this requirement, you must exercise great care in both determining the approach used and the configuration of your selection. It is imperative that you do not allow unauthorized access to your LMTP server. The examples below show both approaches. Some Cyrus LMTP server implementations do not allow SASL-style authentication via plaintext passwords over unencrypted connections. This is not the case with 2.1.5. However, you must realize that this could make your LMTP link vulnerable. If your LMTP communications traverse exposed networks, you should either use an encrypted connection or enable MD5 SASL mechanisms. 5 - Configuring LMTP using main.cf configuration ================================================ This is the simplest LMTP configuration. 5.1 - Delivery mechanisms ------------------------- Postfix main.cf supports three mechanisms to deliver mail to an LMTP server. Each method can use UNIX-domain or TCP sockets as described in a later section. main.cf mechanism 1 ------------------- mailbox_transport = lmtp:unix:/path/name (UNIX-domain socket example) mailbox_transport = lmtp:hostname:port (TCP socket example) Mail that resolves as local (domain is listed in $mydestination) is given to the Postfix local delivery agent. The Postfix local delivery agent expands aliases and .forward files, and delegates mailbox delivery to the Postfix LMTP client which then sends it to the non-Postfix LMTP server. main.cf mechanism 2 ------------------- local_transport = lmtp:unix:/path/name (UNIX-domain socket example) local_transport = lmtp:hostname:port (TCP socket example) Mail that resolves as local (domain is listed in $mydestination) is directly given to the Postfix LMTP client which then sends it to the non-Postfix LMTP server. The mail is not processed by the Postfix local delivery agent; therefore aliases and .forward files are not processed. main.cf mechanism 3 ------------------- fallback_transport = lmtp:unix:/path/name (UNIX-domain socket example) fallback_transport = lmtp:hostname:port (TCP socket example) Mail that resolves as local (domain is listed in $mydestination) is given to the Postfix local delivery agent. The Postfix local delivery agent processes aliases and .forward files, and delivers to /var[/spool]/mail/$user for users that have a UNIX account. Mail for other local users is delegated to the Postfix LMTP client which then sends it to the non-Postfix LMTP server. 5.2 - Examples -------------- 5.2.1 - LMTP over UNIX-domain sockets ------------------------------------- To utilize UNIX-domain sockets for the communication between Postfix and Cyrus, the corresponding configuration files should look something like this: /etc/cyrus.conf: SERVICES { ... lmtpunix cmd="lmtpd" listen="/var/imap/socket/lmtp" prefork=1 ... } /etc/postfix/main.cf: mailbox_transport = lmtp:unix:/var/imap/socket/lmtp /etc/postfix/master.cf: lmtp unix - - n - - lmtp In this case, the Postfix local delivery agent expands aliases and .forward files, and delegates mailbox delivery to the Cyrus lmtpd server via the socket "/var/imap/socket/lmtp". NOTE: Make sure that both the user id that Cyrus runs under and the Postfix user id can access the socket "/var/imap/socket/lmtp". While this is implied by the example above, it is often overlooked and so warrants emphasis. 5.2.2 - LMTP over TCP sockets (non-SASL) ---------------------------------------- For this example, suppose the following files are configured thusly: /etc/cyrus.conf: SERVICES { ... lmtp cmd="lmtpd -a" listen="127.0.0.1:lmtp" prefork=1 ... } /etc/services: lmtp 2003/tcp /etc/postfix/main.cf: mailbox_transport = lmtp:localhost /etc/postfix/master.cf: lmtp unix - - n - - lmtp With the above settings, the Postfix local delivery agent expands aliases and .forward files, and delegates mailbox delivery to the Cyrus LMTP server. Postfix makes a connection to port 2003 on the local host, subsequently transmitting the message to the lmtpd server managed by the Cyrus master process. The port number has been changed in /etc/services from 24 to 2003 as that is what the Cyrus LMTP server is now using. See the Cyrus lmtpd(8) man page to verify that the version you have supports the "-a" option. NOTE: Consider this approach if and only if this particular host does not allow direct user logins or user-controlled processes. Otherwise, this LMTP server may be abused! If the Cyrus lmtp service is to listen on a network other than the local loop-back (127.0.0.1), be sure to install Cyrus with tcp_wrappers support. Then use tcp_wrappers to only allow access to the "lmtp" service from trusted hosts. Otherwise, this LMTP server may be abused! Section 10 contains an example using tcp_wrappers. For the configuration above, replace "deliver" with "lmtp" in the /etc/hosts.allow shown in that example. 5.2.3 - LMTP over TCP sockets (SASL) ------------------------------------ In the following example "cyhost.my.domain" is the name of the Cyrus IMAP/POP server. It is important that you use this name consistently in the Postfix configuration settings. The first approach uses the PLAIN authentication mechanism (see the Cyrus SASL documentation.) Suppose the Cyrus server has the following files configured thusly: /etc/cyrus.conf: SERVICES { ... lmtp cmd="lmtpd" listen="cyhost.my.domain:lmtp" prefork=1 ... } /etc/imapd.conf: lmtp_admins: lmtpuser /etc/services: lmtp 2003/tcp The Postfix host (may be same box) has the following configuration: /etc/postfix/main.cf: mailbox_transport = lmtp:cyhost.my.domain lmtp_sasl_auth_enable = yes lmtp_sasl_password_maps = hash:/etc/postfix/lmtp_sasl_pass lmtp_sasl_security_options = noanonymous /etc/postfix/lmtp_sasl_pass: cyhost.my.domain lmtpuser:password /etc/services: lmtp 2003/tcp /etc/postfix/master.cf: lmtp unix - - n - - lmtp Instead of "hash", use the map type of your choice. Some systems use "dbm" instead. Use "postconf -m" to find out what map types are supported. If your version of Cyrus does not support "lmtp_admins" as a setting in imapd.conf, use "admins" instead. With the above settings, the Postfix local delivery agent expands aliases and .forward files, and delegates mailbox delivery to the Cyrus LMTP server. Postfix makes a connection to port 2003 on the local host, subsequently transmitting the message to the lmtpd server managed by the Cyrus master process. The port number has been changed in /etc/services from 24 to 2003 as that is what the Cyrus LMTP server is now using. The SASL configuration on the Cyrus server will need to accept the user "lmtpuser" using the password specified in /etc/postfix/lmtp_sasl_pass on the Postfix host. If this LMTP conduit exists over an exposed network, you should compile Postfix with MD5 (CRAM or DIGEST) password support. See SASL_README for more details. Then configure Postfix as follows: /etc/postfix/main.cf: lmtp_sasl_security_options = noanonymous, noplaintext On the Cyrus host you should also set: /etc/imapd.conf: lmtp_allowplaintext: no You will need to make sure the "lmtpuser" is in the appropriate SASL database. As an example, the following would add "lmtpuser" to /etc/sasldb2: saslpasswd2 -c -u cyhost.my.domain lmtpuser If you encounter difficulties with "lmtpuser" not being permitted to authenticate to the LMTP server, try the above command with the un-qualified hostname: saslpasswd2 -c -u cyhost lmtpuser Also make sure the Cyrus user has read permission of the SASL database, /etc/sasldb2 in the example above. Incidentally, it is very likely that the Cyrus server and the Postfix server will need to use the same SASL backend databases (e.g., auxprop or saslauthd.) Currently it is not possible to assign different SASL backends for different Cyrus services. Only TLS (SSL) or STARTTLS can be used in conjunction with saslauthd. Since none of these encryption methods are available for LMTP, if you need to encrypt your LMTP connections, you will very likely have to use auxprop throughout. 6 - Configuring LMTP using transport map configuration ====================================================== This approach is quite similar to specifying the LMTP service in the Postfix main.cf configuration file. However, now we will use a transport map to route mail to the appropriate LMTP server, instead of depending on delegation by the Postfix local delivery agent. Why might this approach be useful? This could be handy if you wish to route mail for multiple domains to their respective mail retrieval (IMAP/POP) server. Example: /etc/postfix/transport: domain1.tld lmtp1:unix:/path/name domain2.tld lmtp2:lmtp2host /etc/postfix/master.cf: lmtp1 unix - - n - - lmtp lmtp2 unix - - n - - lmtp /etc/postfix/main.cf: transport_maps = hash:/etc/postfix/transport For details of the Cyrus LMTP server configuration, see section 5. Instead of "hash", use the map type of your choice. Some systems use "dbm" instead. Use "postconf -m" to find out what map types are supported. 7 - Performance considerations ============================== Hopefully the preceding discussion has seemed pretty straight forward. Now things get interesting. After reading the following you will see that there are more factors to consider when setting up LMTP services. 8 - Single instance message store ================================= Presently this topic is more pertinent to sites running Cyrus, but may be a factor with other applications as well. Since 1.6.22, Cyrus has had the feature that if a message containing multiple recipients is received via the LMTP protocol, and all these recipients were on the same Cyrus partition, only one instance of this message would be written to the file system. The other recipients would then see a hard link of this single instance. Depending on your user base, this can be considerable motivation to using LMTP. With the examples in section 5.2, we can increase the number of recipients (to $mydestination) that can be handled at once: /etc/postfix/main.cf: local_destination_recipient_limit = 300 The 300 was arbitrarily chosen for this example. Be sure to pick a number that is appropriate for the capabilities of your hardware. The bigger the number, the more you can leverage the single instance message store. However, if it is too big the LMTP server will need too much time to deliver a message and Postfix will experience timeout errors. Choose this value very carefully. NOTE: Not all local delivery agent transports can support a recipient limit greater than 1. Be sure to check the man page of the specific transport before attempting this with anything but the Postfix LMTP client. If we wish to apply this single instance message store technique with the configuration example in section 6, the setting would be: /etc/postfix/main.cf: lmtp1_destination_recipient_limit = 300 lmtp2_destination_recipient_limit = 300 As previously mentioned, exercise tremendous care backed by extensive analysis of your systems before setting the recipient limit like this. 9 - Improving connection caching performance ============================================ After delivering a message via LMTP, Postfix will keep the connection open for a while, so that it can be reused for a subsequent delivery. This reduces overhead of LMTP servers that create one process per connection. For LMTP connection caching to work, the Postfix LMTP client should not switch destination hosts. This is no problem when you run only one LMTP server. However, if you run multiple LMTP servers, this can be an issue. You can prevent the LMTP client from switching between servers by configuring a separate LMTP delivery transport for each LMTP server: /etc/postfix/master.cf: lmtp1 unix - - n - - lmtp lmtp2 unix - - n - - lmtp . . . . . . . . Configure transport table entries such that the lmtp1 mail delivery transport is used for all deliveries to the LMTP server #1, the mail lmtp2 transport for the LMTP server #2, and so on. /etc/postfix/transport: foo.com lmtp1:lmtp1host bar.com lmtp2:lmtp2host 10 - Appendix: Older Cyrus versions =================================== First of all, if you are using a Cyrus 2.x version prior to 2.1.4, you should really consider upgrading. There have been numerous bug fixes and performance improvements since the early 2.0 releases. Further back, 1.6.24 was the last pre-2.x production release. (Actually, there was a 1.6.25-BETA, but it is uncertain whether this will be released officially as CMU is now focusing support on the 2.x branch.) The following discussion touches on how to configure the Postfix LMTP facilities with Cyrus 1.6.24. One of the significant differences between Cyrus 1.x and 2.x is the inclusion of the "master" process in 2.x. This "master" process is responsible for running the various components of Cyrus, such as imapd, pop3d, and lmtpd. Prior to 2.x, these services were managed by inetd, the Internet services daemon. To utilize LMTP delivery with Cyrus 1.6.24, the first thing to do is configure inetd. This involves the following file edits: /etc/services: lmtp 2003/tcp /etc/inetd.conf: lmtp stream tcp nowait cyrus /usr/sbin/tcpd /usr/cyrus/bin/deliver -e -l /etc/hosts.allow: deliver : localhost : ALLOW deliver : ALL@ALL : DENY The "/usr/sbin/tcpd" is from the tcp_wrappers package, which is discussed in the example "LMTP over TCP sockets, using hosts.allow." It is important that you wrap this LMTP port to protect it from unauthorized access. On some systems, tcpd is built into inetd, so you do not have to specify tcpd in the inetd.conf file. Instead of tcpd/inetd, xinetd can do a similar job of logging and access control. Now comes the Postfix configuration. Basically, the Cyrus 2.x discussions regarding LMTP delivery over TCP are also applicable to Cyrus 1.x, with the exception of the /etc/cyrus.conf file. A typical Postfix configuration might look like this: /etc/postfix/master.cf: lmtp unix - - n - - lmtp /etc/postfix/main.cf: mailbox_transport = lmtp It is also possible to use the transport map to route mail to your Cyrus 1.6.24 LMTP server: /etc/postfix/transport: domain1.tld lmtp1:lmtp1host domain2.tld lmtp2:lmtp2host /etc/postfix/master.cf: lmtp1 unix - - n - - lmtp lmtp2 unix - - n - - lmtp /etc/postfix/main.cf: transport_maps = hash:/etc/postfix/transport If you have read the discussion covering the Cyrus 2.x installation, you will notice the one significant difference with the Postfix configuration is the lack of mention of the UNIX-domain sockets. That is because delivery over UNIX-domain sockets is new with Cyrus 2.x, yet another reason to upgrade. :-)