I've been busy today setting up postfixadmin on my mail server, which is something I should have done from the start.

I've configured the front end and the database, and I've reached the point where I have to actually integrate it into postfix, dovecot, and dkim. That's the danger zone.

I'm going to pause now until I have more time, since a mistake here could mean hours of debugging and fixing, and I have to go to work. Maybe tomorrow.

#PostfixAdmin #Postfix #Linux #ServerAdmin #SelfHosting

I've been running my own #email servers for over two decades now, with spurts of enthusiasm and improvement. The last project has been to run the various software parts in immutable containers on #Kubernetes, and I'm quite happy with the result. I do see a decline in requests for hosted accounts on personal domains, as friends and family seem to settle with accounts on major providers like Gmail. I'm not going to throw in the towel though. Self hosted for the win!

For the curious, my stack is #Postfix, #Rspamd, #Dovecot and #Roundcube for those who prefer webmail over a native client like #Thunderbird or #K9mail. #Sieve for automatically organizing mail in the proper folders. Used to run #PostfixAdmin, but was unhappy with it, so I wrote my own API in Go to edit accounts, mailboxes and aliases. Never got around to write a frontend, but it was a Swagger interface, so.. 😜

Today in private-mail-host adventures (#postfixadmin):
Mail from other people started bouncing. Test messages I sent myself, even from outside, arrived fine, except one.
Problem turned out to be a documented but un-noticed default in #postfix: by default,
mailbox_size_limit = 51200000
which means that the delivery program is run with RLIMIT_FSIZE = 51200000, i.e. cannot write to any file larger than that size. 1/

Почтовый сервер с нуля. Часть вторая

Приветствую всех читателей! Подошло время для второй части нашей серии статей по настройке почтового сервера. Напомню, что в первой части мы рассмотрели основные моменты, касающиеся настройки почтового сервера, а также конфигурировали Exim4 для корректной отправки почты. В этой статье мы настроим полноценный почтовый сервер. Использовать будем PostfixAdmin, Dovecot и RainLoop. Давайте настроим!

https://habr.com/ru/companies/nixys/articles/807681/

#почта #dovecot #postfixadmin #rainloop #exim4 #почтовый_сервер #электронная_почта #php

Почтовый сервер с нуля. Часть вторая

Приветствую всех читателей! Подошло время для выпуска второй статьи из серии по настройке почтового сервера. Если кто-то не успел застать первую часть, то прошу перейти по этой ссылке . В этой статье...

Хабр
Was nimmt man denn heute so als Webinterface zur Administration von Emailkonten? #Postfixadmin? #Vimbadmin? (Also auf Seiten von Postfix & Co)

Me yesterday ....

"Hmm, this PR has been open for ages, it seems to work ... And it looked ok when I scrolled through the code a few weeks ago. If we merge it then we could have a new major release ... *Merge*"

1 hour after merging ... messages start to appear with :

"Hey, nice feature, but .... broken/insecure/should have done it like blah blah ..."

I suppose merging at least got a discussion started?

Still perhaps we'll have PostfixAdmin 3.4 soon. #php #postfix #postfixAdmin

@krafter I think the requirement of webmail combining multiple accounts won't be easy to find. You're better off using a native client to view multiple inboxes.
Otherwise the other recommendations in this thread seem good. #PostfixAdmin also looks promising
Serveur mail et webmail – part. 3 – postfix admin – Mariadb – Mon Jardin

Some notes in the beginning:

DMS, docker mail server, is, as of now (2023-08-08), not intended to be used with a database and postfixadmin. It offers its user and domain management through a script and a text file, where you write in your accounts with hashed passwords or your aliases.

This is not a tutorial, it is my personal story with the topic. I might rewrite this as a tutorial at a later point in time.

Motivation

What I want to do is, replacing my current native setup with a docker solution that I can setup easily and reproducible in case of server change/malfunction or the need to restore a backup.

The native setup consists of

  • postfix – how obvious
  • PostgreSQL
  • PostfixAdmin
  • Dovecot
  • RoundcubeMail
  • Rspamd
  • imapproxy for Roundcube, for keeping connections low
    • (don’t think that I will transfer that thing…)
  • opendkimd

And of course, the new setup should be capable of the same.

Why?

My problem is of course a bit self-produced. I am a Arch Linux user – every-fuckin-where. And with that I sometimes get incompatibilities. As with Arch you get almost bleeding edge packages, the applications, e.g. roundcubemail or postfixadmin, aren’t ready for the newest PHP most of the time.

My motivation is now to move the email service with all its components into a docker deployment, so that any upgrade of my base system isn’t interfering with the service at all. Target is to be able to do an upgrade schedule of the machine as I see fit and having a different upgrade schedule for the services.

I did this approach already with a couple of services, e.g. nextcloud (AIO) and quassel-core.

Now there could be someone questioning my Arch Linux usage on server systems, of course…
Yes, I could move to an Ubuntu server with more “stability”, only to have a big act of upgrading to every new LTS version.
And for a move to another Linux distribution, I would have to move the services anyway…

Whatever.

Having the deployment in docker makes it even easier, if I would ever do this.

Get started…

For continuing, I expect that you have at least basic knowledge about all the involved services (postfix, dovecot, postgresql, dns entries, rspamd, postfixadmin, roundcubemail, lets encrypt, etc.). I won’t go into details, but may provide links for further reading, if you’re lucky. 🙂

Now let’s get started…

DMS compose.yml

My first steps were:

First, I retrieved the compose.yaml from the DMS github project repository and as well as the mailserver.env.
Then, I added the necessary images to the compose.yaml

compose.yaml diff to the original

diff --git a/compose.orig.yml b/compose.yml--- a/compose.orig.yml+++ b/compose.yml@@ -23,9 +23,34 @@ services: restart: always stop_grace_period: 1m # Uncomment if using `ENABLE_FAIL2BAN=1`:- # cap_add:- # - NET_ADMIN+ cap_add:+ - NET_ADMIN healthcheck:- test: "ss --listening --tcp | grep -P 'LISTEN.+:smtp' || exit 1"+ test: ["CMD-SHELL", "ss --listening --tcp | grep -P 'LISTEN.+:smtp' || exit 1"] timeout: 3s retries: 0+ mailserverdb:+ image: postgres:14+ restart: always+ env_file: db.env+ volumes:+ - ./docker-data/postgres/data:/var/lib/postgresql/data+ healthcheck:+ test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]+ interval: 1s+ timeout: 5s+ retries: 10+ postfixadmin:+ image: postfixadmin:apache+ restart: always+ env_file: postfixadmin.env+ ports:+ - 8080:80+ roundcube:+ image: roundcube/roundcubemail:latest+ restart: always+ env_file: roundcube.env+ ports:+ - 8000:80+ volumes:+ - ./docker-data/roundcube/data:/var/roundcube/db

Then I changed the mailserver.env to reflect my settings (yours might of course differ…)

mailserver.env diff to the original

diff --git a/mailserver.orig.env b/mailserver.envindex 038e23b..7a6cbe5 100644--- a/mailserver.orig.env+++ b/mailserver.env@@ -72,7 +72,7 @@ PERMIT_DOCKER=none # `/etc/localtime`, which you can alternatively mount into the container. The value of this variable # must follow the pattern `AREA/ZONE`, i.e. of you want to use Germany's time zone, use `Europe/Berlin`. # You can lookup all available timezones here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List-TZ=+TZ=Europe/Berlin # In case you network interface differs from 'eth0', e.g. when you are using HostNetworking in Kubernetes, # you can set NETWORK_INTERFACE to whatever interface you want. This interface will then be used.@@ -98,12 +98,12 @@ ENABLE_SRS=0 # Enables the OpenDKIM service. # **1** => Enabled # 0 => Disabled-ENABLE_OPENDKIM=1+ENABLE_OPENDKIM=0 # Enables the OpenDMARC service. # **1** => Enabled # 0 => Disabled-ENABLE_OPENDMARC=1+ENABLE_OPENDMARC=0 # Enabled `policyd-spf` in Postfix's configuration. You will likely want to set this@@ -111,7 +111,7 @@ ENABLE_OPENDMARC=1 # # - 0 => Disabled # - **1** => Enabled-ENABLE_POLICYD_SPF=1+ENABLE_POLICYD_SPF=0 # 1 => Enables POP3 service # empty => disables POP3@@ -125,13 +125,13 @@ ENABLE_CLAMAV=0 # Enables Rspamd # **0** => Disabled # 1 => Enabled-ENABLE_RSPAMD=0+ENABLE_RSPAMD=1 # When `ENABLE_RSPAMD=1`, an internal Redis instance is enabled implicitly. # This setting provides an opt-out to allow using an external instance instead. # 0 => Disabled # 1 => Enabled-ENABLE_RSPAMD_REDIS=+ENABLE_RSPAMD_REDIS=1 # When enabled, #@@ -140,7 +140,7 @@ ENABLE_RSPAMD_REDIS= # # **0** => disabled # 1 => enabled-RSPAMD_LEARN=0+RSPAMD_LEARN=1 # Controls whether the Rspamd Greylisting module is enabled. # This module can further assist in avoiding spam emails by greylisting@@ -148,7 +148,7 @@ RSPAMD_LEARN=0 # # **0** => disabled # 1 => enabled-RSPAMD_GREYLISTING=0+RSPAMD_GREYLISTING=1 # Can be used to enable or disable the Hfilter group module. #@@ -164,7 +164,7 @@ RSPAMD_HFILTER_HOSTNAME_UNKNOWN_SCORE=6 # Amavis content filter (used for ClamAV & SpamAssassin) # 0 => Disabled # 1 => Enabled-ENABLE_AMAVIS=1+ENABLE_AMAVIS=0 # -1/-2/-3 => Only show errors # **0** => Show warnings@@ -176,13 +176,13 @@ AMAVIS_LOGLEVEL=0 # Note: Emails will be rejected, if they don't pass the block list checks! # **0** => DNS block lists are disabled # 1 => DNS block lists are enabled-ENABLE_DNSBL=0+ENABLE_DNSBL=1 # If you enable Fail2Ban, don't forget to add the following lines to your `compose.yaml`: # cap_add: # - NET_ADMIN # Otherwise, `nftables` won't be able to ban IPs.-ENABLE_FAIL2BAN=0+ENABLE_FAIL2BAN=1 # Fail2Ban blocktype # drop => drop packet (send NO reply)@@ -191,7 +191,7 @@ FAIL2BAN_BLOCKTYPE=drop # 1 => Enables Managesieve on port 4190 # empty => disables Managesieve-ENABLE_MANAGESIEVE=+ENABLE_MANAGESIEVE=1 # **enforce** => Allow other tests to complete. Reject attempts to deliver mail with a 550 SMTP reply, and log the helo/sender/recipient information. Repeat this test the next time the client connects. # drop => Drop the connection immediately with a 521 SMTP reply. Repeat this test the next time the client connects.@@ -246,7 +246,7 @@ ENABLE_QUOTAS=1 # Set the message size limit for all users. If set to zero, the size will be unlimited (not recommended!) # # empty => 10240000 (~10 MB)-POSTFIX_MESSAGE_SIZE_LIMIT=+POSTFIX_MESSAGE_SIZE_LIMIT=20480000 # Mails larger than this limit won't be scanned. # ClamAV must be enabled (ENABLE_CLAMAV=1) for this.

Notes:
– opendkim and opendmarc are disabled, as rspamd can do that nowadays
– SPF is now in rspamd too, as it seems…
– I don’t need Virus scanning as of now, it anyway has a huge impact on performance, so Amavis or ClamAV are disabled

Continuing with the configuration of the postgresql instance through an .env file:

db.env

POSTGRES_USER=postfixPOSTGRES_PASSWORD=POSTGRES_DB=postfix

And the postfixadmin instance through an .env file:

postfixadmin.env

POSTFIXADMIN_DB_TYPE=pgsql #... - sqlite, mysqli, pgsqlPOSTFIXADMIN_DB_NAME=postfix #.... - database name or path to database file (sqlite)POSTFIXADMIN_DB_USER=postfix #... - mysqli/pgsql only (db server user name)POSTFIXADMIN_DB_HOST=mailserverdb #... - hostname for database, default is localhost.#POSTFIXADMIN_DB_PORT=#... - port for the database (optional):POSTFIXADMIN_DB_PASSWORD=#... - mysqli/pgsql only (db server user password)POSTFIXADMIN_ENCRYPT='php_crypt:SHA512::{SHA512-CRYPT}'#... - database password encryption (e.g. md5crypt, SHA512-CRYPT)POSTFIXADMIN_SETUP_PASSWORD='$2y$10$hYwsErlyEvAEK8mHuP0lLewicIrnFH6ZaJrCADb62Ann1ExwrAhH.'#... - generated from setup.php or php -r "echo password_hash('mysecretpassword', PASSWORD_DEFAULT);"

Note: Setup password hash is an example.

Actually, postfixadmin is already accessible and can be setup and used. The rest of the services are of course still unusable.

Postfix configurationWhy it was a challenge for me…

It was a challenge for me as my configuration grew hysterically (historically) over eight years. The files of DMS and mine were not really comparable, so I got down to the approach of stripping both versions of all empty lines and comments, sorting the lines and then comparing what’s left. Which got me down to:

Pseudocode and/or example lines!

# pseudocode and/or example lines!# remove comments, empty lines and sortcat main.cf | grep -v -E "^#|^$" | sort > old-main.cf# doing this with both main.cf files, lets you take the approach ofvimdiff old-main.cf dms-main.cf

Configure postfix to access the postgresql database

The actual configuration of postfix comes down to the settings for the four mappings of

  • smtpd_sender_login_maps
  • virtual_alias_maps
  • virtual_mailbox_domains
  • virtual_mailbox_maps

As we are working with postfixadmin the correct queries need to be set

sql/smtpd_sender_login_maps.cf

user = postfixpassword = dbname = postfixhosts = postgresql://postfix:@mailserverdb/postfixquery = SELECT username AS allowedUser FROM mailbox WHERE username='%s' AND active = true UNION SELECT goto FROM alias WHERE address='%s' AND active = true sql/virtual_alias_maps.cf

user = postfixpassword = dbname = postfixhosts = postgresql://postfix:@mailserverdb/postfixquery = SELECT goto FROM alias where address = '%s' and active = '1'table = aliasselect_field = gotowhere_field = addressadditional_conditions = and active = '1' sql/virtual_mailbox_domains.cf

user = postfixpassword = dbname = postfixhosts = postgresql://postfix:@mailserverdb/postfixquery = SELECT domain FROM domain where domain = '%s' and backupmx = '0' and active = '1'table = domainselect_field = domainwhere_field = domainadditional_conditions = and backupmx = '0' and active = '1' sql/virtual_mailbox_maps.cf

user = postfixpassword = dbname = postfixhosts = postgresql://postfix:@mailserverdb/postfixquery = SELECT CONCAT(domain, '/', local_part) FROM mailbox WHERE username = '%s' and active = '1'table = mailboxselect_field = CONCAT(domain, '/', local_part)where_field = usernameadditional_conditions = and active = '1'

Configure dovecot

Now dovecot needs the same SQL access to the database managed by postfixadmin and also needs to know about the password hashing algorithm.

In DMS the /etc/dovecot/dovecot-sql.conf.ext needs to be overwritten.
Like this example:

dovecot-sql.conf.ext

# I removed all the comments, to only show the actual important datadriver = pgsqlconnect = host=mailserverdb dbname=postfix user=postfix password= default_pass_scheme = SHA512-CRYPTuser_query = \ SELECT '/var/mail/%d/%n' as home, 'maildir:/var/mail/%d/%n' as mail, \ 5000 AS uid, 5000 AS gid, concat('dirsize:storage=', quota) AS quota \ FROM mailbox WHERE username = '%u' AND active = true password_query = \ SELECT username as user, password, '/var/mail/%d/%n' as userdb_home, \ 'maildir:/var/mail/%d/%n' as userdb_mail, 5000 as userdb_uid, 5000 as userdb_gid \ FROM mailbox WHERE username = '%u' AND active = true

pgsql

Remember what I said about DMS and databases? Yes? Good.

That DMS can work with the database you have to tweak it through user-patches.sh. I do not actually like that approach, especially if you would want to run the images without root policies enabled it will fail, but in my case it’s still okayish.

user-patches.sh

#!/usr/bin/env bashapt-get updateapt-get install -y postfix-pgsql dovecot-pgsql

Yes, that simple. Still without nothing will work with the postgresql database. In an optimization step the cache of repository and packages could be cleaned aswell, but for now it’s only about a working system.

Sending and receiving mail

To get to the point where the services can send and receive mail, I had to find out that my settings in dovecot were wrong. The sql queries suggested the user vmail with the uid=1001 and the gid=1002 which is obviously not available in DMS. So I changed that to the docker user/group id=5000 and it began working inside dovecot at least. Logging into roundcube without errors at last.

In the postfix-main.cf I still had one error, that I accidentally put in the wrong hostname. Typical typo. Also it complained that the same domain shouldn’t be listed in mydestination and virtual_mailbox_domains, so I removed it from mydestination.

After a restart, postfix was able to receive mail. YAY.

Now for sending mails…

Initially I had problems here. But I found out that the settings in my overwrite main.cf (dms/config/postfix-main.cf) did have an error. Actually, the variable smtpd_tls_chain_files was still set to the default ‘snakeoil’ variant of DMS and I had to set this to my correct lets-encrypt certificate (first the key, then the fullchain.cem) and my postfix could also send mails.

Additional settings (DKIM, DMARC, SPF)

The only additional setting where you should check with dms to finally have the full chain working is the rspamd DKIM setting. Here you should actually follow the guide (rspamd tab!) to generate a DKIM key. It immediately spits out the settings you have to do in your DNS configuration.

Same for DMARC and SPF, as there’s no key required for this, just follow the guide from DMS.

Managesieve, rspamd webinterface

Last but not least I want to see how to get managesieve and rspamd webinterface running.

Managesieve

Managesieve needs some extra configuration in roundcubemail. So you have to add at least this to your config.inc.php

$config['managesieve_host'] = 'tls://domain.to'; $config['managesieve_auth_type'] = 'PLAIN';

Not doing this, managesieve tries to access localhost, and with encryption and authentication, that will fail miserably. Been there, done that. 😉

rspamd web

This is also actually quite easy.

  • Copy out of the running container the file /etc/rspamd/local.d/worker-controller.inc
    • e.g. with this command:
      docker cp mailserver:/etc/rspamd/local.d/worker-controller.inc ./docker-data/dms/config/rspamd/
  • Run the command rspamadm pw inside the running container
    • docker-compose exec -it mailserver rspamadm pw
  • Copy the result into worker-controller.inc, like this:
    • password = "$2$wcopyxj5y8zeokzhbc6wm63tpq9magfg$f3omsrw4tgdq6x3pw16inkshms7tn3amix776refrt4pw2pujwdb";

Resulting file content:

# documentation: https://rspamd.com/doc/workers/controller.htmlbind_socket = "0.0.0.0:11334";password = "$2$wcopyxj5y8zeokzhbc6wm63tpq9magfg$f3omsrw4tgdq6x3pw16inkshms7tn3amix776refrt4pw2pujwdb";

Add a forwarding for the compose.yml in the ports section of mailserver.
(      - "8003:11334" # rspamd web)

Last but not least, add a line to the volumes section where you mount the worker-controller.inc to it’s place and restart the deployment.

(      - ./docker-data/dms/rspamd/worker-controller.inc:/etc/rspamd/local.d/worker-controller.inc:ro)

Finishing up

If you’ve read through this blog post, thank you for bearing with me through this journey.

For completness I will give you now almost all my config files here, with full content, especially those I showed only partly before, the small stuff i left out.
(Obviously anonymized and without passwords… :P)

And I condensed the config files to only contain actual configuration entries, removing empty lines and comments!

All configuration files

compose.yml

services: mailserver: image: ghcr.io/docker-mailserver/docker-mailserver:latest container_name: mailserver # Provide the FQDN of your mail server here (Your DNS MX record should point to this value) hostname: env_file: mailserver.env # More information about the mail-server ports: # https://docker-mailserver.github.io/docker-mailserver/latest/config/security/understanding-the-ports/ # To avoid conflicts with yaml base-60 float, DO NOT remove the quotation marks. ports: - "25:25" # SMTP (explicit TLS => STARTTLS) - "143:143" # IMAP4 (explicit TLS => STARTTLS) - "465:465" # ESMTP (implicit TLS) - "587:587" # ESMTP (explicit TLS => STARTTLS) - "993:993" # IMAP4 (implicit TLS) - "8003:11334" # rspamd web volumes: - ./docker-data/dms/mail-data/:/var/mail/ - ./docker-data/dms/mail-state/:/var/mail-state/ - ./docker-data/dms/mail-logs/:/var/log/mail/ - ./docker-data/dms/config/:/tmp/docker-mailserver/ - ./docker-data/dms/rspamd/worker-controller.inc:/etc/rspamd/local.d/worker-controller.inc:ro - ./docker-data/dms/config/dovecot-override/conf.d/10-auth.conf:/etc/dovecot/conf.d/10-auth.conf:ro - ./docker-data/dms/config/dovecot-override/conf.d/10-mail.conf:/etc/dovecot/conf.d/10-mail.conf:ro - ./docker-data/dms/config/dovecot-override/conf.d/90-sieve.conf:/etc/dovecot/conf.d/90-sieve.conf:ro - ./docker-data/dms/config/dovecot-override/dovecot-sql.conf.ext:/etc/dovecot/dovecot-sql.conf.ext:ro - ./docker-data/dms/config/postfix-override/sql:/etc/postfix/sql:ro - ./docker-data/dms/certs:/tmp/dms/custom-certs/:ro - /etc/localtime:/etc/localtime:ro restart: always stop_grace_period: 1m # Uncomment if using `ENABLE_FAIL2BAN=1`: cap_add: - NET_ADMIN healthcheck: test: ["CMD-SHELL", "ss --listening --tcp | grep -P 'LISTEN.+:smtp' || exit 1"] timeout: 3s retries: 0 mailserverdb: image: postgres:14 restart: always env_file: db.env volumes: - ./docker-data/postgres/data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"] interval: 1s timeout: 5s retries: 10 postfixadmin: image: postfixadmin:apache restart: always env_file: postfixadmin.env ports: - 8002:80 roundcube: image: roundcube/roundcubemail:latest restart: always env_file: roundcube.env ports: - 8001:80 volumes: - ./docker-data/roundcube/html:/var/www/html - ./docker-data/roundcube/data:/var/roundcube/db - ./docker-data/roundcube/config:/var/roundcube/config

mailserver.env

OVERRIDE_HOSTNAME=DMS_DEBUG=0LOG_LEVEL=infoSUPERVISOR_LOGLEVEL=ONE_DIR=1ACCOUNT_PROVISIONER=POSTMASTER_ADDRESS=ENABLE_UPDATE_CHECK=1UPDATE_CHECK_INTERVAL=1dPERMIT_DOCKER=noneTZ=Europe/BerlinNETWORK_INTERFACE=TLS_LEVEL=SPOOF_PROTECTION=ENABLE_SRS=0ENABLE_OPENDKIM=0ENABLE_OPENDMARC=0ENABLE_POLICYD_SPF=0ENABLE_POP3=ENABLE_CLAMAV=0ENABLE_RSPAMD=1ENABLE_RSPAMD_REDIS=1RSPAMD_LEARN=1RSPAMD_GREYLISTING=1RSPAMD_HFILTER=1RSPAMD_HFILTER_HOSTNAME_UNKNOWN_SCORE=6ENABLE_AMAVIS=0AMAVIS_LOGLEVEL=0ENABLE_DNSBL=1ENABLE_FAIL2BAN=1FAIL2BAN_BLOCKTYPE=dropENABLE_MANAGESIEVE=1POSTSCREEN_ACTION=enforceSMTP_ONLY=SSL_TYPE=manualSSL_CERT_PATH=/tmp/dms/custom-certs/fullchain.cerSSL_KEY_PATH=/tmp/dms/custom-certs/cert.keySSL_ALT_CERT_PATH=SSL_ALT_KEY_PATH=VIRUSMAILS_DELETE_DELAY=POSTFIX_DAGENT=POSTFIX_MAILBOX_SIZE_LIMIT=ENABLE_QUOTAS=1POSTFIX_MESSAGE_SIZE_LIMIT=20480000CLAMAV_MESSAGE_SIZE_LIMIT=PFLOGSUMM_TRIGGER=PFLOGSUMM_RECIPIENT=PFLOGSUMM_SENDER=LOGWATCH_INTERVAL=LOGWATCH_RECIPIENT=LOGWATCH_SENDER=REPORT_RECIPIENT=REPORT_SENDER=LOGROTATE_INTERVAL=weeklyPOSTFIX_REJECT_UNKNOWN_CLIENT_HOSTNAME=0POSTFIX_INET_PROTOCOLS=allDOVECOT_INET_PROTOCOLS=allENABLE_SPAMASSASSIN=0SPAMASSASSIN_SPAM_TO_INBOX=1ENABLE_SPAMASSASSIN_KAM=0MOVE_SPAM_TO_JUNK=1SA_TAG=2.0SA_TAG2=6.31SA_KILL=10.0SA_SPAM_SUBJECT=***SPAM*****ENABLE_FETCHMAIL=0FETCHMAIL_POLL=300ENABLE_GETMAIL=0GETMAIL_POLL=5ENABLE_LDAP=LDAP_START_TLS=LDAP_SERVER_HOST=LDAP_SEARCH_BASE=LDAP_BIND_DN=LDAP_BIND_PW=LDAP_QUERY_FILTER_USER=LDAP_QUERY_FILTER_GROUP=LDAP_QUERY_FILTER_ALIAS=LDAP_QUERY_FILTER_DOMAIN=DOVECOT_TLS=DOVECOT_USER_FILTER=DOVECOT_PASS_FILTER=DOVECOT_MAILBOX_FORMAT=maildirDOVECOT_AUTH_BIND=ENABLE_POSTGREY=0POSTGREY_DELAY=300POSTGREY_MAX_AGE=35POSTGREY_TEXT="Delayed by Postgrey"POSTGREY_AUTO_WHITELIST_CLIENTS=5ENABLE_SASLAUTHD=0SASLAUTHD_MECHANISMS=SASLAUTHD_MECH_OPTIONS=SASLAUTHD_LDAP_SERVER=SASLAUTHD_LDAP_BIND_DN=SASLAUTHD_LDAP_PASSWORD=SASLAUTHD_LDAP_SEARCH_BASE=SASLAUTHD_LDAP_FILTER=SASLAUTHD_LDAP_START_TLS=SASLAUTHD_LDAP_TLS_CHECK_PEER=SASLAUTHD_LDAP_TLS_CACERT_FILE=SASLAUTHD_LDAP_TLS_CACERT_DIR=SASLAUTHD_LDAP_PASSWORD_ATTR=SASLAUTHD_LDAP_AUTH_METHOD=SASLAUTHD_LDAP_MECH=SRS_SENDER_CLASSES=envelope_senderSRS_EXCLUDE_DOMAINS=SRS_SECRET=DEFAULT_RELAY_HOST=RELAY_HOST=RELAY_PORT=25RELAY_USER=RELAY_PASSWORD=

postfixadmin.env

POSTFIXADMIN_DB_TYPE=pgsql POSTFIXADMIN_DB_NAME=postfix POSTFIXADMIN_DB_USER=postfix POSTFIXADMIN_DB_HOST=mailserverdb#POSTFIXADMIN_DB_PORT= POSTFIXADMIN_DB_PASSWORD=POSTFIXADMIN_ENCRYPT='php_crypt:SHA512::{SHA512-CRYPT}'POSTFIXADMIN_SETUP_PASSWORD='$2y$10$hYwsErlyEvAEK8mHuP0lLewicIrnFH6ZaJrCADb62Ann1ExwrAhH.'

roundcube.env

ROUNDCUBEMAIL_DEFAULT_HOST=tls://domain.to#ROUNDCUBEMAIL_DEFAULT_PORT=143 # defaultROUNDCUBEMAIL_SMTP_SERVER=tls://domain.to#ROUNDCUBEMAIL_SMTP_PORT=587 # default#ROUNDCUBEMAIL_REQUEST_PATH=/ # defaultROUNDCUBEMAIL_PLUGINS=archive,zipdownload,password,managesieveROUNDCUBEMAIL_SKIN=elastic # defaults to larryROUNDCUBEMAIL_UPLOAD_MAX_FILESIZE=20M# ROUNDCUBEMAIL_SPELLCHECK_URIROUNDCUBEMAIL_ASPELL_DICTS=de,en

db.env

POSTGRES_USER=postfixPOSTGRES_PASSWORD=POSTGRES_DB=postfix

dovecot-override/conf.d/10-auth.conf

disable_plaintext_auth = yesauth_realms = domain.toauth_default_realm = domain.toauth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@auth_username_format = %Luauth_mechanisms = plain login!include auth-sql.conf.ext

dovecot-override/conf.d/10-mail.conf

mail_location = maildir:/var/mail/%d/%nnamespace inbox { inbox = yes}mail_uid = 5000mail_gid = 5000mail_privileged_group = dockermail_plugins = $mail_plugins quotamaildir_stat_dirs = yesmaildir_copy_with_hardlinks = yes

dovecot-override/conf.d/90-sieve.conf

plugin { sieve = ~/.dovecot.sieve sieve_dir = ~/sieve sieve_before = /usr/lib/dovecot/sieve-global/before/ sieve_after = /usr/lib/dovecot/sieve-global/after/ sieve_extensions = +notify +imapflags +vnd.dovecot.pipe +vnd.dovecot.filter sieve_plugins = sieve_imapsieve sieve_extprograms recipient_delimiter = + sieve_max_script_size = 1M sieve_max_actions = 32 sieve_pipe_bin_dir = /usr/lib/dovecot/sieve-pipe sieve_filter_bin_dir = /usr/lib/dovecot/sieve-filter}

dovecot-override/dovecot-sql.conf.ext

driver = pgsqlconnect = host=mailserverdb dbname=postfix user=postfix password=default_pass_scheme = SHA512-CRYPTuser_query = \ SELECT '/var/mail/%d/%n' as home, 'maildir:/var/mail/%d/%n' as mail, \ 5000 AS uid, 5000 AS gid, concat('dirsize:storage=', quota) AS quota \ FROM mailbox WHERE username = '%u' AND active = true password_query = \ SELECT username as user, password, '/var/mail/%d/%n' as userdb_home, \ 'maildir:/var/mail/%d/%n' as userdb_mail, 5000 as userdb_uid, 5000 as userdb_gid \ FROM mailbox WHERE username = '%u' AND active = true

postfix-accounts.cf (containing actually just a dummy)

dummy@domain.to|{SHA512-CRYPT}$6$0iuxO1kKZ.TjWX6V$zDfx8w11yHcxHogY8itJVnnoJhNDgfRXZFcmIDbzgicqQY/EimV6Zl6QlyU2tCPyLcbNYqFsxgEef31QzFFv91

postfix-main.cf

alias_database = hash:/etc/aliasesappend_dot_mydomain = nobiff = nobroken_sasl_auth_clients = yescompatibility_level = 2disable_vrfy_command = yesdms_smtpd_sender_restrictions = reject_authenticated_sender_login_mismatch, permit_sasl_authenticated, permit_mynetworks, warn_if_reject reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unauth_pipelining, permitheader_checks = pcre:/etc/postfix/maps/header_checks.pcreinet_interfaces = allinet_protocols = alllocal_recipient_maps = $virtual_alias_mapsmailbox_size_limit = 0maximal_backoff_time = 8000smaximal_queue_lifetime = 7dmessage_size_limit = 21504000milter_default_action = acceptmilter_protocol = 6minimal_backoff_time = 1000smua_sender_restrictions = reject_authenticated_sender_login_mismatch, $dms_smtpd_sender_restrictionsmydestination = localhost.$mydomain, localhostmyhostname = domain.tomynetworks = 172.0.0.0/24 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 [fe80::]/64mynetworks_style = hostmyorigin = localhostnon_smtpd_milters =proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks $smtpd_sender_login_mapspostscreen_bare_newline_action = enforcepostscreen_dnsbl_action = enforcepostscreen_dnsbl_sites = b.barracudacentral.org*2 bl.mailspike.net=127.0.0.[2;14;13;12;11;10] bl.spameatingmonkey.net=127.0.0.2 dnsbl.sorbs.net list.dnswl.org=127.0.[0..255].0*-2 list.dnswl.org=127.0.[0..255].1*-3 list.dnswl.org=127.0.[0..255].[2..3]*-4 psbl.surriel.com zen.spamhaus.org=127.0.0.[2..11]*3postscreen_dnsbl_threshold = 3postscreen_dnsbl_whitelist_threshold = -1postscreen_greet_action = enforcereadme_directory = norecipient_delimiter = +relayhost =smtpd_banner = $myhostname ESMTP $mail_name (Arch Linux/GNU)smtpd_client_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, reject_unauth_pipeliningsmtpd_delay_reject = yessmtpd_helo_required = yessmtpd_helo_restrictions = permit_mynetworks, warn_if_reject reject_non_fqdn_hostname, reject_invalid_hostname, reject_invalid_helo_hostname, permitrspamd_milter = inet:localhost:11332smtpd_milters = $rspamd_miltersmtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination, reject_unauth_pipelining, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname, reject_unknown_recipient_domain, check_policy_service inet:localhost:65265smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destinationsmtpd_sasl_auth_enable = yessmtpd_sasl_authenticated_header = yessmtpd_sasl_local_domain = $mydomainsmtpd_sasl_path = /dev/shm/sasl-auth.socksmtpd_sasl_security_options = noanonymoussmtpd_sasl_type = dovecotsmtpd_sender_login_maps = pgsql:/etc/postfix/sql/virtual_sender_login_maps.cfsmtpd_sender_restrictions = $dms_smtpd_sender_restrictionssmtpd_soft_error_limit = 3smtpd_tls_CApath = /etc/ssl/certssmtpd_tls_chain_files = /tmp/dms/custom-certs/cert.key /tmp/dms/custom-certs/fullchain.cersmtpd_tls_dh1024_param_file = /etc/postfix/dhparams.pemsmtpd_tls_exclude_ciphers = aNULL, SEED, CAMELLIA, RSA+AES, SHA1smtpd_tls_loglevel = 1smtpd_tls_received_header = yessmtpd_tls_mandatory_ciphers = highsmtpd_tls_mandatory_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1smtpd_tls_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1smtpd_tls_security_level = maysmtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scachesmtpd_tls_session_cache_timeout = 3600ssmtp_helo_timeout = 60ssmtp_tls_note_starttls_offer = yessmtp_header_checks = pcre:/etc/postfix/maps/sender_header_filter.pcresmtp_tls_CApath = /etc/ssl/certssmtp_tls_loglevel = 1smtp_tls_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1smtp_tls_security_level = maytls_high_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384tls_preempt_cipherlist = yestls_ssl_options = NO_COMPRESSION, NO_RENEGOTIATIONsmtp_tls_session_cache_database = btree:${data_directory}/smtp_scachetls_random_source = dev:/dev/urandomunknown_local_recipient_reject_code = 450virtual_alias_maps = pgsql:/etc/postfix/sql/virtual_alias_maps.cfvirtual_mailbox_base = /var/mailvirtual_mailbox_domains = pgsql:/etc/postfix/sql/virtual_domains_maps.cfvirtual_mailbox_maps = pgsql:/etc/postfix/sql/virtual_mailbox_maps.cfvirtual_transport = lmtp:unix:/var/run/dovecot/lmtp

postfix-override/sql/virtual_*_maps.cf (all in one, separated by comment)

# virtual_alias_maps.cfuser = postfixdbname = postfixhosts = postgresql://postfix:@mailserverdb/postfixquery = SELECT goto FROM alias where address = '%s' and active = '1'table = aliasselect_field = gotowhere_field = addressadditional_conditions = and active = '1'# virtual_domains_maps.cfuser = postfixdbname = postfixhosts = postgresql://postfix:@mailserverdb/postfixquery = SELECT domain FROM domain where domain = '%s' and backupmx = '0' and active = '1'table = domainselect_field = domainwhere_field = domainadditional_conditions = and backupmx = '0' and active = '1'# virtual_mailbox_maps.cfuser = postfixdbname = postfixhosts = postgresql://postfix:@mailserverdb/postfixquery = SELECT CONCAT(domain, '/', local_part) FROM mailbox WHERE username = '%s' and active = '1'table = mailboxselect_field = CONCAT(domain, '/', local_part)where_field = usernameadditional_conditions = and active = '1'# virtual_sender_login_maps.cfuser = postfixdbname = postfixhosts = postgresql://postfix:@mailserverdb/postfixquery = SELECT username AS allowedUser FROM mailbox WHERE username='%s' AND active = true UNION SELECT goto FROM alias WHERE address='%s' AND active = true

At last, if anyone spots errors or has suggestions to improve the configurations, feel free to comment.

Share this:

Related

#docker #dovecot #email #linux #migration #postfix #postfixadmin #roundcubemail

https://www.mmo.to/2023/08/setting-up-dms-docker-mailserver-with-postgresql-postfixadmin-and-roundcubemail/

GitHub - docker-mailserver/docker-mailserver: Production-ready fullstack but simple mail server (SMTP, IMAP, LDAP, Antispam, Antivirus, etc.) running inside a container.

Production-ready fullstack but simple mail server (SMTP, IMAP, LDAP, Antispam, Antivirus, etc.) running inside a container. - docker-mailserver/docker-mailserver

GitHub

I enable PHP debugging on my test systems to give me an awareness of what an application is doing.

#postfixadmin is making me reconsider that practice. #sysadmin