How to create a mailserver selfhosted in 2022 . Tutorial Google GMAIL alternative
In this post we'll make our own IMAP mail server via selfhosting. Yeah I know it's boring and won't receive a prize to do that.
The drawing how the Stable Diffusion AI see the current email situation
WHY A SELF HOSTED MAIL SERVER ?
- Is still usefull an email in 2022? Yes, maybe not for casual chatting but as identity to register in online services. The phone number shuld be avoided.
- decentralization, mail is a protocol not a service. And it shouldn't be only in the hands of a few players. Anti SPAM rules, DKIM, DMARC, SPF, reverse DNS, TLS/SSL and blacklists can be an issue.
- Chat Control, CSS (Client Side Scanning and Server Side Scanning), CSAM,.. In EU are trying to force the service provider to scan the user data to fight the children abuses, opening a huge backdoor for the user privacy. Like the GreenPass it won't solve the issue but it will limit the people lives.
- Third because I can :) protonmail, tutanota and all the over "super secure privacy-oriented VPN easy TOR anonymous things" are just buzzwords. You can't really trust a service that manages your unencrypted data. End-to-End encryption can mitigate it but other data are still exposed
At the end you'll get a working IMAP mail server
mail.greatreset.com
andklaus@greatreset.com
and of course greatreset.com it'just an example domain.
PREREQUISITES
- Knowledge: linux terminal, docker, docker-compose, DNS
- $ A domain like
greatreset.com
- $ Public IP (It means a VPS with 2Gb RAM (512Mb minimun)
Lets start: an easy mailserver to deploy docker-mailserver
There are tons of mailservers webmail 1-click solutions, but this one is the most complete and flexible to deploy. It plays nice with reverse proxies and it doesn't take the full control of your machine.
Installation
Please check the official docker-mailserver docs for the updated commands.
The following commands will provide the docker-compose.yml
and a script helper setup.sh
, very useful to avoid to change some configs manually.
DMS_GITHUB_URL='https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master'
wget "${DMS_GITHUB_URL}/docker-compose.yml"
wget "${DMS_GITHUB_URL}/mailserver.env"
wget "${DMS_GITHUB_URL}/setup.sh"
chmod a+x ./setup.sh
My current docker-compose.yml
looks like this:
# docker-compose.yml
version: '3'
services:
mailserver:
image: docker.io/mailserver/docker-mailserver:latest
container_name: mailserver
# If the FQDN for your mail-server is only two labels (eg: example.com),
# you can assign this entirely to `hostname` and remove `domainname`.
hostname: mail
domainname: greatreset.com
env_file: mailserver.env
# More information about the mail-server ports:
# https://docker-mailserver.github.io/docker-mailserver/edge/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)
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/
- /etc/localtime:/etc/localtime:ro
# !! traefix 1.7 no buono
# - /apps/traefik/config/acme.json:/etc/letsencrypt/acme.json:ro
# - ./docker-data/certbot/certs/:/etc/letsencrypt
# Traefik acme
- /apps/traefik/letsencrypt/acme.json:/etc/letsencrypt/acme.json:ro
restart: always
stop_grace_period: 1m
environment:
- SSL_TYPE=letsencrypt
- SSL_DOMAIN=mail.greatreset.com
- ENABLE_SPAMASSASSIN=1
- SPAMASSASSIN_SPAM_TO_INBOX=1
- ENABLE_CLAMAV=1
- ENABLE_FAIL2BAN=1
- ENABLE_POSTGREY=1
- ENABLE_SASLAUTHD=0
- ONE_DIR=1
cap_add:
- NET_ADMIN
healthcheck:
test: "ss --listening --tcp | grep -P 'LISTEN.+:smtp' || exit 1"
timeout: 3s
retries: 0
mailacme:
image: docker.io/traefik/whoami:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.mailacme.rule=Host(`mail.greatreset.com`)"
- "traefik.http.routers.mailacme.entrypoints=websecure"
- "traefik.http.routers.mailacme.tls.certresolver=myresolver"
networks:
- web
networks:
web:
external: true
You can specify other configurations in mailserver.env
but I've left it as is.
docker-compose up -d
Will start the environment and with docker compose logs -f
you can see what is going on. Some errors, for different reasons, aren't available there.
My first email address selfhosted
./setup.sh email add klaus@greatreset.com
# or if you prefer postmaster@greatreset.com
It will be asked to pick a password for the email account you are creating.
This is the most tricky part, hard to debug and you also need to wait the DNS propagation.
Some DNS configurations: DKIM SPF DMARC
These steps aren't mandatory but if you don't do them your messages will go 100% in the Spam folder! So don't skip this part
Check the official doc for more details.
Now you need to add some records to your DNS, usually it's done via the domain provider web interface.
DKIM
You can also specify multiple domains comma separated.
./setup.sh config dkim domain greatreset.com
Then you need to copy the DKIM key from your config and clean it by removing the " char.
sudo cat docker-data/dms/config/opendkim/keys/greatreset.com/mail.txt
Now you are ready to fill the form, just choose the right type like this:
Wait some minutes and check if the values are propagated via DNS
$ dig mail._domainkey.greatreset.com MX | grep MX
; <<>> DiG 9.18.7 <<>> mail._domainkey.greatreset.com MX
;mail._domainkey.greatreset.com. IN MX
..
$ dig mail._domainkey.greatreset.com TXT
...
mail._domainkey.greatreset.com. 1787 IN TXT "v=DKIM1; k=rsa; p=..."
...
$ dig _dmarc.greatreset.com TXT
..
_dmarc.greatreset.com. 1699 IN TXT "v=DMARC1; p=none"
..
HTTPS SSL TLS
Email communication, like HTTP, is unencrypted by default, so you need some valid certificates to obtain the HTTPS but for IMAP.
This can be complicated if your ports 80 443 are busy with a reverse proxy like nginx, caddy or traefik.
My advice is to use the traefik v2
way (here) if you can otherwise the letsencrypt
way (here) is standalone but you need to stop the reverse proxy, change the docker-compose.yml during the verification to avoid the ports conflict.
rDNS Reverse DNS
This is optional, but it helps to get the maximun score. It means that your VPS public IP will be resolved to your mail.greatreset.com
server
Congrats, now your mailserver is ready! But it's not over!
Configure IMAP parameters in the Mail Client
user: klaus@greatreset.com
password: xxx
IMAP
mail.greatreset.com SSL/TLS port 993
SMTP
mail.greatreset.com SSL/TLS port 465
You can pick a software like Thunderbird (desktop Linux, Mac, Windows) or K-9 Mail (Android) or a Webmail like Mail app in Nextcloud.
You can a more GMail -like experience enabling the "conversation extension" in Thunderbird.
Test your Configuration
If you did everything correctly you should have at least 10/10 score in www.mail-tester.com, you can send a email message to it to see your score and debug if you missed some parts, you can open each section to see the details. Another tool is the MX and DKIM checker online (here)
Congratulation redpilled, now you are outsite the Matrix and you need to mantain it by yourself.
Be ready to do:
- updates (the official project will send a message every time a new version is released.
- backups
- and security brute force mitigations
This IP from Vietnam 103.133.107.152
is already trying a brute force attack to find an OpenRelay. Good luck with the firewall!
Oct 13 11:52:13 mail postfix/submission/smtpd[420557]: connect from unknown[103.133.107.152]
Oct 13 11:52:13 mail postfix/submission/smtpd[420557]: SSL_accept error from unknown[103.133.107.152]: lost connection
Oct 13 11:52:13 mail postfix/submission/smtpd[420557]: lost connection after STARTTLS from unknown[103.133.107.152]
Oct 13 11:52:13 mail postfix/submission/smtpd[420557]: disconnect from unknown[103.133.107.152] ehlo=1 starttls=0/1 commands=1/2
Oct 13 11:52:14 mail postfix/postscreen[420688]: CONNECT from [103.133.107.152]:30261 to [172.31.0.2]:25
Oct 13 11:52:14 mail postfix/postscreen[420688]: HANGUP after 0 from [103.133.107.152]:30261 in tests before SMTP handshake
Oct 13 11:52:14 mail postfix/postscreen[420688]: DISCONNECT [103.133.107.152]:30261
Oct 13 11:52:14 mail postfix/postscreen[420688]: CONNECT from [103.133.107.152]:30284 to [172.31.0.2]:25
Oct 13 11:52:20 mail postfix/postscreen[420688]: PASS NEW [103.133.107.152]:30284
Oct 13 11:52:20 mail postfix/smtpd[420709]: connect from unknown[103.133.107.152]
Oct 13 11:52:20 mail postfix/smtpd[420709]: NOQUEUE: reject: RCPT from unknown[103.133.107.152]: 554 5.7.1 <irdi33@yahoo.com>: Relay access denied; from=<irdi33@yahoo.com> to=<irdi33@yahoo.com> proto=SMTP helo=<win-oy0k2ahb8s6.domain>
But the fail2ban
provided already is doing a great job
root@mail:/# zgrep 'Ban' /var/log/fail2ban.log*
2022-10-12 18:58:10,978 fail2ban.actions [729]: NOTICE [dovecot] Ban 2.56.58.89
2022-10-12 18:58:12,580 fail2ban.actions [729]: NOTICE [postfix-sasl] Ban 2.56.58.89
2022-10-12 23:34:20,228 fail2ban.actions [729]: NOTICE [dovecot] Ban 58.246.96.36
2022-10-12 23:34:21,391 fail2ban.actions [729]: NOTICE [postfix-sasl] Ban 58.246.96.36
2022-10-13 11:52:41,469 fail2ban.actions [729]: NOTICE [dovecot] Ban 103.133.107.152
2022-10-13 11:52:42,876 fail2ban.actions [729]: NOTICE [postfix-sasl] Ban 103.133.107.152
Se sei interessato al tema del selfhosting, di come farti il cloud in casa, su Techonsapevole Academy altri video di approfondimento.