Tutorial: Your own mail server (Dovecot, Postfix, Rspamd) with tight Nextcloud (on Apache) integration for Debian

I created a relatively comprehensive tutorial on how to set up a mail server
(Postfix, Dovecot, Rspamd,…) for unlimited users and domains and tightly integrate it with Nextcloud (on Apache). My goal was to create an all-in-one, step-by-step tutorial from beginning to end with the most modern and secure features known to me. Obviously it has A+ rating for the TLS, uses Let’s Encrypt etc. I tried to explain key concepts and provide the “why” on most configuration choices, so you actually understand why things are done the way they are done.

I partly used other tutorials as a basis, but also did a lot of research and
e.g. used much stricter spam reducing parameters and also e.g. a normalized db on PostgreSQL which is imho superior to MariaDB.

You can check it out on 123qwe.com. Check the Overview section to see the architecture in more detail.

I hope it will be useful to someone. Constructive feedback is of course very welcome and appreciated.


Wahoo, just spend a few minutes on it, quiet a job…

It was. :slight_smile:

whoa! looks great. thanks so far. will dive into it in a bit… <3

The tutorial looks amazing on first glance. Great job. Thank you for the effort in creating it and sharing it. However, how do you get around the issue with hosting an email server from a residential IP address?

From Ars Technica article:
So you want your own e-mail server. Excellent! The first decision, before we even get into things like operating systems and applications, is where you’re going to put it. If you’re on a residential ISP connection, you will face a number of challenges in running an e-mail server out of your closet. In addition to almost certainly finding the standard set of e-mail TCP ports blocked, your IP address is also almost certainly already on one or more blacklists in order to cut down on the amount of spam being spewed out by virus-infected home computers. Whether or not you’re actually spewing any spam is irrelevant—that ship has long since sailed, and residential IP addresses are almost universally considered poisoned. There are numerous tools you can use to see if your address is on a blacklist—make sure to check before you start.

I don’t, I am using a virtual server that I “rent”. This is much more reliable and comes with a very fast connection. It’s really expensive to get an Internet plan with high upload and that kind of availability.

Of course there is the drawback of less privacy because potentially a malicious admin of the hoster could access the vhost, but at least afaics it’s illegal in Germany and not trivial because they don’t have a user on my OS, so they would have to go a few levels lower. Since you should assume that any cloud, even Nextcloud, can be compromised (e.g. zero day exploits) I would not recommend to put anything there, that if compromised, would have catastrophic implications for you anyway. So using a vhost is a compromise I can live with.

That’s why E2EE is so important actually.

For hosting a mailserver at home, you could use a “smarthost” to send mail and Fetchmail to pull IMAP/POP3 mailboxes. Not quite a private mail server, but at least the mails stay locally on your own server.

Afaik E2EE is unfortunately still in alpha and should not be used in production environments.

True, the Nextcloud implementation isn’t, but I just wanted to mention it as a measure against snooping server operators. Aside from that, other options exist in the meantime, like for example Cryptomator.

1st I have to thank you for the great work you have done with this tutorial.

But I have to admit, that after reading there are still some open questions:

  1. Why PostgreSQL?

can you explain this statement with a bit more background info?

  1. Why no virus scan implementation?
    Is there a special reason why you did not even mention a virus scan in this context?

  2. What’s about redis?
    As far as I know Rspamd depends on redis when it comes to caching. Why do you use APCu instead of redis for caching in nextcloud?

These questions are no criticism at all, but will help me to get a deeper understanding of the subject.

Why PostgreSQL?

For me the reasons are

  • a lower memory footprint
  • more convenient functions, e.g. ILIKE for case insensitive search which is a mess in MariaDB, i.e. queries becomes way more complex instead of just using ILIKE instead of LIKE as you can with Postgres.
  • PostgreSQL just feels more rounded, is more standard compliant and creates less hassle. MariaDB (to me personally) feels too “hacky” compared to Postgres. Another example is that to make MariaDB queries secure with PDO in PHP you need to make sure the right charset is used. In Postgres “it just works”.

Why no virus scan implementation?

Because virus scanners are mostly snake oil, i.e. give you a wrong sense of security while detecting few viruses that really matter. This might be even more true for desktop solutions but I just decided that its not worth the effort for the little to no gain.

What’s about redis?

I actually state in the tutorial that you should use Redis for larger user bases and provide links to instructions on how to set up Redis. I did not include it merely because at some point I had to make a cut (you can always explain more and do more but time is limited) and for my use case I don’t need it (relatively few users). But if you do, just follow the links.

Thx for your explanations. Honestly Database is just a black box for me at the moment. So any real-world comparison is more than welcome.

Thank you for posting this tutorial, it’s exactly what I wanted to do :smiley:

I’m hoping that you can help, or point me in a helpful direction, since you know much more about this topic than I do.

After starting dovecot, when I check the error log, it says

mail dovecot: auth: Fatal: sql /etc/dovecot/dovecot-sql.conf.ext: Error in configuration file /etc/dovecot/dovecot-sql.conf.ext line 72: Unknown setting: password

Then command startup failed, throttling for x seconds, imap error login timeout.

I went triple-checked the tutorial to make sure I’d typed correctly (checked to make sure I typed it properly, tried putting password on a different line, tried putting it all on one line the way I’d done it initially in case it auto-misformatted).

These seemed most relevant, but I checked others:

There were others that were more relevant, but they didn’t have answers, and I lost track of them (sorry!)

It seems that the issue actually has nothing to do with the password setting, since by all accounts that is an actual setting that is supposed to be there.

Every test up to this point has worked successfully, except the SSL setup; I used the --staging option for that, but when I reran it without that, it said the certificates were already there and to use force renew. When I visit my domain in a browser it says
But that is fixed with
and I was going to do that afterwords, when everything else was set up, since I didn’t want to lose my place. I’m not sure if that’s related but I want to give as much information as possible.

So, I’m not sure where to look next, since the error seems to be of the “something other than what the error says is causing it to spit this error out” type, but everything else has tested as working.

Any help would be greatly appreciated, and thank you for this tutorial :smiley:

Okay, I switched (in the offending file mentioned in the previous post) from to localhost since they mean the same thing and the latter was used both originally in the file and in the dovecot wiki. /var/log/mail.err didn’t spit out an error when I reloaded dovecot, nor when I tried the start command. I’m going to consider this fixed for now and keep going. I’ll update as events warrant.

Update: I went back to where I was, and the next step was test the mail server. I used the telnet command, and it worked. Wtf. Let’s see if it sticks.

Update2: Test email went through. Seems to have worked, in both directions…

Hey, I am very busy with a non-hobby project atm, so I haven’t had the time to come here and didn’t see your question. Glad, it works now.

Hi all, hi @PancakeConnaisseur ! This tutorial is awesome, very detailed and everything is explained very well. But I have one issue with it. I’m using environment where we have MariaDB(MySQL) already deployed. I don’t want to install additional database instance just to maintain email addresses.

I was never working with PostgreSQL and it seems MySQL lacks some features like for example user-defined domain…

Can anybody help translating these SQL statements to MySQL?

Thank you so much.

Now that is how a tutorial is done easy to follow and learned a lot. Of course at the very end ran into a problem and have been stuck for a couple days. After installing User Backend Using Raw SQL I cant access the Users in the profile so I am not able to create any users. I get an internal error page and nextcloud.log gives error “File”:"/var/www/nextcloud/apps/user_backend_sql_raw/lib/Dbs/Postgresql.php",“Line”:30,“CustomMessage”:"–"} . This is the file the error is referring to.
namespace OCA\UserBackendSqlRaw\Dbs;
24 use OCA\UserBackendSqlRaw\Db;
25 use \PDO;
27 class Postgresql extends Db {
29 protected function createDbHandle() {
30 return new PDO($this->assembleDsn());
31 }
33 protected function assembleDsn() {
34 return ‘pgsql:host=’ . $this->config->getDbHost()
35 . ‘;port=’ . $this->config->getDbPort()
36 . ‘;dbname=’ . $this->config->getDbName()
37 . ‘;user=’ . $this->config->getDbUser()
38 . ‘;password=’ . $this->config->getDbPassword();
39 }
40 }

Any clues would be great.
UPDATE: This was solved by removing \ symbol in the mail_admin password. Once removed User Backend Using Raw SQL connected perfectly. This really was the best tutorial I have ever used and just what I needed. Thanks @PancakeConnaisseur you really raised the bar on tutorials with this one.

1 Like

After weeks of research, testing and writing I have released an updated version for Debian 10 (Buster). You can view the changes in the changelog.

The main things are:

  • Debian 10 packages
  • TLS security and password hashing ramped up
  • simplifications in Apache configuration

Feedback is very welcome. Either here or in the comments on the site.


3 posts were split to a new topic: TLS can’t open secure connection to own mailserver

Just realized that both links were dead. I change the structure of the guide after the release and forgot to update them here. :man_facepalming:. It is fixed now.

1 Like