Postfix and Dovecot – Using ENV Variables in Configuration Files

dovecotenvironment-variableslinuxpostfixtroubleshooting

I'm trying to dockerize my mailing server and I'm having some troubles regarding how am I supposed to use environment variables inside Postfix and Dovecot configuration files (I'm using the latest packages available through apt for ubuntu:18.04).

I have already imported the variables I want to use within Dovecot.conf (1) and main.cf (2), but I honestly don't now exactly which syntax I must follow in order to use these.

(1) Dovecot.conf

import_environment= MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD, DOMAIN_NAME, CERTS_DIR, DOVECOT_SASL_PORT

(2) Postfix's main.cf

import_environment= MYSQL_DATABASE, MYSQL_USER, {MYSQL_PASSWORD}, DOMAIN_NAME, CERTS_DIR, DOVECOT_SASL_PORT

According to Dovecot's docs, I am supposed to use env:MYSQL_DATABASE whenever I want to refer to my database, env:DOMAIN_NAME whenever I want to refer to my domain name, and so on.
However, according to this mailing list from 2019, a user is refering to their ENV variables as %{env:EXAMPLE_VAR}. Which approach is the correct one? Are they both equally valid?

About Postfix, on the other hand, I could not find anything related to what syntax must be used when referring to environment variables, and I'd very much appreciate if someone could tell me how should I proceed.

Thanks a lot!

Best Answer

You're right, dovecot allows variable expansion using the environment as a source. %{env:FOR_WHAT_ITS_WORTH} is the correct syntax. Keep in mind though, that dovecot has two types of configuration files: the "normal" ones ending in .conf and those that end in .conf.ext, usually used for external connections like fetching the user database from LDAP or some SQL DBMS. The latter do not provide variable expansion at all, so you need to take a different approach (more on that below).

When it comes to postfix, there is no standard mechanism I know of and the documentation does not mention anything about it.

There is a solution to this, that, you might have already guessed, involves some work but works for anything you want to containerize. I assume you are using some docker-entrypoint.sh script to launch postfix and dovecot inside your container and that checks before-hand if first time setup has been done. If not, it runs first time setup. You might even run this setup unconditionally every time your container fires up to change the configuration according to what's to be found in the environment.

Let's say you have prepared your configuration files outside the container and copy them over by something in your docker file that looks like COPY config /root/config.tpl. Inside these configuration files are standard shell variables, e. g. bind_dn = ${MY_BIND_DN} and you have escaped all $ and \ characters in your configuration templates. What you can do now is simply filtering the templates through eval and then place the output where it belongs. See this example for clarification.

for CONFIG_TEMPLATE in /root/config.tpl ; do
  cat ${CONFIG_TEMPLATE} | eval "echo \"$(cat ${CONFIG_TEMPLATE})\"" > /etc/dovecot/conf.d/${CONFIG_TEMPLATE}
done

That's pretty much, I know. Nevertheless it works great unless there's too much to escape in your configuration files and it allows you to configure almost everything that's configuration file based on container start from the environment.