# emailwiz Setup ![](0.png) In this tutorial we're going to setup a self hosted mail server using lukesmith's [emailwiz.sh](https://github.com/LukeSmithxyz/emailwiz/blob/master/emailwiz.sh) script: ## **Initial Setup** First step is, get a VPS on [vultr.com](https://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: ![](1.png) ![](2.png) if you're confused about the MX record, here it is (do not forget the trailing dot at the end): ![](3.png) 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.md root@mail:~# curl mail.void.yt Welcome to mail.void.yt ! ` ![](16.png) And when we check the website, it says that it is secured via Letsencrypt! ![](17.png) 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: ![](4.png) ![](15.png) (Yes, you must put the TLD, not the mail.TLD) ![](6.png) Now that's done, let's update our dns records as described above: ![](7.png) ![](8.png) ![](14.png) 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 ![](20.png) ![](21.png) ![](22.png) 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: ![](23.png) 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: ![](24.png) Now let's reply to our mail to test if we can recieve mails from gmail: ![](25.png) If you don't recieve mail from gmail, do a DKIM test from [appmaildev](https://appmaildev.com/en/dkim) ![](26.png) You might need to wait 12 hours or so for your DNS records to propagate, most notably for the DKIM record. ![](27.png) Looks good! and when we try to send a mail from gmail to our server we recieve it: ![](28.png) 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](../rainloop/index.md). 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