Nethence NEWDOC OLDDOC Lab Webmail Your IP BBDock  

Setting up Postfix as a Docker container

Dockerizing a strong anti-spam Postfix MX


The container is ideally data-independend and possibly load-balance-ready. So the shared Docker volume may also be some NFS or shared disk fs on the Docker host side.

Liberating port 25 from the Docker host

We are going to setup an MX inside a container, therefore the smtp port needs to be freed from the Docker host.

You should see e.g. that port 25 is taken,

netstat -antpe --inet --inet6|grep LISTEN

Assuming it’s an RHEL/CentOS docker host, disable Postfix from it,

service postfix stop
chkconfig postfix off

and check again.

Launching the container

Make sure that either the shared volume doesn’t or does exist whether it’s a fresh installation or not,

sudo ls -alhF /data/postfixprod/

Run the container based on the custom Ubuntu Docker image,

docker ps -a | grep $app
docker run -d --name $app -h $app \
    -p 25:25 -p 587:587 -p 143:143 \
    -v /data/$app:/home \
docker exec -ti postfixprod bash

Note. in case you need to link some Postfix & Dovecot mappings to MariaDB,

    --link mariadbprod:mariadb \

Note. (optional) also if you like to,

    -v /data/postfixprod.conf:/etc/postfix \
    -v /data/postfixprod.spool:/var/spool/postfix \

And proceed with the Postfix guide.

Ready to go

Write the new init for the Docker container to start the daemons,

cd ~/
cat > init.bash <<-EOF
cp -pf /etc/resolv.conf /etc/hosts /etc/services /var/spool/postfix/etc/
tail -F /var/log/mail.err &
#/usr/lib/postfix/sbin/master -w
/usr/sbin/postfix start
while true; do sleep 120; done
chmod +x init.bash

and run it,


Note. master without -w if you want it to be the remaining process of the container’s entrypoint (CMD). See man 8 master. I prefer to use a fake init as remaining process so I can eventually really restart the postfix daemon while keeping the container up and running (e.g. for dovecot).

See the the Postfix guide to run some checks.

Everything’s fine? Then commit to an image from the Docker host and change the entrypoint against the new init,

docker commit --change='CMD ["/root/init.bash"]' -p postfixprod postfixprod.`date +%s`.ready

or if the good entrypoint already has been applied, simply,

docker commit -p postfixprod postfixprod.`date +%s`.ready


You can then launch the container with its new init,

docker ps -a | grep $app
docker run -d --name $app -h $app \
    -p 25:25 -p 587:587 -p 143:143 \
    -v /data/$app:/home \
docker logs $app
docker exec -ti $app ps auxfw
#docker exec -ti $app bash


Host Integration

Configure the System D service,

cd /etc/systemd/system
vi postfixprod.service

Description=postfixprod container

ExecStart=/usr/bin/docker start -a postfixprod
ExecStop=/usr/bin/docker stop -t 30 postfixprod


systemctl daemon-reload

Eventually restart the shit using System D now,

#docker stop postfixprod
#systemctl start postfixprod
#systemctl status postfixprod

Enable the shit at startup,

systemctl enable postfixprod
systemctl status postfixprod