In this tutorial we're going to setup a self hosted mail server using lukesmith's emailwiz.sh script:
First step is, get a VPS on vultr.com, and ssh to it after you've setup an A record to it, for me it's mail.void.yt
[ 10.66.66.2/32 ] [ /dev/pts/37 ] [~]
→ ssh root@mail.void.yt
Welcome to Ubuntu 21.10 (GNU/Linux 5.13.0-20-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Sun Oct 31 01:36:43 PM UTC 2021
System load: 0.04 Processes: 143
Usage of /: 10.3% of 54.41GB Users logged in: 0
Memory usage: 11% IPv4 address for enp1s0: 45.32.9.224
Swap usage: 0%
0 updates can be applied immediately.
Last login: Sun Oct 31 13:34:04 2021 from 78.141.239.68
root@mail:~# apt update -y ; apt upgrade -y ; apt install vim tmux curl certbot python3-certbot-nginx nginx -y
root@mail:~# curl -LO lukesmith.xyz/emailwiz.sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 178 100 178 0 0 221 0 --:--:-- --:--:-- --:--:-- 221
100 154 100 154 0 0 104 0 0:00:01 0:00:01 --:--:-- 104
100 12137 100 12137 0 0 7122 0 0:00:01 0:00:01 --:--:-- 455k
root@mail:~# chmod +x emailwiz.sh
root@mail:~# systemctl disable --now ufw
Now before we continue, let's update the DNS and Reverse DNS:
if you're confused about the MX record, here it is (do not forget the trailing dot at the end):
Once that's done, make sure the DNS record points to your VPS:
root@mail:~# curl ifconfig.me ; echo; echo; nslookup mail.void.yt
45.76.133.0
Server: 108.61.10.10
Address: 108.61.10.10#53
Non-authoritative answer:
Name: mail.void.yt
Address: 45.76.133.0
Name: mail.void.yt
Address: 2001:19f0:7001:4de1:5400:3ff:fea6:e93f
Name: mail.void.yt
Address: 2001:19f0:7002:e3c:5400:3ff:fea7:8e7
Name: mail.void.yt
Address: 2001:19f0:7401:85a0:5400:3ff:fea7:20d2
Name: mail.void.yt
Address: 2001:19f0:7402:2c6:5400:3ff:fea7:22a3
Then we're going to setup a basic nginx website along with a free TLS certificate using certbot:
root@mail:~# vim /etc/nginx/sites-available/default
root@mail:~# cat /etc/nginx/sites-available/mail.void.yt.conf
server {
listen 80;
listen [::]:80 ;
root /var/www/mail;
index index.html;
server_name mail.void.yt;
location / {
try_files $uri $uri/ =404;
}
}
root@mail:~# mv /etc/nginx/sites-available/default /etc/nginx/sites-available/mail.void.yt.conf
root@mail:~# rm -rf /etc/nginx/sites-enabled/default
root@mail:~# ln -s /etc/nginx/sites-available/mail.void.yt.conf /etc/nginx/sites-enabled/mail.void.yt.conf
root@mail:~# systemctl restart nginx
root@mail:~# systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2021-10-31 19:19:48 UTC; 1s ago
Docs: man:nginx(8)
Process: 2211 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
Process: 2212 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
Main PID: 2213 (nginx)
Tasks: 2 (limit: 2340)
Memory: 2.5M
CPU: 23ms
CGroup: /system.slice/nginx.service
├─2213 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
└─2215 nginx: worker process
Oct 31 19:19:48 mail systemd[1]: Starting A high performance web server and a reverse proxy server...
Oct 31 19:19:48 mail systemd[1]: nginx.service: Failed to parse PID from file /run/nginx.pid: Invalid argument
Oct 31 19:19:48 mail systemd[1]: Started A high performance web server and a reverse proxy server.
root@mail:~# cat /etc/nginx/sites-available/mail.void.yt.conf
root@mail:~# mkdir /var/www/mail/
root@mail:~# echo 'Welcome to mail.void.yt !' > /var/www/mail/index.html
root@mail:~# curl mail.void.yt
Welcome to mail.void.yt !
And when we check the website, it says that it is secured via Letsencrypt!
Now let's run luke's emailwiz.sh script:
root@mail:~# sh emailwiz.sh
Installing programs...
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
cpp cpp-11 dns-root-data dovecot-core fontconfig-config fonts-dejavu-core gcc gcc-11 libasan6 libatomic1 libauthen-sasl-perl libc-dev-bin libc-devtools libc6-dev libcc1-0 libclone-perl libcommon-sense-perl libcrypt-dev
libcrypt-openssl-bignum-perl libcrypt-openssl-random-perl libcrypt-openssl-rsa-perl libdeflate0 libdigest-bubblebabble-perl libdigest-hmac-perl libencode-locale-perl libexttextcat-2.0-0 libexttextcat-data libfontconfig1
libgcc-11-dev libgd3 libgomp1 libhtml-parser-perl libhtml-tagset-perl libhttp-date-perl libhttp-message-perl libidn11 libio-html-perl libio-socket-inet6-perl libio-socket-ssl-perl libisl23 libitm1 libjbig0 libjpeg-turbo8
libjpeg8 libjson-perl libjson-xs-perl liblsan0 liblua5.1-0 liblua5.3-0 liblwp-mediatypes-perl libmail-authenticationresults-perl libmail-dkim-perl libmail-spf-perl libmailtools-perl libmemcached11 libmilter1.0.1 libmpc3
libnet-dns-perl libnet-dns-sec-perl libnet-ip-perl libnet-libidn-perl libnet-smtp-ssl-perl libnet-ssleay-perl libnetaddr-ip-perl libnsl-dev libopendbx1 libopendbx1-sqlite3 libopendkim11 libperl4-corelibs-perl libquadmath0
librbl1 libsocket6-perl libsodium23 libsys-hostname-long-perl libtiff5 libtimedate-perl libtirpc-dev libtsan0 libtypes-serialiser-perl libubsan1 libunbound8 liburi-perl libvbr2 libwebp6 libxpm4 linux-libc-dev make
manpages-dev opendkim-tools perl-openssl-defaults re2c rpcsvc-proto sa-compile ssl-cert
Suggested packages:
cpp-doc gcc-11-locales dovecot-gssapi dovecot-ldap dovecot-lmtpd dovecot-lucene dovecot-managesieved dovecot-mysql dovecot-pgsql dovecot-pop3d dovecot-solr dovecot-sqlite dovecot-submissiond ntp gcc-multilib autoconf
automake libtool flex bison gdb gcc-doc gcc-11-multilib gcc-11-doc libgssapi-perl glibc-doc libgd-tools libdata-dump-perl libwww-perl make-doc procmail postfix-mysql postfix-pgsql postfix-ldap postfix-pcre postfix-lmdb
postfix-sqlite resolvconf postfix-cdb mail-reader postfix-doc razor libdbi-perl pyzor libencode-detect-perl libgeoip2-perl libnet-patricia-perl libbsd-resource-perl
The following NEW packages will be installed:
cpp cpp-11 dns-root-data dovecot-core dovecot-imapd dovecot-sieve fontconfig-config fonts-dejavu-core gcc gcc-11 libasan6 libatomic1 libauthen-sasl-perl libc-dev-bin libc-devtools libc6-dev libcc1-0 libclone-perl
libcommon-sense-perl libcrypt-dev libcrypt-openssl-bignum-perl libcrypt-openssl-random-perl libcrypt-openssl-rsa-perl libdeflate0 libdigest-bubblebabble-perl libdigest-hmac-perl libencode-locale-perl libexttextcat-2.0-0
libexttextcat-data libfontconfig1 libgcc-11-dev libgd3 libgomp1 libhtml-parser-perl libhtml-tagset-perl libhttp-date-perl libhttp-message-perl libidn11 libio-html-perl libio-socket-inet6-perl libio-socket-ssl-perl libisl23
libitm1 libjbig0 libjpeg-turbo8 libjpeg8 libjson-perl libjson-xs-perl liblsan0 liblua5.1-0 liblua5.3-0 liblwp-mediatypes-perl libmail-authenticationresults-perl libmail-dkim-perl libmail-spf-perl libmailtools-perl
libmemcached11 libmilter1.0.1 libmpc3 libnet-dns-perl libnet-dns-sec-perl libnet-ip-perl libnet-libidn-perl libnet-smtp-ssl-perl libnet-ssleay-perl libnetaddr-ip-perl libnsl-dev libopendbx1 libopendbx1-sqlite3 libopendkim11
libperl4-corelibs-perl libquadmath0 librbl1 libsocket6-perl libsodium23 libsys-hostname-long-perl libtiff5 libtimedate-perl libtirpc-dev libtsan0 libtypes-serialiser-perl libubsan1 libunbound8 liburi-perl libvbr2 libwebp6
libxpm4 linux-libc-dev make manpages-dev opendkim opendkim-tools perl-openssl-defaults postfix re2c rpcsvc-proto sa-compile spamassassin spamc ssl-cert
0 upgraded, 100 newly installed, 0 to remove and 0 not upgraded.
Need to get 138 MB of archives.
After this operation, 421 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
When you get prompted by postfix configuration, do the following:
(Yes, you must put the TLD, not the mail.TLD)
Now that's done, let's update our dns records as described above:
Now the way this server works is that if you have a user that is in the mailgroup, he can log into the mail server. Let's add our first user:
root@mail:~# useradd -G mail -m nothing
useradd: warning: the home directory /home/nothing already exists.
useradd: Not copying any file from skel directory into it.
root@mail:~# passwd nothing
New password:
Retype new password:
passwd: password updated successfully
Now let's check if the server has the ports we need opened:
root@mail:~# apt install nmap -y
root@mail:~# nmap 127.0.0.1
Starting Nmap 7.80 ( https://nmap.org ) at 2021-10-31 19:33 UTC
Nmap scan report for localhost (127.0.0.1)
Host is up (0.0000030s latency).
Not shown: 991 closed ports
PORT STATE SERVICE
22/tcp open ssh
25/tcp open smtp
80/tcp open http
143/tcp open imap
443/tcp open https
465/tcp open smtps
587/tcp open submission
783/tcp open spamassassin
993/tcp open imaps
the ports we need are opened on the serverside, let's check them from the clientside:
[ 10.66.66.2/32 ] [ /dev/pts/0 ] [~]
→ nmap mail.void.yt
Starting Nmap 7.92 ( https://nmap.org ) at 2021-10-31 20:34 UTC
Nmap scan report for mail.void.yt (45.76.133.0)
Host is up (0.033s latency).
Other addresses for mail.void.yt (not scanned): 2001:19f0:7402:2c6:5400:3ff:fea7:22a3 2001:19f0:7001:4de1:5400:3ff:fea6:e93f 2001:19f0:7401:85a0:5400:3ff:fea7:20d2 2001:19f0:7002:e3c:5400:3ff:fea7:8e7
Not shown: 989 closed tcp ports (conn-refused)
PORT STATE SERVICE
22/tcp open ssh
25/tcp open smtp
80/tcp open http
139/tcp filtered netbios-ssn
143/tcp open imap
443/tcp open https
445/tcp filtered microsoft-ds
465/tcp open smtps
587/tcp open submission
993/tcp open imaps
1688/tcp filtered nsjtp-data
Looks good aswell! Now let's test if our server works, let's connect to it using thunderbird:
[ 10.66.66.2/32 ] [ /dev/pts/38 ] [~]
→ sudo pacman -S thunderbird
[ 10.66.66.2/32 ] [ /dev/pts/38 ] [~]
→ thunderbird
Looks like the connection was successful, now let's try to send the mail to a gmail address, which is probably the most picky email service provider:
So by default when gmail recieves a new domain name, it flags it as spam, wait a few weeks and it will no longer consider it as spam, in the mean time let's signal it as non-spam:
Now let's reply to our mail to test if we can recieve mails from gmail:
If you don't recieve mail from gmail, do a DKIM test from appmaildev
You might need to wait 12 hours or so for your DNS records to propagate, most notably for the DKIM record.
Looks good! and when we try to send a mail from gmail to our server we recieve it:
And that's it! We managed to setup a public mail server!
If you want a web interface for your mail server, check out my tutorial on how to install rainloop here.
If thunderbird gives you the invalid SSL certificate error, do not click add exception, but rather edit dovecot's ssl config:
root@mail:~# vim /etc/dovecot/conf.d/10-ssl.conf
root@mail:~# cat /etc/dovecot/conf.d/10-ssl.conf | grep ssl_
#ssl_cert = </etc/dovecot/private/dovecot.pem
#ssl_key = </etc/dovecot/private/dovecot.key
ssl_cert = </etc/letsencrypt/live/mail.void.yt/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.void.yt/privkey.pem
Donate XMR: 8AUYjhQeG3D5aodJDtqG499N5jXXM71gYKD8LgSsFB9BUV1o7muLv3DXHoydRTK4SZaaUBq4EAUqpZHLrX2VZLH71Jrd9k8
Contact: nihilist@contact.nowhere.moe (PGP)