summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blog/dst/a/mail_server_with_postfix.html576
-rw-r--r--blog/dst/a/website_with_nginx.html34
-rw-r--r--blog/dst/index.html3
-rw-r--r--blog/dst/sitemap.xml5
-rw-r--r--blog/src/.files3
5 files changed, 600 insertions, 21 deletions
diff --git a/blog/dst/a/mail_server_with_postfix.html b/blog/dst/a/mail_server_with_postfix.html
new file mode 100644
index 0000000..eafb6bf
--- /dev/null
+++ b/blog/dst/a/mail_server_with_postfix.html
@@ -0,0 +1,576 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <script type="text/javascript" src="https://static.luevano.xyz/scripts/theme.js"></script>
+
+ <link id="code-theme-css" rel="stylesheet" type="text/css" href="https://static.luevano.xyz/hl/styles/solarized-dark.min.css">
+ <script type="text/javascript" src="https://static.luevano.xyz/hl/highlight.min.js"></script>
+ <script type="text/javascript">hljs.initHighlightingOnLoad();</script>
+ <link rel="stylesheet" type="text/css" href="https://static.luevano.xyz/fa/css/all.min.css">
+ <link id="theme-css" rel="stylesheet" type="text/css" href="https://static.luevano.xyz/css/dark.css">
+ <link rel="stylesheet" type="text/css" href="https://static.luevano.xyz/css/general_style.css">
+
+ <link rel="icon" href="https://static.luevano.xyz/fa/svgs/solid/dragon.svg">
+ <meta charset="utf-8">
+
+ <title>Luévano's Blog</title>
+ </head>
+
+ <body>
+ <div id="theme-switcher-container">
+ <i class="fas fa-sun"></i>
+ <label class="switch theme">
+ <input id="theme-switch" type="checkbox" onclick="toggleTheme()">
+ <span class="slider round"></span>
+ </label>
+ <i class="fas fa-moon"></i>
+ </div>
+
+ <header>
+ <ul class="menubar">
+ <li>
+ <a href="https://luevano.xyz/"><i class="fas fa-home" alt="Home"></i><span>Home</span></a>
+ </li>
+
+ <li>
+ <a href="https://blog.luevano.xyz/"><i class="fas fa-book-open" alt="Blog"></i><span>Blog</span></a>
+ </li>
+
+ <li><i class="fab fa-git" alt="Git"></i><span>Git</span>
+ <ul>
+ <li><a href="https://git.luevano.xyz/" target="_blank"><i class="fab fa-git-alt" alt="Git-alt"></i></a></li>
+
+ <li><a href="https://github.com/luevano" target="_blank"><i class="fab fa-github" alt="Github"></i></a></li>
+
+ <li><a href="https://gitlab.com/dluevano" target="_blank"><i class="fab fa-gitlab" alt="Gitlab"></i></a></li>
+ </ul>
+ </li>
+
+ <li><i class="fas fa-box-open" alt="Stuff"></i><span>Stuff</span>
+ <ul>
+ <li><a href="https://gb.luevano.xyz/"><i class="fas fa-gamepad" alt="Gameboy"></i><span>Gameboy</span></a></li>
+ </ul>
+ </li>
+
+ <li>
+ <a href="https://luevano.xyz/donate"><i class="fas fa-donate" alt="Donate"></i><span>Donate</span></a>
+ <ul>
+ <li><a href="https://paypal.me/dlvna"><i class="fab fa-paypal" alt="Paypal"></i><span>Paypal</span></a></li>
+ </ul>
+ </li>
+ </ul>
+ </nav>
+ </header>
+<h1>Create a Mail server with Postfix, Dovecot, SpamAssassin and OpenDKIM</h1>
+
+<p>The entry is going to be long because it's a <em>tedious</em> process. This is also based on <a href="https://github.com/LukeSmithxyz/emailwiz">Luke Smith's script</a>, but adapted to Arch Linux (his script works on debian-based distributions). This entry is mostly so I can record all the notes required while I'm in the process of installing/configuring the mail server on a new VPS of mine; also I'm going to be writing a script that does everything in one go (for Arch Linux), that will be hosted <a href="https://git.luevano.xyz/server_scripts.git">here</a>.</p>
+
+<p>This configuration works for local users (users that appear in <code>/etc/passwd</code>), and does not use any type of SQL. And note that most if not all commands executed here are run with root privileges.</p>
+
+<p>More in depth configuration is detailed in the Arch Wiki for each package used here.</p>
+
+<h2>Prerequisites</h2>
+
+<p>Basically the same as with the <a href="https://blog.luevano.xyz/a/website_with_nginx.html">website with Nginx and Certbot</a>:</p>
+
+<ul>
+<li>A domain name. Got mine on <a href="https://www.epik.com/?affid=da5ne9ru4">Epik</a> (affiliate link, btw).
+
+<ul>
+<li>Later we'll be adding some <strong>MX</strong> and <strong>TXT</strong> records.</li>
+<li>You also need a <strong>CNAME</strong> for &#8220;mail&#8221; and (optionally) &#8220;www.mail&#8221;, or whatever you want to call the sub-domains (although the <a href="https://tools.ietf.org/html/rfc2181#section-10.3">RFC 2181</a> states that it NEEDS to be an <strong>A</strong> record, fuck the police), to actually work and to get SSL certificate (you can also use the SSL certificate obtained if you created a website following my other notes on <code>nginx</code> and <code>certbot</code>).</li>
+</ul></li>
+<li>A VPS or somewhere else to host. I'm using <a href="https://www.vultr.com/?ref=8732849">Vultr</a> (also an affiliate link).
+
+<ul>
+<li>Also <code>ssh</code> configured.</li>
+<li>Ports 25, 587 (SMTP), 465 (SMTPS), 143 (IMAP) and 993 (IMAPS) open on the firewall (I use <code>ufw</code>).</li>
+<li>With <code>nginx</code> and <code>certbot</code> setup and running.</li>
+</ul></li>
+</ul>
+
+<h2>Postfix</h2>
+
+<p><a href="https://wiki.archlinux.org/index.php/Postfix">Postfix</a> is a &#8220;mail transfer agent&#8221; which is the component of the mail server that receives and sends emails via SMTP.</p>
+
+<p>Install the <code>postfix</code> package:</p>
+
+<pre><code class="language-sh">pacman -S postfix
+</code></pre>
+
+<p>We have two main files to configure (inside <code>/etc/postfix</code>): <code>master.cf</code> (<a href="https://man.archlinux.org/man/master.5">master(5)</a>) and <code>main.cf</code> (<a href="https://man.archlinux.org/man/postconf.5">postconf(5)</a>). We're going to edit <code>main.cf</code> first either by using the command <code>postconf -e 'setting'</code> or by editing the file itself (I prefer to edit the file).</p>
+
+<p>Note that the default file itself has a lot of comments with description on what each thing does (or you can look up the manual, linked above), I used what Luke's script did plus some other settings that worked for me.</p>
+
+<p>Now, first locate where your website cert is, mine is at the default location <code>/etc/letsencrypt/live/</code>, so my <code>certdir</code> is <code>/etc/letsencrypt/live/luevano.xyz</code>. Given this information, change <code>{yourcertdir}</code> on the corresponding lines. The configuration described below has to be appended in the <code>main.cf</code> configuration file.</p>
+
+<p>Certificates and ciphers to use for authentication and security:</p>
+
+<pre><code class="language-conf">smtpd_tls_key_file = {yourcertdir}/privkey.pem
+smtpd_tls_cert_file = {yourcertdir}/fullchain.pem
+smtpd_use_tls = yes
+smtpd_tls_auth_only = yes
+smtp_tls_security_level = may
+smtp_tls_loglevel = 1
+smtp_tls_CAfile = {yourcertdir}/cert.pem
+smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
+smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
+smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
+smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
+tls_preempt_cipherlist = yes
+smtpd_tls_exclude_ciphers = aNULL, LOW, EXP, MEDIUM, ADH, AECDH, MD5,
+ DSS, ECDSA, CAMELLIA128, 3DES, CAMELLIA256,
+ RSA+AES, eNULL
+
+smtp_tls_CApath = /etc/ssl/certs
+smtpd_tls_CApath = /etc/ssl/certs
+
+smtpd_relay_restrictions = permit_sasl_authenticated, permit_mynetworks, defer_unauth_destination
+</code></pre>
+
+<p>Also, for the <em>connection</em> with <code>dovecot</code>, append the next few lines (telling postfix that <code>dovecot</code> will use user/password for authentication):</p>
+
+<pre><code class="language-conf">smtpd_sasl_auth_enable = yes
+smtpd_sasl_type = dovecot
+smtpd_sasl_path = private/auth
+smtpd_sasl_security_options = noanonymous, noplaintext
+smtpd_sasl_tls_security_options = noanonymous
+</code></pre>
+
+<p>Specify the mailbox home (this is going to be a directory inside your user's home):</p>
+
+<pre><code class="language-conf">home_mailbox = Mail/Inbox/
+</code></pre>
+
+<p>Pre-configuration to work seamlessly with <code>dovecot</code> and <code>opendkim</code>:</p>
+
+<pre><code class="language-conf">myhostname = {yourdomainname}
+mydomain = localdomain
+mydestination = $myhostname, localhost.$mydomain, localhost
+
+milter_default_action = accept
+milter_protocol = 6
+smtpd_milters = inet:127.0.0.1:8891
+non_smtpd_milters = inet:127.0.0.1:8891
+mailbox_command = /usr/lib/dovecot/deliver
+</code></pre>
+
+<p>Where <code>{yourdomainname}</code> is <code>luevano.xyz</code> in my case, or if you have <code>localhost</code> configured to your domain, then use <code>localhost</code> for <code>myhostname</code> (<code>myhostname = localhost</code>).</p>
+
+<p>Lastly, if you don't want the sender's IP and user agent (application used to send the mail), add the following line:</p>
+
+<pre><code class="language-conf">smtp_header_checks = regexp:/etc/postfix/smtp_header_checks
+</code></pre>
+
+<p>And create the <code>/etc/postfix/smtp_header_checks</code> file with the following content:</p>
+
+<pre><code class="language-conf">/^Received: .*/ IGNORE
+/^User-Agent: .*/ IGNORE
+</code></pre>
+
+<p>That's it for <code>main.cf</code>, now we have to configure <code>master.cf</code>. This one is a bit more tricky.</p>
+
+<p>First look up lines (they're uncommented) <code>smtp inet n - n - - smtpd</code>, <code>smtp unix - - n - - smtp</code> and <code>-o syslog_name=postfix/$service_name</code> and either delete or uncomment them&#8230; or just run <code>sed -i "/^\s*-o/d;/^\s*submission/d;/\s*smtp/d" /etc/postfix/master.cf</code> as stated in Luke's script.</p>
+
+<p>Lastly, append the following lines to complete postfix setup and pre-configure for <code>spamassassin</code>.</p>
+
+<pre><code class="language-conf">smtp unix - - n - - smtp
+smtp inet n - y - - smtpd
+ -o content_filter=spamassassin
+submission inet n - y - - smtpd
+ -o syslog_name=postfix/submission
+ -o smtpd_tls_security_level=encrypt
+ -o smtpd_sasl_auth_enable=yes
+ -o smtpd_tls_auth_only=yes
+smtps inet n - y - - smtpd
+ -o syslog_name=postfix/smtps
+ -o smtpd_tls_wrappermode=yes
+ -o smtpd_sasl_auth_enable=yes
+spamassassin unix - n n - - pipe
+ user=spamd argv=/usr/bin/vendor_perl/spamc -f -e /usr/sbin/sendmail -oi -f \${sender} \${recipient}
+</code></pre>
+
+<p>Now, I ran into some problems with postfix, one being <a href="https://www.faqforge.com/linux/fix-for-opensuse-error-postfixmaster-fatal-0-0-0-0smtps-servname-not-supported-for-ai_socktype/">smtps: Servname not supported for ai_socktype</a>, to fix it, as <em>Till</em> posted in that site, edit <code>/etc/services</code> and add:</p>
+
+<pre><code class="language-conf">smtps 465/tcp
+smtps 465/udp
+</code></pre>
+
+<p>Before starting the <code>postfix</code> service, you need to run <code>newaliases</code> first (but you can do a bit of configuration beforehand). Edit the file <code>/etc/postfix/aliases</code> and edit accordingly. I only change the <code>root: you</code> line (where <code>you</code> is the account that will be receiving &#8220;root&#8221; mail). Check the Arch Wiki for more info and other alternatives/options. After you're done, run:</p>
+
+<pre><code class="language-sh">postalias /etc/postfix/aliases
+newaliases
+</code></pre>
+
+<p>At this point you're done configuring <code>postfix</code> and you can already start/enable the <code>postfix</code> service:</p>
+
+<pre><code class="language-sh">systemctl start postfix.service
+systemctl enable postfix.service
+</code></pre>
+
+<h2>Dovecot</h2>
+
+<p><a href="https://wiki.archlinux.org/index.php/Dovecot">Dovecot</a> is an IMAP and POP3 server, which is what lets an email application retrieve the mail.</p>
+
+<p>Install the <code>dovecot</code> and <code>pigeonhole</code> (sieve for <code>dovecot</code>) packages:</p>
+
+<pre><code class="language-sh">pacman -S dovecot pigeonhole
+</code></pre>
+
+<p>On arch, by default, there is no <code>/etc/dovecot</code> directory with default configurations set in place, but the package does provide the example configuration files. Create the <code>dovecot</code> directory under <code>/etc</code> and, optionally, copy the <code>dovecot.conf</code> file and <code>conf.d</code> directory under the just created <code>dovecot</code> directory:</p>
+
+<pre><code class="language-sh">mkdir /etc/dovecot
+cp /usr/share/doc/dovecot/example-config/dovecot.conf /etc/dovecot/dovecot.conf
+cp -r /usr/share/doc/dovecot/example-config/conf.d /etc/dovecot
+</code></pre>
+
+<p>As Luke stated, <code>dovecot</code> comes with a lot of &#8220;modules&#8221; (under <code>/etc/dovecot/conf.d/</code> if you copied that folder) for all sorts of configurations that you can include, but I do as he does and just edits/creates the whole <code>dovecot.conf</code> file; although, I would like to check each of the separate configuration files <code>dovecot</code> provides I think the options Luke provides are more than good enough.</p>
+
+<p>I'm working with an empty <code>dovecot.conf</code> file. Add the following lines for SSL and login configuration (also replace <code>{yourcertdir}</code> with the same certificate directory described in the Postfix section above, note that the <code>&#60;</code> is required):</p>
+
+<pre><code class="language-conf">ssl = required
+ssl_cert = &#60;{yourcertdir}/fullchain.pem
+ssl_key = &#60;{yourcertdir}/privkey.pem
+ssl_min_protocol = TLSv1.2
+ssl_cipher_list = ALL:!RSA:!CAMELLIA:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4:!SHA1:!SHA256:!SHA384:!LOW@STRENGTH
+ssl_prefer_server_ciphers = yes
+ssl_dh = &#60;/etc/dovecot/dh.pem
+
+auth_mechanisms = plain login
+auth_username_format = %n
+protocols = $protocols imap
+</code></pre>
+
+<p>You may notice we specify a file we don't have under <code>/etc/dovecot</code>: <code>dh.pem</code>. We need to create it with <code>openssl</code> (you should already have it installed if you've been following this entry and the one for <code>nginx</code>). Just run (might take a few minutes):</p>
+
+<pre><code class="language-sh">openssl dhparam -out /etc/dovecot/dh.pem 4096
+</code></pre>
+
+<p>After that, the next lines define what a &#8220;valid user is&#8221; (really just sets the database for users and passwords to be the local users with their password):</p>
+
+<pre><code class="language-conf">userdb {
+ driver = passwd
+}
+
+passdb {
+ driver = pam
+}
+</code></pre>
+
+<p>Next, comes the mail directory structure (has to match the one described in the Postfix section). Here, the <code>LAYOUT</code> option is important so the boxes are <code>.Sent</code> instead of <code>Sent</code>. Add the next lines (plus any you like):</p>
+
+<pre><code class="language-conf">mail_location = maildir:~/Mail:INBOX=~/Mail/Inbox:LAYOUT=fs
+namespace inbox {
+ inbox = yes
+
+ mailbox Drafts {
+ special_use = \Drafts
+ auto = subscribe
+ }
+
+ mailbox Junk {
+ special_use = \Junk
+ auto = subscribe
+ autoexpunge = 30d
+ }
+
+ mailbox Sent {
+ special_use = \Sent
+ auto = subscribe
+ }
+
+ mailbox Trash {
+ special_use = \Trash
+ }
+
+ mailbox Archive {
+ special_use = \Archive
+ }
+}
+</code></pre>
+
+<p>Also include this so Postfix can use Dovecot's authentication system:</p>
+
+<pre><code class="language-conf">service auth {
+ unix_listener /var/spool/postfix/private/auth {
+ mode = 0660
+ user = postfix
+ group = postfix
+ }
+}
+</code></pre>
+
+<p>Lastly (for <code>dovecot</code> at least), the plugin configuration for <code>sieve</code> (<code>pigeonhole</code>):</p>
+
+<pre><code class="language-conf">protocol lda {
+ mail_plugins = $mail_plugins sieve
+}
+
+protocol lmtp {
+ mail_plugins = $mail_plugins sieve
+}
+
+plugin {
+ sieve = ~/.dovecot.sieve
+ sieve_default = /var/lib/dovecot/sieve/default.sieve
+ sieve_dir = ~/.sieve
+ sieve_global_dir = /var/lib/dovecot/sieve/
+</code></pre>
+
+<p>Where <code>/var/lib/dovecot/sieve/default.sieve</code> doesn't exist yet. Create the folders:</p>
+
+<pre><code class="language-sh">mkdir -p /var/lib/dovecot/sieve
+</code></pre>
+
+<p>And create the file <code>default.sieve</code> inside that just created folder with the content:</p>
+
+<pre><code class="language-conf">require ["fileinto", "mailbox"];
+if header :contains "X-Spam-Flag" "YES" {
+ fileinto "Junk";
+}
+</code></pre>
+
+<p>Now, if you don't have a <code>vmail</code> (virtual mail) user, create one and change the ownership of the <code>/var/lib/dovecot</code> directory to this user:</p>
+
+<pre><code class="language-sh">grep -q "^vmail:" /etc/passwd || useradd -m vmail -s /usr/bin/nologin
+chown -R vmail:vmail /var/lib/dovecot
+</code></pre>
+
+<p>Note that I also changed the shell for <code>vmail</code> to be <code>/usr/bin/nologin</code>. After that, run:</p>
+
+<pre><code class="language-sh">sievec /var/lib/dovecot/sieve/default.sieve
+</code></pre>
+
+<p>To compile the configuration file (a <code>default.svbin</code> file will be created next to <code>default.sieve</code>).</p>
+
+<p>Next, add the following lines to <code>/etc/pam.d/dovecot</code> if not already present (shouldn't be there if you've been following these notes):</p>
+
+<pre><code class="language-conf">auth required pam_unix.so nullok
+account required pam_unix.so
+</code></pre>
+
+<p>That's it for <code>dovecot</code>, at this point you can start/enable the <code>dovecot</code> service:</p>
+
+<pre><code class="language-sh">systemctl start dovecot.service
+systemctl enable dovecot.service
+</code></pre>
+
+<h1>OpenDKIM</h1>
+
+<p><a href="https://wiki.archlinux.org/index.php/OpenDKIM">OpenDKIM</a> is needed so services like G**gle (we don't mention that name here [[[this is a meme]]]) don't throw the mail to the trash. DKIM stands for &#8220;DomainKeys Identified Mail&#8221;.</p>
+
+<p>Install the <code>opendkim</code> package:</p>
+
+<pre><code class="language-sh">pacman -S opendkim
+</code></pre>
+
+<p>Generate the keys for your domain:</p>
+
+<pre><code class="language-sh">opendkim-genkey -D /etc/opendkim -d {yourdomain} -s {yoursubdomain} -r -b 2048
+</code></pre>
+
+<p>Where you need to change <code>{yourdomain}</code> and <code>{yoursubdomain}</code> (doesn't really need to be the sub-domain, could be anything that describes your key) accordingly, for me it's <code>luevano.xyz</code> and <code>mail</code>, respectively. After that, we need to create some files inside the <code>/etc/opendkim</code> directory. First, create the file <code>KeyTable</code> with the content:</p>
+
+<pre><code class="language-conf">{yoursubdomain}._domainkey.{yourdomain} {yourdomain}:{yoursubdomain}:/etc/opendkim/{yoursubdomain}.private
+</code></pre>
+
+<p>So, for me it would be:</p>
+
+<pre><code class="language-conf">mail._domainkey.luevano.xyz luevano.xyz:mail:/etc/opendkim/mail.private
+</code></pre>
+
+<p>Next, create the file <code>SigningTable</code> with the content:</p>
+
+<pre><code class="language-conf">*@{yourdomain} {yoursubdomain}._domainkey.{yourdomain}
+</code></pre>
+
+<p>Again, for me it would be:</p>
+
+<pre><code class="language-conf">*@luevano.xyz mail._domainkey.luevano.xyz
+</code></pre>
+
+<p>And, lastly create the file <code>TrustedHosts</code> with the content:</p>
+
+<pre><code class="language-conf">127.0.0.1
+::1
+10.1.0.0/16
+1.2.3.4/24
+localhost
+{yourserverip}
+...
+</code></pre>
+
+<p>And more, make sure to include your server IP and something like <code>subdomain.domainname</code>.</p>
+
+<p>Next, edit <code>/etc/opendkim/opendkim.conf</code> to reflect the changes (or rather, additions) of these files, as well as some other configuration. You can look up the example configuration file located at <code>/usr/share/doc/opendkim/opendkim.conf.sample</code>, but I'm creating a blank one with the contents:</p>
+
+<pre><code class="language-conf">Domain {yourdomain}
+Selector {yoursubdomain}
+
+Syslog Yes
+UserID opendkim
+
+KeyFile /etc/opendkim/{yoursubdomain}.private
+Socket inet:8891@localhost
+</code></pre>
+
+<p>Now, change the permissions for all the files inside <code>/etc/opendkim</code>:</p>
+
+<pre><code class="language-conf">chown -R root:opendkim /etc/opendkim
+chmod g+r /etc/postfix/dkim/*
+</code></pre>
+
+<p>I'm using <code>root:opendkim</code> so <code>opendkim</code> doesn't complain about the <code>{yoursubdomani}.private</code> being insecure (you can change that by using the option <code>RequireSafeKeys False</code> in the <code>opendkim.conf</code> file, as stated <a href="http://lists.opendkim.org/archive/opendkim/users/2014/12/3331.html">here</a>).</p>
+
+<p>That's it for the general configuration, but you could go more in depth and be more secure with some extra configuration as described in the <a href="https://wiki.archlinux.org/index.php/OpenDKIM#Security">Arch Wiki entry for OpenDKIM</a>.</p>
+
+<p>Now, just start/enable the <code>opendkim</code> service:</p>
+
+<pre><code class="language-sh">systemctl start opendkim.service
+systemctl enable opendkim.service
+</code></pre>
+
+<p>And don't forget to add the following <strong>TXT</strong> records on your domain registrar (these examples are for Epik):</p>
+
+<ol start="1">
+<li><em>DKIM</em> entry: look up your <code>{yoursubdomain}.txt</code> file, it should look something like:</li>
+</ol>
+
+<pre><code class="language-txt">{yoursubdomain}._domainkey IN TXT ( "v=DKIM1; k=rsa; s=email; "
+ "p=..."
+ "..." ) ; ----- DKIM key mail for {yourdomain}
+</code></pre>
+
+<p>In the TXT record you will place <code>{yoursubdomain}._domainkey</code> as the &#8220;Host&#8221; and <code>"v=DKIM1; k=rsa; s=email; " "p=..." "..."</code> in the &#8220;TXT Value&#8221; (replace the dots with the actual value you see in your file).</p>
+
+<ol start="2">
+<li><p><em>DMARC</em> entry: just <code>_dmarc.{yourdomain}</code> as the &#8220;Host&#8221; and <code>"v=DMARC1; p=reject; rua=mailto:dmarc@{yourdomain}; fo=1"</code> as the &#8220;TXT Value&#8221;.</p></li>
+<li><p><em>SPF</em> entry: just <code>@</code> as the &#8220;Host&#8221; and <code>"v=spf1 mx a:{yoursubdomain}.{yourdomain} - all"</code> as the &#8220;TXT Value&#8221;.</p></li>
+</ol>
+
+<p>And at this point you could test your mail for spoofing and more, but you don't know -yet- how to login (it's really easy, but I'm gonna state that at the end of this entry).</p>
+
+<h2>SpamAssassin</h2>
+
+<p><a href="https://wiki.archlinux.org/index.php/SpamAssassin">SpamAssassin</a> is just <em>a mail filter to identify spam</em>.</p>
+
+<p>Install the <code>spamassassin</code> package (which will install a bunch of ugly <code>perl</code> packages&#8230;):</p>
+
+<pre><code class="language-sh">pacman -S spamassassin
+</code></pre>
+
+<p>For some reason, the permissions on all <code>spamassassin</code> stuff are all over the place. First, change owner of the executables, and directories:</p>
+
+<pre><code class="language-sh">chown spamd:spamd /usr/bin/vendor_perl/sa-*
+chown spamd:spamd /usr/bin/vendor_perl/spam*
+chwown -R spamd:spamd /etc/mail/spamassassin
+</code></pre>
+
+<p>Then, you can edit <code>local.cf</code> (located in <code>/etc/mail/spamassassin</code>) to fit your needs (I only uncommented the <code>rewrite_header Subject ...</code> line). And then you can run the following command to update the patterns and compile them:</p>
+
+<pre><code class="language-sh">sudo -u spamd sa-update
+sudo -u spamd sa-compile
+</code></pre>
+
+<p>And since this should be run periodically, create the service <code>spamassassin-update.service</code> under <code>/etc/systemd/system</code> with the following content:</p>
+
+<pre><code class="language-conf">[Unit]
+Description=SpamAssassin housekeeping
+After=network.target
+
+[Service]
+User=spamd
+Group=spamd
+Type=oneshot
+
+ExecStart=/usr/bin/vendor_perl/sa-update --allowplugins
+SuccessExitStatus=1
+ExecStart=/usr/bin/vendor_perl/sa-compile
+ExecStart=/usr/bin/systemctl -q --no-block try-restart spamassassin.service
+</code></pre>
+
+<p>And you could also execute <code>sa-learn</code> to train <code>spamassassin</code>'s bayes filter, but this works for me. Then create the timer <code>spamassassin-update.timer</code> under the same directory, with the content:</p>
+
+<pre><code class="language-conf">[Unit]
+Description=SpamAssassin housekeeping
+
+[Timer]
+OnCalendar=daily
+Persistent=true
+
+[Install]
+WantedBy=timers.target
+</code></pre>
+
+<p>You can now start/enable the <code>spamassassin-update</code> timer:</p>
+
+<pre><code class="language-sh">systemctl start spamassassin-update.timer
+systemctl enable spamassassin-update.timer
+</code></pre>
+
+<p>Next, you may want to edit the <code>spamassassin</code> service before starting and enabling it, because by default, it could <a href="https://rimuhosting.com/howto/memory.jsp">spawn a lot of &#8220;childs&#8221;</a> eating a lot of resources and you really only need one child. Append <code>--max-children=1</code> to the line <code>ExecStart=...</code> in <code>/usr/bin/systemd/system/spamassassin.service</code>:</p>
+
+<pre><code class="language-conf">...
+ExecStart=/usr/bin/vendor_perl/spamd -x -u spamd -g spamd --listen=/run/spamd/spamd.sock --listen=localhost --max-children=1
+...
+</code></pre>
+
+<p>Finally, start and enable the <code>spamassassin</code> service:</p>
+
+<pre><code class="language-sh">systemctl start spamassassin.service
+systemctl enable spamassassin.service
+</code></pre>
+
+<h2>Wrapping up</h2>
+
+<p>We should have a working mail server by now. Before continuing check your journal logs (<code>journalctl -xe --unit={unit}</code>, where <code>{unit}</code> could be <code>spamassassin.service</code>for example) to see if there was any error whatsoever and try to debug it, it should be a typo somewhere (the logs are generally really descriptive) because all the settings and steps detailed here just (literally just finished doing everything on a new server as of the writing of this text) worked <em>(((it just werks on my machine)))</em>.</p>
+
+<p>Now, to actually use the mail service: first of all, you need a <em>normal</em> account (don't use root) that belongs to the <code>mail</code> group (<code>gpasswd -a user group</code> to add a user <code>user</code> to group <code>group</code>) and that has a password.</p>
+
+<p>Next, to actually login into a mail app/program/whateveryouwanttocallit, you will use the following settings, at least for <code>thunderdbird</code>(I tested in windows default mail app and you don't need a lot of settings):</p>
+
+<ul>
+<li>* server: subdomain.domain (mail.luevano.xyz in my case)</li>
+<li><strong>SMTP</strong> port: 587</li>
+<li><strong>SMTPS</strong> port: 465 (I use this one)</li>
+<li><strong>IMAP</strong> port: 143</li>
+<li><strong>IMAPS</strong> port: 993 (again, I use this one)</li>
+<li>Connection/security: SSL/TLS</li>
+<li>Authentication method: Normal password</li>
+<li>Username: just your <code>user</code>, not the whole email (<code>david</code> in my case)</li>
+<li>Password: your <code>user</code> password (as in the password you use to login to the server with that user)</li>
+</ul>
+
+<p>All that's left to do is test your mail server for spoofing, and to see if everything is setup correctly. Go to <a href="https://www.appmaildev.com/en/dkim">DKIM Test</a> and follow the instructions (basically click next, and send an email with whatever content to the email that they provide). After you send the email, you should see something like:</p>
+
+<p><img src="https://static.luevano.xyz/images/b/notes/mail/dkim_test_successful.png" alt="DKIM Test successful" /></p>
+
+<p>(Yes, I blurred a lot in the picture just to be sure, either way what's important is the list on the bottom part of the image)</p>
+
+<p>Finally, that's actually it for this entry, if you have any problem whatsoever you have my info down below.</p>
+
+<div class=timestamp>
+<hr>
+<p>Created: Sat, Mar 20, 2021 @ 02:23 MST</p>
+</div>
+ <footer class="footer">
+ <i class="fas fa-envelope" alt="Email"></i>
+ Email
+ <a href="mailto:david@luevano.xyz">
+ david@luevano.xyz
+ </a>
+ <br>
+
+ <i class="fas fa-rss" alt="RSS"></i>
+ RSS
+ <a href="https://blog.luevano.xyz/rss.xml">
+ https://blog.luevano.xyz/rss.xml
+ </a>
+ <br>
+
+ <i class="fas fa-donate" alt="Donate"></i>
+ <a href="https://luevano.xyz/donate">Donate</a>
+ <a href="https://paypal.me/dlvna"><i class="fab fa-paypal" alt="Paypal"></i></a>
+ </footer>
+ </body>
+</html>
diff --git a/blog/dst/a/website_with_nginx.html b/blog/dst/a/website_with_nginx.html
index 45366e4..69b371b 100644
--- a/blog/dst/a/website_with_nginx.html
+++ b/blog/dst/a/website_with_nginx.html
@@ -65,7 +65,7 @@
<p>These are general notes on how to setup a Nginx web server plus Certbot for SSL certificates, initially learned from <a href="https://www.youtube.com/watch?v=OWAqilIVNgE">Luke's video</a> and after some use and research I added more stuff to the mix. And, actually at the time of writing this entry, I'm configuring the web server again on a new VPS instance, so this is going to be fresh.</p>
-<p>As a side note, (((i use arch btw))) so everything here es aimed at an Arch Linux distro, and I'm doing everything on a VPS.</p>
+<p>As a side note, (((i use arch btw))) so everything here es aimed at an Arch Linux distro, and I'm doing everything on a VPS. Also note that most if not all commands here are executed with root privileges.</p>
<h2>Prerequisites</h2>
@@ -81,7 +81,7 @@
<ul>
<li>With <code>ssh</code> already configured both on the local machine and on the remote machine.</li>
-<li>Firewall already configured to allow ports 80 (http) and 443 (https). I use <code>ufw</code> so it's just a matter of doing <code>ufw allow 80,443/tcp</code> as root and you're golden.</li>
+<li>Firewall already configured to allow ports 80 (HTTP) and 443 (HTTPS). I use <code>ufw</code> so it's just a matter of doing <code>ufw allow 80,443/tcp</code> as root and you're golden.</li>
<li><code>cron</code> installed if you follow along (you could use <code>systemd</code> timers, or some other method you prefer to automate running commands every X time).</li>
</ul></li>
</ul>
@@ -90,9 +90,9 @@
<p>You have two options: <code>nginx</code> and <code>nginx-mainline</code>. I prefer <code>nginx-mainline</code> because it's the &#8220;up to date&#8221; package even though <code>nginx</code> is labeled to be the &#8220;stable&#8221; version. Install the package and enable/start the service:</p>
-<pre><code class="language-sh"># pacman -S nginx-mainline
-# systemctl enable nginx.service
-# systemctl start nginx.service
+<pre><code class="language-sh">pacman -S nginx-mainline
+systemctl enable nginx.service
+systemctl start nginx.service
</code></pre>
<p>And that's it, at this point you can already look at the default initial page of nginx if you enter the ip of your server in a web browser. You should see something like this:</p>
@@ -101,7 +101,7 @@
<p>As stated in the welcome page, configuration is needed, head to the directory of nginx:</p>
-<pre><code class="language-sh"># cd /etc/nginx
+<pre><code class="language-sh">cd /etc/nginx
</code></pre>
<p>Here you have several files, the important one is <code>nginx.conf</code>, which as its name implies, contains general configuration of the web server. If you peek into the file, you will see that it contains around 120 lines, most of which are commented out and contains the welcome page server block. While you can configure a website in this file, it's common practice to do it on a separate file (so you can scale really easily if needed for mor websites or sub-domains).</p>
@@ -129,9 +129,9 @@ http {
<p>Next, inside the directory <code>/etc/nginx/</code> create the <code>sites-available</code> and <code>sites-enabled</code>, and go into the <code>sites-available</code> one:</p>
-<pre><code class="language-sh"># mkdir sites-available
-# mkdir sites-enabled
-# cd sites-available
+<pre><code class="language-sh">mkdir sites-available
+mkdir sites-enabled
+cd sites-available
</code></pre>
<p>Here, create a new <code>.conf</code> file for your website and add the following lines (this is just the sample content more or less):</p>
@@ -166,15 +166,15 @@ http {
<p>Then, make a symbolic from this config file to the <code>sites-enabled</code> directory:</p>
-<pre><code class="language-sh"># ln -s /etc/nginx/sites-available/your_config_file.conf /etc/nginx/sites-enabled
+<pre><code class="language-sh">ln -s /etc/nginx/sites-available/your_config_file.conf /etc/nginx/sites-enabled
</code></pre>
<p>This is so the <code>nginx.conf</code> file can look up the newly created server config. With this method of having each server configuration file separate you can easily &#8220;deactivate&#8221; any website by just deleting the symbolic link in <code>sites-enabled</code> and you're good, or just add new configuration files and keep everything nice and tidy.</p>
<p>All you have to do now is restart (or enable and start if you haven't already) the nginx service (and optionally test the configuration):</p>
-<pre><code class="language-sh"># nginx -t
-# systemctl restart nginx
+<pre><code class="language-sh">nginx -t
+systemctl restart nginx
</code></pre>
<p>If everything goes correctly, you can now go to your website by typing &#8220;domain.name&#8221; on a web browser. But you will see a &#8220;404 Not Found&#8221; page like the following (maybe with different nginx version):</p>
@@ -200,19 +200,19 @@ http {
<p>The only &#8220;bad&#8221; (bloated) thing about certbot, is that it uses <code>python</code>, but for me it doesn't matter too much. You may want to look up another alternative if you prefer. Install the packages <code>certbot</code> and <code>certbot-nginx</code>:</p>
-<pre><code class="language-sh"># pacman -S certbot certbot-nginx
+<pre><code class="language-sh">pacman -S certbot certbot-nginx
</code></pre>
<p>After that, all you have to do now is run <code>certbot</code> and follow the instructions given by the tool:</p>
-<pre><code class="language-sh"># certbot --nginx
+<pre><code class="language-sh">certbot --nginx
</code></pre>
<p>It will ask you for some information, for you to accept some agreements and the names to activate https for. Also, you will want to &#8220;say yes&#8221; to the redirection from http to https. And that's it, you can now go to your website and see that you have https active.</p>
-<p>Now, the certificate given by certbot expires every 3 months or something like that, so you want to renew this certificate every once in a while. Using <code>cron</code>, you can do this by running:</p>
+<p>Now, the certificate given by <code>certbot</code> expires every 3 months or something like that, so you want to renew this certificate every once in a while. Using <code>cron</code>, you can do this by running:</p>
-<pre><code class="language-sh"># crontab -e
+<pre><code class="language-sh">crontab -e
</code></pre>
<p>And a file will be opened where you need to add a new rule for certbot, just append the line: <code>1 1 1 * * certbot renew</code> (renew on the first day of every month) and you're good. Alternatively use <code>systemd</code> timers as stated in the <a href="https://wiki.archlinux.org/index.php/Certbot#Automatic_renewal">Arch Linux Wiki</a>.</p>
@@ -223,7 +223,7 @@ http {
<div class=timestamp>
<hr>
-<p>Created: Sat, Mar 13, 2021 @ 23:08 MST</p>
+<p>Created: Thu, Mar 18, 2021 @ 19:58 MST</p>
</div>
<footer class="footer">
<i class="fas fa-envelope" alt="Email"></i>
diff --git a/blog/dst/index.html b/blog/dst/index.html
index 115a1f9..703c74b 100644
--- a/blog/dst/index.html
+++ b/blog/dst/index.html
@@ -71,8 +71,9 @@
<h3>March 2021</h3>
+<li>Mar 20 - <a href=https://blog.luevano.xyz/a/mail_server_with_postfix>Create a Mail server with Postfix, Dovecot, SpamAssassin and OpenDKIM</a></li>
+<li>Mar 18 - <a href=https://blog.luevano.xyz/a/website_with_nginx>Create a website with Nginx and Certbot</a></li>
<li>Mar 15 - <a href=https://blog.luevano.xyz/a/el_blog_ya_tiene_timestamps>Así es raza, el blog ya tiene timestamps</a></li>
-<li>Mar 13 - <a href=https://blog.luevano.xyz/a/website_with_nginx>Create a website with Nginx and Certbot</a></li>
<li>Mar 13 - <a href=https://blog.luevano.xyz/a/shell_scripting>Shell scripting tutorial video notes</a></li>
<li>Mar 13 - <a href=https://blog.luevano.xyz/a/linux_video_notes>Linux tutorial video notes</a></li>
<li>Mar 02 - <a href=https://blog.luevano.xyz/a/sql_video_notes>SQL tutorial video notes</a></li>
diff --git a/blog/dst/sitemap.xml b/blog/dst/sitemap.xml
index a759acf..afad9d9 100644
--- a/blog/dst/sitemap.xml
+++ b/blog/dst/sitemap.xml
@@ -4,11 +4,12 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
-<url><loc>https://blog.luevano.xyz/index.html</loc><lastmod>2021-03-18</lastmod><priority>1.0</priority></url>
-<url><loc>https://blog.luevano.xyz/a/website_with_nginx.html</loc><lastmod>2021-03-13</lastmod><priority>1.0</priority></url>
+<url><loc>https://blog.luevano.xyz/index.html</loc><lastmod>2021-03-20</lastmod><priority>1.0</priority></url>
+<url><loc>https://blog.luevano.xyz/a/website_with_nginx.html</loc><lastmod>2021-03-18</lastmod><priority>1.0</priority></url>
<url><loc>https://blog.luevano.xyz/a/el_blog_ya_tiene_timestamps.html</loc><lastmod>2021-03-15</lastmod><priority>1.0</priority></url>
<url><loc>https://blog.luevano.xyz/a/shell_scripting.html</loc><lastmod>2021-03-13</lastmod><priority>1.0</priority></url>
<url><loc>https://blog.luevano.xyz/a/sql_video_notes.html</loc><lastmod>2021-03-02</lastmod><priority>1.0</priority></url>
<url><loc>https://blog.luevano.xyz/a/first_blog_post.html</loc><lastmod>2021-02-27</lastmod><priority>1.0</priority></url>
<url><loc>https://blog.luevano.xyz/a/linux_video_notes.html</loc><lastmod>2021-03-13</lastmod><priority>1.0</priority></url>
+<url><loc>https://blog.luevano.xyz/a/mail_server_with_postfix.html</loc><lastmod>2021-03-20</lastmod><priority>1.0</priority></url>
</urlset>
diff --git a/blog/src/.files b/blog/src/.files
index 0f25a16..810e603 100644
--- a/blog/src/.files
+++ b/blog/src/.files
@@ -1,7 +1,8 @@
1615856381 0 ./index.md
-1615702088 0 ./a/website_with_nginx.md
+1616122695 0 ./a/website_with_nginx.md
1615862784 0 ./a/el_blog_ya_tiene_timestamps.md
1615701454 0 ./a/shell_scripting.md
1614695711 0 ./a/sql_video_notes.md
1614431313 0 ./a/first_blog_post.md
1615701443 0 ./a/linux_video_notes.md
+1616232199 0 ./a/mail_server_with_postfix.md