<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.alpinelinux.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=DavesCodeMusings</id>
	<title>Alpine Linux - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.alpinelinux.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=DavesCodeMusings"/>
	<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/wiki/Special:Contributions/DavesCodeMusings"/>
	<updated>2026-04-30T00:56:01Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30969</id>
		<title>Small-Time Email with Exim and Dovecot</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30969"/>
		<updated>2025-09-22T21:54:08Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Creating Mail Directories for Users */ using root shell prompt to show the command requiring root privs&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want a super-simple SMTP / IMAP setup for a home server, this is the guide for you. This document covers the minimum steps to get email delivery up and running on a small home network. You&#039;re not going to want to use this for any serious enterprise stuff, but for a small home LAN it works well.&lt;br /&gt;
&lt;br /&gt;
== Why would anyone do this? ==&lt;br /&gt;
&lt;br /&gt;
My personal motivation for creating this small-time email setup was to deliver alerts from [https://mmonit.com/monit/ Monit] so I would know when my system needed attention. You can use it for this or similar minimalist email needs. Just don&#039;t do anything crazy like exposing it to the internet.&lt;br /&gt;
&lt;br /&gt;
== Why Exim and Dovecot? ==&lt;br /&gt;
&lt;br /&gt;
For an email server, Exim is easy to configure. Dovecot is a little more complex, but not insurmountable. Both are well documented.&lt;br /&gt;
&lt;br /&gt;
== Installing the Packages ==&lt;br /&gt;
The first step is to install Exim, Dovecot, and Mailx. (Mailx is used for testing.)&lt;br /&gt;
&lt;br /&gt;
  apk add {{pkg|exim|arch=}} {{pkg|dovecot|arch=}} {{pkg|mailx|arch=}}&lt;br /&gt;
&lt;br /&gt;
== Configuring Exim ==&lt;br /&gt;
&lt;br /&gt;
The next step is to get Exim working for delivering email to users on the system. This is a pretty simple configuration and there are only a few parameters to change in the delivered exim.conf file.&lt;br /&gt;
&lt;br /&gt;
# Make a backup of {{path|/etc/exim/exim.conf}}&lt;br /&gt;
# Open {{path|/etc/exim/exim.conf}} in your favorite text editor.&lt;br /&gt;
# Make the changes stated below and save.&lt;br /&gt;
&lt;br /&gt;
Find the lines that look like this:&lt;br /&gt;
&lt;br /&gt;
  # group = mail&lt;br /&gt;
  # mode = 0660&lt;br /&gt;
&lt;br /&gt;
They&#039;ll be under the heading of &amp;lt;code&amp;gt;local_delivery:&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you find them, remove the comment (hash symbol). The local_delivery section should now look like this:&lt;br /&gt;
&lt;br /&gt;
  local_delivery:&lt;br /&gt;
    driver = appendfile&lt;br /&gt;
    file = /var/mail/$local_part_data&lt;br /&gt;
    delivery_date_add&lt;br /&gt;
    envelope_to_add&lt;br /&gt;
    return_path_add&lt;br /&gt;
    group = mail&lt;br /&gt;
    mode = 0660&lt;br /&gt;
&lt;br /&gt;
The only thing changed is the removal of the hash symbol from the last two lines.&lt;br /&gt;
&lt;br /&gt;
== Fixing Ownership and Permissions on /var/mail ==&lt;br /&gt;
&lt;br /&gt;
As it stands, Exim will not be able to deliver messages to /var/mail, where the user mailboxes are stored. This is due to permissions.&lt;br /&gt;
&lt;br /&gt;
To fix it, run these two commands:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
&lt;br /&gt;
When you&#039;re done, verify it with &amp;lt;code&amp;gt;ls -ld /var/mail&amp;lt;/code&amp;gt;. It should look like this:&lt;br /&gt;
&lt;br /&gt;
  $ ls -ld /var/mail/&lt;br /&gt;
  drwxrwsr-x    3 root     mail          4096 May 11 12:58 /var/mail/&lt;br /&gt;
&lt;br /&gt;
Setting the group ownership to &#039;&#039;mail&#039;&#039;, lets exim write to users&#039; mailboxes when new mail comes in.&lt;br /&gt;
&lt;br /&gt;
== Starting the Exim Service ==&lt;br /&gt;
&lt;br /&gt;
Start Exim and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service exim start&lt;br /&gt;
  rc-update add exim&lt;br /&gt;
&lt;br /&gt;
== Testing the Exim Setup ==&lt;br /&gt;
&lt;br /&gt;
Log in a a regular user and try sending a test email to yourself. You can do this with the mail command, like this:&lt;br /&gt;
&lt;br /&gt;
  $ mail -s Testing dave&lt;br /&gt;
  This is a test.&lt;br /&gt;
  .&lt;br /&gt;
&lt;br /&gt;
This sends a test message to the user dave. (Obviously, you&#039;ll want to replace dave with your username.) The final . on the last line is important. It tells the mail command the message is done.&lt;br /&gt;
&lt;br /&gt;
When the message is sent, check that you received it by running &amp;lt;code&amp;gt;mail&amp;lt;/code&amp;gt; with no command-line parameters. If everything went well, it should look like the example below.&lt;br /&gt;
&lt;br /&gt;
  $ mail&lt;br /&gt;
  Mail version 8.1.2 01/15/2001.  Type ? for help.&lt;br /&gt;
  &amp;quot;/var/mail/dave&amp;quot;: 1 messages&lt;br /&gt;
  &amp;gt;   1 dave@myserver.home      Wed May 11 03:51  27/847   &amp;quot;Testing&amp;quot;&lt;br /&gt;
  &amp;amp;&lt;br /&gt;
&lt;br /&gt;
You can type the message number (1) to display the contents of the mail and then type q to quit the mail program.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting Mail Delivery ==&lt;br /&gt;
&lt;br /&gt;
If the mail test fails, look in the directory {{path|/var/spool/exim/msglog}}. If there are files there, they are stuck messages. The files are plain text. Display the contents to show any error messages. In most cases, the problem will be related to permissions on the {{path|/var/mail}} directory or the mailbox files within the directory.&lt;br /&gt;
&lt;br /&gt;
The directory permissions should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -ld /var/mail&lt;br /&gt;
  drwxrwsr-x    3 root     mail&lt;br /&gt;
&lt;br /&gt;
The permissions on mailbox files inside should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -l /var/mail&lt;br /&gt;
  -rw-rw----    1 dave     mail&lt;br /&gt;
&lt;br /&gt;
== Configuring Dovecot ==&lt;br /&gt;
&lt;br /&gt;
If everything is working with local delivery, it&#039;s time to set up IMAP using Dovecot.&lt;br /&gt;
&lt;br /&gt;
The Dovecot package for Alpine comes with twenty configuration files in {{path|/etc/dovecot/conf.d}}. As a small-time email admin, you may feel overwhelmed. Don&#039;t worry, everything can be condensed down to a single config file of just over twenty lines.&lt;br /&gt;
&lt;br /&gt;
First, make a backup copy of {{path|/etc/dovecot/dovecot.conf}}.&lt;br /&gt;
&lt;br /&gt;
Next, create a new dovecot.conf that looks like what&#039;s shown below.&lt;br /&gt;
&lt;br /&gt;
{{Note| The example configuration below is for Dovecot version 2.4 used in Alpine Linux 3.22. It is not compatible with Dovecot 2.3 used in earlier versions of Alpine.}}&lt;br /&gt;
&lt;br /&gt;
  dovecot_config_version = 2.4.0&lt;br /&gt;
  auth_allow_cleartext = yes&lt;br /&gt;
  dovecot_storage_version = 2.4.0&lt;br /&gt;
  first_valid_uid = 8&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  mail_driver = mbox&lt;br /&gt;
  mail_gid = mail&lt;br /&gt;
  mail_home = /home/%{user}&lt;br /&gt;
  mail_inbox_path = /var/mail/%{user}&lt;br /&gt;
  mail_path = /home/%{user}/mail&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_uid = %{user}&lt;br /&gt;
  protocols {&lt;br /&gt;
    imap = yes&lt;br /&gt;
  }&lt;br /&gt;
  passdb passwd {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    passwd_file_path = /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl_server {&lt;br /&gt;
    cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
    key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
This config does not have the &amp;lt;code&amp;gt;!include conf.d/*.conf&amp;lt;/code&amp;gt; that was in the original dovecot.conf, so those twenty files in conf.d are going to be ignored. Everything is now in this single dovecot.conf.&lt;br /&gt;
&lt;br /&gt;
== Starting the Dovecot Service ==&lt;br /&gt;
&lt;br /&gt;
Start Dovecot and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Credentials for Dovecot Users ==&lt;br /&gt;
&lt;br /&gt;
As it is configured, Dovecot will use {{path|/etc/passwd}} for looking up user information, but not authentication. Technically, {{path|/etc/passwd}} authentication can be done using Pluggable Authentication Modules (PAM), but PAM is not part of the base install of Alpine Linux. The next best thing is to use a separate password file for Dovecot credentials and to use the same SHA512-Crypt hashing algorithm used in {{path|/etc/passwd}}.&lt;br /&gt;
&lt;br /&gt;
The Dovecot configuration above specifies a password file of {{path|/etc/dovecot/passwd}}. The Dovecot password file looks like this:&lt;br /&gt;
&lt;br /&gt;
  dave:{SHA512-CRYPT}$6$mQ1rxB0gZHqg8Tg9$nxZ8odJZ6xVpmOVpsnYfAo1i7SuoLDhsvoykieukWF9NyNBq.WwhDA7udcYxP1iEm/IzlBmnwz6/vOO3SX8gA.&lt;br /&gt;
&lt;br /&gt;
There are two fields, username and password, separated by a colon. Notice the {SHA512-CRYPT} prefix to the password. This indicates the hashing algorithm.&lt;br /&gt;
&lt;br /&gt;
You can create passwords with the &amp;lt;code&amp;gt;doveadm&amp;lt;/code&amp;gt; command, like this:&lt;br /&gt;
&lt;br /&gt;
  # doveadm pw -s sha512-crypt&lt;br /&gt;
  Enter new password:&lt;br /&gt;
  Retype new password:&lt;br /&gt;
&lt;br /&gt;
The command will output the hashed password. You&#039;ll need to edit Dovecot&#039;s password file with a text editor and create the username/password pair by hand.&lt;br /&gt;
&lt;br /&gt;
The permissions on the Dovecot password file should be such that dovecot can read it, but not write to it. Only root should be able to write it.&lt;br /&gt;
&lt;br /&gt;
  ls -l /etc/dovecot/passwd&lt;br /&gt;
  -rw-r-----    1 root     dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Mail Directories for Users ==&lt;br /&gt;
The IMAP server will use the user&#039;s home directory to store mail folders. These are configured to go in ~/mail. You&#039;ll need to make sure this directory exists with the proper permissions for each user accessing email via IMAP.&lt;br /&gt;
&lt;br /&gt;
The following command shows how you can create ~/mail for the user dave:&lt;br /&gt;
&lt;br /&gt;
  # install -d -o dave -g dave -m770 ~dave/mail&lt;br /&gt;
&lt;br /&gt;
== Testing the Dovecot Setup ==&lt;br /&gt;
&lt;br /&gt;
To test IMAP, you&#039;ll need an email client. Personally, I&#039;ve used [https://www.thunderbird.net Thunderbird] on Windows, [https://alpineapp.email/ Alpine Mail] on Linux, and [https://k9mail.app/ K-9 Mail] on Android. The trickiest part is getting the email client to trust the self-signed certificates. Configuring email clients is beyond the scope of this document.&lt;br /&gt;
&lt;br /&gt;
From the server side, the Dovecot log file can help you diagnose errors. The dovecot.conf file specifies the location of the log file.&lt;br /&gt;
&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
&lt;br /&gt;
One of the common errors I&#039;ve seen looks like this:&lt;br /&gt;
&lt;br /&gt;
  Disconnected: TLS initialization failed.&lt;br /&gt;
  Error: Failed to initialize SSL server context: Can&#039;t load SSL certificate&lt;br /&gt;
&lt;br /&gt;
This was the result of a typographical error I made in the Dovecot config file.&lt;br /&gt;
&lt;br /&gt;
You can further simplify things by commenting out the ssl lines in the dovecot.conf so it looks like this:&lt;br /&gt;
&lt;br /&gt;
  # ssl_server {&lt;br /&gt;
  #   cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
  #   key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  # }&lt;br /&gt;
&lt;br /&gt;
Now TLS is out of the picture, letting you diagnose other potential problems. However, you may have to do some work to convince your mail client that sending login credentials in cleartext is okay. Only do this on a network where you trust your users!&lt;br /&gt;
&lt;br /&gt;
== Using and Enjoying Your Small-Time Email Setup ==&lt;br /&gt;
&lt;br /&gt;
Now that everything is setup, you can start sending yourself cat pictures or you can configure other programs to use the email system to send notifications. For example, I use [https://mmonit.com/monit/ Monit] to keep an eye on services and file system space. When Monit detects a problem, it sends me an email.&lt;br /&gt;
&lt;br /&gt;
The setup presented in this guide uses port 25 for SMTP and port 143 for IMAP. There are no dedicated TLS ports. Encryption is done using STARTTLS.&lt;br /&gt;
&lt;br /&gt;
== A Word About Aliases ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve ever used {{path|/etc/aliases}} for mail delivery, you should be aware that Exim puts this file in {{path|/etc/mail/aliases}}. The format is the same as Sendmail.&lt;br /&gt;
&lt;br /&gt;
== Scripted Installation and Configuration ==&lt;br /&gt;
&lt;br /&gt;
If you like living dangerously (or if you have a test system you don&#039;t care about) you can do all of the server configuration presented above with a single script, as shown below:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
  &lt;br /&gt;
  apk add exim mailx&lt;br /&gt;
  &lt;br /&gt;
  sed -i~ \&lt;br /&gt;
    -e &#039;s/# group = mail/  group = mail/&#039; \&lt;br /&gt;
    -e &#039;s/# mode = 0660/  mode = 0660/&#039; \&lt;br /&gt;
    /etc/exim/exim.conf&lt;br /&gt;
  &lt;br /&gt;
  ln -s mail/aliases /etc/aliases&lt;br /&gt;
  &lt;br /&gt;
  rc-update add exim&lt;br /&gt;
  service exim start&lt;br /&gt;
  &lt;br /&gt;
  apk add dovecot&lt;br /&gt;
  &lt;br /&gt;
  mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf~&lt;br /&gt;
  &lt;br /&gt;
  cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/dovecot/dovecot.conf&lt;br /&gt;
  dovecot_config_version = 2.4.0&lt;br /&gt;
  auth_allow_cleartext = yes&lt;br /&gt;
  dovecot_storage_version = 2.4.0&lt;br /&gt;
  first_valid_uid = 8&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  mail_driver = mbox&lt;br /&gt;
  mail_gid = mail&lt;br /&gt;
  mail_home = /home/%{user}&lt;br /&gt;
  mail_inbox_path = /var/mail/%{user}&lt;br /&gt;
  mail_path = /home/%{user}/mail&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_uid = %{user}&lt;br /&gt;
  protocols {&lt;br /&gt;
    imap = yes&lt;br /&gt;
  }&lt;br /&gt;
  passdb passwd {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    passwd_file_path = /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl_server {&lt;br /&gt;
    cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
    key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  }&lt;br /&gt;
  EOF&lt;br /&gt;
  &lt;br /&gt;
  touch /etc/dovecot/passwd&lt;br /&gt;
  chown root:dovecot /etc/dovecot/passwd&lt;br /&gt;
  chmod 640 /etc/dovecot/passwd&lt;br /&gt;
  &lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
  &lt;br /&gt;
  echo &amp;quot;Create dovecot user passwords with: doveadm pw -s sha512-crypt and add to {{path|/etc/dovecot/passwd}}&amp;quot;&lt;br /&gt;
  echo &amp;quot;Create user mail directories with: install -d -o username -g dave -m770 ~username/mail&amp;quot;&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30968</id>
		<title>Small-Time Email with Exim and Dovecot</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30968"/>
		<updated>2025-09-22T21:52:14Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Configuring Dovecot */ update conf file line count for new Dovecot version 2.4&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want a super-simple SMTP / IMAP setup for a home server, this is the guide for you. This document covers the minimum steps to get email delivery up and running on a small home network. You&#039;re not going to want to use this for any serious enterprise stuff, but for a small home LAN it works well.&lt;br /&gt;
&lt;br /&gt;
== Why would anyone do this? ==&lt;br /&gt;
&lt;br /&gt;
My personal motivation for creating this small-time email setup was to deliver alerts from [https://mmonit.com/monit/ Monit] so I would know when my system needed attention. You can use it for this or similar minimalist email needs. Just don&#039;t do anything crazy like exposing it to the internet.&lt;br /&gt;
&lt;br /&gt;
== Why Exim and Dovecot? ==&lt;br /&gt;
&lt;br /&gt;
For an email server, Exim is easy to configure. Dovecot is a little more complex, but not insurmountable. Both are well documented.&lt;br /&gt;
&lt;br /&gt;
== Installing the Packages ==&lt;br /&gt;
The first step is to install Exim, Dovecot, and Mailx. (Mailx is used for testing.)&lt;br /&gt;
&lt;br /&gt;
  apk add {{pkg|exim|arch=}} {{pkg|dovecot|arch=}} {{pkg|mailx|arch=}}&lt;br /&gt;
&lt;br /&gt;
== Configuring Exim ==&lt;br /&gt;
&lt;br /&gt;
The next step is to get Exim working for delivering email to users on the system. This is a pretty simple configuration and there are only a few parameters to change in the delivered exim.conf file.&lt;br /&gt;
&lt;br /&gt;
# Make a backup of {{path|/etc/exim/exim.conf}}&lt;br /&gt;
# Open {{path|/etc/exim/exim.conf}} in your favorite text editor.&lt;br /&gt;
# Make the changes stated below and save.&lt;br /&gt;
&lt;br /&gt;
Find the lines that look like this:&lt;br /&gt;
&lt;br /&gt;
  # group = mail&lt;br /&gt;
  # mode = 0660&lt;br /&gt;
&lt;br /&gt;
They&#039;ll be under the heading of &amp;lt;code&amp;gt;local_delivery:&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you find them, remove the comment (hash symbol). The local_delivery section should now look like this:&lt;br /&gt;
&lt;br /&gt;
  local_delivery:&lt;br /&gt;
    driver = appendfile&lt;br /&gt;
    file = /var/mail/$local_part_data&lt;br /&gt;
    delivery_date_add&lt;br /&gt;
    envelope_to_add&lt;br /&gt;
    return_path_add&lt;br /&gt;
    group = mail&lt;br /&gt;
    mode = 0660&lt;br /&gt;
&lt;br /&gt;
The only thing changed is the removal of the hash symbol from the last two lines.&lt;br /&gt;
&lt;br /&gt;
== Fixing Ownership and Permissions on /var/mail ==&lt;br /&gt;
&lt;br /&gt;
As it stands, Exim will not be able to deliver messages to /var/mail, where the user mailboxes are stored. This is due to permissions.&lt;br /&gt;
&lt;br /&gt;
To fix it, run these two commands:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
&lt;br /&gt;
When you&#039;re done, verify it with &amp;lt;code&amp;gt;ls -ld /var/mail&amp;lt;/code&amp;gt;. It should look like this:&lt;br /&gt;
&lt;br /&gt;
  $ ls -ld /var/mail/&lt;br /&gt;
  drwxrwsr-x    3 root     mail          4096 May 11 12:58 /var/mail/&lt;br /&gt;
&lt;br /&gt;
Setting the group ownership to &#039;&#039;mail&#039;&#039;, lets exim write to users&#039; mailboxes when new mail comes in.&lt;br /&gt;
&lt;br /&gt;
== Starting the Exim Service ==&lt;br /&gt;
&lt;br /&gt;
Start Exim and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service exim start&lt;br /&gt;
  rc-update add exim&lt;br /&gt;
&lt;br /&gt;
== Testing the Exim Setup ==&lt;br /&gt;
&lt;br /&gt;
Log in a a regular user and try sending a test email to yourself. You can do this with the mail command, like this:&lt;br /&gt;
&lt;br /&gt;
  $ mail -s Testing dave&lt;br /&gt;
  This is a test.&lt;br /&gt;
  .&lt;br /&gt;
&lt;br /&gt;
This sends a test message to the user dave. (Obviously, you&#039;ll want to replace dave with your username.) The final . on the last line is important. It tells the mail command the message is done.&lt;br /&gt;
&lt;br /&gt;
When the message is sent, check that you received it by running &amp;lt;code&amp;gt;mail&amp;lt;/code&amp;gt; with no command-line parameters. If everything went well, it should look like the example below.&lt;br /&gt;
&lt;br /&gt;
  $ mail&lt;br /&gt;
  Mail version 8.1.2 01/15/2001.  Type ? for help.&lt;br /&gt;
  &amp;quot;/var/mail/dave&amp;quot;: 1 messages&lt;br /&gt;
  &amp;gt;   1 dave@myserver.home      Wed May 11 03:51  27/847   &amp;quot;Testing&amp;quot;&lt;br /&gt;
  &amp;amp;&lt;br /&gt;
&lt;br /&gt;
You can type the message number (1) to display the contents of the mail and then type q to quit the mail program.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting Mail Delivery ==&lt;br /&gt;
&lt;br /&gt;
If the mail test fails, look in the directory {{path|/var/spool/exim/msglog}}. If there are files there, they are stuck messages. The files are plain text. Display the contents to show any error messages. In most cases, the problem will be related to permissions on the {{path|/var/mail}} directory or the mailbox files within the directory.&lt;br /&gt;
&lt;br /&gt;
The directory permissions should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -ld /var/mail&lt;br /&gt;
  drwxrwsr-x    3 root     mail&lt;br /&gt;
&lt;br /&gt;
The permissions on mailbox files inside should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -l /var/mail&lt;br /&gt;
  -rw-rw----    1 dave     mail&lt;br /&gt;
&lt;br /&gt;
== Configuring Dovecot ==&lt;br /&gt;
&lt;br /&gt;
If everything is working with local delivery, it&#039;s time to set up IMAP using Dovecot.&lt;br /&gt;
&lt;br /&gt;
The Dovecot package for Alpine comes with twenty configuration files in {{path|/etc/dovecot/conf.d}}. As a small-time email admin, you may feel overwhelmed. Don&#039;t worry, everything can be condensed down to a single config file of just over twenty lines.&lt;br /&gt;
&lt;br /&gt;
First, make a backup copy of {{path|/etc/dovecot/dovecot.conf}}.&lt;br /&gt;
&lt;br /&gt;
Next, create a new dovecot.conf that looks like what&#039;s shown below.&lt;br /&gt;
&lt;br /&gt;
{{Note| The example configuration below is for Dovecot version 2.4 used in Alpine Linux 3.22. It is not compatible with Dovecot 2.3 used in earlier versions of Alpine.}}&lt;br /&gt;
&lt;br /&gt;
  dovecot_config_version = 2.4.0&lt;br /&gt;
  auth_allow_cleartext = yes&lt;br /&gt;
  dovecot_storage_version = 2.4.0&lt;br /&gt;
  first_valid_uid = 8&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  mail_driver = mbox&lt;br /&gt;
  mail_gid = mail&lt;br /&gt;
  mail_home = /home/%{user}&lt;br /&gt;
  mail_inbox_path = /var/mail/%{user}&lt;br /&gt;
  mail_path = /home/%{user}/mail&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_uid = %{user}&lt;br /&gt;
  protocols {&lt;br /&gt;
    imap = yes&lt;br /&gt;
  }&lt;br /&gt;
  passdb passwd {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    passwd_file_path = /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl_server {&lt;br /&gt;
    cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
    key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
This config does not have the &amp;lt;code&amp;gt;!include conf.d/*.conf&amp;lt;/code&amp;gt; that was in the original dovecot.conf, so those twenty files in conf.d are going to be ignored. Everything is now in this single dovecot.conf.&lt;br /&gt;
&lt;br /&gt;
== Starting the Dovecot Service ==&lt;br /&gt;
&lt;br /&gt;
Start Dovecot and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Credentials for Dovecot Users ==&lt;br /&gt;
&lt;br /&gt;
As it is configured, Dovecot will use {{path|/etc/passwd}} for looking up user information, but not authentication. Technically, {{path|/etc/passwd}} authentication can be done using Pluggable Authentication Modules (PAM), but PAM is not part of the base install of Alpine Linux. The next best thing is to use a separate password file for Dovecot credentials and to use the same SHA512-Crypt hashing algorithm used in {{path|/etc/passwd}}.&lt;br /&gt;
&lt;br /&gt;
The Dovecot configuration above specifies a password file of {{path|/etc/dovecot/passwd}}. The Dovecot password file looks like this:&lt;br /&gt;
&lt;br /&gt;
  dave:{SHA512-CRYPT}$6$mQ1rxB0gZHqg8Tg9$nxZ8odJZ6xVpmOVpsnYfAo1i7SuoLDhsvoykieukWF9NyNBq.WwhDA7udcYxP1iEm/IzlBmnwz6/vOO3SX8gA.&lt;br /&gt;
&lt;br /&gt;
There are two fields, username and password, separated by a colon. Notice the {SHA512-CRYPT} prefix to the password. This indicates the hashing algorithm.&lt;br /&gt;
&lt;br /&gt;
You can create passwords with the &amp;lt;code&amp;gt;doveadm&amp;lt;/code&amp;gt; command, like this:&lt;br /&gt;
&lt;br /&gt;
  # doveadm pw -s sha512-crypt&lt;br /&gt;
  Enter new password:&lt;br /&gt;
  Retype new password:&lt;br /&gt;
&lt;br /&gt;
The command will output the hashed password. You&#039;ll need to edit Dovecot&#039;s password file with a text editor and create the username/password pair by hand.&lt;br /&gt;
&lt;br /&gt;
The permissions on the Dovecot password file should be such that dovecot can read it, but not write to it. Only root should be able to write it.&lt;br /&gt;
&lt;br /&gt;
  ls -l /etc/dovecot/passwd&lt;br /&gt;
  -rw-r-----    1 root     dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Mail Directories for Users ==&lt;br /&gt;
The IMAP server will use the user&#039;s home directory to store mail folders. These are configured to go in ~/mail. You&#039;ll need to make sure this directory exists with the proper permissions for each user accessing email via IMAP.&lt;br /&gt;
&lt;br /&gt;
The following command shows how you can create ~/mail for the user dave:&lt;br /&gt;
&lt;br /&gt;
  install -d -o dave -g dave -m770 ~dave/mail&lt;br /&gt;
&lt;br /&gt;
== Testing the Dovecot Setup ==&lt;br /&gt;
&lt;br /&gt;
To test IMAP, you&#039;ll need an email client. Personally, I&#039;ve used [https://www.thunderbird.net Thunderbird] on Windows, [https://alpineapp.email/ Alpine Mail] on Linux, and [https://k9mail.app/ K-9 Mail] on Android. The trickiest part is getting the email client to trust the self-signed certificates. Configuring email clients is beyond the scope of this document.&lt;br /&gt;
&lt;br /&gt;
From the server side, the Dovecot log file can help you diagnose errors. The dovecot.conf file specifies the location of the log file.&lt;br /&gt;
&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
&lt;br /&gt;
One of the common errors I&#039;ve seen looks like this:&lt;br /&gt;
&lt;br /&gt;
  Disconnected: TLS initialization failed.&lt;br /&gt;
  Error: Failed to initialize SSL server context: Can&#039;t load SSL certificate&lt;br /&gt;
&lt;br /&gt;
This was the result of a typographical error I made in the Dovecot config file.&lt;br /&gt;
&lt;br /&gt;
You can further simplify things by commenting out the ssl lines in the dovecot.conf so it looks like this:&lt;br /&gt;
&lt;br /&gt;
  # ssl_server {&lt;br /&gt;
  #   cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
  #   key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  # }&lt;br /&gt;
&lt;br /&gt;
Now TLS is out of the picture, letting you diagnose other potential problems. However, you may have to do some work to convince your mail client that sending login credentials in cleartext is okay. Only do this on a network where you trust your users!&lt;br /&gt;
&lt;br /&gt;
== Using and Enjoying Your Small-Time Email Setup ==&lt;br /&gt;
&lt;br /&gt;
Now that everything is setup, you can start sending yourself cat pictures or you can configure other programs to use the email system to send notifications. For example, I use [https://mmonit.com/monit/ Monit] to keep an eye on services and file system space. When Monit detects a problem, it sends me an email.&lt;br /&gt;
&lt;br /&gt;
The setup presented in this guide uses port 25 for SMTP and port 143 for IMAP. There are no dedicated TLS ports. Encryption is done using STARTTLS.&lt;br /&gt;
&lt;br /&gt;
== A Word About Aliases ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve ever used {{path|/etc/aliases}} for mail delivery, you should be aware that Exim puts this file in {{path|/etc/mail/aliases}}. The format is the same as Sendmail.&lt;br /&gt;
&lt;br /&gt;
== Scripted Installation and Configuration ==&lt;br /&gt;
&lt;br /&gt;
If you like living dangerously (or if you have a test system you don&#039;t care about) you can do all of the server configuration presented above with a single script, as shown below:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
  &lt;br /&gt;
  apk add exim mailx&lt;br /&gt;
  &lt;br /&gt;
  sed -i~ \&lt;br /&gt;
    -e &#039;s/# group = mail/  group = mail/&#039; \&lt;br /&gt;
    -e &#039;s/# mode = 0660/  mode = 0660/&#039; \&lt;br /&gt;
    /etc/exim/exim.conf&lt;br /&gt;
  &lt;br /&gt;
  ln -s mail/aliases /etc/aliases&lt;br /&gt;
  &lt;br /&gt;
  rc-update add exim&lt;br /&gt;
  service exim start&lt;br /&gt;
  &lt;br /&gt;
  apk add dovecot&lt;br /&gt;
  &lt;br /&gt;
  mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf~&lt;br /&gt;
  &lt;br /&gt;
  cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/dovecot/dovecot.conf&lt;br /&gt;
  dovecot_config_version = 2.4.0&lt;br /&gt;
  auth_allow_cleartext = yes&lt;br /&gt;
  dovecot_storage_version = 2.4.0&lt;br /&gt;
  first_valid_uid = 8&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  mail_driver = mbox&lt;br /&gt;
  mail_gid = mail&lt;br /&gt;
  mail_home = /home/%{user}&lt;br /&gt;
  mail_inbox_path = /var/mail/%{user}&lt;br /&gt;
  mail_path = /home/%{user}/mail&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_uid = %{user}&lt;br /&gt;
  protocols {&lt;br /&gt;
    imap = yes&lt;br /&gt;
  }&lt;br /&gt;
  passdb passwd {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    passwd_file_path = /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl_server {&lt;br /&gt;
    cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
    key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  }&lt;br /&gt;
  EOF&lt;br /&gt;
  &lt;br /&gt;
  touch /etc/dovecot/passwd&lt;br /&gt;
  chown root:dovecot /etc/dovecot/passwd&lt;br /&gt;
  chmod 640 /etc/dovecot/passwd&lt;br /&gt;
  &lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
  &lt;br /&gt;
  echo &amp;quot;Create dovecot user passwords with: doveadm pw -s sha512-crypt and add to {{path|/etc/dovecot/passwd}}&amp;quot;&lt;br /&gt;
  echo &amp;quot;Create user mail directories with: install -d -o username -g dave -m770 ~username/mail&amp;quot;&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30967</id>
		<title>Small-Time Email with Exim and Dovecot</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30967"/>
		<updated>2025-09-22T21:49:43Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Testing the Exim Setup */ include shell prompt for consistency with other example screen output&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want a super-simple SMTP / IMAP setup for a home server, this is the guide for you. This document covers the minimum steps to get email delivery up and running on a small home network. You&#039;re not going to want to use this for any serious enterprise stuff, but for a small home LAN it works well.&lt;br /&gt;
&lt;br /&gt;
== Why would anyone do this? ==&lt;br /&gt;
&lt;br /&gt;
My personal motivation for creating this small-time email setup was to deliver alerts from [https://mmonit.com/monit/ Monit] so I would know when my system needed attention. You can use it for this or similar minimalist email needs. Just don&#039;t do anything crazy like exposing it to the internet.&lt;br /&gt;
&lt;br /&gt;
== Why Exim and Dovecot? ==&lt;br /&gt;
&lt;br /&gt;
For an email server, Exim is easy to configure. Dovecot is a little more complex, but not insurmountable. Both are well documented.&lt;br /&gt;
&lt;br /&gt;
== Installing the Packages ==&lt;br /&gt;
The first step is to install Exim, Dovecot, and Mailx. (Mailx is used for testing.)&lt;br /&gt;
&lt;br /&gt;
  apk add {{pkg|exim|arch=}} {{pkg|dovecot|arch=}} {{pkg|mailx|arch=}}&lt;br /&gt;
&lt;br /&gt;
== Configuring Exim ==&lt;br /&gt;
&lt;br /&gt;
The next step is to get Exim working for delivering email to users on the system. This is a pretty simple configuration and there are only a few parameters to change in the delivered exim.conf file.&lt;br /&gt;
&lt;br /&gt;
# Make a backup of {{path|/etc/exim/exim.conf}}&lt;br /&gt;
# Open {{path|/etc/exim/exim.conf}} in your favorite text editor.&lt;br /&gt;
# Make the changes stated below and save.&lt;br /&gt;
&lt;br /&gt;
Find the lines that look like this:&lt;br /&gt;
&lt;br /&gt;
  # group = mail&lt;br /&gt;
  # mode = 0660&lt;br /&gt;
&lt;br /&gt;
They&#039;ll be under the heading of &amp;lt;code&amp;gt;local_delivery:&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you find them, remove the comment (hash symbol). The local_delivery section should now look like this:&lt;br /&gt;
&lt;br /&gt;
  local_delivery:&lt;br /&gt;
    driver = appendfile&lt;br /&gt;
    file = /var/mail/$local_part_data&lt;br /&gt;
    delivery_date_add&lt;br /&gt;
    envelope_to_add&lt;br /&gt;
    return_path_add&lt;br /&gt;
    group = mail&lt;br /&gt;
    mode = 0660&lt;br /&gt;
&lt;br /&gt;
The only thing changed is the removal of the hash symbol from the last two lines.&lt;br /&gt;
&lt;br /&gt;
== Fixing Ownership and Permissions on /var/mail ==&lt;br /&gt;
&lt;br /&gt;
As it stands, Exim will not be able to deliver messages to /var/mail, where the user mailboxes are stored. This is due to permissions.&lt;br /&gt;
&lt;br /&gt;
To fix it, run these two commands:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
&lt;br /&gt;
When you&#039;re done, verify it with &amp;lt;code&amp;gt;ls -ld /var/mail&amp;lt;/code&amp;gt;. It should look like this:&lt;br /&gt;
&lt;br /&gt;
  $ ls -ld /var/mail/&lt;br /&gt;
  drwxrwsr-x    3 root     mail          4096 May 11 12:58 /var/mail/&lt;br /&gt;
&lt;br /&gt;
Setting the group ownership to &#039;&#039;mail&#039;&#039;, lets exim write to users&#039; mailboxes when new mail comes in.&lt;br /&gt;
&lt;br /&gt;
== Starting the Exim Service ==&lt;br /&gt;
&lt;br /&gt;
Start Exim and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service exim start&lt;br /&gt;
  rc-update add exim&lt;br /&gt;
&lt;br /&gt;
== Testing the Exim Setup ==&lt;br /&gt;
&lt;br /&gt;
Log in a a regular user and try sending a test email to yourself. You can do this with the mail command, like this:&lt;br /&gt;
&lt;br /&gt;
  $ mail -s Testing dave&lt;br /&gt;
  This is a test.&lt;br /&gt;
  .&lt;br /&gt;
&lt;br /&gt;
This sends a test message to the user dave. (Obviously, you&#039;ll want to replace dave with your username.) The final . on the last line is important. It tells the mail command the message is done.&lt;br /&gt;
&lt;br /&gt;
When the message is sent, check that you received it by running &amp;lt;code&amp;gt;mail&amp;lt;/code&amp;gt; with no command-line parameters. If everything went well, it should look like the example below.&lt;br /&gt;
&lt;br /&gt;
  $ mail&lt;br /&gt;
  Mail version 8.1.2 01/15/2001.  Type ? for help.&lt;br /&gt;
  &amp;quot;/var/mail/dave&amp;quot;: 1 messages&lt;br /&gt;
  &amp;gt;   1 dave@myserver.home      Wed May 11 03:51  27/847   &amp;quot;Testing&amp;quot;&lt;br /&gt;
  &amp;amp;&lt;br /&gt;
&lt;br /&gt;
You can type the message number (1) to display the contents of the mail and then type q to quit the mail program.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting Mail Delivery ==&lt;br /&gt;
&lt;br /&gt;
If the mail test fails, look in the directory {{path|/var/spool/exim/msglog}}. If there are files there, they are stuck messages. The files are plain text. Display the contents to show any error messages. In most cases, the problem will be related to permissions on the {{path|/var/mail}} directory or the mailbox files within the directory.&lt;br /&gt;
&lt;br /&gt;
The directory permissions should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -ld /var/mail&lt;br /&gt;
  drwxrwsr-x    3 root     mail&lt;br /&gt;
&lt;br /&gt;
The permissions on mailbox files inside should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -l /var/mail&lt;br /&gt;
  -rw-rw----    1 dave     mail&lt;br /&gt;
&lt;br /&gt;
== Configuring Dovecot ==&lt;br /&gt;
&lt;br /&gt;
If everything is working with local delivery, it&#039;s time to set up IMAP using Dovecot.&lt;br /&gt;
&lt;br /&gt;
The Dovecot package for Alpine comes with twenty configuration files in {{path|/etc/dovecot/conf.d}}. As a small-time email admin, you may feel overwhelmed. Don&#039;t worry, everything can be condensed down to a single config file of sixteen lines.&lt;br /&gt;
&lt;br /&gt;
First, make a backup copy of {{path|/etc/dovecot/dovecot.conf}}.&lt;br /&gt;
&lt;br /&gt;
Next, create a new dovecot.conf that looks like what&#039;s shown below.&lt;br /&gt;
&lt;br /&gt;
{{Note| The example configuration below is for Dovecot version 2.4 used in Alpine Linux 3.22. It is not compatible with Dovecot 2.3 used in earlier versions of Alpine.}}&lt;br /&gt;
&lt;br /&gt;
  dovecot_config_version = 2.4.0&lt;br /&gt;
  auth_allow_cleartext = yes&lt;br /&gt;
  dovecot_storage_version = 2.4.0&lt;br /&gt;
  first_valid_uid = 8&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  mail_driver = mbox&lt;br /&gt;
  mail_gid = mail&lt;br /&gt;
  mail_home = /home/%{user}&lt;br /&gt;
  mail_inbox_path = /var/mail/%{user}&lt;br /&gt;
  mail_path = /home/%{user}/mail&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_uid = %{user}&lt;br /&gt;
  protocols {&lt;br /&gt;
    imap = yes&lt;br /&gt;
  }&lt;br /&gt;
  passdb passwd {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    passwd_file_path = /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl_server {&lt;br /&gt;
    cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
    key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
This config does not have the &amp;lt;code&amp;gt;!include conf.d/*.conf&amp;lt;/code&amp;gt; that was in the original dovecot.conf, so those twenty files in conf.d are going to be ignored. Everything is now in this single dovecot.conf.&lt;br /&gt;
&lt;br /&gt;
== Starting the Dovecot Service ==&lt;br /&gt;
&lt;br /&gt;
Start Dovecot and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Credentials for Dovecot Users ==&lt;br /&gt;
&lt;br /&gt;
As it is configured, Dovecot will use {{path|/etc/passwd}} for looking up user information, but not authentication. Technically, {{path|/etc/passwd}} authentication can be done using Pluggable Authentication Modules (PAM), but PAM is not part of the base install of Alpine Linux. The next best thing is to use a separate password file for Dovecot credentials and to use the same SHA512-Crypt hashing algorithm used in {{path|/etc/passwd}}.&lt;br /&gt;
&lt;br /&gt;
The Dovecot configuration above specifies a password file of {{path|/etc/dovecot/passwd}}. The Dovecot password file looks like this:&lt;br /&gt;
&lt;br /&gt;
  dave:{SHA512-CRYPT}$6$mQ1rxB0gZHqg8Tg9$nxZ8odJZ6xVpmOVpsnYfAo1i7SuoLDhsvoykieukWF9NyNBq.WwhDA7udcYxP1iEm/IzlBmnwz6/vOO3SX8gA.&lt;br /&gt;
&lt;br /&gt;
There are two fields, username and password, separated by a colon. Notice the {SHA512-CRYPT} prefix to the password. This indicates the hashing algorithm.&lt;br /&gt;
&lt;br /&gt;
You can create passwords with the &amp;lt;code&amp;gt;doveadm&amp;lt;/code&amp;gt; command, like this:&lt;br /&gt;
&lt;br /&gt;
  # doveadm pw -s sha512-crypt&lt;br /&gt;
  Enter new password:&lt;br /&gt;
  Retype new password:&lt;br /&gt;
&lt;br /&gt;
The command will output the hashed password. You&#039;ll need to edit Dovecot&#039;s password file with a text editor and create the username/password pair by hand.&lt;br /&gt;
&lt;br /&gt;
The permissions on the Dovecot password file should be such that dovecot can read it, but not write to it. Only root should be able to write it.&lt;br /&gt;
&lt;br /&gt;
  ls -l /etc/dovecot/passwd&lt;br /&gt;
  -rw-r-----    1 root     dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Mail Directories for Users ==&lt;br /&gt;
The IMAP server will use the user&#039;s home directory to store mail folders. These are configured to go in ~/mail. You&#039;ll need to make sure this directory exists with the proper permissions for each user accessing email via IMAP.&lt;br /&gt;
&lt;br /&gt;
The following command shows how you can create ~/mail for the user dave:&lt;br /&gt;
&lt;br /&gt;
  install -d -o dave -g dave -m770 ~dave/mail&lt;br /&gt;
&lt;br /&gt;
== Testing the Dovecot Setup ==&lt;br /&gt;
&lt;br /&gt;
To test IMAP, you&#039;ll need an email client. Personally, I&#039;ve used [https://www.thunderbird.net Thunderbird] on Windows, [https://alpineapp.email/ Alpine Mail] on Linux, and [https://k9mail.app/ K-9 Mail] on Android. The trickiest part is getting the email client to trust the self-signed certificates. Configuring email clients is beyond the scope of this document.&lt;br /&gt;
&lt;br /&gt;
From the server side, the Dovecot log file can help you diagnose errors. The dovecot.conf file specifies the location of the log file.&lt;br /&gt;
&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
&lt;br /&gt;
One of the common errors I&#039;ve seen looks like this:&lt;br /&gt;
&lt;br /&gt;
  Disconnected: TLS initialization failed.&lt;br /&gt;
  Error: Failed to initialize SSL server context: Can&#039;t load SSL certificate&lt;br /&gt;
&lt;br /&gt;
This was the result of a typographical error I made in the Dovecot config file.&lt;br /&gt;
&lt;br /&gt;
You can further simplify things by commenting out the ssl lines in the dovecot.conf so it looks like this:&lt;br /&gt;
&lt;br /&gt;
  # ssl_server {&lt;br /&gt;
  #   cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
  #   key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  # }&lt;br /&gt;
&lt;br /&gt;
Now TLS is out of the picture, letting you diagnose other potential problems. However, you may have to do some work to convince your mail client that sending login credentials in cleartext is okay. Only do this on a network where you trust your users!&lt;br /&gt;
&lt;br /&gt;
== Using and Enjoying Your Small-Time Email Setup ==&lt;br /&gt;
&lt;br /&gt;
Now that everything is setup, you can start sending yourself cat pictures or you can configure other programs to use the email system to send notifications. For example, I use [https://mmonit.com/monit/ Monit] to keep an eye on services and file system space. When Monit detects a problem, it sends me an email.&lt;br /&gt;
&lt;br /&gt;
The setup presented in this guide uses port 25 for SMTP and port 143 for IMAP. There are no dedicated TLS ports. Encryption is done using STARTTLS.&lt;br /&gt;
&lt;br /&gt;
== A Word About Aliases ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve ever used {{path|/etc/aliases}} for mail delivery, you should be aware that Exim puts this file in {{path|/etc/mail/aliases}}. The format is the same as Sendmail.&lt;br /&gt;
&lt;br /&gt;
== Scripted Installation and Configuration ==&lt;br /&gt;
&lt;br /&gt;
If you like living dangerously (or if you have a test system you don&#039;t care about) you can do all of the server configuration presented above with a single script, as shown below:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
  &lt;br /&gt;
  apk add exim mailx&lt;br /&gt;
  &lt;br /&gt;
  sed -i~ \&lt;br /&gt;
    -e &#039;s/# group = mail/  group = mail/&#039; \&lt;br /&gt;
    -e &#039;s/# mode = 0660/  mode = 0660/&#039; \&lt;br /&gt;
    /etc/exim/exim.conf&lt;br /&gt;
  &lt;br /&gt;
  ln -s mail/aliases /etc/aliases&lt;br /&gt;
  &lt;br /&gt;
  rc-update add exim&lt;br /&gt;
  service exim start&lt;br /&gt;
  &lt;br /&gt;
  apk add dovecot&lt;br /&gt;
  &lt;br /&gt;
  mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf~&lt;br /&gt;
  &lt;br /&gt;
  cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/dovecot/dovecot.conf&lt;br /&gt;
  dovecot_config_version = 2.4.0&lt;br /&gt;
  auth_allow_cleartext = yes&lt;br /&gt;
  dovecot_storage_version = 2.4.0&lt;br /&gt;
  first_valid_uid = 8&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  mail_driver = mbox&lt;br /&gt;
  mail_gid = mail&lt;br /&gt;
  mail_home = /home/%{user}&lt;br /&gt;
  mail_inbox_path = /var/mail/%{user}&lt;br /&gt;
  mail_path = /home/%{user}/mail&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_uid = %{user}&lt;br /&gt;
  protocols {&lt;br /&gt;
    imap = yes&lt;br /&gt;
  }&lt;br /&gt;
  passdb passwd {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    passwd_file_path = /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl_server {&lt;br /&gt;
    cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
    key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  }&lt;br /&gt;
  EOF&lt;br /&gt;
  &lt;br /&gt;
  touch /etc/dovecot/passwd&lt;br /&gt;
  chown root:dovecot /etc/dovecot/passwd&lt;br /&gt;
  chmod 640 /etc/dovecot/passwd&lt;br /&gt;
  &lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
  &lt;br /&gt;
  echo &amp;quot;Create dovecot user passwords with: doveadm pw -s sha512-crypt and add to {{path|/etc/dovecot/passwd}}&amp;quot;&lt;br /&gt;
  echo &amp;quot;Create user mail directories with: install -d -o username -g dave -m770 ~username/mail&amp;quot;&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30962</id>
		<title>Small-Time Email with Exim and Dovecot</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30962"/>
		<updated>2025-09-22T17:35:33Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Configuring Dovecot */ fix proper name casing typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want a super-simple SMTP / IMAP setup for a home server, this is the guide for you. This document covers the minimum steps to get email delivery up and running on a small home network. You&#039;re not going to want to use this for any serious enterprise stuff, but for a small home LAN it works well.&lt;br /&gt;
&lt;br /&gt;
== Why would anyone do this? ==&lt;br /&gt;
&lt;br /&gt;
My personal motivation for creating this small-time email setup was to deliver alerts from [https://mmonit.com/monit/ Monit] so I would know when my system needed attention. You can use it for this or similar minimalist email needs. Just don&#039;t do anything crazy like exposing it to the internet.&lt;br /&gt;
&lt;br /&gt;
== Why Exim and Dovecot? ==&lt;br /&gt;
&lt;br /&gt;
For an email server, Exim is easy to configure. Dovecot is a little more complex, but not insurmountable. Both are well documented.&lt;br /&gt;
&lt;br /&gt;
== Installing the Packages ==&lt;br /&gt;
The first step is to install Exim, Dovecot, and Mailx. (Mailx is used for testing.)&lt;br /&gt;
&lt;br /&gt;
  apk add {{pkg|exim|arch=}} {{pkg|dovecot|arch=}} {{pkg|mailx|arch=}}&lt;br /&gt;
&lt;br /&gt;
== Configuring Exim ==&lt;br /&gt;
&lt;br /&gt;
The next step is to get Exim working for delivering email to users on the system. This is a pretty simple configuration and there are only a few parameters to change in the delivered exim.conf file.&lt;br /&gt;
&lt;br /&gt;
# Make a backup of {{path|/etc/exim/exim.conf}}&lt;br /&gt;
# Open {{path|/etc/exim/exim.conf}} in your favorite text editor.&lt;br /&gt;
# Make the changes stated below and save.&lt;br /&gt;
&lt;br /&gt;
Find the lines that look like this:&lt;br /&gt;
&lt;br /&gt;
  # group = mail&lt;br /&gt;
  # mode = 0660&lt;br /&gt;
&lt;br /&gt;
They&#039;ll be under the heading of &amp;lt;code&amp;gt;local_delivery:&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you find them, remove the comment (hash symbol). The local_delivery section should now look like this:&lt;br /&gt;
&lt;br /&gt;
  local_delivery:&lt;br /&gt;
    driver = appendfile&lt;br /&gt;
    file = /var/mail/$local_part_data&lt;br /&gt;
    delivery_date_add&lt;br /&gt;
    envelope_to_add&lt;br /&gt;
    return_path_add&lt;br /&gt;
    group = mail&lt;br /&gt;
    mode = 0660&lt;br /&gt;
&lt;br /&gt;
The only thing changed is the removal of the hash symbol from the last two lines.&lt;br /&gt;
&lt;br /&gt;
== Fixing Ownership and Permissions on /var/mail ==&lt;br /&gt;
&lt;br /&gt;
As it stands, Exim will not be able to deliver messages to /var/mail, where the user mailboxes are stored. This is due to permissions.&lt;br /&gt;
&lt;br /&gt;
To fix it, run these two commands:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
&lt;br /&gt;
When you&#039;re done, verify it with &amp;lt;code&amp;gt;ls -ld /var/mail&amp;lt;/code&amp;gt;. It should look like this:&lt;br /&gt;
&lt;br /&gt;
  $ ls -ld /var/mail/&lt;br /&gt;
  drwxrwsr-x    3 root     mail          4096 May 11 12:58 /var/mail/&lt;br /&gt;
&lt;br /&gt;
Setting the group ownership to &#039;&#039;mail&#039;&#039;, lets exim write to users&#039; mailboxes when new mail comes in.&lt;br /&gt;
&lt;br /&gt;
== Starting the Exim Service ==&lt;br /&gt;
&lt;br /&gt;
Start Exim and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service exim start&lt;br /&gt;
  rc-update add exim&lt;br /&gt;
&lt;br /&gt;
== Testing the Exim Setup ==&lt;br /&gt;
&lt;br /&gt;
Log in a a regular user and try sending a test email to yourself. You can do this with the mail command, like this:&lt;br /&gt;
&lt;br /&gt;
  mail -s Testing dave&lt;br /&gt;
  This is a test.&lt;br /&gt;
  .&lt;br /&gt;
&lt;br /&gt;
This sends a test message to the user dave. (Obviously, you&#039;ll want to replace dave with your username.) The final . on the last line is important. It tells the mail command the message is done.&lt;br /&gt;
&lt;br /&gt;
When the message is sent, check that you received it by running &amp;lt;code&amp;gt;mail&amp;lt;/code&amp;gt; with no command-line parameters. If everything went well, it should look like the example below.&lt;br /&gt;
&lt;br /&gt;
  $ mail&lt;br /&gt;
  Mail version 8.1.2 01/15/2001.  Type ? for help.&lt;br /&gt;
  &amp;quot;/var/mail/dave&amp;quot;: 1 messages&lt;br /&gt;
  &amp;gt;   1 dave@myserver.home      Wed May 11 03:51  27/847   &amp;quot;Testing&amp;quot;&lt;br /&gt;
  &amp;amp;&lt;br /&gt;
&lt;br /&gt;
You can type the message number (1) to display the contents of the mail and then type q to quit the mail program.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting Mail Delivery ==&lt;br /&gt;
&lt;br /&gt;
If the mail test fails, look in the directory {{path|/var/spool/exim/msglog}}. If there are files there, they are stuck messages. The files are plain text. Display the contents to show any error messages. In most cases, the problem will be related to permissions on the {{path|/var/mail}} directory or the mailbox files within the directory.&lt;br /&gt;
&lt;br /&gt;
The directory permissions should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -ld /var/mail&lt;br /&gt;
  drwxrwsr-x    3 root     mail&lt;br /&gt;
&lt;br /&gt;
The permissions on mailbox files inside should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -l /var/mail&lt;br /&gt;
  -rw-rw----    1 dave     mail&lt;br /&gt;
&lt;br /&gt;
== Configuring Dovecot ==&lt;br /&gt;
&lt;br /&gt;
If everything is working with local delivery, it&#039;s time to set up IMAP using Dovecot.&lt;br /&gt;
&lt;br /&gt;
The Dovecot package for Alpine comes with twenty configuration files in {{path|/etc/dovecot/conf.d}}. As a small-time email admin, you may feel overwhelmed. Don&#039;t worry, everything can be condensed down to a single config file of sixteen lines.&lt;br /&gt;
&lt;br /&gt;
First, make a backup copy of {{path|/etc/dovecot/dovecot.conf}}.&lt;br /&gt;
&lt;br /&gt;
Next, create a new dovecot.conf that looks like what&#039;s shown below.&lt;br /&gt;
&lt;br /&gt;
{{Note| The example configuration below is for Dovecot version 2.4 used in Alpine Linux 3.22. It is not compatible with Dovecot 2.3 used in earlier versions of Alpine.}}&lt;br /&gt;
&lt;br /&gt;
  dovecot_config_version = 2.4.0&lt;br /&gt;
  auth_allow_cleartext = yes&lt;br /&gt;
  dovecot_storage_version = 2.4.0&lt;br /&gt;
  first_valid_uid = 8&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  mail_driver = mbox&lt;br /&gt;
  mail_gid = mail&lt;br /&gt;
  mail_home = /home/%{user}&lt;br /&gt;
  mail_inbox_path = /var/mail/%{user}&lt;br /&gt;
  mail_path = /home/%{user}/mail&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_uid = %{user}&lt;br /&gt;
  protocols {&lt;br /&gt;
    imap = yes&lt;br /&gt;
  }&lt;br /&gt;
  passdb passwd {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    passwd_file_path = /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl_server {&lt;br /&gt;
    cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
    key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
This config does not have the &amp;lt;code&amp;gt;!include conf.d/*.conf&amp;lt;/code&amp;gt; that was in the original dovecot.conf, so those twenty files in conf.d are going to be ignored. Everything is now in this single dovecot.conf.&lt;br /&gt;
&lt;br /&gt;
== Starting the Dovecot Service ==&lt;br /&gt;
&lt;br /&gt;
Start Dovecot and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Credentials for Dovecot Users ==&lt;br /&gt;
&lt;br /&gt;
As it is configured, Dovecot will use {{path|/etc/passwd}} for looking up user information, but not authentication. Technically, {{path|/etc/passwd}} authentication can be done using Pluggable Authentication Modules (PAM), but PAM is not part of the base install of Alpine Linux. The next best thing is to use a separate password file for Dovecot credentials and to use the same SHA512-Crypt hashing algorithm used in {{path|/etc/passwd}}.&lt;br /&gt;
&lt;br /&gt;
The Dovecot configuration above specifies a password file of {{path|/etc/dovecot/passwd}}. The Dovecot password file looks like this:&lt;br /&gt;
&lt;br /&gt;
  dave:{SHA512-CRYPT}$6$mQ1rxB0gZHqg8Tg9$nxZ8odJZ6xVpmOVpsnYfAo1i7SuoLDhsvoykieukWF9NyNBq.WwhDA7udcYxP1iEm/IzlBmnwz6/vOO3SX8gA.&lt;br /&gt;
&lt;br /&gt;
There are two fields, username and password, separated by a colon. Notice the {SHA512-CRYPT} prefix to the password. This indicates the hashing algorithm.&lt;br /&gt;
&lt;br /&gt;
You can create passwords with the &amp;lt;code&amp;gt;doveadm&amp;lt;/code&amp;gt; command, like this:&lt;br /&gt;
&lt;br /&gt;
  # doveadm pw -s sha512-crypt&lt;br /&gt;
  Enter new password:&lt;br /&gt;
  Retype new password:&lt;br /&gt;
&lt;br /&gt;
The command will output the hashed password. You&#039;ll need to edit Dovecot&#039;s password file with a text editor and create the username/password pair by hand.&lt;br /&gt;
&lt;br /&gt;
The permissions on the Dovecot password file should be such that dovecot can read it, but not write to it. Only root should be able to write it.&lt;br /&gt;
&lt;br /&gt;
  ls -l /etc/dovecot/passwd&lt;br /&gt;
  -rw-r-----    1 root     dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Mail Directories for Users ==&lt;br /&gt;
The IMAP server will use the user&#039;s home directory to store mail folders. These are configured to go in ~/mail. You&#039;ll need to make sure this directory exists with the proper permissions for each user accessing email via IMAP.&lt;br /&gt;
&lt;br /&gt;
The following command shows how you can create ~/mail for the user dave:&lt;br /&gt;
&lt;br /&gt;
  install -d -o dave -g dave -m770 ~dave/mail&lt;br /&gt;
&lt;br /&gt;
== Testing the Dovecot Setup ==&lt;br /&gt;
&lt;br /&gt;
To test IMAP, you&#039;ll need an email client. Personally, I&#039;ve used [https://www.thunderbird.net Thunderbird] on Windows, [https://alpineapp.email/ Alpine Mail] on Linux, and [https://k9mail.app/ K-9 Mail] on Android. The trickiest part is getting the email client to trust the self-signed certificates. Configuring email clients is beyond the scope of this document.&lt;br /&gt;
&lt;br /&gt;
From the server side, the Dovecot log file can help you diagnose errors. The dovecot.conf file specifies the location of the log file.&lt;br /&gt;
&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
&lt;br /&gt;
One of the common errors I&#039;ve seen looks like this:&lt;br /&gt;
&lt;br /&gt;
  Disconnected: TLS initialization failed.&lt;br /&gt;
  Error: Failed to initialize SSL server context: Can&#039;t load SSL certificate&lt;br /&gt;
&lt;br /&gt;
This was the result of a typographical error I made in the Dovecot config file.&lt;br /&gt;
&lt;br /&gt;
You can further simplify things by commenting out the ssl lines in the dovecot.conf so it looks like this:&lt;br /&gt;
&lt;br /&gt;
  # ssl_server {&lt;br /&gt;
  #   cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
  #   key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  # }&lt;br /&gt;
&lt;br /&gt;
Now TLS is out of the picture, letting you diagnose other potential problems. However, you may have to do some work to convince your mail client that sending login credentials in cleartext is okay. Only do this on a network where you trust your users!&lt;br /&gt;
&lt;br /&gt;
== Using and Enjoying Your Small-Time Email Setup ==&lt;br /&gt;
&lt;br /&gt;
Now that everything is setup, you can start sending yourself cat pictures or you can configure other programs to use the email system to send notifications. For example, I use [https://mmonit.com/monit/ Monit] to keep an eye on services and file system space. When Monit detects a problem, it sends me an email.&lt;br /&gt;
&lt;br /&gt;
The setup presented in this guide uses port 25 for SMTP and port 143 for IMAP. There are no dedicated TLS ports. Encryption is done using STARTTLS.&lt;br /&gt;
&lt;br /&gt;
== A Word About Aliases ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve ever used {{path|/etc/aliases}} for mail delivery, you should be aware that Exim puts this file in {{path|/etc/mail/aliases}}. The format is the same as Sendmail.&lt;br /&gt;
&lt;br /&gt;
== Scripted Installation and Configuration ==&lt;br /&gt;
&lt;br /&gt;
If you like living dangerously (or if you have a test system you don&#039;t care about) you can do all of the server configuration presented above with a single script, as shown below:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
  &lt;br /&gt;
  apk add exim mailx&lt;br /&gt;
  &lt;br /&gt;
  sed -i~ \&lt;br /&gt;
    -e &#039;s/# group = mail/  group = mail/&#039; \&lt;br /&gt;
    -e &#039;s/# mode = 0660/  mode = 0660/&#039; \&lt;br /&gt;
    /etc/exim/exim.conf&lt;br /&gt;
  &lt;br /&gt;
  ln -s mail/aliases /etc/aliases&lt;br /&gt;
  &lt;br /&gt;
  rc-update add exim&lt;br /&gt;
  service exim start&lt;br /&gt;
  &lt;br /&gt;
  apk add dovecot&lt;br /&gt;
  &lt;br /&gt;
  mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf~&lt;br /&gt;
  &lt;br /&gt;
  cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/dovecot/dovecot.conf&lt;br /&gt;
  dovecot_config_version = 2.4.0&lt;br /&gt;
  auth_allow_cleartext = yes&lt;br /&gt;
  dovecot_storage_version = 2.4.0&lt;br /&gt;
  first_valid_uid = 8&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  mail_driver = mbox&lt;br /&gt;
  mail_gid = mail&lt;br /&gt;
  mail_home = /home/%{user}&lt;br /&gt;
  mail_inbox_path = /var/mail/%{user}&lt;br /&gt;
  mail_path = /home/%{user}/mail&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_uid = %{user}&lt;br /&gt;
  protocols {&lt;br /&gt;
    imap = yes&lt;br /&gt;
  }&lt;br /&gt;
  passdb passwd {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    passwd_file_path = /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl_server {&lt;br /&gt;
    cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
    key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  }&lt;br /&gt;
  EOF&lt;br /&gt;
  &lt;br /&gt;
  touch /etc/dovecot/passwd&lt;br /&gt;
  chown root:dovecot /etc/dovecot/passwd&lt;br /&gt;
  chmod 640 /etc/dovecot/passwd&lt;br /&gt;
  &lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
  &lt;br /&gt;
  echo &amp;quot;Create dovecot user passwords with: doveadm pw -s sha512-crypt and add to {{path|/etc/dovecot/passwd}}&amp;quot;&lt;br /&gt;
  echo &amp;quot;Create user mail directories with: install -d -o username -g dave -m770 ~username/mail&amp;quot;&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30961</id>
		<title>Small-Time Email with Exim and Dovecot</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30961"/>
		<updated>2025-09-22T17:34:34Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: Update to reflect breaking changes in dovecot.conf starting with Dovecot version 2.4&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want a super-simple SMTP / IMAP setup for a home server, this is the guide for you. This document covers the minimum steps to get email delivery up and running on a small home network. You&#039;re not going to want to use this for any serious enterprise stuff, but for a small home LAN it works well.&lt;br /&gt;
&lt;br /&gt;
== Why would anyone do this? ==&lt;br /&gt;
&lt;br /&gt;
My personal motivation for creating this small-time email setup was to deliver alerts from [https://mmonit.com/monit/ Monit] so I would know when my system needed attention. You can use it for this or similar minimalist email needs. Just don&#039;t do anything crazy like exposing it to the internet.&lt;br /&gt;
&lt;br /&gt;
== Why Exim and Dovecot? ==&lt;br /&gt;
&lt;br /&gt;
For an email server, Exim is easy to configure. Dovecot is a little more complex, but not insurmountable. Both are well documented.&lt;br /&gt;
&lt;br /&gt;
== Installing the Packages ==&lt;br /&gt;
The first step is to install Exim, Dovecot, and Mailx. (Mailx is used for testing.)&lt;br /&gt;
&lt;br /&gt;
  apk add {{pkg|exim|arch=}} {{pkg|dovecot|arch=}} {{pkg|mailx|arch=}}&lt;br /&gt;
&lt;br /&gt;
== Configuring Exim ==&lt;br /&gt;
&lt;br /&gt;
The next step is to get Exim working for delivering email to users on the system. This is a pretty simple configuration and there are only a few parameters to change in the delivered exim.conf file.&lt;br /&gt;
&lt;br /&gt;
# Make a backup of {{path|/etc/exim/exim.conf}}&lt;br /&gt;
# Open {{path|/etc/exim/exim.conf}} in your favorite text editor.&lt;br /&gt;
# Make the changes stated below and save.&lt;br /&gt;
&lt;br /&gt;
Find the lines that look like this:&lt;br /&gt;
&lt;br /&gt;
  # group = mail&lt;br /&gt;
  # mode = 0660&lt;br /&gt;
&lt;br /&gt;
They&#039;ll be under the heading of &amp;lt;code&amp;gt;local_delivery:&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you find them, remove the comment (hash symbol). The local_delivery section should now look like this:&lt;br /&gt;
&lt;br /&gt;
  local_delivery:&lt;br /&gt;
    driver = appendfile&lt;br /&gt;
    file = /var/mail/$local_part_data&lt;br /&gt;
    delivery_date_add&lt;br /&gt;
    envelope_to_add&lt;br /&gt;
    return_path_add&lt;br /&gt;
    group = mail&lt;br /&gt;
    mode = 0660&lt;br /&gt;
&lt;br /&gt;
The only thing changed is the removal of the hash symbol from the last two lines.&lt;br /&gt;
&lt;br /&gt;
== Fixing Ownership and Permissions on /var/mail ==&lt;br /&gt;
&lt;br /&gt;
As it stands, Exim will not be able to deliver messages to /var/mail, where the user mailboxes are stored. This is due to permissions.&lt;br /&gt;
&lt;br /&gt;
To fix it, run these two commands:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
&lt;br /&gt;
When you&#039;re done, verify it with &amp;lt;code&amp;gt;ls -ld /var/mail&amp;lt;/code&amp;gt;. It should look like this:&lt;br /&gt;
&lt;br /&gt;
  $ ls -ld /var/mail/&lt;br /&gt;
  drwxrwsr-x    3 root     mail          4096 May 11 12:58 /var/mail/&lt;br /&gt;
&lt;br /&gt;
Setting the group ownership to &#039;&#039;mail&#039;&#039;, lets exim write to users&#039; mailboxes when new mail comes in.&lt;br /&gt;
&lt;br /&gt;
== Starting the Exim Service ==&lt;br /&gt;
&lt;br /&gt;
Start Exim and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service exim start&lt;br /&gt;
  rc-update add exim&lt;br /&gt;
&lt;br /&gt;
== Testing the Exim Setup ==&lt;br /&gt;
&lt;br /&gt;
Log in a a regular user and try sending a test email to yourself. You can do this with the mail command, like this:&lt;br /&gt;
&lt;br /&gt;
  mail -s Testing dave&lt;br /&gt;
  This is a test.&lt;br /&gt;
  .&lt;br /&gt;
&lt;br /&gt;
This sends a test message to the user dave. (Obviously, you&#039;ll want to replace dave with your username.) The final . on the last line is important. It tells the mail command the message is done.&lt;br /&gt;
&lt;br /&gt;
When the message is sent, check that you received it by running &amp;lt;code&amp;gt;mail&amp;lt;/code&amp;gt; with no command-line parameters. If everything went well, it should look like the example below.&lt;br /&gt;
&lt;br /&gt;
  $ mail&lt;br /&gt;
  Mail version 8.1.2 01/15/2001.  Type ? for help.&lt;br /&gt;
  &amp;quot;/var/mail/dave&amp;quot;: 1 messages&lt;br /&gt;
  &amp;gt;   1 dave@myserver.home      Wed May 11 03:51  27/847   &amp;quot;Testing&amp;quot;&lt;br /&gt;
  &amp;amp;&lt;br /&gt;
&lt;br /&gt;
You can type the message number (1) to display the contents of the mail and then type q to quit the mail program.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting Mail Delivery ==&lt;br /&gt;
&lt;br /&gt;
If the mail test fails, look in the directory {{path|/var/spool/exim/msglog}}. If there are files there, they are stuck messages. The files are plain text. Display the contents to show any error messages. In most cases, the problem will be related to permissions on the {{path|/var/mail}} directory or the mailbox files within the directory.&lt;br /&gt;
&lt;br /&gt;
The directory permissions should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -ld /var/mail&lt;br /&gt;
  drwxrwsr-x    3 root     mail&lt;br /&gt;
&lt;br /&gt;
The permissions on mailbox files inside should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -l /var/mail&lt;br /&gt;
  -rw-rw----    1 dave     mail&lt;br /&gt;
&lt;br /&gt;
== Configuring Dovecot ==&lt;br /&gt;
&lt;br /&gt;
If everything is working with local delivery, it&#039;s time to set up IMAP using Dovecot.&lt;br /&gt;
&lt;br /&gt;
The Dovecot package for Alpine comes with twenty configuration files in {{path|/etc/dovecot/conf.d}}. As a small-time email admin, you may feel overwhelmed. Don&#039;t worry, everything can be condensed down to a single config file of sixteen lines.&lt;br /&gt;
&lt;br /&gt;
First, make a backup copy of {{path|/etc/dovecot/dovecot.conf}}.&lt;br /&gt;
&lt;br /&gt;
Next, create a new dovecot.conf that looks like what&#039;s shown below.&lt;br /&gt;
&lt;br /&gt;
{{Note| The example configuration below is for Dovecot version 2.4 used in Alpine Linux 3.22. It is not compatible with dovecot 2.3 used in earlier versions of Alpine.}}&lt;br /&gt;
&lt;br /&gt;
  dovecot_config_version = 2.4.0&lt;br /&gt;
  auth_allow_cleartext = yes&lt;br /&gt;
  dovecot_storage_version = 2.4.0&lt;br /&gt;
  first_valid_uid = 8&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  mail_driver = mbox&lt;br /&gt;
  mail_gid = mail&lt;br /&gt;
  mail_home = /home/%{user}&lt;br /&gt;
  mail_inbox_path = /var/mail/%{user}&lt;br /&gt;
  mail_path = /home/%{user}/mail&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_uid = %{user}&lt;br /&gt;
  protocols {&lt;br /&gt;
    imap = yes&lt;br /&gt;
  }&lt;br /&gt;
  passdb passwd {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    passwd_file_path = /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl_server {&lt;br /&gt;
    cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
    key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
This config does not have the &amp;lt;code&amp;gt;!include conf.d/*.conf&amp;lt;/code&amp;gt; that was in the original dovecot.conf, so those twenty files in conf.d are going to be ignored. Everything is now in this single dovecot.conf.&lt;br /&gt;
&lt;br /&gt;
== Starting the Dovecot Service ==&lt;br /&gt;
&lt;br /&gt;
Start Dovecot and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Credentials for Dovecot Users ==&lt;br /&gt;
&lt;br /&gt;
As it is configured, Dovecot will use {{path|/etc/passwd}} for looking up user information, but not authentication. Technically, {{path|/etc/passwd}} authentication can be done using Pluggable Authentication Modules (PAM), but PAM is not part of the base install of Alpine Linux. The next best thing is to use a separate password file for Dovecot credentials and to use the same SHA512-Crypt hashing algorithm used in {{path|/etc/passwd}}.&lt;br /&gt;
&lt;br /&gt;
The Dovecot configuration above specifies a password file of {{path|/etc/dovecot/passwd}}. The Dovecot password file looks like this:&lt;br /&gt;
&lt;br /&gt;
  dave:{SHA512-CRYPT}$6$mQ1rxB0gZHqg8Tg9$nxZ8odJZ6xVpmOVpsnYfAo1i7SuoLDhsvoykieukWF9NyNBq.WwhDA7udcYxP1iEm/IzlBmnwz6/vOO3SX8gA.&lt;br /&gt;
&lt;br /&gt;
There are two fields, username and password, separated by a colon. Notice the {SHA512-CRYPT} prefix to the password. This indicates the hashing algorithm.&lt;br /&gt;
&lt;br /&gt;
You can create passwords with the &amp;lt;code&amp;gt;doveadm&amp;lt;/code&amp;gt; command, like this:&lt;br /&gt;
&lt;br /&gt;
  # doveadm pw -s sha512-crypt&lt;br /&gt;
  Enter new password:&lt;br /&gt;
  Retype new password:&lt;br /&gt;
&lt;br /&gt;
The command will output the hashed password. You&#039;ll need to edit Dovecot&#039;s password file with a text editor and create the username/password pair by hand.&lt;br /&gt;
&lt;br /&gt;
The permissions on the Dovecot password file should be such that dovecot can read it, but not write to it. Only root should be able to write it.&lt;br /&gt;
&lt;br /&gt;
  ls -l /etc/dovecot/passwd&lt;br /&gt;
  -rw-r-----    1 root     dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Mail Directories for Users ==&lt;br /&gt;
The IMAP server will use the user&#039;s home directory to store mail folders. These are configured to go in ~/mail. You&#039;ll need to make sure this directory exists with the proper permissions for each user accessing email via IMAP.&lt;br /&gt;
&lt;br /&gt;
The following command shows how you can create ~/mail for the user dave:&lt;br /&gt;
&lt;br /&gt;
  install -d -o dave -g dave -m770 ~dave/mail&lt;br /&gt;
&lt;br /&gt;
== Testing the Dovecot Setup ==&lt;br /&gt;
&lt;br /&gt;
To test IMAP, you&#039;ll need an email client. Personally, I&#039;ve used [https://www.thunderbird.net Thunderbird] on Windows, [https://alpineapp.email/ Alpine Mail] on Linux, and [https://k9mail.app/ K-9 Mail] on Android. The trickiest part is getting the email client to trust the self-signed certificates. Configuring email clients is beyond the scope of this document.&lt;br /&gt;
&lt;br /&gt;
From the server side, the Dovecot log file can help you diagnose errors. The dovecot.conf file specifies the location of the log file.&lt;br /&gt;
&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
&lt;br /&gt;
One of the common errors I&#039;ve seen looks like this:&lt;br /&gt;
&lt;br /&gt;
  Disconnected: TLS initialization failed.&lt;br /&gt;
  Error: Failed to initialize SSL server context: Can&#039;t load SSL certificate&lt;br /&gt;
&lt;br /&gt;
This was the result of a typographical error I made in the Dovecot config file.&lt;br /&gt;
&lt;br /&gt;
You can further simplify things by commenting out the ssl lines in the dovecot.conf so it looks like this:&lt;br /&gt;
&lt;br /&gt;
  # ssl_server {&lt;br /&gt;
  #   cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
  #   key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  # }&lt;br /&gt;
&lt;br /&gt;
Now TLS is out of the picture, letting you diagnose other potential problems. However, you may have to do some work to convince your mail client that sending login credentials in cleartext is okay. Only do this on a network where you trust your users!&lt;br /&gt;
&lt;br /&gt;
== Using and Enjoying Your Small-Time Email Setup ==&lt;br /&gt;
&lt;br /&gt;
Now that everything is setup, you can start sending yourself cat pictures or you can configure other programs to use the email system to send notifications. For example, I use [https://mmonit.com/monit/ Monit] to keep an eye on services and file system space. When Monit detects a problem, it sends me an email.&lt;br /&gt;
&lt;br /&gt;
The setup presented in this guide uses port 25 for SMTP and port 143 for IMAP. There are no dedicated TLS ports. Encryption is done using STARTTLS.&lt;br /&gt;
&lt;br /&gt;
== A Word About Aliases ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve ever used {{path|/etc/aliases}} for mail delivery, you should be aware that Exim puts this file in {{path|/etc/mail/aliases}}. The format is the same as Sendmail.&lt;br /&gt;
&lt;br /&gt;
== Scripted Installation and Configuration ==&lt;br /&gt;
&lt;br /&gt;
If you like living dangerously (or if you have a test system you don&#039;t care about) you can do all of the server configuration presented above with a single script, as shown below:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
  &lt;br /&gt;
  apk add exim mailx&lt;br /&gt;
  &lt;br /&gt;
  sed -i~ \&lt;br /&gt;
    -e &#039;s/# group = mail/  group = mail/&#039; \&lt;br /&gt;
    -e &#039;s/# mode = 0660/  mode = 0660/&#039; \&lt;br /&gt;
    /etc/exim/exim.conf&lt;br /&gt;
  &lt;br /&gt;
  ln -s mail/aliases /etc/aliases&lt;br /&gt;
  &lt;br /&gt;
  rc-update add exim&lt;br /&gt;
  service exim start&lt;br /&gt;
  &lt;br /&gt;
  apk add dovecot&lt;br /&gt;
  &lt;br /&gt;
  mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf~&lt;br /&gt;
  &lt;br /&gt;
  cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/dovecot/dovecot.conf&lt;br /&gt;
  dovecot_config_version = 2.4.0&lt;br /&gt;
  auth_allow_cleartext = yes&lt;br /&gt;
  dovecot_storage_version = 2.4.0&lt;br /&gt;
  first_valid_uid = 8&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  mail_driver = mbox&lt;br /&gt;
  mail_gid = mail&lt;br /&gt;
  mail_home = /home/%{user}&lt;br /&gt;
  mail_inbox_path = /var/mail/%{user}&lt;br /&gt;
  mail_path = /home/%{user}/mail&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_uid = %{user}&lt;br /&gt;
  protocols {&lt;br /&gt;
    imap = yes&lt;br /&gt;
  }&lt;br /&gt;
  passdb passwd {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    passwd_file_path = /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl_server {&lt;br /&gt;
    cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
    key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
  }&lt;br /&gt;
  EOF&lt;br /&gt;
  &lt;br /&gt;
  touch /etc/dovecot/passwd&lt;br /&gt;
  chown root:dovecot /etc/dovecot/passwd&lt;br /&gt;
  chmod 640 /etc/dovecot/passwd&lt;br /&gt;
  &lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
  &lt;br /&gt;
  echo &amp;quot;Create dovecot user passwords with: doveadm pw -s sha512-crypt and add to {{path|/etc/dovecot/passwd}}&amp;quot;&lt;br /&gt;
  echo &amp;quot;Create user mail directories with: install -d -o username -g dave -m770 ~username/mail&amp;quot;&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30951</id>
		<title>Small-Time Email with Exim and Dovecot</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30951"/>
		<updated>2025-09-21T15:51:28Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Testing the Dovecot Setup */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want a super-simple SMTP / IMAP setup for a home server, this is the guide for you. This document covers the minimum steps to get email delivery up and running on a small home network. You&#039;re not going to want to use this for any serious enterprise stuff, but for a small home LAN it works well.&lt;br /&gt;
&lt;br /&gt;
== Why would anyone do this? ==&lt;br /&gt;
&lt;br /&gt;
My personal motivation for creating this small-time email setup was to deliver alerts from [https://mmonit.com/monit/ Monit] so I would know when my system needed attention. You can use it for this or similar minimalist email needs. Just don&#039;t do anything crazy like exposing it to the internet.&lt;br /&gt;
&lt;br /&gt;
== Why Exim and Dovecot? ==&lt;br /&gt;
&lt;br /&gt;
For an email server, Exim is easy to configure. Dovecot is a little more complex, but not insurmountable. Both are well documented.&lt;br /&gt;
&lt;br /&gt;
== Installing the Packages ==&lt;br /&gt;
The first step is to install Exim, Dovecot, and Mailx. (Mailx is used for testing.)&lt;br /&gt;
&lt;br /&gt;
  apk add {{pkg|exim|arch=}} {{pkg|dovecot|arch=}} {{pkg|mailx|arch=}}&lt;br /&gt;
&lt;br /&gt;
== Configuring Exim ==&lt;br /&gt;
&lt;br /&gt;
The next step is to get Exim working for delivering email to users on the system. This is a pretty simple configuration and there are only a few parameters to change in the delivered exim.conf file.&lt;br /&gt;
&lt;br /&gt;
# Make a backup of {{path|/etc/exim/exim.conf}}&lt;br /&gt;
# Open {{path|/etc/exim/exim.conf}} in your favorite text editor.&lt;br /&gt;
# Make the changes stated below and save.&lt;br /&gt;
&lt;br /&gt;
Find the lines that look like this:&lt;br /&gt;
&lt;br /&gt;
  # group = mail&lt;br /&gt;
  # mode = 0660&lt;br /&gt;
&lt;br /&gt;
They&#039;ll be under the heading of &amp;lt;code&amp;gt;local_delivery:&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you find them, remove the comment (hash symbol). The local_delivery section should now look like this:&lt;br /&gt;
&lt;br /&gt;
  local_delivery:&lt;br /&gt;
    driver = appendfile&lt;br /&gt;
    file = /var/mail/$local_part_data&lt;br /&gt;
    delivery_date_add&lt;br /&gt;
    envelope_to_add&lt;br /&gt;
    return_path_add&lt;br /&gt;
    group = mail&lt;br /&gt;
    mode = 0660&lt;br /&gt;
&lt;br /&gt;
The only thing changed is the removal of the hash symbol from the last two lines.&lt;br /&gt;
&lt;br /&gt;
== Fixing Ownership and Permissions on /var/mail ==&lt;br /&gt;
&lt;br /&gt;
As it stands, Exim will not be able to deliver messages to /var/mail, where the user mailboxes are stored. This is due to permissions.&lt;br /&gt;
&lt;br /&gt;
To fix it, run these two commands:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
&lt;br /&gt;
When you&#039;re done, verify it with &amp;lt;code&amp;gt;ls -ld /var/mail&amp;lt;/code&amp;gt;. It should look something like this:&lt;br /&gt;
&lt;br /&gt;
  $ ls -ld /var/mail/&lt;br /&gt;
  drwxrwsr-x    3 root     mail          4096 May 11 12:58 /var/mail/&lt;br /&gt;
&lt;br /&gt;
Setting the group ownership to &#039;&#039;mail&#039;&#039;, lets exim write to users&#039; mailboxes when new mail comes in.&lt;br /&gt;
&lt;br /&gt;
== Starting the Exim Service ==&lt;br /&gt;
&lt;br /&gt;
Start Exim and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service exim start&lt;br /&gt;
  rc-update add exim&lt;br /&gt;
&lt;br /&gt;
== Testing the Exim Setup ==&lt;br /&gt;
&lt;br /&gt;
Log in a a regular user and try sending a test email to yourself. You can do this with the mail command, like this:&lt;br /&gt;
&lt;br /&gt;
  mail -s Testing dave&lt;br /&gt;
  This is a test.&lt;br /&gt;
  .&lt;br /&gt;
&lt;br /&gt;
This sends a test message to the user dave. (Obviously, you&#039;ll want to replace dave with your username.) The final . on the last line is important. It tells the mail command the message is done.&lt;br /&gt;
&lt;br /&gt;
When the message is sent, check that you received it by running &amp;lt;code&amp;gt;mail&amp;lt;/code&amp;gt; with no command-line parameters. If everything went well, it should look like the example below.&lt;br /&gt;
&lt;br /&gt;
  $ mail&lt;br /&gt;
  Mail version 8.1 6/6/93.  Type ? for help.&lt;br /&gt;
  &amp;quot;/var/mail/dave&amp;quot;: 1 messages&lt;br /&gt;
  &amp;gt;   1 dave@myserver.home      Wed May 11 03:51  27/847   &amp;quot;Testing&amp;quot;&lt;br /&gt;
  &amp;amp;&lt;br /&gt;
&lt;br /&gt;
You can type the message number (1) to display the contents of the mail and then type q to quit the mail program.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting Mail Delivery ==&lt;br /&gt;
&lt;br /&gt;
If the mail test fails, look in the directory {{path|/var/spool/exim/msglog}}. If there are files there, they are stuck messages. The files are plain text. Display the contents to show any error messages. In most cases, the problem will be related to permissions on the {{path|/var/mail}} directory or the mailbox files within the directory.&lt;br /&gt;
&lt;br /&gt;
The directory permissions should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -ld /var/mail&lt;br /&gt;
  drwxrwsr-x    3 root     mail&lt;br /&gt;
&lt;br /&gt;
The permissions on mailbox files inside should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -l&lt;br /&gt;
  -rw-rw----    1 dave     mail&lt;br /&gt;
&lt;br /&gt;
== Configuring Dovecot ==&lt;br /&gt;
&lt;br /&gt;
If everything is working with local delivery, it&#039;s time to set up IMAP using Dovecot.&lt;br /&gt;
&lt;br /&gt;
{{Note| The example configuration below is for Dovecot version 2.3 used in Alpine Linux 3.21 and earlier. It is not compatible with dovecot 2.4 used in Alpine 3.22.}}&lt;br /&gt;
&lt;br /&gt;
The Dovecot package for Alpine comes with twenty configuration files in {{path|/etc/dovecot/conf.d}}. As a small-time email admin, you may feel overwhelmed. Don&#039;t worry, everything can be condensed down to a single config file of sixteen lines.&lt;br /&gt;
&lt;br /&gt;
First, make a backup copy of {{path|/etc/dovecot/dovecot.conf}}.&lt;br /&gt;
&lt;br /&gt;
Next, create a new dovecot.conf that looks like this:&lt;br /&gt;
&lt;br /&gt;
 listen = *&lt;br /&gt;
 log_path = /var/log/dovecot.log&lt;br /&gt;
 protocols = imap&lt;br /&gt;
 disable_plaintext_auth = no&lt;br /&gt;
 mail_privileged_group = mail&lt;br /&gt;
 mail_location = mbox:~/mail:INBOX=/var/mail/%u&lt;br /&gt;
 userdb {&lt;br /&gt;
   driver = passwd&lt;br /&gt;
 }&lt;br /&gt;
 passdb {&lt;br /&gt;
   driver = ldap&lt;br /&gt;
   args = /etc/dovecot/ldap-auth.ext&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
 ssl=yes&lt;br /&gt;
 ssl_cert=&amp;lt;/etc/ssl/dovecot/server.pem&lt;br /&gt;
 ssl_key=&amp;lt;/etc/ssl/dovecot/server.key&lt;br /&gt;
&lt;br /&gt;
This config does not have the &amp;lt;code&amp;gt;!include conf.d/*.conf&amp;lt;/code&amp;gt; that was in the original dovecot.conf, so those twenty files in conf.d are going to be ignored. Everything is now in this single dovecot.conf.&lt;br /&gt;
&lt;br /&gt;
== Starting the Dovecot Service ==&lt;br /&gt;
&lt;br /&gt;
Start Dovecot and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Credentials for Dovecot Users ==&lt;br /&gt;
&lt;br /&gt;
As it is configured, Dovecot will use {{path|/etc/passwd}} for looking up user information, but not authentication. Technically, {{path|/etc/passwd}} authentication can be done using Pluggable Authentication Modules (PAM), but PAM is not part of the base install of Alpine Linux. The next best thing is to use a separate password file for Dovecot credentials and to use the same SHA512-Crypt hashing algorithm used in {{path|/etc/passwd}}.&lt;br /&gt;
&lt;br /&gt;
The Dovecot configuration above specifies a password file of {{path|/etc/dovecot/passwd}}. The Dovecot password file looks like this:&lt;br /&gt;
&lt;br /&gt;
  dave:{SHA512-CRYPT}$6$mQ1rxB0gZHqg8Tg9$nxZ8odJZ6xVpmOVpsnYfAo1i7SuoLDhsvoykieukWF9NyNBq.WwhDA7udcYxP1iEm/IzlBmnwz6/vOO3SX8gA.&lt;br /&gt;
&lt;br /&gt;
There are two fields, username and password, separated by a colon. Notice the {SHA512-CRYPT} prefix to the password. This indicates the hashing algorithm.&lt;br /&gt;
&lt;br /&gt;
You can create passwords with the &amp;lt;code&amp;gt;doveadm&amp;lt;/code&amp;gt; command, like this:&lt;br /&gt;
&lt;br /&gt;
  # doveadm pw -s sha512-crypt&lt;br /&gt;
  Enter new password:&lt;br /&gt;
  Retype new password:&lt;br /&gt;
&lt;br /&gt;
The command will output the hashed password. You&#039;ll need to edit Dovecot&#039;s password file with a text editor and create the username/password pair by hand.&lt;br /&gt;
&lt;br /&gt;
The permissions on the Dovecot password file should be such that dovecot can read it, but not write to it. Only root should be able to write it.&lt;br /&gt;
&lt;br /&gt;
  ls -l /etc/dovecot/passwd&lt;br /&gt;
  -rw-r-----    1 root     dovecot&lt;br /&gt;
&lt;br /&gt;
== Testing the Dovecot Setup ==&lt;br /&gt;
&lt;br /&gt;
To test IMAP, you&#039;ll need an email client. Personally, I&#039;ve used [https://www.thunderbird.net Thunderbird] on Windows and [https://k9mail.app/ K-9 Mail] on Android. The trickiest part is getting the email client to trust the self-signed certificates. Configuring email clients is beyond the scope of this document.&lt;br /&gt;
&lt;br /&gt;
From the server side, the Dovecot log file can help you diagnose errors. The dovecot.conf file specifies the location of the log file.&lt;br /&gt;
&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
&lt;br /&gt;
One of the common errors I&#039;ve seen looks like this:&lt;br /&gt;
&lt;br /&gt;
  Disconnected: TLS initialization failed.&lt;br /&gt;
  Error: Failed to initialize SSL server context: Can&#039;t load SSL certificate&lt;br /&gt;
&lt;br /&gt;
This was the result of a typographical error I made in the Dovecot config file.&lt;br /&gt;
&lt;br /&gt;
You can further simplify things by commenting out the ssl lines in the dovecot.conf so it looks like this:&lt;br /&gt;
&lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  #ssl=yes&lt;br /&gt;
  #ssl_cert=&amp;lt;/etc/ssl/dovecot/server.pem&lt;br /&gt;
  #ssl_key=&amp;lt;/etc/ssl/dovecot/server.key&lt;br /&gt;
&lt;br /&gt;
Now TLS is out of the picture, letting you diagnose other potential problems. However, you may have to do some work to convince your mail client that sending login credentials in cleartext is okay. Only do this on a network where you trust your users!&lt;br /&gt;
&lt;br /&gt;
== Using and Enjoying Your Small-Time Email Setup ==&lt;br /&gt;
&lt;br /&gt;
Now that everything is setup, you can start sending yourself cat pictures or you can configure other programs to use the email system to send notifications. For example, I use [https://mmonit.com/monit/ Monit] to keep an eye on services and file system space. When Monit detects a problem, it sends me an email.&lt;br /&gt;
&lt;br /&gt;
The setup presented in this guide uses port 25 for SMTP and port 143 for IMAP. There are no dedicated TLS ports. Encryption is done using STARTTLS.&lt;br /&gt;
&lt;br /&gt;
== A Word About Aliases ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve ever used {{path|/etc/aliases}} for mail delivery, you should be aware that Exim puts this file in {{path|/etc/mail/aliases}}. The format is the same as Sendmail.&lt;br /&gt;
&lt;br /&gt;
== Scripted Installation and Configuration ==&lt;br /&gt;
&lt;br /&gt;
If you like living dangerously (or if you have a test system you don&#039;t care about) you can do all of the server configuration presented above with a single script, as shown below:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
  &lt;br /&gt;
  apk add exim mailx&lt;br /&gt;
  &lt;br /&gt;
  sed -i~ \&lt;br /&gt;
    -e &#039;s/# group = mail/  group = mail/&#039; \&lt;br /&gt;
    -e &#039;s/# mode = 0660/  mode = 0660/&#039; \&lt;br /&gt;
    /etc/exim/exim.conf&lt;br /&gt;
  &lt;br /&gt;
  ln -s mail/aliases /etc/aliases&lt;br /&gt;
  &lt;br /&gt;
  rc-update add exim&lt;br /&gt;
  service exim start&lt;br /&gt;
  &lt;br /&gt;
  apk add dovecot&lt;br /&gt;
  &lt;br /&gt;
  mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf~&lt;br /&gt;
  &lt;br /&gt;
  cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/dovecot/dovecot.conf&lt;br /&gt;
  listen = *&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  protocols = imap&lt;br /&gt;
  disable_plaintext_auth = no&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_location = mbox:~/mail:INBOX=/var/mail/%u&lt;br /&gt;
  userdb {&lt;br /&gt;
    driver = passwd&lt;br /&gt;
  }&lt;br /&gt;
  passdb {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    args = scheme=sha512-crypt username_format=%n /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl=yes&lt;br /&gt;
  ssl_cert=&amp;lt;/etc/ssl/dovecot/server.pem&lt;br /&gt;
  ssl_key=&amp;lt;/etc/ssl/dovecot/server.key&lt;br /&gt;
  EOF&lt;br /&gt;
  &lt;br /&gt;
  touch /etc/dovecot/passwd&lt;br /&gt;
  chown root:dovecot /etc/dovecot/passwd&lt;br /&gt;
  chmod 640 /etc/dovecot/passwd&lt;br /&gt;
  &lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
  &lt;br /&gt;
  echo &amp;quot;Create dovecot user passwords with: doveadm pw -s sha512-crypt&amp;quot;&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30950</id>
		<title>Small-Time Email with Exim and Dovecot</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30950"/>
		<updated>2025-09-21T15:50:06Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Configuring Dovecot */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want a super-simple SMTP / IMAP setup for a home server, this is the guide for you. This document covers the minimum steps to get email delivery up and running on a small home network. You&#039;re not going to want to use this for any serious enterprise stuff, but for a small home LAN it works well.&lt;br /&gt;
&lt;br /&gt;
== Why would anyone do this? ==&lt;br /&gt;
&lt;br /&gt;
My personal motivation for creating this small-time email setup was to deliver alerts from [https://mmonit.com/monit/ Monit] so I would know when my system needed attention. You can use it for this or similar minimalist email needs. Just don&#039;t do anything crazy like exposing it to the internet.&lt;br /&gt;
&lt;br /&gt;
== Why Exim and Dovecot? ==&lt;br /&gt;
&lt;br /&gt;
For an email server, Exim is easy to configure. Dovecot is a little more complex, but not insurmountable. Both are well documented.&lt;br /&gt;
&lt;br /&gt;
== Installing the Packages ==&lt;br /&gt;
The first step is to install Exim, Dovecot, and Mailx. (Mailx is used for testing.)&lt;br /&gt;
&lt;br /&gt;
  apk add {{pkg|exim|arch=}} {{pkg|dovecot|arch=}} {{pkg|mailx|arch=}}&lt;br /&gt;
&lt;br /&gt;
== Configuring Exim ==&lt;br /&gt;
&lt;br /&gt;
The next step is to get Exim working for delivering email to users on the system. This is a pretty simple configuration and there are only a few parameters to change in the delivered exim.conf file.&lt;br /&gt;
&lt;br /&gt;
# Make a backup of {{path|/etc/exim/exim.conf}}&lt;br /&gt;
# Open {{path|/etc/exim/exim.conf}} in your favorite text editor.&lt;br /&gt;
# Make the changes stated below and save.&lt;br /&gt;
&lt;br /&gt;
Find the lines that look like this:&lt;br /&gt;
&lt;br /&gt;
  # group = mail&lt;br /&gt;
  # mode = 0660&lt;br /&gt;
&lt;br /&gt;
They&#039;ll be under the heading of &amp;lt;code&amp;gt;local_delivery:&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you find them, remove the comment (hash symbol). The local_delivery section should now look like this:&lt;br /&gt;
&lt;br /&gt;
  local_delivery:&lt;br /&gt;
    driver = appendfile&lt;br /&gt;
    file = /var/mail/$local_part_data&lt;br /&gt;
    delivery_date_add&lt;br /&gt;
    envelope_to_add&lt;br /&gt;
    return_path_add&lt;br /&gt;
    group = mail&lt;br /&gt;
    mode = 0660&lt;br /&gt;
&lt;br /&gt;
The only thing changed is the removal of the hash symbol from the last two lines.&lt;br /&gt;
&lt;br /&gt;
== Fixing Ownership and Permissions on /var/mail ==&lt;br /&gt;
&lt;br /&gt;
As it stands, Exim will not be able to deliver messages to /var/mail, where the user mailboxes are stored. This is due to permissions.&lt;br /&gt;
&lt;br /&gt;
To fix it, run these two commands:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
&lt;br /&gt;
When you&#039;re done, verify it with &amp;lt;code&amp;gt;ls -ld /var/mail&amp;lt;/code&amp;gt;. It should look something like this:&lt;br /&gt;
&lt;br /&gt;
  $ ls -ld /var/mail/&lt;br /&gt;
  drwxrwsr-x    3 root     mail          4096 May 11 12:58 /var/mail/&lt;br /&gt;
&lt;br /&gt;
Setting the group ownership to &#039;&#039;mail&#039;&#039;, lets exim write to users&#039; mailboxes when new mail comes in.&lt;br /&gt;
&lt;br /&gt;
== Starting the Exim Service ==&lt;br /&gt;
&lt;br /&gt;
Start Exim and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service exim start&lt;br /&gt;
  rc-update add exim&lt;br /&gt;
&lt;br /&gt;
== Testing the Exim Setup ==&lt;br /&gt;
&lt;br /&gt;
Log in a a regular user and try sending a test email to yourself. You can do this with the mail command, like this:&lt;br /&gt;
&lt;br /&gt;
  mail -s Testing dave&lt;br /&gt;
  This is a test.&lt;br /&gt;
  .&lt;br /&gt;
&lt;br /&gt;
This sends a test message to the user dave. (Obviously, you&#039;ll want to replace dave with your username.) The final . on the last line is important. It tells the mail command the message is done.&lt;br /&gt;
&lt;br /&gt;
When the message is sent, check that you received it by running &amp;lt;code&amp;gt;mail&amp;lt;/code&amp;gt; with no command-line parameters. If everything went well, it should look like the example below.&lt;br /&gt;
&lt;br /&gt;
  $ mail&lt;br /&gt;
  Mail version 8.1 6/6/93.  Type ? for help.&lt;br /&gt;
  &amp;quot;/var/mail/dave&amp;quot;: 1 messages&lt;br /&gt;
  &amp;gt;   1 dave@myserver.home      Wed May 11 03:51  27/847   &amp;quot;Testing&amp;quot;&lt;br /&gt;
  &amp;amp;&lt;br /&gt;
&lt;br /&gt;
You can type the message number (1) to display the contents of the mail and then type q to quit the mail program.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting Mail Delivery ==&lt;br /&gt;
&lt;br /&gt;
If the mail test fails, look in the directory {{path|/var/spool/exim/msglog}}. If there are files there, they are stuck messages. The files are plain text. Display the contents to show any error messages. In most cases, the problem will be related to permissions on the {{path|/var/mail}} directory or the mailbox files within the directory.&lt;br /&gt;
&lt;br /&gt;
The directory permissions should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -ld /var/mail&lt;br /&gt;
  drwxrwsr-x    3 root     mail&lt;br /&gt;
&lt;br /&gt;
The permissions on mailbox files inside should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -l&lt;br /&gt;
  -rw-rw----    1 dave     mail&lt;br /&gt;
&lt;br /&gt;
== Configuring Dovecot ==&lt;br /&gt;
&lt;br /&gt;
If everything is working with local delivery, it&#039;s time to set up IMAP using Dovecot.&lt;br /&gt;
&lt;br /&gt;
{{Note| The example configuration below is for Dovecot version 2.3 used in Alpine Linux 3.21 and earlier. It is not compatible with dovecot 2.4 used in Alpine 3.22.}}&lt;br /&gt;
&lt;br /&gt;
The Dovecot package for Alpine comes with twenty configuration files in {{path|/etc/dovecot/conf.d}}. As a small-time email admin, you may feel overwhelmed. Don&#039;t worry, everything can be condensed down to a single config file of sixteen lines.&lt;br /&gt;
&lt;br /&gt;
First, make a backup copy of {{path|/etc/dovecot/dovecot.conf}}.&lt;br /&gt;
&lt;br /&gt;
Next, create a new dovecot.conf that looks like this:&lt;br /&gt;
&lt;br /&gt;
 listen = *&lt;br /&gt;
 log_path = /var/log/dovecot.log&lt;br /&gt;
 protocols = imap&lt;br /&gt;
 disable_plaintext_auth = no&lt;br /&gt;
 mail_privileged_group = mail&lt;br /&gt;
 mail_location = mbox:~/mail:INBOX=/var/mail/%u&lt;br /&gt;
 userdb {&lt;br /&gt;
   driver = passwd&lt;br /&gt;
 }&lt;br /&gt;
 passdb {&lt;br /&gt;
   driver = ldap&lt;br /&gt;
   args = /etc/dovecot/ldap-auth.ext&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
 ssl=yes&lt;br /&gt;
 ssl_cert=&amp;lt;/etc/ssl/dovecot/server.pem&lt;br /&gt;
 ssl_key=&amp;lt;/etc/ssl/dovecot/server.key&lt;br /&gt;
&lt;br /&gt;
This config does not have the &amp;lt;code&amp;gt;!include conf.d/*.conf&amp;lt;/code&amp;gt; that was in the original dovecot.conf, so those twenty files in conf.d are going to be ignored. Everything is now in this single dovecot.conf.&lt;br /&gt;
&lt;br /&gt;
== Starting the Dovecot Service ==&lt;br /&gt;
&lt;br /&gt;
Start Dovecot and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Credentials for Dovecot Users ==&lt;br /&gt;
&lt;br /&gt;
As it is configured, Dovecot will use {{path|/etc/passwd}} for looking up user information, but not authentication. Technically, {{path|/etc/passwd}} authentication can be done using Pluggable Authentication Modules (PAM), but PAM is not part of the base install of Alpine Linux. The next best thing is to use a separate password file for Dovecot credentials and to use the same SHA512-Crypt hashing algorithm used in {{path|/etc/passwd}}.&lt;br /&gt;
&lt;br /&gt;
The Dovecot configuration above specifies a password file of {{path|/etc/dovecot/passwd}}. The Dovecot password file looks like this:&lt;br /&gt;
&lt;br /&gt;
  dave:{SHA512-CRYPT}$6$mQ1rxB0gZHqg8Tg9$nxZ8odJZ6xVpmOVpsnYfAo1i7SuoLDhsvoykieukWF9NyNBq.WwhDA7udcYxP1iEm/IzlBmnwz6/vOO3SX8gA.&lt;br /&gt;
&lt;br /&gt;
There are two fields, username and password, separated by a colon. Notice the {SHA512-CRYPT} prefix to the password. This indicates the hashing algorithm.&lt;br /&gt;
&lt;br /&gt;
You can create passwords with the &amp;lt;code&amp;gt;doveadm&amp;lt;/code&amp;gt; command, like this:&lt;br /&gt;
&lt;br /&gt;
  # doveadm pw -s sha512-crypt&lt;br /&gt;
  Enter new password:&lt;br /&gt;
  Retype new password:&lt;br /&gt;
&lt;br /&gt;
The command will output the hashed password. You&#039;ll need to edit Dovecot&#039;s password file with a text editor and create the username/password pair by hand.&lt;br /&gt;
&lt;br /&gt;
The permissions on the Dovecot password file should be such that dovecot can read it, but not write to it. Only root should be able to write it.&lt;br /&gt;
&lt;br /&gt;
  ls -l /etc/dovecot/passwd&lt;br /&gt;
  -rw-r-----    1 root     dovecot&lt;br /&gt;
&lt;br /&gt;
== Testing the Dovecot Setup ==&lt;br /&gt;
&lt;br /&gt;
To test IMAP, you&#039;ll need an email client. Personally, I&#039;ve used [https://www.thunderbird.net Thunderbird] on Windows and [https://k9mail.app/ K-9 Mail] on Android. The trickiest part is getting the email client to trust the self-signed certificates. Configuring email clients is beyond the scope of this document.&lt;br /&gt;
&lt;br /&gt;
From the server side, the Dovecot log file can help you diagnose errors. The dovecot.conf file specifies the location of the log file.&lt;br /&gt;
&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
&lt;br /&gt;
One of the common errors I&#039;ve seen looks like this:&lt;br /&gt;
&lt;br /&gt;
  Disconnected: TLS initialization failed.&lt;br /&gt;
  Error: Failed to initialize SSL server context: Can&#039;t load SSL certificate&lt;br /&gt;
&lt;br /&gt;
This was the result of a typographical error I made in the Dovecot config file.&lt;br /&gt;
&lt;br /&gt;
You can further simplify things by commenting out the ssl lines in the dovecot.conf so it looks like this:&lt;br /&gt;
&lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  #ssl=yes&lt;br /&gt;
  #ssl_server_cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
  #ssl_server_key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
&lt;br /&gt;
Now TLS is out of the picture, letting you diagnose other potential problems. However, you may have to do some work to convince your mail client that sending login credentials in cleartext is okay. Only do this on a network where you trust your users!&lt;br /&gt;
&lt;br /&gt;
== Using and Enjoying Your Small-Time Email Setup ==&lt;br /&gt;
&lt;br /&gt;
Now that everything is setup, you can start sending yourself cat pictures or you can configure other programs to use the email system to send notifications. For example, I use [https://mmonit.com/monit/ Monit] to keep an eye on services and file system space. When Monit detects a problem, it sends me an email.&lt;br /&gt;
&lt;br /&gt;
The setup presented in this guide uses port 25 for SMTP and port 143 for IMAP. There are no dedicated TLS ports. Encryption is done using STARTTLS.&lt;br /&gt;
&lt;br /&gt;
== A Word About Aliases ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve ever used {{path|/etc/aliases}} for mail delivery, you should be aware that Exim puts this file in {{path|/etc/mail/aliases}}. The format is the same as Sendmail.&lt;br /&gt;
&lt;br /&gt;
== Scripted Installation and Configuration ==&lt;br /&gt;
&lt;br /&gt;
If you like living dangerously (or if you have a test system you don&#039;t care about) you can do all of the server configuration presented above with a single script, as shown below:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
  &lt;br /&gt;
  apk add exim mailx&lt;br /&gt;
  &lt;br /&gt;
  sed -i~ \&lt;br /&gt;
    -e &#039;s/# group = mail/  group = mail/&#039; \&lt;br /&gt;
    -e &#039;s/# mode = 0660/  mode = 0660/&#039; \&lt;br /&gt;
    /etc/exim/exim.conf&lt;br /&gt;
  &lt;br /&gt;
  ln -s mail/aliases /etc/aliases&lt;br /&gt;
  &lt;br /&gt;
  rc-update add exim&lt;br /&gt;
  service exim start&lt;br /&gt;
  &lt;br /&gt;
  apk add dovecot&lt;br /&gt;
  &lt;br /&gt;
  mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf~&lt;br /&gt;
  &lt;br /&gt;
  cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/dovecot/dovecot.conf&lt;br /&gt;
  listen = *&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  protocols = imap&lt;br /&gt;
  disable_plaintext_auth = no&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_location = mbox:~/mail:INBOX=/var/mail/%u&lt;br /&gt;
  userdb {&lt;br /&gt;
    driver = passwd&lt;br /&gt;
  }&lt;br /&gt;
  passdb {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    args = scheme=sha512-crypt username_format=%n /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl=yes&lt;br /&gt;
  ssl_cert=&amp;lt;/etc/ssl/dovecot/server.pem&lt;br /&gt;
  ssl_key=&amp;lt;/etc/ssl/dovecot/server.key&lt;br /&gt;
  EOF&lt;br /&gt;
  &lt;br /&gt;
  touch /etc/dovecot/passwd&lt;br /&gt;
  chown root:dovecot /etc/dovecot/passwd&lt;br /&gt;
  chmod 640 /etc/dovecot/passwd&lt;br /&gt;
  &lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
  &lt;br /&gt;
  echo &amp;quot;Create dovecot user passwords with: doveadm pw -s sha512-crypt&amp;quot;&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30949</id>
		<title>Small-Time Email with Exim and Dovecot</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30949"/>
		<updated>2025-09-21T15:11:27Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Configuring Dovecot */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want a super-simple SMTP / IMAP setup for a home server, this is the guide for you. This document covers the minimum steps to get email delivery up and running on a small home network. You&#039;re not going to want to use this for any serious enterprise stuff, but for a small home LAN it works well.&lt;br /&gt;
&lt;br /&gt;
== Why would anyone do this? ==&lt;br /&gt;
&lt;br /&gt;
My personal motivation for creating this small-time email setup was to deliver alerts from [https://mmonit.com/monit/ Monit] so I would know when my system needed attention. You can use it for this or similar minimalist email needs. Just don&#039;t do anything crazy like exposing it to the internet.&lt;br /&gt;
&lt;br /&gt;
== Why Exim and Dovecot? ==&lt;br /&gt;
&lt;br /&gt;
For an email server, Exim is easy to configure. Dovecot is a little more complex, but not insurmountable. Both are well documented.&lt;br /&gt;
&lt;br /&gt;
== Installing the Packages ==&lt;br /&gt;
The first step is to install Exim, Dovecot, and Mailx. (Mailx is used for testing.)&lt;br /&gt;
&lt;br /&gt;
  apk add {{pkg|exim|arch=}} {{pkg|dovecot|arch=}} {{pkg|mailx|arch=}}&lt;br /&gt;
&lt;br /&gt;
== Configuring Exim ==&lt;br /&gt;
&lt;br /&gt;
The next step is to get Exim working for delivering email to users on the system. This is a pretty simple configuration and there are only a few parameters to change in the delivered exim.conf file.&lt;br /&gt;
&lt;br /&gt;
# Make a backup of {{path|/etc/exim/exim.conf}}&lt;br /&gt;
# Open {{path|/etc/exim/exim.conf}} in your favorite text editor.&lt;br /&gt;
# Make the changes stated below and save.&lt;br /&gt;
&lt;br /&gt;
Find the lines that look like this:&lt;br /&gt;
&lt;br /&gt;
  # group = mail&lt;br /&gt;
  # mode = 0660&lt;br /&gt;
&lt;br /&gt;
They&#039;ll be under the heading of &amp;lt;code&amp;gt;local_delivery:&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you find them, remove the comment (hash symbol). The local_delivery section should now look like this:&lt;br /&gt;
&lt;br /&gt;
  local_delivery:&lt;br /&gt;
    driver = appendfile&lt;br /&gt;
    file = /var/mail/$local_part_data&lt;br /&gt;
    delivery_date_add&lt;br /&gt;
    envelope_to_add&lt;br /&gt;
    return_path_add&lt;br /&gt;
    group = mail&lt;br /&gt;
    mode = 0660&lt;br /&gt;
&lt;br /&gt;
The only thing changed is the removal of the hash symbol from the last two lines.&lt;br /&gt;
&lt;br /&gt;
== Fixing Ownership and Permissions on /var/mail ==&lt;br /&gt;
&lt;br /&gt;
As it stands, Exim will not be able to deliver messages to /var/mail, where the user mailboxes are stored. This is due to permissions.&lt;br /&gt;
&lt;br /&gt;
To fix it, run these two commands:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
&lt;br /&gt;
When you&#039;re done, verify it with &amp;lt;code&amp;gt;ls -ld /var/mail&amp;lt;/code&amp;gt;. It should look something like this:&lt;br /&gt;
&lt;br /&gt;
  $ ls -ld /var/mail/&lt;br /&gt;
  drwxrwsr-x    3 root     mail          4096 May 11 12:58 /var/mail/&lt;br /&gt;
&lt;br /&gt;
Setting the group ownership to &#039;&#039;mail&#039;&#039;, lets exim write to users&#039; mailboxes when new mail comes in.&lt;br /&gt;
&lt;br /&gt;
== Starting the Exim Service ==&lt;br /&gt;
&lt;br /&gt;
Start Exim and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service exim start&lt;br /&gt;
  rc-update add exim&lt;br /&gt;
&lt;br /&gt;
== Testing the Exim Setup ==&lt;br /&gt;
&lt;br /&gt;
Log in a a regular user and try sending a test email to yourself. You can do this with the mail command, like this:&lt;br /&gt;
&lt;br /&gt;
  mail -s Testing dave&lt;br /&gt;
  This is a test.&lt;br /&gt;
  .&lt;br /&gt;
&lt;br /&gt;
This sends a test message to the user dave. (Obviously, you&#039;ll want to replace dave with your username.) The final . on the last line is important. It tells the mail command the message is done.&lt;br /&gt;
&lt;br /&gt;
When the message is sent, check that you received it by running &amp;lt;code&amp;gt;mail&amp;lt;/code&amp;gt; with no command-line parameters. If everything went well, it should look like the example below.&lt;br /&gt;
&lt;br /&gt;
  $ mail&lt;br /&gt;
  Mail version 8.1 6/6/93.  Type ? for help.&lt;br /&gt;
  &amp;quot;/var/mail/dave&amp;quot;: 1 messages&lt;br /&gt;
  &amp;gt;   1 dave@myserver.home      Wed May 11 03:51  27/847   &amp;quot;Testing&amp;quot;&lt;br /&gt;
  &amp;amp;&lt;br /&gt;
&lt;br /&gt;
You can type the message number (1) to display the contents of the mail and then type q to quit the mail program.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting Mail Delivery ==&lt;br /&gt;
&lt;br /&gt;
If the mail test fails, look in the directory {{path|/var/spool/exim/msglog}}. If there are files there, they are stuck messages. The files are plain text. Display the contents to show any error messages. In most cases, the problem will be related to permissions on the {{path|/var/mail}} directory or the mailbox files within the directory.&lt;br /&gt;
&lt;br /&gt;
The directory permissions should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -ld /var/mail&lt;br /&gt;
  drwxrwsr-x    3 root     mail&lt;br /&gt;
&lt;br /&gt;
The permissions on mailbox files inside should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -l&lt;br /&gt;
  -rw-rw----    1 dave     mail&lt;br /&gt;
&lt;br /&gt;
== Configuring Dovecot ==&lt;br /&gt;
&lt;br /&gt;
If everything is working with local delivery, it&#039;s time to set up IMAP using Dovecot.&lt;br /&gt;
&lt;br /&gt;
{{Note| The example configuration below is for Dovecot version 2.4 used in Alpine Linux 3.22 and later. It is not compatible with older versions.}}&lt;br /&gt;
&lt;br /&gt;
The Dovecot package for Alpine comes with twenty configuration files in {{path|/etc/dovecot/conf.d}}. As a small-time email admin, you may feel overwhelmed. Don&#039;t worry, everything can be condensed down to a single config file of sixteen lines.&lt;br /&gt;
&lt;br /&gt;
First, make a backup copy of {{path|/etc/dovecot/dovecot.conf}}.&lt;br /&gt;
&lt;br /&gt;
Next, create a new dovecot.conf that looks like this:&lt;br /&gt;
&lt;br /&gt;
 dovecot_config_version = 2.4.0&lt;br /&gt;
 dovecot_storage_version = 2.4.0&lt;br /&gt;
 listen = *&lt;br /&gt;
 log_path = /var/log/dovecot.log&lt;br /&gt;
 protocols = imap&lt;br /&gt;
 auth_allow_cleartext = yes&lt;br /&gt;
 mail_privileged_group = mail&lt;br /&gt;
 mail_driver = maildir&lt;br /&gt;
 mail_path = ~/mail&lt;br /&gt;
 mail_inbox_path = /var/mail/%u&lt;br /&gt;
 first_valid_uid = 8&lt;br /&gt;
 mail_uid = mail&lt;br /&gt;
 mail_gid = mail&lt;br /&gt;
 userdb passwd {&lt;br /&gt;
   driver = passwd-file&lt;br /&gt;
   passwd_file_path = /etc/dovecot/passwd&lt;br /&gt;
 }&lt;br /&gt;
 # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
 ssl=yes&lt;br /&gt;
 ssl_server_cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
 ssl_server_key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
&lt;br /&gt;
This config does not have the &amp;lt;code&amp;gt;!include conf.d/*.conf&amp;lt;/code&amp;gt; that was in the original dovecot.conf, so those twenty files in conf.d are going to be ignored. Everything is now in this single dovecot.conf.&lt;br /&gt;
&lt;br /&gt;
== Starting the Dovecot Service ==&lt;br /&gt;
&lt;br /&gt;
Start Dovecot and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Credentials for Dovecot Users ==&lt;br /&gt;
&lt;br /&gt;
As it is configured, Dovecot will use {{path|/etc/passwd}} for looking up user information, but not authentication. Technically, {{path|/etc/passwd}} authentication can be done using Pluggable Authentication Modules (PAM), but PAM is not part of the base install of Alpine Linux. The next best thing is to use a separate password file for Dovecot credentials and to use the same SHA512-Crypt hashing algorithm used in {{path|/etc/passwd}}.&lt;br /&gt;
&lt;br /&gt;
The Dovecot configuration above specifies a password file of {{path|/etc/dovecot/passwd}}. The Dovecot password file looks like this:&lt;br /&gt;
&lt;br /&gt;
  dave:{SHA512-CRYPT}$6$mQ1rxB0gZHqg8Tg9$nxZ8odJZ6xVpmOVpsnYfAo1i7SuoLDhsvoykieukWF9NyNBq.WwhDA7udcYxP1iEm/IzlBmnwz6/vOO3SX8gA.&lt;br /&gt;
&lt;br /&gt;
There are two fields, username and password, separated by a colon. Notice the {SHA512-CRYPT} prefix to the password. This indicates the hashing algorithm.&lt;br /&gt;
&lt;br /&gt;
You can create passwords with the &amp;lt;code&amp;gt;doveadm&amp;lt;/code&amp;gt; command, like this:&lt;br /&gt;
&lt;br /&gt;
  # doveadm pw -s sha512-crypt&lt;br /&gt;
  Enter new password:&lt;br /&gt;
  Retype new password:&lt;br /&gt;
&lt;br /&gt;
The command will output the hashed password. You&#039;ll need to edit Dovecot&#039;s password file with a text editor and create the username/password pair by hand.&lt;br /&gt;
&lt;br /&gt;
The permissions on the Dovecot password file should be such that dovecot can read it, but not write to it. Only root should be able to write it.&lt;br /&gt;
&lt;br /&gt;
  ls -l /etc/dovecot/passwd&lt;br /&gt;
  -rw-r-----    1 root     dovecot&lt;br /&gt;
&lt;br /&gt;
== Testing the Dovecot Setup ==&lt;br /&gt;
&lt;br /&gt;
To test IMAP, you&#039;ll need an email client. Personally, I&#039;ve used [https://www.thunderbird.net Thunderbird] on Windows and [https://k9mail.app/ K-9 Mail] on Android. The trickiest part is getting the email client to trust the self-signed certificates. Configuring email clients is beyond the scope of this document.&lt;br /&gt;
&lt;br /&gt;
From the server side, the Dovecot log file can help you diagnose errors. The dovecot.conf file specifies the location of the log file.&lt;br /&gt;
&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
&lt;br /&gt;
One of the common errors I&#039;ve seen looks like this:&lt;br /&gt;
&lt;br /&gt;
  Disconnected: TLS initialization failed.&lt;br /&gt;
  Error: Failed to initialize SSL server context: Can&#039;t load SSL certificate&lt;br /&gt;
&lt;br /&gt;
This was the result of a typographical error I made in the Dovecot config file.&lt;br /&gt;
&lt;br /&gt;
You can further simplify things by commenting out the ssl lines in the dovecot.conf so it looks like this:&lt;br /&gt;
&lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  #ssl=yes&lt;br /&gt;
  #ssl_server_cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
  #ssl_server_key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
&lt;br /&gt;
Now TLS is out of the picture, letting you diagnose other potential problems. However, you may have to do some work to convince your mail client that sending login credentials in cleartext is okay. Only do this on a network where you trust your users!&lt;br /&gt;
&lt;br /&gt;
== Using and Enjoying Your Small-Time Email Setup ==&lt;br /&gt;
&lt;br /&gt;
Now that everything is setup, you can start sending yourself cat pictures or you can configure other programs to use the email system to send notifications. For example, I use [https://mmonit.com/monit/ Monit] to keep an eye on services and file system space. When Monit detects a problem, it sends me an email.&lt;br /&gt;
&lt;br /&gt;
The setup presented in this guide uses port 25 for SMTP and port 143 for IMAP. There are no dedicated TLS ports. Encryption is done using STARTTLS.&lt;br /&gt;
&lt;br /&gt;
== A Word About Aliases ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve ever used {{path|/etc/aliases}} for mail delivery, you should be aware that Exim puts this file in {{path|/etc/mail/aliases}}. The format is the same as Sendmail.&lt;br /&gt;
&lt;br /&gt;
== Scripted Installation and Configuration ==&lt;br /&gt;
&lt;br /&gt;
If you like living dangerously (or if you have a test system you don&#039;t care about) you can do all of the server configuration presented above with a single script, as shown below:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
  &lt;br /&gt;
  apk add exim mailx&lt;br /&gt;
  &lt;br /&gt;
  sed -i~ \&lt;br /&gt;
    -e &#039;s/# group = mail/  group = mail/&#039; \&lt;br /&gt;
    -e &#039;s/# mode = 0660/  mode = 0660/&#039; \&lt;br /&gt;
    /etc/exim/exim.conf&lt;br /&gt;
  &lt;br /&gt;
  ln -s mail/aliases /etc/aliases&lt;br /&gt;
  &lt;br /&gt;
  rc-update add exim&lt;br /&gt;
  service exim start&lt;br /&gt;
  &lt;br /&gt;
  apk add dovecot&lt;br /&gt;
  &lt;br /&gt;
  mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf~&lt;br /&gt;
  &lt;br /&gt;
  cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/dovecot/dovecot.conf&lt;br /&gt;
  listen = *&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  protocols = imap&lt;br /&gt;
  disable_plaintext_auth = no&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_location = mbox:~/mail:INBOX=/var/mail/%u&lt;br /&gt;
  userdb {&lt;br /&gt;
    driver = passwd&lt;br /&gt;
  }&lt;br /&gt;
  passdb {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    args = scheme=sha512-crypt username_format=%n /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl=yes&lt;br /&gt;
  ssl_cert=&amp;lt;/etc/ssl/dovecot/server.pem&lt;br /&gt;
  ssl_key=&amp;lt;/etc/ssl/dovecot/server.key&lt;br /&gt;
  EOF&lt;br /&gt;
  &lt;br /&gt;
  touch /etc/dovecot/passwd&lt;br /&gt;
  chown root:dovecot /etc/dovecot/passwd&lt;br /&gt;
  chmod 640 /etc/dovecot/passwd&lt;br /&gt;
  &lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
  &lt;br /&gt;
  echo &amp;quot;Create dovecot user passwords with: doveadm pw -s sha512-crypt&amp;quot;&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30947</id>
		<title>Small-Time Email with Exim and Dovecot</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30947"/>
		<updated>2025-09-21T14:31:05Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Testing the Dovecot Setup */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want a super-simple SMTP / IMAP setup for a home server, this is the guide for you. This document covers the minimum steps to get email delivery up and running on a small home network. You&#039;re not going to want to use this for any serious enterprise stuff, but for a small home LAN it works well.&lt;br /&gt;
&lt;br /&gt;
== Why would anyone do this? ==&lt;br /&gt;
&lt;br /&gt;
My personal motivation for creating this small-time email setup was to deliver alerts from [https://mmonit.com/monit/ Monit] so I would know when my system needed attention. You can use it for this or similar minimalist email needs. Just don&#039;t do anything crazy like exposing it to the internet.&lt;br /&gt;
&lt;br /&gt;
== Why Exim and Dovecot? ==&lt;br /&gt;
&lt;br /&gt;
For an email server, Exim is easy to configure. Dovecot is a little more complex, but not insurmountable. Both are well documented.&lt;br /&gt;
&lt;br /&gt;
== Installing the Packages ==&lt;br /&gt;
The first step is to install Exim, Dovecot, and Mailx. (Mailx is used for testing.)&lt;br /&gt;
&lt;br /&gt;
  apk add {{pkg|exim|arch=}} {{pkg|dovecot|arch=}} {{pkg|mailx|arch=}}&lt;br /&gt;
&lt;br /&gt;
== Configuring Exim ==&lt;br /&gt;
&lt;br /&gt;
The next step is to get Exim working for delivering email to users on the system. This is a pretty simple configuration and there are only a few parameters to change in the delivered exim.conf file.&lt;br /&gt;
&lt;br /&gt;
# Make a backup of {{path|/etc/exim/exim.conf}}&lt;br /&gt;
# Open {{path|/etc/exim/exim.conf}} in your favorite text editor.&lt;br /&gt;
# Make the changes stated below and save.&lt;br /&gt;
&lt;br /&gt;
Find the lines that look like this:&lt;br /&gt;
&lt;br /&gt;
  # group = mail&lt;br /&gt;
  # mode = 0660&lt;br /&gt;
&lt;br /&gt;
They&#039;ll be under the heading of &amp;lt;code&amp;gt;local_delivery:&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you find them, remove the comment (hash symbol). The local_delivery section should now look like this:&lt;br /&gt;
&lt;br /&gt;
  local_delivery:&lt;br /&gt;
    driver = appendfile&lt;br /&gt;
    file = /var/mail/$local_part_data&lt;br /&gt;
    delivery_date_add&lt;br /&gt;
    envelope_to_add&lt;br /&gt;
    return_path_add&lt;br /&gt;
    group = mail&lt;br /&gt;
    mode = 0660&lt;br /&gt;
&lt;br /&gt;
The only thing changed is the removal of the hash symbol from the last two lines.&lt;br /&gt;
&lt;br /&gt;
== Fixing Ownership and Permissions on /var/mail ==&lt;br /&gt;
&lt;br /&gt;
As it stands, Exim will not be able to deliver messages to /var/mail, where the user mailboxes are stored. This is due to permissions.&lt;br /&gt;
&lt;br /&gt;
To fix it, run these two commands:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
&lt;br /&gt;
When you&#039;re done, verify it with &amp;lt;code&amp;gt;ls -ld /var/mail&amp;lt;/code&amp;gt;. It should look something like this:&lt;br /&gt;
&lt;br /&gt;
  $ ls -ld /var/mail/&lt;br /&gt;
  drwxrwsr-x    3 root     mail          4096 May 11 12:58 /var/mail/&lt;br /&gt;
&lt;br /&gt;
Setting the group ownership to &#039;&#039;mail&#039;&#039;, lets exim write to users&#039; mailboxes when new mail comes in.&lt;br /&gt;
&lt;br /&gt;
== Starting the Exim Service ==&lt;br /&gt;
&lt;br /&gt;
Start Exim and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service exim start&lt;br /&gt;
  rc-update add exim&lt;br /&gt;
&lt;br /&gt;
== Testing the Exim Setup ==&lt;br /&gt;
&lt;br /&gt;
Log in a a regular user and try sending a test email to yourself. You can do this with the mail command, like this:&lt;br /&gt;
&lt;br /&gt;
  mail -s Testing dave&lt;br /&gt;
  This is a test.&lt;br /&gt;
  .&lt;br /&gt;
&lt;br /&gt;
This sends a test message to the user dave. (Obviously, you&#039;ll want to replace dave with your username.) The final . on the last line is important. It tells the mail command the message is done.&lt;br /&gt;
&lt;br /&gt;
When the message is sent, check that you received it by running &amp;lt;code&amp;gt;mail&amp;lt;/code&amp;gt; with no command-line parameters. If everything went well, it should look like the example below.&lt;br /&gt;
&lt;br /&gt;
  $ mail&lt;br /&gt;
  Mail version 8.1 6/6/93.  Type ? for help.&lt;br /&gt;
  &amp;quot;/var/mail/dave&amp;quot;: 1 messages&lt;br /&gt;
  &amp;gt;   1 dave@myserver.home      Wed May 11 03:51  27/847   &amp;quot;Testing&amp;quot;&lt;br /&gt;
  &amp;amp;&lt;br /&gt;
&lt;br /&gt;
You can type the message number (1) to display the contents of the mail and then type q to quit the mail program.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting Mail Delivery ==&lt;br /&gt;
&lt;br /&gt;
If the mail test fails, look in the directory {{path|/var/spool/exim/msglog}}. If there are files there, they are stuck messages. The files are plain text. Display the contents to show any error messages. In most cases, the problem will be related to permissions on the {{path|/var/mail}} directory or the mailbox files within the directory.&lt;br /&gt;
&lt;br /&gt;
The directory permissions should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -ld /var/mail&lt;br /&gt;
  drwxrwsr-x    3 root     mail&lt;br /&gt;
&lt;br /&gt;
The permissions on mailbox files inside should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -l&lt;br /&gt;
  -rw-rw----    1 dave     mail&lt;br /&gt;
&lt;br /&gt;
== Configuring Dovecot ==&lt;br /&gt;
&lt;br /&gt;
If everything is working with local delivery, it&#039;s time to set up IMAP using Dovecot.&lt;br /&gt;
&lt;br /&gt;
{{Note| The example configuration below is for Dovecot version 2.4 used in Alpine Linux 3.22 and later. It is not compatible with older versions.}}&lt;br /&gt;
&lt;br /&gt;
The Dovecot package for Alpine comes with twenty configuration files in {{path|/etc/dovecot/conf.d}}. As a small-time email admin, you may feel overwhelmed. Don&#039;t worry, everything can be condensed down to a single config file of sixteen lines.&lt;br /&gt;
&lt;br /&gt;
First, make a backup copy of {{path|/etc/dovecot/dovecot.conf}}.&lt;br /&gt;
&lt;br /&gt;
Next, create a new dovecot.conf that looks like this:&lt;br /&gt;
&lt;br /&gt;
 dovecot_config_version = 2.4.0&lt;br /&gt;
 dovecot_storage_version = 2.4.0&lt;br /&gt;
 listen = *&lt;br /&gt;
 log_path = /var/log/dovecot.log&lt;br /&gt;
 protocols = imap&lt;br /&gt;
 auth_allow_cleartext = yes&lt;br /&gt;
 mail_privileged_group = mail&lt;br /&gt;
 mail_driver = maildir&lt;br /&gt;
 mail_path = ~/mail&lt;br /&gt;
 mail_inbox_path = /var/mail/%u&lt;br /&gt;
 userdb passwd {&lt;br /&gt;
   driver = passwd-file&lt;br /&gt;
   passwd_file_path = /etc/dovecot/passwd&lt;br /&gt;
 }&lt;br /&gt;
 # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
 ssl=yes&lt;br /&gt;
 ssl_server_cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
 ssl_server_key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
&lt;br /&gt;
This config does not have the &amp;lt;code&amp;gt;!include conf.d/*.conf&amp;lt;/code&amp;gt; that was in the original dovecot.conf, so those twenty files in conf.d are going to be ignored. Everything is now in this single dovecot.conf.&lt;br /&gt;
&lt;br /&gt;
== Starting the Dovecot Service ==&lt;br /&gt;
&lt;br /&gt;
Start Dovecot and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Credentials for Dovecot Users ==&lt;br /&gt;
&lt;br /&gt;
As it is configured, Dovecot will use {{path|/etc/passwd}} for looking up user information, but not authentication. Technically, {{path|/etc/passwd}} authentication can be done using Pluggable Authentication Modules (PAM), but PAM is not part of the base install of Alpine Linux. The next best thing is to use a separate password file for Dovecot credentials and to use the same SHA512-Crypt hashing algorithm used in {{path|/etc/passwd}}.&lt;br /&gt;
&lt;br /&gt;
The Dovecot configuration above specifies a password file of {{path|/etc/dovecot/passwd}}. The Dovecot password file looks like this:&lt;br /&gt;
&lt;br /&gt;
  dave:{SHA512-CRYPT}$6$mQ1rxB0gZHqg8Tg9$nxZ8odJZ6xVpmOVpsnYfAo1i7SuoLDhsvoykieukWF9NyNBq.WwhDA7udcYxP1iEm/IzlBmnwz6/vOO3SX8gA.&lt;br /&gt;
&lt;br /&gt;
There are two fields, username and password, separated by a colon. Notice the {SHA512-CRYPT} prefix to the password. This indicates the hashing algorithm.&lt;br /&gt;
&lt;br /&gt;
You can create passwords with the &amp;lt;code&amp;gt;doveadm&amp;lt;/code&amp;gt; command, like this:&lt;br /&gt;
&lt;br /&gt;
  # doveadm pw -s sha512-crypt&lt;br /&gt;
  Enter new password:&lt;br /&gt;
  Retype new password:&lt;br /&gt;
&lt;br /&gt;
The command will output the hashed password. You&#039;ll need to edit Dovecot&#039;s password file with a text editor and create the username/password pair by hand.&lt;br /&gt;
&lt;br /&gt;
The permissions on the Dovecot password file should be such that dovecot can read it, but not write to it. Only root should be able to write it.&lt;br /&gt;
&lt;br /&gt;
  ls -l /etc/dovecot/passwd&lt;br /&gt;
  -rw-r-----    1 root     dovecot&lt;br /&gt;
&lt;br /&gt;
== Testing the Dovecot Setup ==&lt;br /&gt;
&lt;br /&gt;
To test IMAP, you&#039;ll need an email client. Personally, I&#039;ve used [https://www.thunderbird.net Thunderbird] on Windows and [https://k9mail.app/ K-9 Mail] on Android. The trickiest part is getting the email client to trust the self-signed certificates. Configuring email clients is beyond the scope of this document.&lt;br /&gt;
&lt;br /&gt;
From the server side, the Dovecot log file can help you diagnose errors. The dovecot.conf file specifies the location of the log file.&lt;br /&gt;
&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
&lt;br /&gt;
One of the common errors I&#039;ve seen looks like this:&lt;br /&gt;
&lt;br /&gt;
  Disconnected: TLS initialization failed.&lt;br /&gt;
  Error: Failed to initialize SSL server context: Can&#039;t load SSL certificate&lt;br /&gt;
&lt;br /&gt;
This was the result of a typographical error I made in the Dovecot config file.&lt;br /&gt;
&lt;br /&gt;
You can further simplify things by commenting out the ssl lines in the dovecot.conf so it looks like this:&lt;br /&gt;
&lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  #ssl=yes&lt;br /&gt;
  #ssl_server_cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
  #ssl_server_key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
&lt;br /&gt;
Now TLS is out of the picture, letting you diagnose other potential problems. However, you may have to do some work to convince your mail client that sending login credentials in cleartext is okay. Only do this on a network where you trust your users!&lt;br /&gt;
&lt;br /&gt;
== Using and Enjoying Your Small-Time Email Setup ==&lt;br /&gt;
&lt;br /&gt;
Now that everything is setup, you can start sending yourself cat pictures or you can configure other programs to use the email system to send notifications. For example, I use [https://mmonit.com/monit/ Monit] to keep an eye on services and file system space. When Monit detects a problem, it sends me an email.&lt;br /&gt;
&lt;br /&gt;
The setup presented in this guide uses port 25 for SMTP and port 143 for IMAP. There are no dedicated TLS ports. Encryption is done using STARTTLS.&lt;br /&gt;
&lt;br /&gt;
== A Word About Aliases ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve ever used {{path|/etc/aliases}} for mail delivery, you should be aware that Exim puts this file in {{path|/etc/mail/aliases}}. The format is the same as Sendmail.&lt;br /&gt;
&lt;br /&gt;
== Scripted Installation and Configuration ==&lt;br /&gt;
&lt;br /&gt;
If you like living dangerously (or if you have a test system you don&#039;t care about) you can do all of the server configuration presented above with a single script, as shown below:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
  &lt;br /&gt;
  apk add exim mailx&lt;br /&gt;
  &lt;br /&gt;
  sed -i~ \&lt;br /&gt;
    -e &#039;s/# group = mail/  group = mail/&#039; \&lt;br /&gt;
    -e &#039;s/# mode = 0660/  mode = 0660/&#039; \&lt;br /&gt;
    /etc/exim/exim.conf&lt;br /&gt;
  &lt;br /&gt;
  ln -s mail/aliases /etc/aliases&lt;br /&gt;
  &lt;br /&gt;
  rc-update add exim&lt;br /&gt;
  service exim start&lt;br /&gt;
  &lt;br /&gt;
  apk add dovecot&lt;br /&gt;
  &lt;br /&gt;
  mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf~&lt;br /&gt;
  &lt;br /&gt;
  cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/dovecot/dovecot.conf&lt;br /&gt;
  listen = *&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  protocols = imap&lt;br /&gt;
  disable_plaintext_auth = no&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_location = mbox:~/mail:INBOX=/var/mail/%u&lt;br /&gt;
  userdb {&lt;br /&gt;
    driver = passwd&lt;br /&gt;
  }&lt;br /&gt;
  passdb {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    args = scheme=sha512-crypt username_format=%n /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl=yes&lt;br /&gt;
  ssl_cert=&amp;lt;/etc/ssl/dovecot/server.pem&lt;br /&gt;
  ssl_key=&amp;lt;/etc/ssl/dovecot/server.key&lt;br /&gt;
  EOF&lt;br /&gt;
  &lt;br /&gt;
  touch /etc/dovecot/passwd&lt;br /&gt;
  chown root:dovecot /etc/dovecot/passwd&lt;br /&gt;
  chmod 640 /etc/dovecot/passwd&lt;br /&gt;
  &lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
  &lt;br /&gt;
  echo &amp;quot;Create dovecot user passwords with: doveadm pw -s sha512-crypt&amp;quot;&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30946</id>
		<title>Small-Time Email with Exim and Dovecot</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30946"/>
		<updated>2025-09-21T14:28:53Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Configuring Dovecot */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want a super-simple SMTP / IMAP setup for a home server, this is the guide for you. This document covers the minimum steps to get email delivery up and running on a small home network. You&#039;re not going to want to use this for any serious enterprise stuff, but for a small home LAN it works well.&lt;br /&gt;
&lt;br /&gt;
== Why would anyone do this? ==&lt;br /&gt;
&lt;br /&gt;
My personal motivation for creating this small-time email setup was to deliver alerts from [https://mmonit.com/monit/ Monit] so I would know when my system needed attention. You can use it for this or similar minimalist email needs. Just don&#039;t do anything crazy like exposing it to the internet.&lt;br /&gt;
&lt;br /&gt;
== Why Exim and Dovecot? ==&lt;br /&gt;
&lt;br /&gt;
For an email server, Exim is easy to configure. Dovecot is a little more complex, but not insurmountable. Both are well documented.&lt;br /&gt;
&lt;br /&gt;
== Installing the Packages ==&lt;br /&gt;
The first step is to install Exim, Dovecot, and Mailx. (Mailx is used for testing.)&lt;br /&gt;
&lt;br /&gt;
  apk add {{pkg|exim|arch=}} {{pkg|dovecot|arch=}} {{pkg|mailx|arch=}}&lt;br /&gt;
&lt;br /&gt;
== Configuring Exim ==&lt;br /&gt;
&lt;br /&gt;
The next step is to get Exim working for delivering email to users on the system. This is a pretty simple configuration and there are only a few parameters to change in the delivered exim.conf file.&lt;br /&gt;
&lt;br /&gt;
# Make a backup of {{path|/etc/exim/exim.conf}}&lt;br /&gt;
# Open {{path|/etc/exim/exim.conf}} in your favorite text editor.&lt;br /&gt;
# Make the changes stated below and save.&lt;br /&gt;
&lt;br /&gt;
Find the lines that look like this:&lt;br /&gt;
&lt;br /&gt;
  # group = mail&lt;br /&gt;
  # mode = 0660&lt;br /&gt;
&lt;br /&gt;
They&#039;ll be under the heading of &amp;lt;code&amp;gt;local_delivery:&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you find them, remove the comment (hash symbol). The local_delivery section should now look like this:&lt;br /&gt;
&lt;br /&gt;
  local_delivery:&lt;br /&gt;
    driver = appendfile&lt;br /&gt;
    file = /var/mail/$local_part_data&lt;br /&gt;
    delivery_date_add&lt;br /&gt;
    envelope_to_add&lt;br /&gt;
    return_path_add&lt;br /&gt;
    group = mail&lt;br /&gt;
    mode = 0660&lt;br /&gt;
&lt;br /&gt;
The only thing changed is the removal of the hash symbol from the last two lines.&lt;br /&gt;
&lt;br /&gt;
== Fixing Ownership and Permissions on /var/mail ==&lt;br /&gt;
&lt;br /&gt;
As it stands, Exim will not be able to deliver messages to /var/mail, where the user mailboxes are stored. This is due to permissions.&lt;br /&gt;
&lt;br /&gt;
To fix it, run these two commands:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
&lt;br /&gt;
When you&#039;re done, verify it with &amp;lt;code&amp;gt;ls -ld /var/mail&amp;lt;/code&amp;gt;. It should look something like this:&lt;br /&gt;
&lt;br /&gt;
  $ ls -ld /var/mail/&lt;br /&gt;
  drwxrwsr-x    3 root     mail          4096 May 11 12:58 /var/mail/&lt;br /&gt;
&lt;br /&gt;
Setting the group ownership to &#039;&#039;mail&#039;&#039;, lets exim write to users&#039; mailboxes when new mail comes in.&lt;br /&gt;
&lt;br /&gt;
== Starting the Exim Service ==&lt;br /&gt;
&lt;br /&gt;
Start Exim and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service exim start&lt;br /&gt;
  rc-update add exim&lt;br /&gt;
&lt;br /&gt;
== Testing the Exim Setup ==&lt;br /&gt;
&lt;br /&gt;
Log in a a regular user and try sending a test email to yourself. You can do this with the mail command, like this:&lt;br /&gt;
&lt;br /&gt;
  mail -s Testing dave&lt;br /&gt;
  This is a test.&lt;br /&gt;
  .&lt;br /&gt;
&lt;br /&gt;
This sends a test message to the user dave. (Obviously, you&#039;ll want to replace dave with your username.) The final . on the last line is important. It tells the mail command the message is done.&lt;br /&gt;
&lt;br /&gt;
When the message is sent, check that you received it by running &amp;lt;code&amp;gt;mail&amp;lt;/code&amp;gt; with no command-line parameters. If everything went well, it should look like the example below.&lt;br /&gt;
&lt;br /&gt;
  $ mail&lt;br /&gt;
  Mail version 8.1 6/6/93.  Type ? for help.&lt;br /&gt;
  &amp;quot;/var/mail/dave&amp;quot;: 1 messages&lt;br /&gt;
  &amp;gt;   1 dave@myserver.home      Wed May 11 03:51  27/847   &amp;quot;Testing&amp;quot;&lt;br /&gt;
  &amp;amp;&lt;br /&gt;
&lt;br /&gt;
You can type the message number (1) to display the contents of the mail and then type q to quit the mail program.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting Mail Delivery ==&lt;br /&gt;
&lt;br /&gt;
If the mail test fails, look in the directory {{path|/var/spool/exim/msglog}}. If there are files there, they are stuck messages. The files are plain text. Display the contents to show any error messages. In most cases, the problem will be related to permissions on the {{path|/var/mail}} directory or the mailbox files within the directory.&lt;br /&gt;
&lt;br /&gt;
The directory permissions should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -ld /var/mail&lt;br /&gt;
  drwxrwsr-x    3 root     mail&lt;br /&gt;
&lt;br /&gt;
The permissions on mailbox files inside should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -l&lt;br /&gt;
  -rw-rw----    1 dave     mail&lt;br /&gt;
&lt;br /&gt;
== Configuring Dovecot ==&lt;br /&gt;
&lt;br /&gt;
If everything is working with local delivery, it&#039;s time to set up IMAP using Dovecot.&lt;br /&gt;
&lt;br /&gt;
{{Note| The example configuration below is for Dovecot version 2.4 used in Alpine Linux 3.22 and later. It is not compatible with older versions.}}&lt;br /&gt;
&lt;br /&gt;
The Dovecot package for Alpine comes with twenty configuration files in {{path|/etc/dovecot/conf.d}}. As a small-time email admin, you may feel overwhelmed. Don&#039;t worry, everything can be condensed down to a single config file of sixteen lines.&lt;br /&gt;
&lt;br /&gt;
First, make a backup copy of {{path|/etc/dovecot/dovecot.conf}}.&lt;br /&gt;
&lt;br /&gt;
Next, create a new dovecot.conf that looks like this:&lt;br /&gt;
&lt;br /&gt;
 dovecot_config_version = 2.4.0&lt;br /&gt;
 dovecot_storage_version = 2.4.0&lt;br /&gt;
 listen = *&lt;br /&gt;
 log_path = /var/log/dovecot.log&lt;br /&gt;
 protocols = imap&lt;br /&gt;
 auth_allow_cleartext = yes&lt;br /&gt;
 mail_privileged_group = mail&lt;br /&gt;
 mail_driver = maildir&lt;br /&gt;
 mail_path = ~/mail&lt;br /&gt;
 mail_inbox_path = /var/mail/%u&lt;br /&gt;
 userdb passwd {&lt;br /&gt;
   driver = passwd-file&lt;br /&gt;
   passwd_file_path = /etc/dovecot/passwd&lt;br /&gt;
 }&lt;br /&gt;
 # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
 ssl=yes&lt;br /&gt;
 ssl_server_cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
 ssl_server_key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
&lt;br /&gt;
This config does not have the &amp;lt;code&amp;gt;!include conf.d/*.conf&amp;lt;/code&amp;gt; that was in the original dovecot.conf, so those twenty files in conf.d are going to be ignored. Everything is now in this single dovecot.conf.&lt;br /&gt;
&lt;br /&gt;
== Starting the Dovecot Service ==&lt;br /&gt;
&lt;br /&gt;
Start Dovecot and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Credentials for Dovecot Users ==&lt;br /&gt;
&lt;br /&gt;
As it is configured, Dovecot will use {{path|/etc/passwd}} for looking up user information, but not authentication. Technically, {{path|/etc/passwd}} authentication can be done using Pluggable Authentication Modules (PAM), but PAM is not part of the base install of Alpine Linux. The next best thing is to use a separate password file for Dovecot credentials and to use the same SHA512-Crypt hashing algorithm used in {{path|/etc/passwd}}.&lt;br /&gt;
&lt;br /&gt;
The Dovecot configuration above specifies a password file of {{path|/etc/dovecot/passwd}}. The Dovecot password file looks like this:&lt;br /&gt;
&lt;br /&gt;
  dave:{SHA512-CRYPT}$6$mQ1rxB0gZHqg8Tg9$nxZ8odJZ6xVpmOVpsnYfAo1i7SuoLDhsvoykieukWF9NyNBq.WwhDA7udcYxP1iEm/IzlBmnwz6/vOO3SX8gA.&lt;br /&gt;
&lt;br /&gt;
There are two fields, username and password, separated by a colon. Notice the {SHA512-CRYPT} prefix to the password. This indicates the hashing algorithm.&lt;br /&gt;
&lt;br /&gt;
You can create passwords with the &amp;lt;code&amp;gt;doveadm&amp;lt;/code&amp;gt; command, like this:&lt;br /&gt;
&lt;br /&gt;
  # doveadm pw -s sha512-crypt&lt;br /&gt;
  Enter new password:&lt;br /&gt;
  Retype new password:&lt;br /&gt;
&lt;br /&gt;
The command will output the hashed password. You&#039;ll need to edit Dovecot&#039;s password file with a text editor and create the username/password pair by hand.&lt;br /&gt;
&lt;br /&gt;
The permissions on the Dovecot password file should be such that dovecot can read it, but not write to it. Only root should be able to write it.&lt;br /&gt;
&lt;br /&gt;
  ls -l /etc/dovecot/passwd&lt;br /&gt;
  -rw-r-----    1 root     dovecot&lt;br /&gt;
&lt;br /&gt;
== Testing the Dovecot Setup ==&lt;br /&gt;
&lt;br /&gt;
To test IMAP, you&#039;ll need an email client. Personally, I&#039;ve used [https://www.thunderbird.net Thunderbird] on Windows and [https://k9mail.app/ K-9 Mail] on Android. The trickiest part is getting the email client to trust the self-signed certificates. Configuring email clients is beyond the scope of this document.&lt;br /&gt;
&lt;br /&gt;
From the server side, the Dovecot log file can help you diagnose errors. The dovecot.conf file specifies the location of the log file.&lt;br /&gt;
&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
&lt;br /&gt;
One of the common errors I&#039;ve seen looks like this:&lt;br /&gt;
&lt;br /&gt;
  Disconnected: TLS initialization failed.&lt;br /&gt;
  Error: Failed to initialize SSL server context: Can&#039;t load SSL certificate&lt;br /&gt;
&lt;br /&gt;
This was the result of a typographical error I made in the Dovecot config file.&lt;br /&gt;
&lt;br /&gt;
You can further simplify things by commenting out the ssl lines in the dovecot.conf so it looks like this:&lt;br /&gt;
&lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  #ssl=yes&lt;br /&gt;
  #ssl_cert=&amp;lt;/etc/ssl/dovecot/server.pem&lt;br /&gt;
  #ssl_key=&amp;lt;/etc/ssl/dovecot/server.key&lt;br /&gt;
&lt;br /&gt;
Now TLS is out of the picture, letting you diagnose other potential problems. However, you may have to do some work to convince your mail client that sending login credentials in cleartext is okay. Only do this on a network where you trust your users!&lt;br /&gt;
&lt;br /&gt;
== Using and Enjoying Your Small-Time Email Setup ==&lt;br /&gt;
&lt;br /&gt;
Now that everything is setup, you can start sending yourself cat pictures or you can configure other programs to use the email system to send notifications. For example, I use [https://mmonit.com/monit/ Monit] to keep an eye on services and file system space. When Monit detects a problem, it sends me an email.&lt;br /&gt;
&lt;br /&gt;
The setup presented in this guide uses port 25 for SMTP and port 143 for IMAP. There are no dedicated TLS ports. Encryption is done using STARTTLS.&lt;br /&gt;
&lt;br /&gt;
== A Word About Aliases ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve ever used {{path|/etc/aliases}} for mail delivery, you should be aware that Exim puts this file in {{path|/etc/mail/aliases}}. The format is the same as Sendmail.&lt;br /&gt;
&lt;br /&gt;
== Scripted Installation and Configuration ==&lt;br /&gt;
&lt;br /&gt;
If you like living dangerously (or if you have a test system you don&#039;t care about) you can do all of the server configuration presented above with a single script, as shown below:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
  &lt;br /&gt;
  apk add exim mailx&lt;br /&gt;
  &lt;br /&gt;
  sed -i~ \&lt;br /&gt;
    -e &#039;s/# group = mail/  group = mail/&#039; \&lt;br /&gt;
    -e &#039;s/# mode = 0660/  mode = 0660/&#039; \&lt;br /&gt;
    /etc/exim/exim.conf&lt;br /&gt;
  &lt;br /&gt;
  ln -s mail/aliases /etc/aliases&lt;br /&gt;
  &lt;br /&gt;
  rc-update add exim&lt;br /&gt;
  service exim start&lt;br /&gt;
  &lt;br /&gt;
  apk add dovecot&lt;br /&gt;
  &lt;br /&gt;
  mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf~&lt;br /&gt;
  &lt;br /&gt;
  cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/dovecot/dovecot.conf&lt;br /&gt;
  listen = *&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  protocols = imap&lt;br /&gt;
  disable_plaintext_auth = no&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_location = mbox:~/mail:INBOX=/var/mail/%u&lt;br /&gt;
  userdb {&lt;br /&gt;
    driver = passwd&lt;br /&gt;
  }&lt;br /&gt;
  passdb {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    args = scheme=sha512-crypt username_format=%n /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl=yes&lt;br /&gt;
  ssl_cert=&amp;lt;/etc/ssl/dovecot/server.pem&lt;br /&gt;
  ssl_key=&amp;lt;/etc/ssl/dovecot/server.key&lt;br /&gt;
  EOF&lt;br /&gt;
  &lt;br /&gt;
  touch /etc/dovecot/passwd&lt;br /&gt;
  chown root:dovecot /etc/dovecot/passwd&lt;br /&gt;
  chmod 640 /etc/dovecot/passwd&lt;br /&gt;
  &lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
  &lt;br /&gt;
  echo &amp;quot;Create dovecot user passwords with: doveadm pw -s sha512-crypt&amp;quot;&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30945</id>
		<title>Small-Time Email with Exim and Dovecot</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30945"/>
		<updated>2025-09-21T14:01:45Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Configuring Dovecot */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want a super-simple SMTP / IMAP setup for a home server, this is the guide for you. This document covers the minimum steps to get email delivery up and running on a small home network. You&#039;re not going to want to use this for any serious enterprise stuff, but for a small home LAN it works well.&lt;br /&gt;
&lt;br /&gt;
== Why would anyone do this? ==&lt;br /&gt;
&lt;br /&gt;
My personal motivation for creating this small-time email setup was to deliver alerts from [https://mmonit.com/monit/ Monit] so I would know when my system needed attention. You can use it for this or similar minimalist email needs. Just don&#039;t do anything crazy like exposing it to the internet.&lt;br /&gt;
&lt;br /&gt;
== Why Exim and Dovecot? ==&lt;br /&gt;
&lt;br /&gt;
For an email server, Exim is easy to configure. Dovecot is a little more complex, but not insurmountable. Both are well documented.&lt;br /&gt;
&lt;br /&gt;
== Installing the Packages ==&lt;br /&gt;
The first step is to install Exim, Dovecot, and Mailx. (Mailx is used for testing.)&lt;br /&gt;
&lt;br /&gt;
  apk add {{pkg|exim|arch=}} {{pkg|dovecot|arch=}} {{pkg|mailx|arch=}}&lt;br /&gt;
&lt;br /&gt;
== Configuring Exim ==&lt;br /&gt;
&lt;br /&gt;
The next step is to get Exim working for delivering email to users on the system. This is a pretty simple configuration and there are only a few parameters to change in the delivered exim.conf file.&lt;br /&gt;
&lt;br /&gt;
# Make a backup of {{path|/etc/exim/exim.conf}}&lt;br /&gt;
# Open {{path|/etc/exim/exim.conf}} in your favorite text editor.&lt;br /&gt;
# Make the changes stated below and save.&lt;br /&gt;
&lt;br /&gt;
Find the lines that look like this:&lt;br /&gt;
&lt;br /&gt;
  # group = mail&lt;br /&gt;
  # mode = 0660&lt;br /&gt;
&lt;br /&gt;
They&#039;ll be under the heading of &amp;lt;code&amp;gt;local_delivery:&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you find them, remove the comment (hash symbol). The local_delivery section should now look like this:&lt;br /&gt;
&lt;br /&gt;
  local_delivery:&lt;br /&gt;
    driver = appendfile&lt;br /&gt;
    file = /var/mail/$local_part_data&lt;br /&gt;
    delivery_date_add&lt;br /&gt;
    envelope_to_add&lt;br /&gt;
    return_path_add&lt;br /&gt;
    group = mail&lt;br /&gt;
    mode = 0660&lt;br /&gt;
&lt;br /&gt;
The only thing changed is the removal of the hash symbol from the last two lines.&lt;br /&gt;
&lt;br /&gt;
== Fixing Ownership and Permissions on /var/mail ==&lt;br /&gt;
&lt;br /&gt;
As it stands, Exim will not be able to deliver messages to /var/mail, where the user mailboxes are stored. This is due to permissions.&lt;br /&gt;
&lt;br /&gt;
To fix it, run these two commands:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
&lt;br /&gt;
When you&#039;re done, verify it with &amp;lt;code&amp;gt;ls -ld /var/mail&amp;lt;/code&amp;gt;. It should look something like this:&lt;br /&gt;
&lt;br /&gt;
  $ ls -ld /var/mail/&lt;br /&gt;
  drwxrwsr-x    3 root     mail          4096 May 11 12:58 /var/mail/&lt;br /&gt;
&lt;br /&gt;
Setting the group ownership to &#039;&#039;mail&#039;&#039;, lets exim write to users&#039; mailboxes when new mail comes in.&lt;br /&gt;
&lt;br /&gt;
== Starting the Exim Service ==&lt;br /&gt;
&lt;br /&gt;
Start Exim and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service exim start&lt;br /&gt;
  rc-update add exim&lt;br /&gt;
&lt;br /&gt;
== Testing the Exim Setup ==&lt;br /&gt;
&lt;br /&gt;
Log in a a regular user and try sending a test email to yourself. You can do this with the mail command, like this:&lt;br /&gt;
&lt;br /&gt;
  mail -s Testing dave&lt;br /&gt;
  This is a test.&lt;br /&gt;
  .&lt;br /&gt;
&lt;br /&gt;
This sends a test message to the user dave. (Obviously, you&#039;ll want to replace dave with your username.) The final . on the last line is important. It tells the mail command the message is done.&lt;br /&gt;
&lt;br /&gt;
When the message is sent, check that you received it by running &amp;lt;code&amp;gt;mail&amp;lt;/code&amp;gt; with no command-line parameters. If everything went well, it should look like the example below.&lt;br /&gt;
&lt;br /&gt;
  $ mail&lt;br /&gt;
  Mail version 8.1 6/6/93.  Type ? for help.&lt;br /&gt;
  &amp;quot;/var/mail/dave&amp;quot;: 1 messages&lt;br /&gt;
  &amp;gt;   1 dave@myserver.home      Wed May 11 03:51  27/847   &amp;quot;Testing&amp;quot;&lt;br /&gt;
  &amp;amp;&lt;br /&gt;
&lt;br /&gt;
You can type the message number (1) to display the contents of the mail and then type q to quit the mail program.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting Mail Delivery ==&lt;br /&gt;
&lt;br /&gt;
If the mail test fails, look in the directory {{path|/var/spool/exim/msglog}}. If there are files there, they are stuck messages. The files are plain text. Display the contents to show any error messages. In most cases, the problem will be related to permissions on the {{path|/var/mail}} directory or the mailbox files within the directory.&lt;br /&gt;
&lt;br /&gt;
The directory permissions should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -ld /var/mail&lt;br /&gt;
  drwxrwsr-x    3 root     mail&lt;br /&gt;
&lt;br /&gt;
The permissions on mailbox files inside should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -l&lt;br /&gt;
  -rw-rw----    1 dave     mail&lt;br /&gt;
&lt;br /&gt;
== Configuring Dovecot ==&lt;br /&gt;
&lt;br /&gt;
If everything is working with local delivery, it&#039;s time to set up IMAP using Dovecot.&lt;br /&gt;
&lt;br /&gt;
{{Note| The example configuration below is for Dovecot version 2.4 used in Alpine Linux 3.22 and later. It is not compatible with older versions.}}&lt;br /&gt;
&lt;br /&gt;
The Dovecot package for Alpine comes with twenty configuration files in {{path|/etc/dovecot/conf.d}}. As a small-time email admin, you may feel overwhelmed. Don&#039;t worry, everything can be condensed down to a single config file of sixteen lines.&lt;br /&gt;
&lt;br /&gt;
First, make a backup copy of {{path|/etc/dovecot/dovecot.conf}}.&lt;br /&gt;
&lt;br /&gt;
Next, create a new dovecot.conf that looks like this:&lt;br /&gt;
&lt;br /&gt;
 dovecot_config_version = 2.4.0&lt;br /&gt;
 dovecot_storage_version = 2.4.0&lt;br /&gt;
 listen = *&lt;br /&gt;
 log_path = /var/log/dovecot.log&lt;br /&gt;
 protocols = imap&lt;br /&gt;
 auth_allow_cleartext = yes&lt;br /&gt;
 mail_privileged_group = mail&lt;br /&gt;
 mail_driver = maildir&lt;br /&gt;
 mail_path = ~/mail&lt;br /&gt;
 mail_inbox_path = /var/mail/%u&lt;br /&gt;
 userdb passwd {&lt;br /&gt;
   driver = passwd&lt;br /&gt;
 }&lt;br /&gt;
 # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
 ssl=yes&lt;br /&gt;
 ssl_server_cert_file = /etc/ssl/dovecot/server.pem&lt;br /&gt;
 ssl_server_key_file = /etc/ssl/dovecot/server.key&lt;br /&gt;
&lt;br /&gt;
This config does not have the &amp;lt;code&amp;gt;!include conf.d/*.conf&amp;lt;/code&amp;gt; that was in the original dovecot.conf, so those twenty files in conf.d are going to be ignored. Everything is now in this single dovecot.conf.&lt;br /&gt;
&lt;br /&gt;
== Starting the Dovecot Service ==&lt;br /&gt;
&lt;br /&gt;
Start Dovecot and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Credentials for Dovecot Users ==&lt;br /&gt;
&lt;br /&gt;
As it is configured, Dovecot will use {{path|/etc/passwd}} for looking up user information, but not authentication. Technically, {{path|/etc/passwd}} authentication can be done using Pluggable Authentication Modules (PAM), but PAM is not part of the base install of Alpine Linux. The next best thing is to use a separate password file for Dovecot credentials and to use the same SHA512-Crypt hashing algorithm used in {{path|/etc/passwd}}.&lt;br /&gt;
&lt;br /&gt;
The Dovecot configuration above specifies a password file of {{path|/etc/dovecot/passwd}}. The Dovecot password file looks like this:&lt;br /&gt;
&lt;br /&gt;
  dave:{SHA512-CRYPT}$6$mQ1rxB0gZHqg8Tg9$nxZ8odJZ6xVpmOVpsnYfAo1i7SuoLDhsvoykieukWF9NyNBq.WwhDA7udcYxP1iEm/IzlBmnwz6/vOO3SX8gA.&lt;br /&gt;
&lt;br /&gt;
There are two fields, username and password, separated by a colon. Notice the {SHA512-CRYPT} prefix to the password. This indicates the hashing algorithm.&lt;br /&gt;
&lt;br /&gt;
You can create passwords with the &amp;lt;code&amp;gt;doveadm&amp;lt;/code&amp;gt; command, like this:&lt;br /&gt;
&lt;br /&gt;
  # doveadm pw -s sha512-crypt&lt;br /&gt;
  Enter new password:&lt;br /&gt;
  Retype new password:&lt;br /&gt;
&lt;br /&gt;
The command will output the hashed password. You&#039;ll need to edit Dovecot&#039;s password file with a text editor and create the username/password pair by hand.&lt;br /&gt;
&lt;br /&gt;
The permissions on the Dovecot password file should be such that dovecot can read it, but not write to it. Only root should be able to write it.&lt;br /&gt;
&lt;br /&gt;
  ls -l /etc/dovecot/passwd&lt;br /&gt;
  -rw-r-----    1 root     dovecot&lt;br /&gt;
&lt;br /&gt;
== Testing the Dovecot Setup ==&lt;br /&gt;
&lt;br /&gt;
To test IMAP, you&#039;ll need an email client. Personally, I&#039;ve used [https://www.thunderbird.net Thunderbird] on Windows and [https://k9mail.app/ K-9 Mail] on Android. The trickiest part is getting the email client to trust the self-signed certificates. Configuring email clients is beyond the scope of this document.&lt;br /&gt;
&lt;br /&gt;
From the server side, the Dovecot log file can help you diagnose errors. The dovecot.conf file specifies the location of the log file.&lt;br /&gt;
&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
&lt;br /&gt;
One of the common errors I&#039;ve seen looks like this:&lt;br /&gt;
&lt;br /&gt;
  Disconnected: TLS initialization failed.&lt;br /&gt;
  Error: Failed to initialize SSL server context: Can&#039;t load SSL certificate&lt;br /&gt;
&lt;br /&gt;
This was the result of a typographical error I made in the Dovecot config file.&lt;br /&gt;
&lt;br /&gt;
You can further simplify things by commenting out the ssl lines in the dovecot.conf so it looks like this:&lt;br /&gt;
&lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  #ssl=yes&lt;br /&gt;
  #ssl_cert=&amp;lt;/etc/ssl/dovecot/server.pem&lt;br /&gt;
  #ssl_key=&amp;lt;/etc/ssl/dovecot/server.key&lt;br /&gt;
&lt;br /&gt;
Now TLS is out of the picture, letting you diagnose other potential problems. However, you may have to do some work to convince your mail client that sending login credentials in cleartext is okay. Only do this on a network where you trust your users!&lt;br /&gt;
&lt;br /&gt;
== Using and Enjoying Your Small-Time Email Setup ==&lt;br /&gt;
&lt;br /&gt;
Now that everything is setup, you can start sending yourself cat pictures or you can configure other programs to use the email system to send notifications. For example, I use [https://mmonit.com/monit/ Monit] to keep an eye on services and file system space. When Monit detects a problem, it sends me an email.&lt;br /&gt;
&lt;br /&gt;
The setup presented in this guide uses port 25 for SMTP and port 143 for IMAP. There are no dedicated TLS ports. Encryption is done using STARTTLS.&lt;br /&gt;
&lt;br /&gt;
== A Word About Aliases ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve ever used {{path|/etc/aliases}} for mail delivery, you should be aware that Exim puts this file in {{path|/etc/mail/aliases}}. The format is the same as Sendmail.&lt;br /&gt;
&lt;br /&gt;
== Scripted Installation and Configuration ==&lt;br /&gt;
&lt;br /&gt;
If you like living dangerously (or if you have a test system you don&#039;t care about) you can do all of the server configuration presented above with a single script, as shown below:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
  &lt;br /&gt;
  apk add exim mailx&lt;br /&gt;
  &lt;br /&gt;
  sed -i~ \&lt;br /&gt;
    -e &#039;s/# group = mail/  group = mail/&#039; \&lt;br /&gt;
    -e &#039;s/# mode = 0660/  mode = 0660/&#039; \&lt;br /&gt;
    /etc/exim/exim.conf&lt;br /&gt;
  &lt;br /&gt;
  ln -s mail/aliases /etc/aliases&lt;br /&gt;
  &lt;br /&gt;
  rc-update add exim&lt;br /&gt;
  service exim start&lt;br /&gt;
  &lt;br /&gt;
  apk add dovecot&lt;br /&gt;
  &lt;br /&gt;
  mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf~&lt;br /&gt;
  &lt;br /&gt;
  cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/dovecot/dovecot.conf&lt;br /&gt;
  listen = *&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  protocols = imap&lt;br /&gt;
  disable_plaintext_auth = no&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_location = mbox:~/mail:INBOX=/var/mail/%u&lt;br /&gt;
  userdb {&lt;br /&gt;
    driver = passwd&lt;br /&gt;
  }&lt;br /&gt;
  passdb {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    args = scheme=sha512-crypt username_format=%n /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl=yes&lt;br /&gt;
  ssl_cert=&amp;lt;/etc/ssl/dovecot/server.pem&lt;br /&gt;
  ssl_key=&amp;lt;/etc/ssl/dovecot/server.key&lt;br /&gt;
  EOF&lt;br /&gt;
  &lt;br /&gt;
  touch /etc/dovecot/passwd&lt;br /&gt;
  chown root:dovecot /etc/dovecot/passwd&lt;br /&gt;
  chmod 640 /etc/dovecot/passwd&lt;br /&gt;
  &lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
  &lt;br /&gt;
  echo &amp;quot;Create dovecot user passwords with: doveadm pw -s sha512-crypt&amp;quot;&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30944</id>
		<title>Small-Time Email with Exim and Dovecot</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_Email_with_Exim_and_Dovecot&amp;diff=30944"/>
		<updated>2025-09-21T13:58:29Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Configuring Dovecot */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want a super-simple SMTP / IMAP setup for a home server, this is the guide for you. This document covers the minimum steps to get email delivery up and running on a small home network. You&#039;re not going to want to use this for any serious enterprise stuff, but for a small home LAN it works well.&lt;br /&gt;
&lt;br /&gt;
== Why would anyone do this? ==&lt;br /&gt;
&lt;br /&gt;
My personal motivation for creating this small-time email setup was to deliver alerts from [https://mmonit.com/monit/ Monit] so I would know when my system needed attention. You can use it for this or similar minimalist email needs. Just don&#039;t do anything crazy like exposing it to the internet.&lt;br /&gt;
&lt;br /&gt;
== Why Exim and Dovecot? ==&lt;br /&gt;
&lt;br /&gt;
For an email server, Exim is easy to configure. Dovecot is a little more complex, but not insurmountable. Both are well documented.&lt;br /&gt;
&lt;br /&gt;
== Installing the Packages ==&lt;br /&gt;
The first step is to install Exim, Dovecot, and Mailx. (Mailx is used for testing.)&lt;br /&gt;
&lt;br /&gt;
  apk add {{pkg|exim|arch=}} {{pkg|dovecot|arch=}} {{pkg|mailx|arch=}}&lt;br /&gt;
&lt;br /&gt;
== Configuring Exim ==&lt;br /&gt;
&lt;br /&gt;
The next step is to get Exim working for delivering email to users on the system. This is a pretty simple configuration and there are only a few parameters to change in the delivered exim.conf file.&lt;br /&gt;
&lt;br /&gt;
# Make a backup of {{path|/etc/exim/exim.conf}}&lt;br /&gt;
# Open {{path|/etc/exim/exim.conf}} in your favorite text editor.&lt;br /&gt;
# Make the changes stated below and save.&lt;br /&gt;
&lt;br /&gt;
Find the lines that look like this:&lt;br /&gt;
&lt;br /&gt;
  # group = mail&lt;br /&gt;
  # mode = 0660&lt;br /&gt;
&lt;br /&gt;
They&#039;ll be under the heading of &amp;lt;code&amp;gt;local_delivery:&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you find them, remove the comment (hash symbol). The local_delivery section should now look like this:&lt;br /&gt;
&lt;br /&gt;
  local_delivery:&lt;br /&gt;
    driver = appendfile&lt;br /&gt;
    file = /var/mail/$local_part_data&lt;br /&gt;
    delivery_date_add&lt;br /&gt;
    envelope_to_add&lt;br /&gt;
    return_path_add&lt;br /&gt;
    group = mail&lt;br /&gt;
    mode = 0660&lt;br /&gt;
&lt;br /&gt;
The only thing changed is the removal of the hash symbol from the last two lines.&lt;br /&gt;
&lt;br /&gt;
== Fixing Ownership and Permissions on /var/mail ==&lt;br /&gt;
&lt;br /&gt;
As it stands, Exim will not be able to deliver messages to /var/mail, where the user mailboxes are stored. This is due to permissions.&lt;br /&gt;
&lt;br /&gt;
To fix it, run these two commands:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
&lt;br /&gt;
When you&#039;re done, verify it with &amp;lt;code&amp;gt;ls -ld /var/mail&amp;lt;/code&amp;gt;. It should look something like this:&lt;br /&gt;
&lt;br /&gt;
  $ ls -ld /var/mail/&lt;br /&gt;
  drwxrwsr-x    3 root     mail          4096 May 11 12:58 /var/mail/&lt;br /&gt;
&lt;br /&gt;
Setting the group ownership to &#039;&#039;mail&#039;&#039;, lets exim write to users&#039; mailboxes when new mail comes in.&lt;br /&gt;
&lt;br /&gt;
== Starting the Exim Service ==&lt;br /&gt;
&lt;br /&gt;
Start Exim and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service exim start&lt;br /&gt;
  rc-update add exim&lt;br /&gt;
&lt;br /&gt;
== Testing the Exim Setup ==&lt;br /&gt;
&lt;br /&gt;
Log in a a regular user and try sending a test email to yourself. You can do this with the mail command, like this:&lt;br /&gt;
&lt;br /&gt;
  mail -s Testing dave&lt;br /&gt;
  This is a test.&lt;br /&gt;
  .&lt;br /&gt;
&lt;br /&gt;
This sends a test message to the user dave. (Obviously, you&#039;ll want to replace dave with your username.) The final . on the last line is important. It tells the mail command the message is done.&lt;br /&gt;
&lt;br /&gt;
When the message is sent, check that you received it by running &amp;lt;code&amp;gt;mail&amp;lt;/code&amp;gt; with no command-line parameters. If everything went well, it should look like the example below.&lt;br /&gt;
&lt;br /&gt;
  $ mail&lt;br /&gt;
  Mail version 8.1 6/6/93.  Type ? for help.&lt;br /&gt;
  &amp;quot;/var/mail/dave&amp;quot;: 1 messages&lt;br /&gt;
  &amp;gt;   1 dave@myserver.home      Wed May 11 03:51  27/847   &amp;quot;Testing&amp;quot;&lt;br /&gt;
  &amp;amp;&lt;br /&gt;
&lt;br /&gt;
You can type the message number (1) to display the contents of the mail and then type q to quit the mail program.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting Mail Delivery ==&lt;br /&gt;
&lt;br /&gt;
If the mail test fails, look in the directory {{path|/var/spool/exim/msglog}}. If there are files there, they are stuck messages. The files are plain text. Display the contents to show any error messages. In most cases, the problem will be related to permissions on the {{path|/var/mail}} directory or the mailbox files within the directory.&lt;br /&gt;
&lt;br /&gt;
The directory permissions should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -ld /var/mail&lt;br /&gt;
  drwxrwsr-x    3 root     mail&lt;br /&gt;
&lt;br /&gt;
The permissions on mailbox files inside should look like this:&lt;br /&gt;
&lt;br /&gt;
  # ls -l&lt;br /&gt;
  -rw-rw----    1 dave     mail&lt;br /&gt;
&lt;br /&gt;
== Configuring Dovecot ==&lt;br /&gt;
&lt;br /&gt;
If everything is working with local delivery, it&#039;s time to set up IMAP using Dovecot.&lt;br /&gt;
&lt;br /&gt;
{{Note| The example configuration below is for Dovecot version 2.4 used in Alpine Linux 3.22 and later. It is not compatible with older versions.}}&lt;br /&gt;
&lt;br /&gt;
The Dovecot package for Alpine comes with twenty configuration files in {{path|/etc/dovecot/conf.d}}. As a small-time email admin, you may feel overwhelmed. Don&#039;t worry, everything can be condensed down to a single config file of sixteen lines.&lt;br /&gt;
&lt;br /&gt;
First, make a backup copy of {{path|/etc/dovecot/dovecot.conf}}.&lt;br /&gt;
&lt;br /&gt;
Next, create a new dovecot.conf that looks like this:&lt;br /&gt;
&lt;br /&gt;
 dovecot_config_version = 2.4.0&lt;br /&gt;
 dovecot_storage_version = 2.4.0&lt;br /&gt;
 listen = *&lt;br /&gt;
 log_path = /var/log/dovecot.log&lt;br /&gt;
 protocols = imap&lt;br /&gt;
 auth_allow_cleartext = yes&lt;br /&gt;
 mail_privileged_group = mail&lt;br /&gt;
 mail_driver = maildir&lt;br /&gt;
 mail_path = ~/mail&lt;br /&gt;
 mail_inbox_path = /var/mail/%u&lt;br /&gt;
 userdb passwd {&lt;br /&gt;
   driver = passwd&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This config does not have the &amp;lt;code&amp;gt;!include conf.d/*.conf&amp;lt;/code&amp;gt; that was in the original dovecot.conf, so those twenty files in conf.d are going to be ignored. Everything is now in this single dovecot.conf.&lt;br /&gt;
&lt;br /&gt;
== Starting the Dovecot Service ==&lt;br /&gt;
&lt;br /&gt;
Start Dovecot and configure it to start at boot time with the usual commands.&lt;br /&gt;
&lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
&lt;br /&gt;
== Creating Credentials for Dovecot Users ==&lt;br /&gt;
&lt;br /&gt;
As it is configured, Dovecot will use {{path|/etc/passwd}} for looking up user information, but not authentication. Technically, {{path|/etc/passwd}} authentication can be done using Pluggable Authentication Modules (PAM), but PAM is not part of the base install of Alpine Linux. The next best thing is to use a separate password file for Dovecot credentials and to use the same SHA512-Crypt hashing algorithm used in {{path|/etc/passwd}}.&lt;br /&gt;
&lt;br /&gt;
The Dovecot configuration above specifies a password file of {{path|/etc/dovecot/passwd}}. The Dovecot password file looks like this:&lt;br /&gt;
&lt;br /&gt;
  dave:{SHA512-CRYPT}$6$mQ1rxB0gZHqg8Tg9$nxZ8odJZ6xVpmOVpsnYfAo1i7SuoLDhsvoykieukWF9NyNBq.WwhDA7udcYxP1iEm/IzlBmnwz6/vOO3SX8gA.&lt;br /&gt;
&lt;br /&gt;
There are two fields, username and password, separated by a colon. Notice the {SHA512-CRYPT} prefix to the password. This indicates the hashing algorithm.&lt;br /&gt;
&lt;br /&gt;
You can create passwords with the &amp;lt;code&amp;gt;doveadm&amp;lt;/code&amp;gt; command, like this:&lt;br /&gt;
&lt;br /&gt;
  # doveadm pw -s sha512-crypt&lt;br /&gt;
  Enter new password:&lt;br /&gt;
  Retype new password:&lt;br /&gt;
&lt;br /&gt;
The command will output the hashed password. You&#039;ll need to edit Dovecot&#039;s password file with a text editor and create the username/password pair by hand.&lt;br /&gt;
&lt;br /&gt;
The permissions on the Dovecot password file should be such that dovecot can read it, but not write to it. Only root should be able to write it.&lt;br /&gt;
&lt;br /&gt;
  ls -l /etc/dovecot/passwd&lt;br /&gt;
  -rw-r-----    1 root     dovecot&lt;br /&gt;
&lt;br /&gt;
== Testing the Dovecot Setup ==&lt;br /&gt;
&lt;br /&gt;
To test IMAP, you&#039;ll need an email client. Personally, I&#039;ve used [https://www.thunderbird.net Thunderbird] on Windows and [https://k9mail.app/ K-9 Mail] on Android. The trickiest part is getting the email client to trust the self-signed certificates. Configuring email clients is beyond the scope of this document.&lt;br /&gt;
&lt;br /&gt;
From the server side, the Dovecot log file can help you diagnose errors. The dovecot.conf file specifies the location of the log file.&lt;br /&gt;
&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
&lt;br /&gt;
One of the common errors I&#039;ve seen looks like this:&lt;br /&gt;
&lt;br /&gt;
  Disconnected: TLS initialization failed.&lt;br /&gt;
  Error: Failed to initialize SSL server context: Can&#039;t load SSL certificate&lt;br /&gt;
&lt;br /&gt;
This was the result of a typographical error I made in the Dovecot config file.&lt;br /&gt;
&lt;br /&gt;
You can further simplify things by commenting out the ssl lines in the dovecot.conf so it looks like this:&lt;br /&gt;
&lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  #ssl=yes&lt;br /&gt;
  #ssl_cert=&amp;lt;/etc/ssl/dovecot/server.pem&lt;br /&gt;
  #ssl_key=&amp;lt;/etc/ssl/dovecot/server.key&lt;br /&gt;
&lt;br /&gt;
Now TLS is out of the picture, letting you diagnose other potential problems. However, you may have to do some work to convince your mail client that sending login credentials in cleartext is okay. Only do this on a network where you trust your users!&lt;br /&gt;
&lt;br /&gt;
== Using and Enjoying Your Small-Time Email Setup ==&lt;br /&gt;
&lt;br /&gt;
Now that everything is setup, you can start sending yourself cat pictures or you can configure other programs to use the email system to send notifications. For example, I use [https://mmonit.com/monit/ Monit] to keep an eye on services and file system space. When Monit detects a problem, it sends me an email.&lt;br /&gt;
&lt;br /&gt;
The setup presented in this guide uses port 25 for SMTP and port 143 for IMAP. There are no dedicated TLS ports. Encryption is done using STARTTLS.&lt;br /&gt;
&lt;br /&gt;
== A Word About Aliases ==&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve ever used {{path|/etc/aliases}} for mail delivery, you should be aware that Exim puts this file in {{path|/etc/mail/aliases}}. The format is the same as Sendmail.&lt;br /&gt;
&lt;br /&gt;
== Scripted Installation and Configuration ==&lt;br /&gt;
&lt;br /&gt;
If you like living dangerously (or if you have a test system you don&#039;t care about) you can do all of the server configuration presented above with a single script, as shown below:&lt;br /&gt;
&lt;br /&gt;
  chgrp mail /var/mail&lt;br /&gt;
  chmod 2775 /var/mail&lt;br /&gt;
  &lt;br /&gt;
  apk add exim mailx&lt;br /&gt;
  &lt;br /&gt;
  sed -i~ \&lt;br /&gt;
    -e &#039;s/# group = mail/  group = mail/&#039; \&lt;br /&gt;
    -e &#039;s/# mode = 0660/  mode = 0660/&#039; \&lt;br /&gt;
    /etc/exim/exim.conf&lt;br /&gt;
  &lt;br /&gt;
  ln -s mail/aliases /etc/aliases&lt;br /&gt;
  &lt;br /&gt;
  rc-update add exim&lt;br /&gt;
  service exim start&lt;br /&gt;
  &lt;br /&gt;
  apk add dovecot&lt;br /&gt;
  &lt;br /&gt;
  mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf~&lt;br /&gt;
  &lt;br /&gt;
  cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/dovecot/dovecot.conf&lt;br /&gt;
  listen = *&lt;br /&gt;
  log_path = /var/log/dovecot.log&lt;br /&gt;
  protocols = imap&lt;br /&gt;
  disable_plaintext_auth = no&lt;br /&gt;
  mail_privileged_group = mail&lt;br /&gt;
  mail_location = mbox:~/mail:INBOX=/var/mail/%u&lt;br /&gt;
  userdb {&lt;br /&gt;
    driver = passwd&lt;br /&gt;
  }&lt;br /&gt;
  passdb {&lt;br /&gt;
    driver = passwd-file&lt;br /&gt;
    args = scheme=sha512-crypt username_format=%n /etc/dovecot/passwd&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  # These are self-signed certs generated when the dovecat apk was installed.&lt;br /&gt;
  ssl=yes&lt;br /&gt;
  ssl_cert=&amp;lt;/etc/ssl/dovecot/server.pem&lt;br /&gt;
  ssl_key=&amp;lt;/etc/ssl/dovecot/server.key&lt;br /&gt;
  EOF&lt;br /&gt;
  &lt;br /&gt;
  touch /etc/dovecot/passwd&lt;br /&gt;
  chown root:dovecot /etc/dovecot/passwd&lt;br /&gt;
  chmod 640 /etc/dovecot/passwd&lt;br /&gt;
  &lt;br /&gt;
  service dovecot start&lt;br /&gt;
  rc-update add dovecot&lt;br /&gt;
  &lt;br /&gt;
  echo &amp;quot;Create dovecot user passwords with: doveadm pw -s sha512-crypt&amp;quot;&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=30897</id>
		<title>Small-Time DNS with BIND9</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=30897"/>
		<updated>2025-09-12T13:54:05Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Blocking Ads */ Typo fix&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document shows how to configure a basic installation of the ISC DNS server, BIND9, for Alpine Linux. This is useful when you want to have a DNS server for your home or home office network. The instructions start with a basic caching, forwarding DNS server. It continues on with adding lookup zones for your LAN hosts. Finally, it gives a peek at setting up ad blocking. You can work through as much or as little as you like depending on your DNS needs.&lt;br /&gt;
&lt;br /&gt;
It should be noted, this document focuses on quick deployment and ease of use for a &#039;&#039;trusted network behind a firewall&#039;&#039;. Do not deploy this configuration on a host that allows DNS queries from the internet.&lt;br /&gt;
&lt;br /&gt;
== Install the Package ==&lt;br /&gt;
&lt;br /&gt;
The usual Alpine apk installation method can be used to install bind9. This will install the named DNS server as well as nslookup and other utilities.&lt;br /&gt;
&lt;br /&gt;
 # apk update&lt;br /&gt;
 # apk add bind&lt;br /&gt;
&lt;br /&gt;
== Configure as a Forwarding DNS Server ==&lt;br /&gt;
&lt;br /&gt;
When configured as a forwarding server, the local DNS server will cache the results of query replies. Queries not found in cache are forwarded to a public DNS server (or your ISP).&lt;br /&gt;
&lt;br /&gt;
The example below uses public DNS servers 1.1.1.1 and 8.8.8.8. You may substitute your ISP’s DNS servers or any other trusted DNS server.&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; named.conf&lt;br /&gt;
 &lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     allow-query { any; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 };&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
After writing the configuration, run named-checkconf to verify it’s correct. Fix any errors before moving on.&lt;br /&gt;
&lt;br /&gt;
=== Start the DNS Server ===&lt;br /&gt;
&lt;br /&gt;
 # service named start&lt;br /&gt;
 # rc-update add named&lt;br /&gt;
&lt;br /&gt;
=== Test Queries Locally ===&lt;br /&gt;
&lt;br /&gt;
First, run nslookup on your Alpine host and set the server to your Alpine host’s IP address. Then, query some internet DNS name and IP addresses. You should see IP addresses and domain names in the reply.&lt;br /&gt;
&lt;br /&gt;
If you see an error, like &#039;&#039;** server can’t find example.com: NXDOMAIN&#039;&#039;, check the configuration in named.conf.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; 1.1.1.1&lt;br /&gt;
 1.1.1.1.in-addr.arpa    name = one.one.one.one.&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you’ll want to configure your host’s /etc/resolv.conf to use its own IP address for DNS lookups.&lt;br /&gt;
&lt;br /&gt;
=== Test Queries from a LAN Client ===&lt;br /&gt;
&lt;br /&gt;
Repeat the test, but from another machine on your network. Be sure to use the Alpine host’s IP address for the nslookup server.&lt;br /&gt;
&lt;br /&gt;
If you see an error like &#039;&#039;*** [192.168.1.100] can’t find example.com: Query refused&#039;&#039;, check your named.conf. Verify there is a line for &#039;&#039;recursion yes;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Here’s a sample of a successful test on a Windows client.&lt;br /&gt;
&lt;br /&gt;
 C:\&amp;gt; nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:  [192.168.1.100]&lt;br /&gt;
 Address:  192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:    example.com&lt;br /&gt;
 Addresses:  2600:1406:bc00:53::b81e:94ce&lt;br /&gt;
           23.215.0.136&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you can configure your DHCP server to use the Alpine host’s IP address for primary DNS.&lt;br /&gt;
&lt;br /&gt;
== Optionally Add LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
So far, only well-known internet hosts are able to be queried. Sometimes it’s useful to have hosts on your own network be available in DNS as well. This requires setting up a zone file.&lt;br /&gt;
&lt;br /&gt;
Creatig a zone file is a little more complex than the configuration thus far, but not insurmountable. There are many examples of zone files to be found on the internet, including [https://bind9.readthedocs.io/en/latest/chapter3.html#example-com-base-zone-file the BIND9 documentation], [https://en.wikipedia.org/wiki/Zone_file#Example_file a Wikipedia article], and [https://wiki.alpinelinux.org/wiki/Setting_up_nsd_DNS_server#Configure another Alpine Wiki DNS howto]. All these can be used as references.&lt;br /&gt;
&lt;br /&gt;
=== Create the Zone File ===&lt;br /&gt;
&lt;br /&gt;
The example below is for a simple home network using the reserved private top-level domain name of &#039;&#039;.home&#039;&#039;. The top half of the file contains details about the domain itself. The bottom half is where individual hosts and their addresses are listed. You will need to adjust names and IP addresses for your network configuration.&lt;br /&gt;
&lt;br /&gt;
 # mkdir /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # chown named /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/bind/zones/home&lt;br /&gt;
 &lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Be sure to check the file using named-checkzone and fix any errors before continuing. The positional parameters are &#039;&#039;zone name&#039;&#039; and &#039;&#039;file name&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
 # named-checkzone home /etc/bind/zone/home&lt;br /&gt;
 zone home/IN: loaded serial 1&lt;br /&gt;
 OK&lt;br /&gt;
&lt;br /&gt;
If you do encounter errors in the output, there is a line number included that will help you track it down.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone File in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Edit /etc/bind/named.conf and append the following lines:&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;home&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/home&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Validate the configuration with the command: named-checkconf. Fix any errors before continuing.&lt;br /&gt;
&lt;br /&gt;
=== Inform the DNS Server of the New Configuration ===&lt;br /&gt;
&lt;br /&gt;
Use the usual Alpine service command to reload the configuration.&lt;br /&gt;
&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
If there are errors, use the named-checkconf and named-checkzone commands to help narrow down the cause.&lt;br /&gt;
&lt;br /&gt;
=== Do Some Test Queries ===&lt;br /&gt;
&lt;br /&gt;
As a final check, revisit the tests using nslookup that were used to verify the forwarding DNS server. This time, in addition to looking up internet hosts, try some queries for the hosts in your zone file.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; router.home&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Name:   router.home&lt;br /&gt;
 Address: 192.168.1.1&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
== Add Zones for localhost ==&lt;br /&gt;
&lt;br /&gt;
To make the configuration complete, there should be a zone for the localhost name so the DNS server will return the familiar 127.0.0.1 address when queried. The DNS server should also respond with &#039;&#039;localhost&#039;&#039; when queried for the IP address &#039;&#039;127.0.0.1&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The process for creating the forward lookup zone is the same as is was for creating the &#039;&#039;home&#039;&#039; zone. What’s new in this step is the concept of reverse lookup zones. This is simply the DNS server returning a name when asked about an IP address.&lt;br /&gt;
&lt;br /&gt;
Here are the steps:&lt;br /&gt;
# Create the zone file&lt;br /&gt;
# Reference the zone in named.conf&lt;br /&gt;
# Reload the configuration&lt;br /&gt;
&lt;br /&gt;
Don’t forget to test with named-checkzone, named-checkconf, and nslookup as you go.&lt;br /&gt;
&lt;br /&gt;
=== Create the Forward Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The zone file for localhost is fairly simple, with only one A record. An example is show below. Create a new file with the path /etc/bind/zones/localhost and copy the contents of the example into it.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 @       IN  A     127.0.0.1&lt;br /&gt;
&lt;br /&gt;
=== Create the Reverse Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The reverse lookup zone file is nearly the same as the forward lookup, but has a PTR record instead of an A record on the last line. Create a new file with the path /etc/bind/zones/1.0.0.127.in-addr.arpa and copy the contents from below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 1       IN  PTR   localhost.     &lt;br /&gt;
&lt;br /&gt;
The rather strange looking naming convention of the file (and the zone itself) is simply the IP address of the reverse zone with its octets in reverse order and the suffix .in-addr.arpa tacked on the end. You can actually name it whatever you want provided it matches the configuration in named.conf. Some examples will use localhost.rev for the reverse lookup filename.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone Files in named.conf ===&lt;br /&gt;
&lt;br /&gt;
After checking the new zone files with named-checkzone, append a reference to them in the named.conf file. The configuration to be added is shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;localhost&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/localhost&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 zone &amp;quot;1.0.0.127.in-addr.arpa&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/1.0.0.127.in-addr.arpa&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
If named-checkconf does not raise any errors, the next step is to reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
== Reverse Lookup Zone for LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
If you created a zone file for hosts on your local network, you should create a reverse lookup zone for completeness. The process is very similar to the creation of the localhost reverse lookup zone. A shortcut method is to copy the forward lookup zone file to a new filename of the IP of your LAN and then replace the A records with their corresponding PTR records.&lt;br /&gt;
&lt;br /&gt;
Following the example given in the forward lookup, the reverse zone would look like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
&lt;br /&gt;
=== On-Going Maintenance of LAN Hosts ===&lt;br /&gt;
&lt;br /&gt;
When using DNS for your own network’s hosts, there are a few steps to keep in mind when you add or remove hosts.&lt;br /&gt;
&lt;br /&gt;
# Increment the serial number on the zone file.&lt;br /&gt;
# Test the zone file with named-checkzone&lt;br /&gt;
# Test the configuration with named-checkconf&lt;br /&gt;
# Reload the named service to make the changes active.&lt;br /&gt;
&lt;br /&gt;
== Blocking Ads ==&lt;br /&gt;
&lt;br /&gt;
The Response Policy Zone (RPZ) feature of BIND9 makes it easy to block access to an unwanted domain by returning a domain not found response instead of an IP address. Three steps are required to get this working.&lt;br /&gt;
&lt;br /&gt;
# Enable the RPZ feature in the options section of named.conf&lt;br /&gt;
# Create a zone file lising unwanted domains.&lt;br /&gt;
# Reference the zone file in named.conf&lt;br /&gt;
&lt;br /&gt;
=== Enable RPZ in named.conf options ===&lt;br /&gt;
&lt;br /&gt;
Below is the options section of named.conf used in all the examples so far, but with the addition of response policy zones. New lines for RPZ appear following the &#039;&#039;recursion yes;&#039;&#039; directive. The remainder of named.conf has been omitted for brevity.&lt;br /&gt;
&lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 &lt;br /&gt;
     response-policy {&lt;br /&gt;
         zone &amp;quot;rpz&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After making the changes, run named-checkconf to ensure there are no problems with the file.&lt;br /&gt;
&lt;br /&gt;
=== Create an RPZ File ===&lt;br /&gt;
&lt;br /&gt;
The RPZ zone file looks a lot like a regular zone file. One way to create it quickly is to start by copying the localhost zone file and then appending the hosts to be blocked.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cp localhost rpz&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt;&amp;gt; rpz&lt;br /&gt;
 example.com    CNAME .&lt;br /&gt;
 *.example.com  CNAME .&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
The CNAME . record instructs BIND9 to return an NXDOMAIN (domain not found) response when the listed domain is queried. You probably wont want to block example.com, but it works well for demonstration purposes.&lt;br /&gt;
&lt;br /&gt;
Check the file for errors by running named-checkzone rpz /etc/bind/zone/rpz and fix any errors before moving on to the next step.&lt;br /&gt;
&lt;br /&gt;
=== Reference the RPZ file in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Just like the instructions for adding localhost and LAN host zones, adding the RPZ zone file involves appending a few lines to named.conf and running named-checkconf before reloading the service.&lt;br /&gt;
&lt;br /&gt;
The format for a new zone should be familiar by now. It looks like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;rpz&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/rpz&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After appending this to named.conf, be sure to run named-checkconf. Then reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
=== Test RPZ Blocking ===&lt;br /&gt;
&lt;br /&gt;
To test, use nslookup just like before when testing the forwarding configuration, LAN hosts, etc. Except this time, you’re hoping to see an error message.&lt;br /&gt;
&lt;br /&gt;
Below an example showing the successful configuration to block example.com.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 ** server can&#039;t find example.com: NXDOMAIN&lt;br /&gt;
&lt;br /&gt;
Continue testing with some other domains that should be allowed just to make sure it’s being blocked by the RPZ policy and not because the server is misconfigured.&lt;br /&gt;
&lt;br /&gt;
=== Maintaining the RPZ File ===&lt;br /&gt;
&lt;br /&gt;
Manually adding blocked domains to the RPZ zone file can quickly become tedious, but with this simple test involving example.com, you can see how it’s done. There are some folks on the internet who curate and maintain blocklists. One such source is https://github.com/hagezi/dns-blocklists&lt;br /&gt;
&lt;br /&gt;
To use an ad blocking RPZ you’ll want to perform the following steps:&lt;br /&gt;
&lt;br /&gt;
# Download the file from the source location.&lt;br /&gt;
# Check the file’s validity with named-checkzone&lt;br /&gt;
# Replace the existing /etc/bind/zones/rpz file with the downloaded one.&lt;br /&gt;
# Reload the configuration by running service named reload&lt;br /&gt;
&lt;br /&gt;
New ad domains pop up all the time. The trick is automating the download of new block lists when they come out. A shell script like the one below can help.&lt;br /&gt;
&lt;br /&gt;
 #! /bin/sh&lt;br /&gt;
 &lt;br /&gt;
 cd /etc/bind/zones || exit 1&lt;br /&gt;
 curl -Os https://raw.githubusercontent.com/hagezi/dns-blocklists/main/rpz/multi.txt || exit 2&lt;br /&gt;
 named-checkzone rpz ./multi.txt || exit 3&lt;br /&gt;
 cp rpz rpz~&lt;br /&gt;
 mv multi.txt rpz&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
== Next Steps ==&lt;br /&gt;
&lt;br /&gt;
This document has taken you through the basics of setting up BIND9 on your Alpine server. There are many more features that haven’t been covered. Some of the interesting ones include:&lt;br /&gt;
&lt;br /&gt;
* Wildcard subdomains&lt;br /&gt;
* IPv6 domains&lt;br /&gt;
* Secondary DNS servers&lt;br /&gt;
* DNSSEC&lt;br /&gt;
&lt;br /&gt;
Whichever you choose to pursue is up to you. See the [https://bind9.readthedocs.io BIND9 documentation] for more information.&lt;br /&gt;
[[Category:Networking]]&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=29201</id>
		<title>Small-Time DNS with BIND9</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=29201"/>
		<updated>2025-03-07T00:46:48Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Configure as a Forwarding DNS Server */ allow queries from anywhere after recent versions of BIND9 now block by default&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document shows how to configure a basic installation of the ISC DNS server, BIND9, for Alpine Linux. This is useful when you want to have a DNS server for your home or home office network. The instructions start with a basic caching, forwarding DNS server. It continues on with adding lookup zones for your LAN hosts. Finally, it gives a peek at setting up ad blocking. You can work through as much or as little as you like depending on your DNS needs.&lt;br /&gt;
&lt;br /&gt;
It should be noted, this document focuses on quick deployment and ease of use for a &#039;&#039;trusted network behind a firewall&#039;&#039;. Do not deploy this configuration on a host that allows DNS queries from the internet.&lt;br /&gt;
&lt;br /&gt;
== Install the Package ==&lt;br /&gt;
&lt;br /&gt;
The usual Alpine apk installation method can be used to install bind9. This will install the named DNS server as well as nslookup and other utilities.&lt;br /&gt;
&lt;br /&gt;
 # apk update&lt;br /&gt;
 # apk add bind&lt;br /&gt;
&lt;br /&gt;
== Configure as a Forwarding DNS Server ==&lt;br /&gt;
&lt;br /&gt;
When configured as a forwarding server, the local DNS server will cache the results of query replies. Queries not found in cache are forwarded to a public DNS server (or your ISP).&lt;br /&gt;
&lt;br /&gt;
The example below uses public DNS servers 1.1.1.1 and 8.8.8.8. You may substitute your ISP’s DNS servers or any other trusted DNS server.&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; named.conf&lt;br /&gt;
 &lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     allow-query { any; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 };&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
After writing the configuration, run named-checkconf to verify it’s correct. Fix any errors before moving on.&lt;br /&gt;
&lt;br /&gt;
=== Start the DNS Server ===&lt;br /&gt;
&lt;br /&gt;
 # service named start&lt;br /&gt;
 # rc-update add named&lt;br /&gt;
&lt;br /&gt;
=== Test Queries Locally ===&lt;br /&gt;
&lt;br /&gt;
First, run nslookup on your Alpine host and set the server to your Alpine host’s IP address. Then, query some internet DNS name and IP addresses. You should see IP addresses and domain names in the reply.&lt;br /&gt;
&lt;br /&gt;
If you see an error, like &#039;&#039;** server can’t find example.com: NXDOMAIN&#039;&#039;, check the configuration in named.conf.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; 1.1.1.1&lt;br /&gt;
 1.1.1.1.in-addr.arpa    name = one.one.one.one.&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you’ll want to configure your host’s /etc/resolv.conf to use its own IP address for DNS lookups.&lt;br /&gt;
&lt;br /&gt;
=== Test Queries from a LAN Client ===&lt;br /&gt;
&lt;br /&gt;
Repeat the test, but from another machine on your network. Be sure to use the Alpine host’s IP address for the nslookup server.&lt;br /&gt;
&lt;br /&gt;
If you see an error like &#039;&#039;*** [192.168.1.100] can’t find example.com: Query refused&#039;&#039;, check your named.conf. Verify there is a line for &#039;&#039;recursion yes;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Here’s a sample of a successful test on a Windows client.&lt;br /&gt;
&lt;br /&gt;
 C:\&amp;gt; nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:  [192.168.1.100]&lt;br /&gt;
 Address:  192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:    example.com&lt;br /&gt;
 Addresses:  2600:1406:bc00:53::b81e:94ce&lt;br /&gt;
           23.215.0.136&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you can configure your DHCP server to use the Alpine host’s IP address for primary DNS.&lt;br /&gt;
&lt;br /&gt;
== Optionally Add LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
So far, only well-known internet hosts are able to be queried. Sometimes it’s useful to have hosts on your own network be available in DNS as well. This requires setting up a zone file.&lt;br /&gt;
&lt;br /&gt;
Creatig a zone file is a little more complex than the configuration thus far, but not insurmountable. There are many examples of zone files to be found on the internet, including [https://bind9.readthedocs.io/en/latest/chapter3.html#example-com-base-zone-file the BIND9 documentation], [https://en.wikipedia.org/wiki/Zone_file#Example_file a Wikipedia article], and [https://wiki.alpinelinux.org/wiki/Setting_up_nsd_DNS_server#Configure another Alpine Wiki DNS howto]. All these can be used as references.&lt;br /&gt;
&lt;br /&gt;
=== Create the Zone File ===&lt;br /&gt;
&lt;br /&gt;
The example below is for a simple home network using the reserved private top-level domain name of &#039;&#039;.home&#039;&#039;. The top half of the file contains details about the domain itself. The bottom half is where individual hosts and their addresses are listed. You will need to adjust names and IP addresses for your network configuration.&lt;br /&gt;
&lt;br /&gt;
 # mkdir /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # chown named /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/bind/zones/home&lt;br /&gt;
 &lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Be sure to check the file using named-checkzone and fix any errors before continuing. The positional parameters are &#039;&#039;zone name&#039;&#039; and &#039;&#039;file name&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
 # named-checkzone home /etc/bind/zone/home&lt;br /&gt;
 zone home/IN: loaded serial 1&lt;br /&gt;
 OK&lt;br /&gt;
&lt;br /&gt;
If you do encounter errors in the output, there is a line number included that will help you track it down.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone File in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Edit /etc/bind/named.conf and append the following lines:&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;home&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/home&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Validate the configuration with the command: named-checkconf. Fix any errors before continuing.&lt;br /&gt;
&lt;br /&gt;
=== Inform the DNS Server of the New Configuration ===&lt;br /&gt;
&lt;br /&gt;
Use the usual Alpine service command to reload the configuration.&lt;br /&gt;
&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
If there are errors, use the named-checkconf and named-checkzone commands to help narrow down the cause.&lt;br /&gt;
&lt;br /&gt;
=== Do Some Test Queries ===&lt;br /&gt;
&lt;br /&gt;
As a final check, revisit the tests using nslookup that were used to verify the forwarding DNS server. This time, in addition to looking up internet hosts, try some queries for the hosts in your zone file.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; router.home&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Name:   router.home&lt;br /&gt;
 Address: 192.168.1.1&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
== Add Zones for localhost ==&lt;br /&gt;
&lt;br /&gt;
To make the configuration complete, there should be a zone for the localhost name so the DNS server will return the familiar 127.0.0.1 address when queried. The DNS server should also respond with &#039;&#039;localhost&#039;&#039; when queried for the IP address &#039;&#039;127.0.0.1&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The process for creating the forward lookup zone is the same as is was for creating the &#039;&#039;home&#039;&#039; zone. What’s new in this step is the concept of reverse lookup zones. This is simply the DNS server returning a name when asked about an IP address.&lt;br /&gt;
&lt;br /&gt;
Here are the steps:&lt;br /&gt;
# Create the zone file&lt;br /&gt;
# Reference the zone in named.conf&lt;br /&gt;
# Reload the configuration&lt;br /&gt;
&lt;br /&gt;
Don’t forget to test with named-checkzone, named-checkconf, and nslookup as you go.&lt;br /&gt;
&lt;br /&gt;
=== Create the Forward Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The zone file for localhost is fairly simple, with only one A record. An example is show below. Create a new file with the path /etc/bind/zones/localhost and copy the contents of the example into it.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 @       IN  A     127.0.0.1&lt;br /&gt;
&lt;br /&gt;
=== Create the Reverse Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The reverse lookup zone file is nearly the same as the forward lookup, but has a PTR record instead of an A record on the last line. Create a new file with the path /etc/bind/zones/1.0.0.127.in-addr.arpa and copy the contents from below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 1       IN  PTR   localhost.     &lt;br /&gt;
&lt;br /&gt;
The rather strange looking naming convention of the file (and the zone itself) is simply the IP address of the reverse zone with its octets in reverse order and the suffix .in-addr.arpa tacked on the end. You can actually name it whatever you want provided it matches the configuration in named.conf. Some examples will use localhost.rev for the reverse lookup filename.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone Files in named.conf ===&lt;br /&gt;
&lt;br /&gt;
After checking the new zone files with named-checkzone, append a reference to them in the named.conf file. The configuration to be added is shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;localhost&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/localhost&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 zone &amp;quot;1.0.0.127.in-addr.arpa&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/1.0.0.127.in-addr.arpa&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
If named-checkconf does not raise any errors, the next step is to reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
== Reverse Lookup Zone for LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
If you created a zone file for hosts on your local network, you should create a reverse lookup zone for completeness. The process is very similar to the creation of the localhost reverse lookup zone. A shortcut method is to copy the forward lookup zone file to a new filename of the IP of your LAN and then replace the A records with their corresponding PTR records.&lt;br /&gt;
&lt;br /&gt;
Following the example given in the forward lookup, the reverse zone would look like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
&lt;br /&gt;
=== On-Going Maintenance of LAN Hosts ===&lt;br /&gt;
&lt;br /&gt;
When using DNS for your own network’s hosts, there are a few steps to keep in mind when you add or remove hosts.&lt;br /&gt;
&lt;br /&gt;
# Increment the serial number on the zone file.&lt;br /&gt;
# Test the zone file with named-checkzone&lt;br /&gt;
# Test the configuration with named-checkconf&lt;br /&gt;
# Reload the named service to make the changes active.&lt;br /&gt;
&lt;br /&gt;
== Blocking Ads ==&lt;br /&gt;
&lt;br /&gt;
The Response Policy Zone (RPZ) feature of BIND9 makes it easy to block access to an unwanted domain by returning a domain not found response instead of an IP address. Three steps are required to get this working.&lt;br /&gt;
&lt;br /&gt;
# Enable to RPZ feature in the options section of named.conf&lt;br /&gt;
# Create a zone file lising unwanted domains.&lt;br /&gt;
# Reference the zone file in named.conf&lt;br /&gt;
&lt;br /&gt;
=== Enable RPZ in named.conf options ===&lt;br /&gt;
&lt;br /&gt;
Below is the options section of named.conf used in all the examples so far, but with the addition of response policy zones. New lines for RPZ appear following the &#039;&#039;recursion yes;&#039;&#039; directive. The remainder of named.conf has been omitted for brevity.&lt;br /&gt;
&lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 &lt;br /&gt;
     response-policy {&lt;br /&gt;
         zone &amp;quot;rpz&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After making the changes, run named-checkconf to ensure there are no problems with the file.&lt;br /&gt;
&lt;br /&gt;
=== Create an RPZ File ===&lt;br /&gt;
&lt;br /&gt;
The RPZ zone file looks a lot like a regular zone file. One way to create it quickly is to start by copying the localhost zone file and then appending the hosts to be blocked.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cp localhost rpz&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt;&amp;gt; rpz&lt;br /&gt;
 example.com    CNAME .&lt;br /&gt;
 *.example.com  CNAME .&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
The CNAME . record instructs BIND9 to return an NXDOMAIN (domain not found) response when the listed domain is queried. You probably wont want to block example.com, but it works well for demonstration purposes.&lt;br /&gt;
&lt;br /&gt;
Check the file for errors by running named-checkzone rpz /etc/bind/zone/rpz and fix any errors before moving on to the next step.&lt;br /&gt;
&lt;br /&gt;
=== Reference the RPZ file in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Just like the instructions for adding localhost and LAN host zones, adding the RPZ zone file involves appending a few lines to named.conf and running named-checkconf before reloading the service.&lt;br /&gt;
&lt;br /&gt;
The format for a new zone should be familiar by now. It looks like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;rpz&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/rpz&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After appending this to named.conf, be sure to run named-checkconf. Then reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
=== Test RPZ Blocking ===&lt;br /&gt;
&lt;br /&gt;
To test, use nslookup just like before when testing the forwarding configuration, LAN hosts, etc. Except this time, you’re hoping to see an error message.&lt;br /&gt;
&lt;br /&gt;
Below an example showing the successful configuration to block example.com.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 ** server can&#039;t find example.com: NXDOMAIN&lt;br /&gt;
&lt;br /&gt;
Continue testing with some other domains that should be allowed just to make sure it’s being blocked by the RPZ policy and not because the server is misconfigured.&lt;br /&gt;
&lt;br /&gt;
=== Maintaining the RPZ File ===&lt;br /&gt;
&lt;br /&gt;
Manually adding blocked domains to the RPZ zone file can quickly become tedious, but with this simple test involving example.com, you can see how it’s done. There are some folks on the internet who curate and maintain blocklists. One such source is https://github.com/hagezi/dns-blocklists&lt;br /&gt;
&lt;br /&gt;
To use an ad blocking RPZ you’ll want to perform the following steps:&lt;br /&gt;
&lt;br /&gt;
# Download the file from the source location.&lt;br /&gt;
# Check the file’s validity with named-checkzone&lt;br /&gt;
# Replace the existing /etc/bind/zones/rpz file with the downloaded one.&lt;br /&gt;
# Reload the configuration by running service named reload&lt;br /&gt;
&lt;br /&gt;
New ad domains pop up all the time. The trick is automating the download of new block lists when they come out. A shell script like the one below can help.&lt;br /&gt;
&lt;br /&gt;
 #! /bin/sh&lt;br /&gt;
 &lt;br /&gt;
 cd /etc/bind/zones || exit 1&lt;br /&gt;
 curl -Os https://raw.githubusercontent.com/hagezi/dns-blocklists/main/rpz/multi.txt || exit 2&lt;br /&gt;
 named-checkzone rpz ./multi.txt || exit 3&lt;br /&gt;
 cp rpz rpz~&lt;br /&gt;
 mv multi.txt rpz&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
== Next Steps ==&lt;br /&gt;
&lt;br /&gt;
This document has taken you through the basics of setting up BIND9 on your Alpine server. There are many more features that haven’t been covered. Some of the interesting ones include:&lt;br /&gt;
&lt;br /&gt;
* Wildcard subdomains&lt;br /&gt;
* IPv6 domains&lt;br /&gt;
* Secondary DNS servers&lt;br /&gt;
* DNSSEC&lt;br /&gt;
&lt;br /&gt;
Whichever you choose to pursue is up to you. See the [https://bind9.readthedocs.io BIND9 documentation] for more information.&lt;br /&gt;
[[Category:Networking]]&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28980</id>
		<title>Small-Time DNS with BIND9</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28980"/>
		<updated>2025-02-10T17:24:33Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Maintaining the RPZ File */ Stop script from failing on first run&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document shows how to configure a basic installation of the ISC DNS server, BIND9, for Alpine Linux. This is useful when you want to have a DNS server for your home or home office network. The instructions start with a basic caching, forwarding DNS server. It continues on with adding lookup zones for your LAN hosts. Finally, it gives a peek at setting up ad blocking. You can work through as much or as little as you like depending on your DNS needs.&lt;br /&gt;
&lt;br /&gt;
It should be noted, this document focuses on quick deployment and ease of use for a &#039;&#039;trusted network behind a firewall&#039;&#039;. Do not deploy this configuration on a host that allows DNS queries from the internet.&lt;br /&gt;
&lt;br /&gt;
== Install the Package ==&lt;br /&gt;
&lt;br /&gt;
The usual Alpine apk installation method can be used to install bind9. This will install the named DNS server as well as nslookup and other utilities.&lt;br /&gt;
&lt;br /&gt;
 # apk update&lt;br /&gt;
 # apk add bind&lt;br /&gt;
&lt;br /&gt;
== Configure as a Forwarding DNS Server ==&lt;br /&gt;
&lt;br /&gt;
When configured as a forwarding server, the local DNS server will cache the results of query replies. Queries not found in cache are forwarded to a public DNS server (or your ISP).&lt;br /&gt;
&lt;br /&gt;
The example below uses public DNS servers 1.1.1.1 and 8.8.8.8. You may substitute your ISP’s DNS servers or any other trusted DNS server.&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; named.conf&lt;br /&gt;
 &lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 };&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
After writing the configuration, run named-checkconf to verify it’s correct. Fix any errors before moving on.&lt;br /&gt;
&lt;br /&gt;
=== Start the DNS Server ===&lt;br /&gt;
&lt;br /&gt;
 # service named start&lt;br /&gt;
 # rc-update add named&lt;br /&gt;
&lt;br /&gt;
=== Test Queries Locally ===&lt;br /&gt;
&lt;br /&gt;
First, run nslookup on your Alpine host and set the server to your Alpine host’s IP address. Then, query some internet DNS name and IP addresses. You should see IP addresses and domain names in the reply.&lt;br /&gt;
&lt;br /&gt;
If you see an error, like &#039;&#039;** server can’t find example.com: NXDOMAIN&#039;&#039;, check the configuration in named.conf.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; 1.1.1.1&lt;br /&gt;
 1.1.1.1.in-addr.arpa    name = one.one.one.one.&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you’ll want to configure your host’s /etc/resolv.conf to use its own IP address for DNS lookups.&lt;br /&gt;
&lt;br /&gt;
=== Test Queries from a LAN Client ===&lt;br /&gt;
&lt;br /&gt;
Repeat the test, but from another machine on your network. Be sure to use the Alpine host’s IP address for the nslookup server.&lt;br /&gt;
&lt;br /&gt;
If you see an error like &#039;&#039;*** [192.168.1.100] can’t find example.com: Query refused&#039;&#039;, check your named.conf. Verify there is a line for &#039;&#039;recursion yes;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Here’s a sample of a successful test on a Windows client.&lt;br /&gt;
&lt;br /&gt;
 C:\&amp;gt; nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:  [192.168.1.100]&lt;br /&gt;
 Address:  192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:    example.com&lt;br /&gt;
 Addresses:  2600:1406:bc00:53::b81e:94ce&lt;br /&gt;
           23.215.0.136&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you can configure your DHCP server to use the Alpine host’s IP address for primary DNS.&lt;br /&gt;
&lt;br /&gt;
== Optionally Add LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
So far, only well-known internet hosts are able to be queried. Sometimes it’s useful to have hosts on your own network be available in DNS as well. This requires setting up a zone file.&lt;br /&gt;
&lt;br /&gt;
Creatig a zone file is a little more complex than the configuration thus far, but not insurmountable. There are many examples of zone files to be found on the internet, including [https://bind9.readthedocs.io/en/latest/chapter3.html#example-com-base-zone-file the BIND9 documentation], [https://en.wikipedia.org/wiki/Zone_file#Example_file a Wikipedia article], and [https://wiki.alpinelinux.org/wiki/Setting_up_nsd_DNS_server#Configure another Alpine Wiki DNS howto]. All these can be used as references.&lt;br /&gt;
&lt;br /&gt;
=== Create the Zone File ===&lt;br /&gt;
&lt;br /&gt;
The example below is for a simple home network using the reserved private top-level domain name of &#039;&#039;.home&#039;&#039;. The top half of the file contains details about the domain itself. The bottom half is where individual hosts and their addresses are listed. You will need to adjust names and IP addresses for your network configuration.&lt;br /&gt;
&lt;br /&gt;
 # mkdir /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # chown named /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/bind/zones/home&lt;br /&gt;
 &lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Be sure to check the file using named-checkzone and fix any errors before continuing. The positional parameters are &#039;&#039;zone name&#039;&#039; and &#039;&#039;file name&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
 # named-checkzone home /etc/bind/zone/home&lt;br /&gt;
 zone home/IN: loaded serial 1&lt;br /&gt;
 OK&lt;br /&gt;
&lt;br /&gt;
If you do encounter errors in the output, there is a line number included that will help you track it down.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone File in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Edit /etc/bind/named.conf and append the following lines:&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;home&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/home&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Validate the configuration with the command: named-checkconf. Fix any errors before continuing.&lt;br /&gt;
&lt;br /&gt;
=== Inform the DNS Server of the New Configuration ===&lt;br /&gt;
&lt;br /&gt;
Use the usual Alpine service command to reload the configuration.&lt;br /&gt;
&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
If there are errors, use the named-checkconf and named-checkzone commands to help narrow down the cause.&lt;br /&gt;
&lt;br /&gt;
=== Do Some Test Queries ===&lt;br /&gt;
&lt;br /&gt;
As a final check, revisit the tests using nslookup that were used to verify the forwarding DNS server. This time, in addition to looking up internet hosts, try some queries for the hosts in your zone file.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; router.home&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Name:   router.home&lt;br /&gt;
 Address: 192.168.1.1&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
== Add Zones for localhost ==&lt;br /&gt;
&lt;br /&gt;
To make the configuration complete, there should be a zone for the localhost name so the DNS server will return the familiar 127.0.0.1 address when queried. The DNS server should also respond with &#039;&#039;localhost&#039;&#039; when queried for the IP address &#039;&#039;127.0.0.1&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The process for creating the forward lookup zone is the same as is was for creating the &#039;&#039;home&#039;&#039; zone. What’s new in this step is the concept of reverse lookup zones. This is simply the DNS server returning a name when asked about an IP address.&lt;br /&gt;
&lt;br /&gt;
Here are the steps:&lt;br /&gt;
# Create the zone file&lt;br /&gt;
# Reference the zone in named.conf&lt;br /&gt;
# Reload the configuration&lt;br /&gt;
&lt;br /&gt;
Don’t forget to test with named-checkzone, named-checkconf, and nslookup as you go.&lt;br /&gt;
&lt;br /&gt;
=== Create the Forward Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The zone file for localhost is fairly simple, with only one A record. An example is show below. Create a new file with the path /etc/bind/zones/localhost and copy the contents of the example into it.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 @       IN  A     127.0.0.1&lt;br /&gt;
&lt;br /&gt;
=== Create the Reverse Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The reverse lookup zone file is nearly the same as the forward lookup, but has a PTR record instead of an A record on the last line. Create a new file with the path /etc/bind/zones/1.0.0.127.in-addr.arpa and copy the contents from below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 1       IN  PTR   localhost.     &lt;br /&gt;
&lt;br /&gt;
The rather strange looking naming convention of the file (and the zone itself) is simply the IP address of the reverse zone with its octets in reverse order and the suffix .in-addr.arpa tacked on the end. You can actually name it whatever you want provided it matches the configuration in named.conf. Some examples will use localhost.rev for the reverse lookup filename.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone Files in named.conf ===&lt;br /&gt;
&lt;br /&gt;
After checking the new zone files with named-checkzone, append a reference to them in the named.conf file. The configuration to be added is shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;localhost&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/localhost&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 zone &amp;quot;1.0.0.127.in-addr.arpa&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/1.0.0.127.in-addr.arpa&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
If named-checkconf does not raise any errors, the next step is to reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
== Reverse Lookup Zone for LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
If you created a zone file for hosts on your local network, you should create a reverse lookup zone for completeness. The process is very similar to the creation of the localhost reverse lookup zone. A shortcut method is to copy the forward lookup zone file to a new filename of the IP of your LAN and then replace the A records with their corresponding PTR records.&lt;br /&gt;
&lt;br /&gt;
Following the example given in the forward lookup, the reverse zone would look like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
&lt;br /&gt;
=== On-Going Maintenance of LAN Hosts ===&lt;br /&gt;
&lt;br /&gt;
When using DNS for your own network’s hosts, there are a few steps to keep in mind when you add or remove hosts.&lt;br /&gt;
&lt;br /&gt;
# Increment the serial number on the zone file.&lt;br /&gt;
# Test the zone file with named-checkzone&lt;br /&gt;
# Test the configuration with named-checkconf&lt;br /&gt;
# Reload the named service to make the changes active.&lt;br /&gt;
&lt;br /&gt;
== Blocking Ads ==&lt;br /&gt;
&lt;br /&gt;
The Response Policy Zone (RPZ) feature of BIND9 makes it easy to block access to an unwanted domain by returning a domain not found response instead of an IP address. Three steps are required to get this working.&lt;br /&gt;
&lt;br /&gt;
# Enable to RPZ feature in the options section of named.conf&lt;br /&gt;
# Create a zone file lising unwanted domains.&lt;br /&gt;
# Reference the zone file in named.conf&lt;br /&gt;
&lt;br /&gt;
=== Enable RPZ in named.conf options ===&lt;br /&gt;
&lt;br /&gt;
Below is the options section of named.conf used in all the examples so far, but with the addition of response policy zones. New lines for RPZ appear following the &#039;&#039;recursion yes;&#039;&#039; directive. The remainder of named.conf has been omitted for brevity.&lt;br /&gt;
&lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 &lt;br /&gt;
     response-policy {&lt;br /&gt;
         zone &amp;quot;rpz&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After making the changes, run named-checkconf to ensure there are no problems with the file.&lt;br /&gt;
&lt;br /&gt;
=== Create an RPZ File ===&lt;br /&gt;
&lt;br /&gt;
The RPZ zone file looks a lot like a regular zone file. One way to create it quickly is to start by copying the localhost zone file and then appending the hosts to be blocked.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cp localhost rpz&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt;&amp;gt; rpz&lt;br /&gt;
 example.com    CNAME .&lt;br /&gt;
 *.example.com  CNAME .&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
The CNAME . record instructs BIND9 to return an NXDOMAIN (domain not found) response when the listed domain is queried. You probably wont want to block example.com, but it works well for demonstration purposes.&lt;br /&gt;
&lt;br /&gt;
Check the file for errors by running named-checkzone rpz /etc/bind/zone/rpz and fix any errors before moving on to the next step.&lt;br /&gt;
&lt;br /&gt;
=== Reference the RPZ file in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Just like the instructions for adding localhost and LAN host zones, adding the RPZ zone file involves appending a few lines to named.conf and running named-checkconf before reloading the service.&lt;br /&gt;
&lt;br /&gt;
The format for a new zone should be familiar by now. It looks like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;rpz&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/rpz&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After appending this to named.conf, be sure to run named-checkconf. Then reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
=== Test RPZ Blocking ===&lt;br /&gt;
&lt;br /&gt;
To test, use nslookup just like before when testing the forwarding configuration, LAN hosts, etc. Except this time, you’re hoping to see an error message.&lt;br /&gt;
&lt;br /&gt;
Below an example showing the successful configuration to block example.com.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 ** server can&#039;t find example.com: NXDOMAIN&lt;br /&gt;
&lt;br /&gt;
Continue testing with some other domains that should be allowed just to make sure it’s being blocked by the RPZ policy and not because the server is misconfigured.&lt;br /&gt;
&lt;br /&gt;
=== Maintaining the RPZ File ===&lt;br /&gt;
&lt;br /&gt;
Manually adding blocked domains to the RPZ zone file can quickly become tedious, but with this simple test involving example.com, you can see how it’s done. There are some folks on the internet who curate and maintain blocklists. One such source is https://github.com/hagezi/dns-blocklists&lt;br /&gt;
&lt;br /&gt;
To use an ad blocking RPZ you’ll want to perform the following steps:&lt;br /&gt;
&lt;br /&gt;
# Download the file from the source location.&lt;br /&gt;
# Check the file’s validity with named-checkzone&lt;br /&gt;
# Replace the existing /etc/bind/zones/rpz file with the downloaded one.&lt;br /&gt;
# Reload the configuration by running service named reload&lt;br /&gt;
&lt;br /&gt;
New ad domains pop up all the time. The trick is automating the download of new block lists when they come out. A shell script like the one below can help.&lt;br /&gt;
&lt;br /&gt;
 #! /bin/sh&lt;br /&gt;
 &lt;br /&gt;
 cd /etc/bind/zones || exit 1&lt;br /&gt;
 curl -Os https://raw.githubusercontent.com/hagezi/dns-blocklists/main/rpz/multi.txt || exit 2&lt;br /&gt;
 named-checkzone rpz ./multi.txt || exit 3&lt;br /&gt;
 cp rpz rpz~&lt;br /&gt;
 mv multi.txt rpz&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
== Next Steps ==&lt;br /&gt;
&lt;br /&gt;
This document has taken you through the basics of setting up BIND9 on your Alpine server. There are many more features that haven’t been covered. Some of the interesting ones include:&lt;br /&gt;
&lt;br /&gt;
* Wildcard subdomains&lt;br /&gt;
* IPv6 domains&lt;br /&gt;
* Secondary DNS servers&lt;br /&gt;
* DNSSEC&lt;br /&gt;
&lt;br /&gt;
Whichever you choose to pursue is up to you. See the [https://bind9.readthedocs.io BIND9 documentation] for more information.&lt;br /&gt;
[[Category:Networking]]&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28916</id>
		<title>Small-Time DNS with BIND9</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28916"/>
		<updated>2025-02-03T19:53:47Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Next Steps */ Removed encryption. DNSSEC is not actually encryption, it&amp;#039;s cryptographic signing.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document shows how to configure a basic installation of the ISC DNS server, BIND9, for Alpine Linux. This is useful when you want to have a DNS server for your home or home office network. The instructions start with a basic caching, forwarding DNS server. It continues on with adding lookup zones for your LAN hosts. Finally, it gives a peek at setting up ad blocking. You can work through as much or as little as you like depending on your DNS needs.&lt;br /&gt;
&lt;br /&gt;
It should be noted, this document focuses on quick deployment and ease of use for a &#039;&#039;trusted network behind a firewall&#039;&#039;. Do not deploy this configuration on a host that allows DNS queries from the internet.&lt;br /&gt;
&lt;br /&gt;
== Install the Package ==&lt;br /&gt;
&lt;br /&gt;
The usual Alpine apk installation method can be used to install bind9. This will install the named DNS server as well as nslookup and other utilities.&lt;br /&gt;
&lt;br /&gt;
 # apk update&lt;br /&gt;
 # apk add bind&lt;br /&gt;
&lt;br /&gt;
== Configure as a Forwarding DNS Server ==&lt;br /&gt;
&lt;br /&gt;
When configured as a forwarding server, the local DNS server will cache the results of query replies. Queries not found in cache are forwarded to a public DNS server (or your ISP).&lt;br /&gt;
&lt;br /&gt;
The example below uses public DNS servers 1.1.1.1 and 8.8.8.8. You may substitute your ISP’s DNS servers or any other trusted DNS server.&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; named.conf&lt;br /&gt;
 &lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 };&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
After writing the configuration, run named-checkconf to verify it’s correct. Fix any errors before moving on.&lt;br /&gt;
&lt;br /&gt;
=== Start the DNS Server ===&lt;br /&gt;
&lt;br /&gt;
 # service named start&lt;br /&gt;
 # rc-update add named&lt;br /&gt;
&lt;br /&gt;
=== Test Queries Locally ===&lt;br /&gt;
&lt;br /&gt;
First, run nslookup on your Alpine host and set the server to your Alpine host’s IP address. Then, query some internet DNS name and IP addresses. You should see IP addresses and domain names in the reply.&lt;br /&gt;
&lt;br /&gt;
If you see an error, like &#039;&#039;** server can’t find example.com: NXDOMAIN&#039;&#039;, check the configuration in named.conf.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; 1.1.1.1&lt;br /&gt;
 1.1.1.1.in-addr.arpa    name = one.one.one.one.&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you’ll want to configure your host’s /etc/resolv.conf to use its own IP address for DNS lookups.&lt;br /&gt;
&lt;br /&gt;
=== Test Queries from a LAN Client ===&lt;br /&gt;
&lt;br /&gt;
Repeat the test, but from another machine on your network. Be sure to use the Alpine host’s IP address for the nslookup server.&lt;br /&gt;
&lt;br /&gt;
If you see an error like &#039;&#039;*** [192.168.1.100] can’t find example.com: Query refused&#039;&#039;, check your named.conf. Verify there is a line for &#039;&#039;recursion yes;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Here’s a sample of a successful test on a Windows client.&lt;br /&gt;
&lt;br /&gt;
 C:\&amp;gt; nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:  [192.168.1.100]&lt;br /&gt;
 Address:  192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:    example.com&lt;br /&gt;
 Addresses:  2600:1406:bc00:53::b81e:94ce&lt;br /&gt;
           23.215.0.136&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you can configure your DHCP server to use the Alpine host’s IP address for primary DNS.&lt;br /&gt;
&lt;br /&gt;
== Optionally Add LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
So far, only well-known internet hosts are able to be queried. Sometimes it’s useful to have hosts on your own network be available in DNS as well. This requires setting up a zone file.&lt;br /&gt;
&lt;br /&gt;
Creatig a zone file is a little more complex than the configuration thus far, but not insurmountable. There are many examples of zone files to be found on the internet, including [https://bind9.readthedocs.io/en/latest/chapter3.html#example-com-base-zone-file the BIND9 documentation], [https://en.wikipedia.org/wiki/Zone_file#Example_file a Wikipedia article], and [https://wiki.alpinelinux.org/wiki/Setting_up_nsd_DNS_server#Configure another Alpine Wiki DNS howto]. All these can be used as references.&lt;br /&gt;
&lt;br /&gt;
=== Create the Zone File ===&lt;br /&gt;
&lt;br /&gt;
The example below is for a simple home network using the reserved private top-level domain name of &#039;&#039;.home&#039;&#039;. The top half of the file contains details about the domain itself. The bottom half is where individual hosts and their addresses are listed. You will need to adjust names and IP addresses for your network configuration.&lt;br /&gt;
&lt;br /&gt;
 # mkdir /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # chown named /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/bind/zones/home&lt;br /&gt;
 &lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Be sure to check the file using named-checkzone and fix any errors before continuing. The positional parameters are &#039;&#039;zone name&#039;&#039; and &#039;&#039;file name&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
 # named-checkzone home /etc/bind/zone/home&lt;br /&gt;
 zone home/IN: loaded serial 1&lt;br /&gt;
 OK&lt;br /&gt;
&lt;br /&gt;
If you do encounter errors in the output, there is a line number included that will help you track it down.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone File in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Edit /etc/bind/named.conf and append the following lines:&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;home&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/home&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Validate the configuration with the command: named-checkconf. Fix any errors before continuing.&lt;br /&gt;
&lt;br /&gt;
=== Inform the DNS Server of the New Configuration ===&lt;br /&gt;
&lt;br /&gt;
Use the usual Alpine service command to reload the configuration.&lt;br /&gt;
&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
If there are errors, use the named-checkconf and named-checkzone commands to help narrow down the cause.&lt;br /&gt;
&lt;br /&gt;
=== Do Some Test Queries ===&lt;br /&gt;
&lt;br /&gt;
As a final check, revisit the tests using nslookup that were used to verify the forwarding DNS server. This time, in addition to looking up internet hosts, try some queries for the hosts in your zone file.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; router.home&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Name:   router.home&lt;br /&gt;
 Address: 192.168.1.1&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
== Add Zones for localhost ==&lt;br /&gt;
&lt;br /&gt;
To make the configuration complete, there should be a zone for the localhost name so the DNS server will return the familiar 127.0.0.1 address when queried. The DNS server should also respond with &#039;&#039;localhost&#039;&#039; when queried for the IP address &#039;&#039;127.0.0.1&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The process for creating the forward lookup zone is the same as is was for creating the &#039;&#039;home&#039;&#039; zone. What’s new in this step is the concept of reverse lookup zones. This is simply the DNS server returning a name when asked about an IP address.&lt;br /&gt;
&lt;br /&gt;
Here are the steps:&lt;br /&gt;
# Create the zone file&lt;br /&gt;
# Reference the zone in named.conf&lt;br /&gt;
# Reload the configuration&lt;br /&gt;
&lt;br /&gt;
Don’t forget to test with named-checkzone, named-checkconf, and nslookup as you go.&lt;br /&gt;
&lt;br /&gt;
=== Create the Forward Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The zone file for localhost is fairly simple, with only one A record. An example is show below. Create a new file with the path /etc/bind/zones/localhost and copy the contents of the example into it.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 @       IN  A     127.0.0.1&lt;br /&gt;
&lt;br /&gt;
=== Create the Reverse Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The reverse lookup zone file is nearly the same as the forward lookup, but has a PTR record instead of an A record on the last line. Create a new file with the path /etc/bind/zones/1.0.0.127.in-addr.arpa and copy the contents from below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 1       IN  PTR   localhost.     &lt;br /&gt;
&lt;br /&gt;
The rather strange looking naming convention of the file (and the zone itself) is simply the IP address of the reverse zone with its octets in reverse order and the suffix .in-addr.arpa tacked on the end. You can actually name it whatever you want provided it matches the configuration in named.conf. Some examples will use localhost.rev for the reverse lookup filename.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone Files in named.conf ===&lt;br /&gt;
&lt;br /&gt;
After checking the new zone files with named-checkzone, append a reference to them in the named.conf file. The configuration to be added is shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;localhost&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/localhost&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 zone &amp;quot;1.0.0.127.in-addr.arpa&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/1.0.0.127.in-addr.arpa&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
If named-checkconf does not raise any errors, the next step is to reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
== Reverse Lookup Zone for LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
If you created a zone file for hosts on your local network, you should create a reverse lookup zone for completeness. The process is very similar to the creation of the localhost reverse lookup zone. A shortcut method is to copy the forward lookup zone file to a new filename of the IP of your LAN and then replace the A records with their corresponding PTR records.&lt;br /&gt;
&lt;br /&gt;
Following the example given in the forward lookup, the reverse zone would look like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
&lt;br /&gt;
=== On-Going Maintenance of LAN Hosts ===&lt;br /&gt;
&lt;br /&gt;
When using DNS for your own network’s hosts, there are a few steps to keep in mind when you add or remove hosts.&lt;br /&gt;
&lt;br /&gt;
# Increment the serial number on the zone file.&lt;br /&gt;
# Test the zone file with named-checkzone&lt;br /&gt;
# Test the configuration with named-checkconf&lt;br /&gt;
# Reload the named service to make the changes active.&lt;br /&gt;
&lt;br /&gt;
== Blocking Ads ==&lt;br /&gt;
&lt;br /&gt;
The Response Policy Zone (RPZ) feature of BIND9 makes it easy to block access to an unwanted domain by returning a domain not found response instead of an IP address. Three steps are required to get this working.&lt;br /&gt;
&lt;br /&gt;
# Enable to RPZ feature in the options section of named.conf&lt;br /&gt;
# Create a zone file lising unwanted domains.&lt;br /&gt;
# Reference the zone file in named.conf&lt;br /&gt;
&lt;br /&gt;
=== Enable RPZ in named.conf options ===&lt;br /&gt;
&lt;br /&gt;
Below is the options section of named.conf used in all the examples so far, but with the addition of response policy zones. New lines for RPZ appear following the &#039;&#039;recursion yes;&#039;&#039; directive. The remainder of named.conf has been omitted for brevity.&lt;br /&gt;
&lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 &lt;br /&gt;
     response-policy {&lt;br /&gt;
         zone &amp;quot;rpz&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After making the changes, run named-checkconf to ensure there are no problems with the file.&lt;br /&gt;
&lt;br /&gt;
=== Create an RPZ File ===&lt;br /&gt;
&lt;br /&gt;
The RPZ zone file looks a lot like a regular zone file. One way to create it quickly is to start by copying the localhost zone file and then appending the hosts to be blocked.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cp localhost rpz&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt;&amp;gt; rpz&lt;br /&gt;
 example.com    CNAME .&lt;br /&gt;
 *.example.com  CNAME .&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
The CNAME . record instructs BIND9 to return an NXDOMAIN (domain not found) response when the listed domain is queried. You probably wont want to block example.com, but it works well for demonstration purposes.&lt;br /&gt;
&lt;br /&gt;
Check the file for errors by running named-checkzone rpz /etc/bind/zone/rpz and fix any errors before moving on to the next step.&lt;br /&gt;
&lt;br /&gt;
=== Reference the RPZ file in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Just like the instructions for adding localhost and LAN host zones, adding the RPZ zone file involves appending a few lines to named.conf and running named-checkconf before reloading the service.&lt;br /&gt;
&lt;br /&gt;
The format for a new zone should be familiar by now. It looks like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;rpz&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/rpz&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After appending this to named.conf, be sure to run named-checkconf. Then reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
=== Test RPZ Blocking ===&lt;br /&gt;
&lt;br /&gt;
To test, use nslookup just like before when testing the forwarding configuration, LAN hosts, etc. Except this time, you’re hoping to see an error message.&lt;br /&gt;
&lt;br /&gt;
Below an example showing the successful configuration to block example.com.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 ** server can&#039;t find example.com: NXDOMAIN&lt;br /&gt;
&lt;br /&gt;
Continue testing with some other domains that should be allowed just to make sure it’s being blocked by the RPZ policy and not because the server is misconfigured.&lt;br /&gt;
&lt;br /&gt;
=== Maintaining the RPZ File ===&lt;br /&gt;
&lt;br /&gt;
Manually adding blocked domains to the RPZ zone file can quickly become tedious, but with this simple test involving example.com, you can see how it’s done. There are some folks on the internet who curate and maintain blocklists. One such source is https://github.com/hagezi/dns-blocklists&lt;br /&gt;
&lt;br /&gt;
To use an ad blocking RPZ you’ll want to perform the following steps:&lt;br /&gt;
&lt;br /&gt;
# Download the file from the source location.&lt;br /&gt;
# Check the file’s validity with named-checkzone&lt;br /&gt;
# Replace the existing /etc/bind/zones/rpz file with the downloaded one.&lt;br /&gt;
# Reload the configuration by running service named reload&lt;br /&gt;
&lt;br /&gt;
New ad domains pop up all the time. The trick is automating the download of new block lists when they come out. A shell script like the one below can help.&lt;br /&gt;
&lt;br /&gt;
 #! /bin/sh&lt;br /&gt;
 &lt;br /&gt;
 cd /etc/bind/zones || exit 1&lt;br /&gt;
 curl -Os https://raw.githubusercontent.com/hagezi/dns-blocklists/main/rpz/multi.txt || exit 2&lt;br /&gt;
 named-checkzone rpz ./multi.txt || exit 3&lt;br /&gt;
 cp rpz rpz~ &amp;amp;&amp;amp; mv multi.txt rpz&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
== Next Steps ==&lt;br /&gt;
&lt;br /&gt;
This document has taken you through the basics of setting up BIND9 on your Alpine server. There are many more features that haven’t been covered. Some of the interesting ones include:&lt;br /&gt;
&lt;br /&gt;
* Wildcard subdomains&lt;br /&gt;
* IPv6 domains&lt;br /&gt;
* Secondary DNS servers&lt;br /&gt;
* DNSSEC&lt;br /&gt;
&lt;br /&gt;
Whichever you choose to pursue is up to you. See the [https://bind9.readthedocs.io BIND9 documentation] for more information.&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28915</id>
		<title>Small-Time DNS with BIND9</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28915"/>
		<updated>2025-02-03T18:42:10Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Create the Zone File */ Remove uninteded line break&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document shows how to configure a basic installation of the ISC DNS server, BIND9, for Alpine Linux. This is useful when you want to have a DNS server for your home or home office network. The instructions start with a basic caching, forwarding DNS server. It continues on with adding lookup zones for your LAN hosts. Finally, it gives a peek at setting up ad blocking. You can work through as much or as little as you like depending on your DNS needs.&lt;br /&gt;
&lt;br /&gt;
It should be noted, this document focuses on quick deployment and ease of use for a &#039;&#039;trusted network behind a firewall&#039;&#039;. Do not deploy this configuration on a host that allows DNS queries from the internet.&lt;br /&gt;
&lt;br /&gt;
== Install the Package ==&lt;br /&gt;
&lt;br /&gt;
The usual Alpine apk installation method can be used to install bind9. This will install the named DNS server as well as nslookup and other utilities.&lt;br /&gt;
&lt;br /&gt;
 # apk update&lt;br /&gt;
 # apk add bind&lt;br /&gt;
&lt;br /&gt;
== Configure as a Forwarding DNS Server ==&lt;br /&gt;
&lt;br /&gt;
When configured as a forwarding server, the local DNS server will cache the results of query replies. Queries not found in cache are forwarded to a public DNS server (or your ISP).&lt;br /&gt;
&lt;br /&gt;
The example below uses public DNS servers 1.1.1.1 and 8.8.8.8. You may substitute your ISP’s DNS servers or any other trusted DNS server.&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; named.conf&lt;br /&gt;
 &lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 };&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
After writing the configuration, run named-checkconf to verify it’s correct. Fix any errors before moving on.&lt;br /&gt;
&lt;br /&gt;
=== Start the DNS Server ===&lt;br /&gt;
&lt;br /&gt;
 # service named start&lt;br /&gt;
 # rc-update add named&lt;br /&gt;
&lt;br /&gt;
=== Test Queries Locally ===&lt;br /&gt;
&lt;br /&gt;
First, run nslookup on your Alpine host and set the server to your Alpine host’s IP address. Then, query some internet DNS name and IP addresses. You should see IP addresses and domain names in the reply.&lt;br /&gt;
&lt;br /&gt;
If you see an error, like &#039;&#039;** server can’t find example.com: NXDOMAIN&#039;&#039;, check the configuration in named.conf.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; 1.1.1.1&lt;br /&gt;
 1.1.1.1.in-addr.arpa    name = one.one.one.one.&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you’ll want to configure your host’s /etc/resolv.conf to use its own IP address for DNS lookups.&lt;br /&gt;
&lt;br /&gt;
=== Test Queries from a LAN Client ===&lt;br /&gt;
&lt;br /&gt;
Repeat the test, but from another machine on your network. Be sure to use the Alpine host’s IP address for the nslookup server.&lt;br /&gt;
&lt;br /&gt;
If you see an error like &#039;&#039;*** [192.168.1.100] can’t find example.com: Query refused&#039;&#039;, check your named.conf. Verify there is a line for &#039;&#039;recursion yes;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Here’s a sample of a successful test on a Windows client.&lt;br /&gt;
&lt;br /&gt;
 C:\&amp;gt; nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:  [192.168.1.100]&lt;br /&gt;
 Address:  192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:    example.com&lt;br /&gt;
 Addresses:  2600:1406:bc00:53::b81e:94ce&lt;br /&gt;
           23.215.0.136&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you can configure your DHCP server to use the Alpine host’s IP address for primary DNS.&lt;br /&gt;
&lt;br /&gt;
== Optionally Add LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
So far, only well-known internet hosts are able to be queried. Sometimes it’s useful to have hosts on your own network be available in DNS as well. This requires setting up a zone file.&lt;br /&gt;
&lt;br /&gt;
Creatig a zone file is a little more complex than the configuration thus far, but not insurmountable. There are many examples of zone files to be found on the internet, including [https://bind9.readthedocs.io/en/latest/chapter3.html#example-com-base-zone-file the BIND9 documentation], [https://en.wikipedia.org/wiki/Zone_file#Example_file a Wikipedia article], and [https://wiki.alpinelinux.org/wiki/Setting_up_nsd_DNS_server#Configure another Alpine Wiki DNS howto]. All these can be used as references.&lt;br /&gt;
&lt;br /&gt;
=== Create the Zone File ===&lt;br /&gt;
&lt;br /&gt;
The example below is for a simple home network using the reserved private top-level domain name of &#039;&#039;.home&#039;&#039;. The top half of the file contains details about the domain itself. The bottom half is where individual hosts and their addresses are listed. You will need to adjust names and IP addresses for your network configuration.&lt;br /&gt;
&lt;br /&gt;
 # mkdir /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # chown named /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/bind/zones/home&lt;br /&gt;
 &lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Be sure to check the file using named-checkzone and fix any errors before continuing. The positional parameters are &#039;&#039;zone name&#039;&#039; and &#039;&#039;file name&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
 # named-checkzone home /etc/bind/zone/home&lt;br /&gt;
 zone home/IN: loaded serial 1&lt;br /&gt;
 OK&lt;br /&gt;
&lt;br /&gt;
If you do encounter errors in the output, there is a line number included that will help you track it down.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone File in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Edit /etc/bind/named.conf and append the following lines:&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;home&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/home&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Validate the configuration with the command: named-checkconf. Fix any errors before continuing.&lt;br /&gt;
&lt;br /&gt;
=== Inform the DNS Server of the New Configuration ===&lt;br /&gt;
&lt;br /&gt;
Use the usual Alpine service command to reload the configuration.&lt;br /&gt;
&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
If there are errors, use the named-checkconf and named-checkzone commands to help narrow down the cause.&lt;br /&gt;
&lt;br /&gt;
=== Do Some Test Queries ===&lt;br /&gt;
&lt;br /&gt;
As a final check, revisit the tests using nslookup that were used to verify the forwarding DNS server. This time, in addition to looking up internet hosts, try some queries for the hosts in your zone file.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; router.home&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Name:   router.home&lt;br /&gt;
 Address: 192.168.1.1&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
== Add Zones for localhost ==&lt;br /&gt;
&lt;br /&gt;
To make the configuration complete, there should be a zone for the localhost name so the DNS server will return the familiar 127.0.0.1 address when queried. The DNS server should also respond with &#039;&#039;localhost&#039;&#039; when queried for the IP address &#039;&#039;127.0.0.1&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The process for creating the forward lookup zone is the same as is was for creating the &#039;&#039;home&#039;&#039; zone. What’s new in this step is the concept of reverse lookup zones. This is simply the DNS server returning a name when asked about an IP address.&lt;br /&gt;
&lt;br /&gt;
Here are the steps:&lt;br /&gt;
# Create the zone file&lt;br /&gt;
# Reference the zone in named.conf&lt;br /&gt;
# Reload the configuration&lt;br /&gt;
&lt;br /&gt;
Don’t forget to test with named-checkzone, named-checkconf, and nslookup as you go.&lt;br /&gt;
&lt;br /&gt;
=== Create the Forward Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The zone file for localhost is fairly simple, with only one A record. An example is show below. Create a new file with the path /etc/bind/zones/localhost and copy the contents of the example into it.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 @       IN  A     127.0.0.1&lt;br /&gt;
&lt;br /&gt;
=== Create the Reverse Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The reverse lookup zone file is nearly the same as the forward lookup, but has a PTR record instead of an A record on the last line. Create a new file with the path /etc/bind/zones/1.0.0.127.in-addr.arpa and copy the contents from below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 1       IN  PTR   localhost.     &lt;br /&gt;
&lt;br /&gt;
The rather strange looking naming convention of the file (and the zone itself) is simply the IP address of the reverse zone with its octets in reverse order and the suffix .in-addr.arpa tacked on the end. You can actually name it whatever you want provided it matches the configuration in named.conf. Some examples will use localhost.rev for the reverse lookup filename.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone Files in named.conf ===&lt;br /&gt;
&lt;br /&gt;
After checking the new zone files with named-checkzone, append a reference to them in the named.conf file. The configuration to be added is shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;localhost&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/localhost&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 zone &amp;quot;1.0.0.127.in-addr.arpa&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/1.0.0.127.in-addr.arpa&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
If named-checkconf does not raise any errors, the next step is to reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
== Reverse Lookup Zone for LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
If you created a zone file for hosts on your local network, you should create a reverse lookup zone for completeness. The process is very similar to the creation of the localhost reverse lookup zone. A shortcut method is to copy the forward lookup zone file to a new filename of the IP of your LAN and then replace the A records with their corresponding PTR records.&lt;br /&gt;
&lt;br /&gt;
Following the example given in the forward lookup, the reverse zone would look like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
&lt;br /&gt;
=== On-Going Maintenance of LAN Hosts ===&lt;br /&gt;
&lt;br /&gt;
When using DNS for your own network’s hosts, there are a few steps to keep in mind when you add or remove hosts.&lt;br /&gt;
&lt;br /&gt;
# Increment the serial number on the zone file.&lt;br /&gt;
# Test the zone file with named-checkzone&lt;br /&gt;
# Test the configuration with named-checkconf&lt;br /&gt;
# Reload the named service to make the changes active.&lt;br /&gt;
&lt;br /&gt;
== Blocking Ads ==&lt;br /&gt;
&lt;br /&gt;
The Response Policy Zone (RPZ) feature of BIND9 makes it easy to block access to an unwanted domain by returning a domain not found response instead of an IP address. Three steps are required to get this working.&lt;br /&gt;
&lt;br /&gt;
# Enable to RPZ feature in the options section of named.conf&lt;br /&gt;
# Create a zone file lising unwanted domains.&lt;br /&gt;
# Reference the zone file in named.conf&lt;br /&gt;
&lt;br /&gt;
=== Enable RPZ in named.conf options ===&lt;br /&gt;
&lt;br /&gt;
Below is the options section of named.conf used in all the examples so far, but with the addition of response policy zones. New lines for RPZ appear following the &#039;&#039;recursion yes;&#039;&#039; directive. The remainder of named.conf has been omitted for brevity.&lt;br /&gt;
&lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 &lt;br /&gt;
     response-policy {&lt;br /&gt;
         zone &amp;quot;rpz&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After making the changes, run named-checkconf to ensure there are no problems with the file.&lt;br /&gt;
&lt;br /&gt;
=== Create an RPZ File ===&lt;br /&gt;
&lt;br /&gt;
The RPZ zone file looks a lot like a regular zone file. One way to create it quickly is to start by copying the localhost zone file and then appending the hosts to be blocked.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cp localhost rpz&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt;&amp;gt; rpz&lt;br /&gt;
 example.com    CNAME .&lt;br /&gt;
 *.example.com  CNAME .&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
The CNAME . record instructs BIND9 to return an NXDOMAIN (domain not found) response when the listed domain is queried. You probably wont want to block example.com, but it works well for demonstration purposes.&lt;br /&gt;
&lt;br /&gt;
Check the file for errors by running named-checkzone rpz /etc/bind/zone/rpz and fix any errors before moving on to the next step.&lt;br /&gt;
&lt;br /&gt;
=== Reference the RPZ file in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Just like the instructions for adding localhost and LAN host zones, adding the RPZ zone file involves appending a few lines to named.conf and running named-checkconf before reloading the service.&lt;br /&gt;
&lt;br /&gt;
The format for a new zone should be familiar by now. It looks like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;rpz&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/rpz&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After appending this to named.conf, be sure to run named-checkconf. Then reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
=== Test RPZ Blocking ===&lt;br /&gt;
&lt;br /&gt;
To test, use nslookup just like before when testing the forwarding configuration, LAN hosts, etc. Except this time, you’re hoping to see an error message.&lt;br /&gt;
&lt;br /&gt;
Below an example showing the successful configuration to block example.com.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 ** server can&#039;t find example.com: NXDOMAIN&lt;br /&gt;
&lt;br /&gt;
Continue testing with some other domains that should be allowed just to make sure it’s being blocked by the RPZ policy and not because the server is misconfigured.&lt;br /&gt;
&lt;br /&gt;
=== Maintaining the RPZ File ===&lt;br /&gt;
&lt;br /&gt;
Manually adding blocked domains to the RPZ zone file can quickly become tedious, but with this simple test involving example.com, you can see how it’s done. There are some folks on the internet who curate and maintain blocklists. One such source is https://github.com/hagezi/dns-blocklists&lt;br /&gt;
&lt;br /&gt;
To use an ad blocking RPZ you’ll want to perform the following steps:&lt;br /&gt;
&lt;br /&gt;
# Download the file from the source location.&lt;br /&gt;
# Check the file’s validity with named-checkzone&lt;br /&gt;
# Replace the existing /etc/bind/zones/rpz file with the downloaded one.&lt;br /&gt;
# Reload the configuration by running service named reload&lt;br /&gt;
&lt;br /&gt;
New ad domains pop up all the time. The trick is automating the download of new block lists when they come out. A shell script like the one below can help.&lt;br /&gt;
&lt;br /&gt;
 #! /bin/sh&lt;br /&gt;
 &lt;br /&gt;
 cd /etc/bind/zones || exit 1&lt;br /&gt;
 curl -Os https://raw.githubusercontent.com/hagezi/dns-blocklists/main/rpz/multi.txt || exit 2&lt;br /&gt;
 named-checkzone rpz ./multi.txt || exit 3&lt;br /&gt;
 cp rpz rpz~ &amp;amp;&amp;amp; mv multi.txt rpz&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
== Next Steps ==&lt;br /&gt;
&lt;br /&gt;
This document has taken you through the basics of setting up BIND9 on your Alpine server. There are many more features that haven’t been covered. Some of the interesting ones include:&lt;br /&gt;
&lt;br /&gt;
* Wildcard subdomains&lt;br /&gt;
* IPv6 domains&lt;br /&gt;
* Secondary DNS servers&lt;br /&gt;
* DNSSEC encryption&lt;br /&gt;
&lt;br /&gt;
Whichever you choose to pursue is up to you. See the [https://bind9.readthedocs.io BIND9 documentation] for more information.&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28914</id>
		<title>Small-Time DNS with BIND9</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28914"/>
		<updated>2025-02-03T18:41:24Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* Create the Zone File */ Add step to fix dir ownership to allow automatic dnssec signing if desired&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document shows how to configure a basic installation of the ISC DNS server, BIND9, for Alpine Linux. This is useful when you want to have a DNS server for your home or home office network. The instructions start with a basic caching, forwarding DNS server. It continues on with adding lookup zones for your LAN hosts. Finally, it gives a peek at setting up ad blocking. You can work through as much or as little as you like depending on your DNS needs.&lt;br /&gt;
&lt;br /&gt;
It should be noted, this document focuses on quick deployment and ease of use for a &#039;&#039;trusted network behind a firewall&#039;&#039;. Do not deploy this configuration on a host that allows DNS queries from the internet.&lt;br /&gt;
&lt;br /&gt;
== Install the Package ==&lt;br /&gt;
&lt;br /&gt;
The usual Alpine apk installation method can be used to install bind9. This will install the named DNS server as well as nslookup and other utilities.&lt;br /&gt;
&lt;br /&gt;
 # apk update&lt;br /&gt;
 # apk add bind&lt;br /&gt;
&lt;br /&gt;
== Configure as a Forwarding DNS Server ==&lt;br /&gt;
&lt;br /&gt;
When configured as a forwarding server, the local DNS server will cache the results of query replies. Queries not found in cache are forwarded to a public DNS server (or your ISP).&lt;br /&gt;
&lt;br /&gt;
The example below uses public DNS servers 1.1.1.1 and 8.8.8.8. You may substitute your ISP’s DNS servers or any other trusted DNS server.&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; named.conf&lt;br /&gt;
 &lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 };&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
After writing the configuration, run named-checkconf to verify it’s correct. Fix any errors before moving on.&lt;br /&gt;
&lt;br /&gt;
=== Start the DNS Server ===&lt;br /&gt;
&lt;br /&gt;
 # service named start&lt;br /&gt;
 # rc-update add named&lt;br /&gt;
&lt;br /&gt;
=== Test Queries Locally ===&lt;br /&gt;
&lt;br /&gt;
First, run nslookup on your Alpine host and set the server to your Alpine host’s IP address. Then, query some internet DNS name and IP addresses. You should see IP addresses and domain names in the reply.&lt;br /&gt;
&lt;br /&gt;
If you see an error, like &#039;&#039;** server can’t find example.com: NXDOMAIN&#039;&#039;, check the configuration in named.conf.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; 1.1.1.1&lt;br /&gt;
 1.1.1.1.in-addr.arpa    name = one.one.one.one.&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you’ll want to configure your host’s /etc/resolv.conf to use its own IP address for DNS lookups.&lt;br /&gt;
&lt;br /&gt;
=== Test Queries from a LAN Client ===&lt;br /&gt;
&lt;br /&gt;
Repeat the test, but from another machine on your network. Be sure to use the Alpine host’s IP address for the nslookup server.&lt;br /&gt;
&lt;br /&gt;
If you see an error like &#039;&#039;*** [192.168.1.100] can’t find example.com: Query refused&#039;&#039;, check your named.conf. Verify there is a line for &#039;&#039;recursion yes;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Here’s a sample of a successful test on a Windows client.&lt;br /&gt;
&lt;br /&gt;
 C:\&amp;gt; nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:  [192.168.1.100]&lt;br /&gt;
 Address:  192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:    example.com&lt;br /&gt;
 Addresses:  2600:1406:bc00:53::b81e:94ce&lt;br /&gt;
           23.215.0.136&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you can configure your DHCP server to use the Alpine host’s IP address for primary DNS.&lt;br /&gt;
&lt;br /&gt;
== Optionally Add LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
So far, only well-known internet hosts are able to be queried. Sometimes it’s useful to have hosts on your own network be available in DNS as well. This requires setting up a zone file.&lt;br /&gt;
&lt;br /&gt;
Creatig a zone file is a little more complex than the configuration thus far, but not insurmountable. There are many examples of zone files to be found on the internet, including [https://bind9.readthedocs.io/en/latest/chapter3.html#example-com-base-zone-file the BIND9 documentation], [https://en.wikipedia.org/wiki/Zone_file#Example_file a Wikipedia article], and [https://wiki.alpinelinux.org/wiki/Setting_up_nsd_DNS_server#Configure another Alpine Wiki DNS howto]. All these can be used as references.&lt;br /&gt;
&lt;br /&gt;
=== Create the Zone File ===&lt;br /&gt;
&lt;br /&gt;
The example below is for a simple home network using the reserved private top-level domain name of &#039;&#039;.home&#039;&#039;. The top half of the file contains details about the domain itself. The bottom half is where individual hosts and their addresses are listed. You will need to adjust names and IP addresses for your network configuration.&lt;br /&gt;
&lt;br /&gt;
 # mkdir /etc/bind/zones&lt;br /&gt;
&lt;br /&gt;
 # chown named /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/bind/zones/home&lt;br /&gt;
 &lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Be sure to check the file using named-checkzone and fix any errors before continuing. The positional parameters are &#039;&#039;zone name&#039;&#039; and &#039;&#039;file name&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
 # named-checkzone home /etc/bind/zone/home&lt;br /&gt;
 zone home/IN: loaded serial 1&lt;br /&gt;
 OK&lt;br /&gt;
&lt;br /&gt;
If you do encounter errors in the output, there is a line number included that will help you track it down.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone File in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Edit /etc/bind/named.conf and append the following lines:&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;home&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/home&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Validate the configuration with the command: named-checkconf. Fix any errors before continuing.&lt;br /&gt;
&lt;br /&gt;
=== Inform the DNS Server of the New Configuration ===&lt;br /&gt;
&lt;br /&gt;
Use the usual Alpine service command to reload the configuration.&lt;br /&gt;
&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
If there are errors, use the named-checkconf and named-checkzone commands to help narrow down the cause.&lt;br /&gt;
&lt;br /&gt;
=== Do Some Test Queries ===&lt;br /&gt;
&lt;br /&gt;
As a final check, revisit the tests using nslookup that were used to verify the forwarding DNS server. This time, in addition to looking up internet hosts, try some queries for the hosts in your zone file.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; router.home&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Name:   router.home&lt;br /&gt;
 Address: 192.168.1.1&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
== Add Zones for localhost ==&lt;br /&gt;
&lt;br /&gt;
To make the configuration complete, there should be a zone for the localhost name so the DNS server will return the familiar 127.0.0.1 address when queried. The DNS server should also respond with &#039;&#039;localhost&#039;&#039; when queried for the IP address &#039;&#039;127.0.0.1&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The process for creating the forward lookup zone is the same as is was for creating the &#039;&#039;home&#039;&#039; zone. What’s new in this step is the concept of reverse lookup zones. This is simply the DNS server returning a name when asked about an IP address.&lt;br /&gt;
&lt;br /&gt;
Here are the steps:&lt;br /&gt;
# Create the zone file&lt;br /&gt;
# Reference the zone in named.conf&lt;br /&gt;
# Reload the configuration&lt;br /&gt;
&lt;br /&gt;
Don’t forget to test with named-checkzone, named-checkconf, and nslookup as you go.&lt;br /&gt;
&lt;br /&gt;
=== Create the Forward Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The zone file for localhost is fairly simple, with only one A record. An example is show below. Create a new file with the path /etc/bind/zones/localhost and copy the contents of the example into it.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 @       IN  A     127.0.0.1&lt;br /&gt;
&lt;br /&gt;
=== Create the Reverse Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The reverse lookup zone file is nearly the same as the forward lookup, but has a PTR record instead of an A record on the last line. Create a new file with the path /etc/bind/zones/1.0.0.127.in-addr.arpa and copy the contents from below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 1       IN  PTR   localhost.     &lt;br /&gt;
&lt;br /&gt;
The rather strange looking naming convention of the file (and the zone itself) is simply the IP address of the reverse zone with its octets in reverse order and the suffix .in-addr.arpa tacked on the end. You can actually name it whatever you want provided it matches the configuration in named.conf. Some examples will use localhost.rev for the reverse lookup filename.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone Files in named.conf ===&lt;br /&gt;
&lt;br /&gt;
After checking the new zone files with named-checkzone, append a reference to them in the named.conf file. The configuration to be added is shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;localhost&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/localhost&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 zone &amp;quot;1.0.0.127.in-addr.arpa&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/1.0.0.127.in-addr.arpa&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
If named-checkconf does not raise any errors, the next step is to reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
== Reverse Lookup Zone for LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
If you created a zone file for hosts on your local network, you should create a reverse lookup zone for completeness. The process is very similar to the creation of the localhost reverse lookup zone. A shortcut method is to copy the forward lookup zone file to a new filename of the IP of your LAN and then replace the A records with their corresponding PTR records.&lt;br /&gt;
&lt;br /&gt;
Following the example given in the forward lookup, the reverse zone would look like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
&lt;br /&gt;
=== On-Going Maintenance of LAN Hosts ===&lt;br /&gt;
&lt;br /&gt;
When using DNS for your own network’s hosts, there are a few steps to keep in mind when you add or remove hosts.&lt;br /&gt;
&lt;br /&gt;
# Increment the serial number on the zone file.&lt;br /&gt;
# Test the zone file with named-checkzone&lt;br /&gt;
# Test the configuration with named-checkconf&lt;br /&gt;
# Reload the named service to make the changes active.&lt;br /&gt;
&lt;br /&gt;
== Blocking Ads ==&lt;br /&gt;
&lt;br /&gt;
The Response Policy Zone (RPZ) feature of BIND9 makes it easy to block access to an unwanted domain by returning a domain not found response instead of an IP address. Three steps are required to get this working.&lt;br /&gt;
&lt;br /&gt;
# Enable to RPZ feature in the options section of named.conf&lt;br /&gt;
# Create a zone file lising unwanted domains.&lt;br /&gt;
# Reference the zone file in named.conf&lt;br /&gt;
&lt;br /&gt;
=== Enable RPZ in named.conf options ===&lt;br /&gt;
&lt;br /&gt;
Below is the options section of named.conf used in all the examples so far, but with the addition of response policy zones. New lines for RPZ appear following the &#039;&#039;recursion yes;&#039;&#039; directive. The remainder of named.conf has been omitted for brevity.&lt;br /&gt;
&lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 &lt;br /&gt;
     response-policy {&lt;br /&gt;
         zone &amp;quot;rpz&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After making the changes, run named-checkconf to ensure there are no problems with the file.&lt;br /&gt;
&lt;br /&gt;
=== Create an RPZ File ===&lt;br /&gt;
&lt;br /&gt;
The RPZ zone file looks a lot like a regular zone file. One way to create it quickly is to start by copying the localhost zone file and then appending the hosts to be blocked.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cp localhost rpz&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt;&amp;gt; rpz&lt;br /&gt;
 example.com    CNAME .&lt;br /&gt;
 *.example.com  CNAME .&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
The CNAME . record instructs BIND9 to return an NXDOMAIN (domain not found) response when the listed domain is queried. You probably wont want to block example.com, but it works well for demonstration purposes.&lt;br /&gt;
&lt;br /&gt;
Check the file for errors by running named-checkzone rpz /etc/bind/zone/rpz and fix any errors before moving on to the next step.&lt;br /&gt;
&lt;br /&gt;
=== Reference the RPZ file in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Just like the instructions for adding localhost and LAN host zones, adding the RPZ zone file involves appending a few lines to named.conf and running named-checkconf before reloading the service.&lt;br /&gt;
&lt;br /&gt;
The format for a new zone should be familiar by now. It looks like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;rpz&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/rpz&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After appending this to named.conf, be sure to run named-checkconf. Then reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
=== Test RPZ Blocking ===&lt;br /&gt;
&lt;br /&gt;
To test, use nslookup just like before when testing the forwarding configuration, LAN hosts, etc. Except this time, you’re hoping to see an error message.&lt;br /&gt;
&lt;br /&gt;
Below an example showing the successful configuration to block example.com.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 ** server can&#039;t find example.com: NXDOMAIN&lt;br /&gt;
&lt;br /&gt;
Continue testing with some other domains that should be allowed just to make sure it’s being blocked by the RPZ policy and not because the server is misconfigured.&lt;br /&gt;
&lt;br /&gt;
=== Maintaining the RPZ File ===&lt;br /&gt;
&lt;br /&gt;
Manually adding blocked domains to the RPZ zone file can quickly become tedious, but with this simple test involving example.com, you can see how it’s done. There are some folks on the internet who curate and maintain blocklists. One such source is https://github.com/hagezi/dns-blocklists&lt;br /&gt;
&lt;br /&gt;
To use an ad blocking RPZ you’ll want to perform the following steps:&lt;br /&gt;
&lt;br /&gt;
# Download the file from the source location.&lt;br /&gt;
# Check the file’s validity with named-checkzone&lt;br /&gt;
# Replace the existing /etc/bind/zones/rpz file with the downloaded one.&lt;br /&gt;
# Reload the configuration by running service named reload&lt;br /&gt;
&lt;br /&gt;
New ad domains pop up all the time. The trick is automating the download of new block lists when they come out. A shell script like the one below can help.&lt;br /&gt;
&lt;br /&gt;
 #! /bin/sh&lt;br /&gt;
 &lt;br /&gt;
 cd /etc/bind/zones || exit 1&lt;br /&gt;
 curl -Os https://raw.githubusercontent.com/hagezi/dns-blocklists/main/rpz/multi.txt || exit 2&lt;br /&gt;
 named-checkzone rpz ./multi.txt || exit 3&lt;br /&gt;
 cp rpz rpz~ &amp;amp;&amp;amp; mv multi.txt rpz&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
== Next Steps ==&lt;br /&gt;
&lt;br /&gt;
This document has taken you through the basics of setting up BIND9 on your Alpine server. There are many more features that haven’t been covered. Some of the interesting ones include:&lt;br /&gt;
&lt;br /&gt;
* Wildcard subdomains&lt;br /&gt;
* IPv6 domains&lt;br /&gt;
* Secondary DNS servers&lt;br /&gt;
* DNSSEC encryption&lt;br /&gt;
&lt;br /&gt;
Whichever you choose to pursue is up to you. See the [https://bind9.readthedocs.io BIND9 documentation] for more information.&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=User:DavesCodeMusings&amp;diff=28907</id>
		<title>User:DavesCodeMusings</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=User:DavesCodeMusings&amp;diff=28907"/>
		<updated>2025-02-03T02:07:11Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I&#039;ve been using Alpine for a few years as a lightweight OS on barebones NUC mini-PCs. My current approach is to run basic services like: email, DNS, LDAP, and system monitoring installed from APKs. Everything else runs in Docker containers. Whenever I figure out how to do something that takes more than a few commands, I tend to write it down. And since I&#039;m writing it down, I might as well share.&lt;br /&gt;
&lt;br /&gt;
I also like to do stuff with ESP microcontrollers and MicroPython. You can find more on that at my GitHub page https://davescodemusings.github.io/&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=User:DavesCodeMusings&amp;diff=28906</id>
		<title>User:DavesCodeMusings</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=User:DavesCodeMusings&amp;diff=28906"/>
		<updated>2025-02-02T23:00:24Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I&#039;ve been using Alpine for a few years as a lightweight OS on barebones NUC mini-PCs. My current approach is to run basic services like: email, DNS, LDAP, and system monitoring at the OS level. Everything else runs in Docker containers. Whenever I figure out how to do something that takes more than a few commands, I tend to write it down. And since I&#039;m writing it down, I might as well share.&lt;br /&gt;
&lt;br /&gt;
I also like to do stuff with ESP microcontrollers and MicroPython. You can find more on that at my GitHub page https://davescodemusings.github.io/&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=User:DavesCodeMusings&amp;diff=28905</id>
		<title>User:DavesCodeMusings</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=User:DavesCodeMusings&amp;diff=28905"/>
		<updated>2025-02-02T22:58:50Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: Created page with &amp;quot;I&amp;#039;ve been using Alpine for a few years as a lightweight OS on barebones NUC mini-PCs. My current approach is to run basic services like: email, DNS, LDAP, and system monitoring at the OS level. Everything else runs in Docker containers. Whenever I figure out how to do something that takes more than a few commands, I tend to write it down. And since I&amp;#039;m writing it down, I might as well share.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I&#039;ve been using Alpine for a few years as a lightweight OS on barebones NUC mini-PCs. My current approach is to run basic services like: email, DNS, LDAP, and system monitoring at the OS level. Everything else runs in Docker containers. Whenever I figure out how to do something that takes more than a few commands, I tend to write it down. And since I&#039;m writing it down, I might as well share.&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28904</id>
		<title>Small-Time DNS with BIND9</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28904"/>
		<updated>2025-02-02T17:35:49Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: Remove redundant title heading&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document shows how to configure a basic installation of the ISC DNS server, BIND9, for Alpine Linux. This is useful when you want to have a DNS server for your home or home office network. The instructions start with a basic caching, forwarding DNS server. It continues on with adding lookup zones for your LAN hosts. Finally, it gives a peek at setting up ad blocking. You can work through as much or as little as you like depending on your DNS needs.&lt;br /&gt;
&lt;br /&gt;
It should be noted, this document focuses on quick deployment and ease of use for a &#039;&#039;trusted network behind a firewall&#039;&#039;. Do not deploy this configuration on a host that allows DNS queries from the internet.&lt;br /&gt;
&lt;br /&gt;
== Install the Package ==&lt;br /&gt;
&lt;br /&gt;
The usual Alpine apk installation method can be used to install bind9. This will install the named DNS server as well as nslookup and other utilities.&lt;br /&gt;
&lt;br /&gt;
 # apk update&lt;br /&gt;
 # apk add bind&lt;br /&gt;
&lt;br /&gt;
== Configure as a Forwarding DNS Server ==&lt;br /&gt;
&lt;br /&gt;
When configured as a forwarding server, the local DNS server will cache the results of query replies. Queries not found in cache are forwarded to a public DNS server (or your ISP).&lt;br /&gt;
&lt;br /&gt;
The example below uses public DNS servers 1.1.1.1 and 8.8.8.8. You may substitute your ISP’s DNS servers or any other trusted DNS server.&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; named.conf&lt;br /&gt;
 &lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 };&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
After writing the configuration, run named-checkconf to verify it’s correct. Fix any errors before moving on.&lt;br /&gt;
&lt;br /&gt;
=== Start the DNS Server ===&lt;br /&gt;
&lt;br /&gt;
 # service named start&lt;br /&gt;
 # rc-update add named&lt;br /&gt;
&lt;br /&gt;
=== Test Queries Locally ===&lt;br /&gt;
&lt;br /&gt;
First, run nslookup on your Alpine host and set the server to your Alpine host’s IP address. Then, query some internet DNS name and IP addresses. You should see IP addresses and domain names in the reply.&lt;br /&gt;
&lt;br /&gt;
If you see an error, like &#039;&#039;** server can’t find example.com: NXDOMAIN&#039;&#039;, check the configuration in named.conf.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; 1.1.1.1&lt;br /&gt;
 1.1.1.1.in-addr.arpa    name = one.one.one.one.&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you’ll want to configure your host’s /etc/resolv.conf to use its own IP address for DNS lookups.&lt;br /&gt;
&lt;br /&gt;
=== Test Queries from a LAN Client ===&lt;br /&gt;
&lt;br /&gt;
Repeat the test, but from another machine on your network. Be sure to use the Alpine host’s IP address for the nslookup server.&lt;br /&gt;
&lt;br /&gt;
If you see an error like &#039;&#039;*** [192.168.1.100] can’t find example.com: Query refused&#039;&#039;, check your named.conf. Verify there is a line for &#039;&#039;recursion yes;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Here’s a sample of a successful test on a Windows client.&lt;br /&gt;
&lt;br /&gt;
 C:\&amp;gt; nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:  [192.168.1.100]&lt;br /&gt;
 Address:  192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:    example.com&lt;br /&gt;
 Addresses:  2600:1406:bc00:53::b81e:94ce&lt;br /&gt;
           23.215.0.136&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you can configure your DHCP server to use the Alpine host’s IP address for primary DNS.&lt;br /&gt;
&lt;br /&gt;
== Optionally Add LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
So far, only well-known internet hosts are able to be queried. Sometimes it’s useful to have hosts on your own network be available in DNS as well. This requires setting up a zone file.&lt;br /&gt;
&lt;br /&gt;
Creatig a zone file is a little more complex than the configuration thus far, but not insurmountable. There are many examples of zone files to be found on the internet, including [https://bind9.readthedocs.io/en/latest/chapter3.html#example-com-base-zone-file the BIND9 documentation], [https://en.wikipedia.org/wiki/Zone_file#Example_file a Wikipedia article], and [https://wiki.alpinelinux.org/wiki/Setting_up_nsd_DNS_server#Configure another Alpine Wiki DNS howto]. All these can be used as references.&lt;br /&gt;
&lt;br /&gt;
=== Create the Zone File ===&lt;br /&gt;
&lt;br /&gt;
The example below is for a simple home network using the reserved private top-level domain name of &#039;&#039;.home&#039;&#039;. The top half of the file contains details about the domain itself. The bottom half is where individual hosts and their addresses are listed. You will need to adjust names and IP addresses for your network configuration.&lt;br /&gt;
&lt;br /&gt;
 # mkdir /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/bind/zones/home&lt;br /&gt;
 &lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Be sure to check the file using named-checkzone and fix any errors before continuing. The positional parameters are &#039;&#039;zone name&#039;&#039; and &#039;&#039;file name&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
 # named-checkzone home /etc/bind/zone/home&lt;br /&gt;
 zone home/IN: loaded serial 1&lt;br /&gt;
 OK&lt;br /&gt;
&lt;br /&gt;
If you do encounter errors in the output, there is a line number included that will help you track it down.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone File in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Edit /etc/bind/named.conf and append the following lines:&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;home&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/home&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Validate the configuration with the command: named-checkconf. Fix any errors before continuing.&lt;br /&gt;
&lt;br /&gt;
=== Inform the DNS Server of the New Configuration ===&lt;br /&gt;
&lt;br /&gt;
Use the usual Alpine service command to reload the configuration.&lt;br /&gt;
&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
If there are errors, use the named-checkconf and named-checkzone commands to help narrow down the cause.&lt;br /&gt;
&lt;br /&gt;
=== Do Some Test Queries ===&lt;br /&gt;
&lt;br /&gt;
As a final check, revisit the tests using nslookup that were used to verify the forwarding DNS server. This time, in addition to looking up internet hosts, try some queries for the hosts in your zone file.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; router.home&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Name:   router.home&lt;br /&gt;
 Address: 192.168.1.1&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
== Add Zones for localhost ==&lt;br /&gt;
&lt;br /&gt;
To make the configuration complete, there should be a zone for the localhost name so the DNS server will return the familiar 127.0.0.1 address when queried. The DNS server should also respond with &#039;&#039;localhost&#039;&#039; when queried for the IP address &#039;&#039;127.0.0.1&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The process for creating the forward lookup zone is the same as is was for creating the &#039;&#039;home&#039;&#039; zone. What’s new in this step is the concept of reverse lookup zones. This is simply the DNS server returning a name when asked about an IP address.&lt;br /&gt;
&lt;br /&gt;
Here are the steps:&lt;br /&gt;
# Create the zone file&lt;br /&gt;
# Reference the zone in named.conf&lt;br /&gt;
# Reload the configuration&lt;br /&gt;
&lt;br /&gt;
Don’t forget to test with named-checkzone, named-checkconf, and nslookup as you go.&lt;br /&gt;
&lt;br /&gt;
=== Create the Forward Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The zone file for localhost is fairly simple, with only one A record. An example is show below. Create a new file with the path /etc/bind/zones/localhost and copy the contents of the example into it.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 @       IN  A     127.0.0.1&lt;br /&gt;
&lt;br /&gt;
=== Create the Reverse Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The reverse lookup zone file is nearly the same as the forward lookup, but has a PTR record instead of an A record on the last line. Create a new file with the path /etc/bind/zones/1.0.0.127.in-addr.arpa and copy the contents from below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 1       IN  PTR   localhost.     &lt;br /&gt;
&lt;br /&gt;
The rather strange looking naming convention of the file (and the zone itself) is simply the IP address of the reverse zone with its octets in reverse order and the suffix .in-addr.arpa tacked on the end. You can actually name it whatever you want provided it matches the configuration in named.conf. Some examples will use localhost.rev for the reverse lookup filename.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone Files in named.conf ===&lt;br /&gt;
&lt;br /&gt;
After checking the new zone files with named-checkzone, append a reference to them in the named.conf file. The configuration to be added is shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;localhost&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/localhost&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 zone &amp;quot;1.0.0.127.in-addr.arpa&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/1.0.0.127.in-addr.arpa&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
If named-checkconf does not raise any errors, the next step is to reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
== Reverse Lookup Zone for LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
If you created a zone file for hosts on your local network, you should create a reverse lookup zone for completeness. The process is very similar to the creation of the localhost reverse lookup zone. A shortcut method is to copy the forward lookup zone file to a new filename of the IP of your LAN and then replace the A records with their corresponding PTR records.&lt;br /&gt;
&lt;br /&gt;
Following the example given in the forward lookup, the reverse zone would look like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
&lt;br /&gt;
=== On-Going Maintenance of LAN Hosts ===&lt;br /&gt;
&lt;br /&gt;
When using DNS for your own network’s hosts, there are a few steps to keep in mind when you add or remove hosts.&lt;br /&gt;
&lt;br /&gt;
# Increment the serial number on the zone file.&lt;br /&gt;
# Test the zone file with named-checkzone&lt;br /&gt;
# Test the configuration with named-checkconf&lt;br /&gt;
# Reload the named service to make the changes active.&lt;br /&gt;
&lt;br /&gt;
== Blocking Ads ==&lt;br /&gt;
&lt;br /&gt;
The Response Policy Zone (RPZ) feature of BIND9 makes it easy to block access to an unwanted domain by returning a domain not found response instead of an IP address. Three steps are required to get this working.&lt;br /&gt;
&lt;br /&gt;
# Enable to RPZ feature in the options section of named.conf&lt;br /&gt;
# Create a zone file lising unwanted domains.&lt;br /&gt;
# Reference the zone file in named.conf&lt;br /&gt;
&lt;br /&gt;
=== Enable RPZ in named.conf options ===&lt;br /&gt;
&lt;br /&gt;
Below is the options section of named.conf used in all the examples so far, but with the addition of response policy zones. New lines for RPZ appear following the &#039;&#039;recursion yes;&#039;&#039; directive. The remainder of named.conf has been omitted for brevity.&lt;br /&gt;
&lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 &lt;br /&gt;
     response-policy {&lt;br /&gt;
         zone &amp;quot;rpz&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After making the changes, run named-checkconf to ensure there are no problems with the file.&lt;br /&gt;
&lt;br /&gt;
=== Create an RPZ File ===&lt;br /&gt;
&lt;br /&gt;
The RPZ zone file looks a lot like a regular zone file. One way to create it quickly is to start by copying the localhost zone file and then appending the hosts to be blocked.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cp localhost rpz&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt;&amp;gt; rpz&lt;br /&gt;
 example.com    CNAME .&lt;br /&gt;
 *.example.com  CNAME .&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
The CNAME . record instructs BIND9 to return an NXDOMAIN (domain not found) response when the listed domain is queried. You probably wont want to block example.com, but it works well for demonstration purposes.&lt;br /&gt;
&lt;br /&gt;
Check the file for errors by running named-checkzone rpz /etc/bind/zone/rpz and fix any errors before moving on to the next step.&lt;br /&gt;
&lt;br /&gt;
=== Reference the RPZ file in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Just like the instructions for adding localhost and LAN host zones, adding the RPZ zone file involves appending a few lines to named.conf and running named-checkconf before reloading the service.&lt;br /&gt;
&lt;br /&gt;
The format for a new zone should be familiar by now. It looks like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;rpz&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/rpz&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After appending this to named.conf, be sure to run named-checkconf. Then reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
=== Test RPZ Blocking ===&lt;br /&gt;
&lt;br /&gt;
To test, use nslookup just like before when testing the forwarding configuration, LAN hosts, etc. Except this time, you’re hoping to see an error message.&lt;br /&gt;
&lt;br /&gt;
Below an example showing the successful configuration to block example.com.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 ** server can&#039;t find example.com: NXDOMAIN&lt;br /&gt;
&lt;br /&gt;
Continue testing with some other domains that should be allowed just to make sure it’s being blocked by the RPZ policy and not because the server is misconfigured.&lt;br /&gt;
&lt;br /&gt;
=== Maintaining the RPZ File ===&lt;br /&gt;
&lt;br /&gt;
Manually adding blocked domains to the RPZ zone file can quickly become tedious, but with this simple test involving example.com, you can see how it’s done. There are some folks on the internet who curate and maintain blocklists. One such source is https://github.com/hagezi/dns-blocklists&lt;br /&gt;
&lt;br /&gt;
To use an ad blocking RPZ you’ll want to perform the following steps:&lt;br /&gt;
&lt;br /&gt;
# Download the file from the source location.&lt;br /&gt;
# Check the file’s validity with named-checkzone&lt;br /&gt;
# Replace the existing /etc/bind/zones/rpz file with the downloaded one.&lt;br /&gt;
# Reload the configuration by running service named reload&lt;br /&gt;
&lt;br /&gt;
New ad domains pop up all the time. The trick is automating the download of new block lists when they come out. A shell script like the one below can help.&lt;br /&gt;
&lt;br /&gt;
 #! /bin/sh&lt;br /&gt;
 &lt;br /&gt;
 cd /etc/bind/zones || exit 1&lt;br /&gt;
 curl -Os https://raw.githubusercontent.com/hagezi/dns-blocklists/main/rpz/multi.txt || exit 2&lt;br /&gt;
 named-checkzone rpz ./multi.txt || exit 3&lt;br /&gt;
 cp rpz rpz~ &amp;amp;&amp;amp; mv multi.txt rpz&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
== Next Steps ==&lt;br /&gt;
&lt;br /&gt;
This document has taken you through the basics of setting up BIND9 on your Alpine server. There are many more features that haven’t been covered. Some of the interesting ones include:&lt;br /&gt;
&lt;br /&gt;
* Wildcard subdomains&lt;br /&gt;
* IPv6 domains&lt;br /&gt;
* Secondary DNS servers&lt;br /&gt;
* DNSSEC encryption&lt;br /&gt;
&lt;br /&gt;
Whichever you choose to pursue is up to you. See the [https://bind9.readthedocs.io BIND9 documentation] for more information.&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28903</id>
		<title>Small-Time DNS with BIND9</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28903"/>
		<updated>2025-02-02T17:02:14Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: substitute primary in place of master&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Small-Time DNS Server with BIND9 =&lt;br /&gt;
&lt;br /&gt;
This document shows how to configure a basic installation of the ISC DNS server, BIND9, for Alpine Linux. This is useful when you want to have a DNS server for your home or home office network. The instructions start with a basic caching, forwarding DNS server. It continues on with adding lookup zones for your LAN hosts. Finally, it gives a peek at setting up ad blocking. You can work through as much or as little as you like depending on your DNS needs.&lt;br /&gt;
&lt;br /&gt;
It should be noted, this document focuses on quick deployment and ease of use for a &#039;&#039;trusted network behind a firewall&#039;&#039;. Do not deploy this configuration on a host that allows DNS queries from the internet.&lt;br /&gt;
&lt;br /&gt;
== Install the Package ==&lt;br /&gt;
&lt;br /&gt;
The usual Alpine apk installation method can be used to install bind9. This will install the named DNS server as well as nslookup and other utilities.&lt;br /&gt;
&lt;br /&gt;
 # apk update&lt;br /&gt;
 # apk add bind&lt;br /&gt;
&lt;br /&gt;
== Configure as a Forwarding DNS Server ==&lt;br /&gt;
&lt;br /&gt;
When configured as a forwarding server, the local DNS server will cache the results of query replies. Queries not found in cache are forwarded to a public DNS server (or your ISP).&lt;br /&gt;
&lt;br /&gt;
The example below uses public DNS servers 1.1.1.1 and 8.8.8.8. You may substitute your ISP’s DNS servers or any other trusted DNS server.&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; named.conf&lt;br /&gt;
 &lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 };&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
After writing the configuration, run named-checkconf to verify it’s correct. Fix any errors before moving on.&lt;br /&gt;
&lt;br /&gt;
=== Start the DNS Server ===&lt;br /&gt;
&lt;br /&gt;
 # service named start&lt;br /&gt;
 # rc-update add named&lt;br /&gt;
&lt;br /&gt;
=== Test Queries Locally ===&lt;br /&gt;
&lt;br /&gt;
First, run nslookup on your Alpine host and set the server to your Alpine host’s IP address. Then, query some internet DNS name and IP addresses. You should see IP addresses and domain names in the reply.&lt;br /&gt;
&lt;br /&gt;
If you see an error, like &#039;&#039;** server can’t find example.com: NXDOMAIN&#039;&#039;, check the configuration in named.conf.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; 1.1.1.1&lt;br /&gt;
 1.1.1.1.in-addr.arpa    name = one.one.one.one.&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you’ll want to configure your host’s /etc/resolv.conf to use its own IP address for DNS lookups.&lt;br /&gt;
&lt;br /&gt;
=== Test Queries from a LAN Client ===&lt;br /&gt;
&lt;br /&gt;
Repeat the test, but from another machine on your network. Be sure to use the Alpine host’s IP address for the nslookup server.&lt;br /&gt;
&lt;br /&gt;
If you see an error like &#039;&#039;*** [192.168.1.100] can’t find example.com: Query refused&#039;&#039;, check your named.conf. Verify there is a line for &#039;&#039;recursion yes;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Here’s a sample of a successful test on a Windows client.&lt;br /&gt;
&lt;br /&gt;
 C:\&amp;gt; nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:  [192.168.1.100]&lt;br /&gt;
 Address:  192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:    example.com&lt;br /&gt;
 Addresses:  2600:1406:bc00:53::b81e:94ce&lt;br /&gt;
           23.215.0.136&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you can configure your DHCP server to use the Alpine host’s IP address for primary DNS.&lt;br /&gt;
&lt;br /&gt;
== Optionally Add LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
So far, only well-known internet hosts are able to be queried. Sometimes it’s useful to have hosts on your own network be available in DNS as well. This requires setting up a zone file.&lt;br /&gt;
&lt;br /&gt;
Creatig a zone file is a little more complex than the configuration thus far, but not insurmountable. There are many examples of zone files to be found on the internet, including [https://bind9.readthedocs.io/en/latest/chapter3.html#example-com-base-zone-file the BIND9 documentation], [https://en.wikipedia.org/wiki/Zone_file#Example_file a Wikipedia article], and [https://wiki.alpinelinux.org/wiki/Setting_up_nsd_DNS_server#Configure another Alpine Wiki DNS howto]. All these can be used as references.&lt;br /&gt;
&lt;br /&gt;
=== Create the Zone File ===&lt;br /&gt;
&lt;br /&gt;
The example below is for a simple home network using the reserved private top-level domain name of &#039;&#039;.home&#039;&#039;. The top half of the file contains details about the domain itself. The bottom half is where individual hosts and their addresses are listed. You will need to adjust names and IP addresses for your network configuration.&lt;br /&gt;
&lt;br /&gt;
 # mkdir /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/bind/zones/home&lt;br /&gt;
 &lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Be sure to check the file using named-checkzone and fix any errors before continuing. The positional parameters are &#039;&#039;zone name&#039;&#039; and &#039;&#039;file name&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
 # named-checkzone home /etc/bind/zone/home&lt;br /&gt;
 zone home/IN: loaded serial 1&lt;br /&gt;
 OK&lt;br /&gt;
&lt;br /&gt;
If you do encounter errors in the output, there is a line number included that will help you track it down.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone File in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Edit /etc/bind/named.conf and append the following lines:&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;home&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/home&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Validate the configuration with the command: named-checkconf. Fix any errors before continuing.&lt;br /&gt;
&lt;br /&gt;
=== Inform the DNS Server of the New Configuration ===&lt;br /&gt;
&lt;br /&gt;
Use the usual Alpine service command to reload the configuration.&lt;br /&gt;
&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
If there are errors, use the named-checkconf and named-checkzone commands to help narrow down the cause.&lt;br /&gt;
&lt;br /&gt;
=== Do Some Test Queries ===&lt;br /&gt;
&lt;br /&gt;
As a final check, revisit the tests using nslookup that were used to verify the forwarding DNS server. This time, in addition to looking up internet hosts, try some queries for the hosts in your zone file.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; router.home&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Name:   router.home&lt;br /&gt;
 Address: 192.168.1.1&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
== Add Zones for localhost ==&lt;br /&gt;
&lt;br /&gt;
To make the configuration complete, there should be a zone for the localhost name so the DNS server will return the familiar 127.0.0.1 address when queried. The DNS server should also respond with &#039;&#039;localhost&#039;&#039; when queried for the IP address &#039;&#039;127.0.0.1&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The process for creating the forward lookup zone is the same as is was for creating the &#039;&#039;home&#039;&#039; zone. What’s new in this step is the concept of reverse lookup zones. This is simply the DNS server returning a name when asked about an IP address.&lt;br /&gt;
&lt;br /&gt;
Here are the steps:&lt;br /&gt;
# Create the zone file&lt;br /&gt;
# Reference the zone in named.conf&lt;br /&gt;
# Reload the configuration&lt;br /&gt;
&lt;br /&gt;
Don’t forget to test with named-checkzone, named-checkconf, and nslookup as you go.&lt;br /&gt;
&lt;br /&gt;
=== Create the Forward Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The zone file for localhost is fairly simple, with only one A record. An example is show below. Create a new file with the path /etc/bind/zones/localhost and copy the contents of the example into it.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 @       IN  A     127.0.0.1&lt;br /&gt;
&lt;br /&gt;
=== Create the Reverse Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The reverse lookup zone file is nearly the same as the forward lookup, but has a PTR record instead of an A record on the last line. Create a new file with the path /etc/bind/zones/1.0.0.127.in-addr.arpa and copy the contents from below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 1       IN  PTR   localhost.     &lt;br /&gt;
&lt;br /&gt;
The rather strange looking naming convention of the file (and the zone itself) is simply the IP address of the reverse zone with its octets in reverse order and the suffix .in-addr.arpa tacked on the end. You can actually name it whatever you want provided it matches the configuration in named.conf. Some examples will use localhost.rev for the reverse lookup filename.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone Files in named.conf ===&lt;br /&gt;
&lt;br /&gt;
After checking the new zone files with named-checkzone, append a reference to them in the named.conf file. The configuration to be added is shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;localhost&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/localhost&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 zone &amp;quot;1.0.0.127.in-addr.arpa&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/1.0.0.127.in-addr.arpa&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
If named-checkconf does not raise any errors, the next step is to reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
== Reverse Lookup Zone for LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
If you created a zone file for hosts on your local network, you should create a reverse lookup zone for completeness. The process is very similar to the creation of the localhost reverse lookup zone. A shortcut method is to copy the forward lookup zone file to a new filename of the IP of your LAN and then replace the A records with their corresponding PTR records.&lt;br /&gt;
&lt;br /&gt;
Following the example given in the forward lookup, the reverse zone would look like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
&lt;br /&gt;
=== On-Going Maintenance of LAN Hosts ===&lt;br /&gt;
&lt;br /&gt;
When using DNS for your own network’s hosts, there are a few steps to keep in mind when you add or remove hosts.&lt;br /&gt;
&lt;br /&gt;
# Increment the serial number on the zone file.&lt;br /&gt;
# Test the zone file with named-checkzone&lt;br /&gt;
# Test the configuration with named-checkconf&lt;br /&gt;
# Reload the named service to make the changes active.&lt;br /&gt;
&lt;br /&gt;
== Blocking Ads ==&lt;br /&gt;
&lt;br /&gt;
The Response Policy Zone (RPZ) feature of BIND9 makes it easy to block access to an unwanted domain by returning a domain not found response instead of an IP address. Three steps are required to get this working.&lt;br /&gt;
&lt;br /&gt;
# Enable to RPZ feature in the options section of named.conf&lt;br /&gt;
# Create a zone file lising unwanted domains.&lt;br /&gt;
# Reference the zone file in named.conf&lt;br /&gt;
&lt;br /&gt;
=== Enable RPZ in named.conf options ===&lt;br /&gt;
&lt;br /&gt;
Below is the options section of named.conf used in all the examples so far, but with the addition of response policy zones. New lines for RPZ appear following the &#039;&#039;recursion yes;&#039;&#039; directive. The remainder of named.conf has been omitted for brevity.&lt;br /&gt;
&lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 &lt;br /&gt;
     response-policy {&lt;br /&gt;
         zone &amp;quot;rpz&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After making the changes, run named-checkconf to ensure there are no problems with the file.&lt;br /&gt;
&lt;br /&gt;
=== Create an RPZ File ===&lt;br /&gt;
&lt;br /&gt;
The RPZ zone file looks a lot like a regular zone file. One way to create it quickly is to start by copying the localhost zone file and then appending the hosts to be blocked.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cp localhost rpz&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt;&amp;gt; rpz&lt;br /&gt;
 example.com    CNAME .&lt;br /&gt;
 *.example.com  CNAME .&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
The CNAME . record instructs BIND9 to return an NXDOMAIN (domain not found) response when the listed domain is queried. You probably wont want to block example.com, but it works well for demonstration purposes.&lt;br /&gt;
&lt;br /&gt;
Check the file for errors by running named-checkzone rpz /etc/bind/zone/rpz and fix any errors before moving on to the next step.&lt;br /&gt;
&lt;br /&gt;
=== Reference the RPZ file in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Just like the instructions for adding localhost and LAN host zones, adding the RPZ zone file involves appending a few lines to named.conf and running named-checkconf before reloading the service.&lt;br /&gt;
&lt;br /&gt;
The format for a new zone should be familiar by now. It looks like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;rpz&amp;quot; {&lt;br /&gt;
     type primary;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/rpz&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After appending this to named.conf, be sure to run named-checkconf. Then reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
=== Test RPZ Blocking ===&lt;br /&gt;
&lt;br /&gt;
To test, use nslookup just like before when testing the forwarding configuration, LAN hosts, etc. Except this time, you’re hoping to see an error message.&lt;br /&gt;
&lt;br /&gt;
Below an example showing the successful configuration to block example.com.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 ** server can&#039;t find example.com: NXDOMAIN&lt;br /&gt;
&lt;br /&gt;
Continue testing with some other domains that should be allowed just to make sure it’s being blocked by the RPZ policy and not because the server is misconfigured.&lt;br /&gt;
&lt;br /&gt;
=== Maintaining the RPZ File ===&lt;br /&gt;
&lt;br /&gt;
Manually adding blocked domains to the RPZ zone file can quickly become tedious, but with this simple test involving example.com, you can see how it’s done. There are some folks on the internet who curate and maintain blocklists. One such source is https://github.com/hagezi/dns-blocklists&lt;br /&gt;
&lt;br /&gt;
To use an ad blocking RPZ you’ll want to perform the following steps:&lt;br /&gt;
&lt;br /&gt;
# Download the file from the source location.&lt;br /&gt;
# Check the file’s validity with named-checkzone&lt;br /&gt;
# Replace the existing /etc/bind/zones/rpz file with the downloaded one.&lt;br /&gt;
# Reload the configuration by running service named reload&lt;br /&gt;
&lt;br /&gt;
New ad domains pop up all the time. The trick is automating the download of new block lists when they come out. A shell script like the one below can help.&lt;br /&gt;
&lt;br /&gt;
 #! /bin/sh&lt;br /&gt;
 &lt;br /&gt;
 cd /etc/bind/zones || exit 1&lt;br /&gt;
 curl -Os https://raw.githubusercontent.com/hagezi/dns-blocklists/main/rpz/multi.txt || exit 2&lt;br /&gt;
 named-checkzone rpz ./multi.txt || exit 3&lt;br /&gt;
 cp rpz rpz~ &amp;amp;&amp;amp; mv multi.txt rpz&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
== Next Steps ==&lt;br /&gt;
&lt;br /&gt;
This document has taken you through the basics of setting up BIND9 on your Alpine server. There are many more features that haven’t been covered. Some of the interesting ones include:&lt;br /&gt;
&lt;br /&gt;
* Wildcard subdomains&lt;br /&gt;
* IPv6 domains&lt;br /&gt;
* Secondary DNS servers&lt;br /&gt;
* DNSSEC encryption&lt;br /&gt;
&lt;br /&gt;
Whichever you choose to pursue is up to you. See the [https://bind9.readthedocs.io BIND9 documentation] for more information.&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28902</id>
		<title>Small-Time DNS with BIND9</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28902"/>
		<updated>2025-02-02T16:32:32Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Small-Time DNS Server with BIND9 =&lt;br /&gt;
&lt;br /&gt;
This document shows how to configure a basic installation of the ISC DNS server, BIND9, for Alpine Linux. This is useful when you want to have a DNS server for your home or home office network. The instructions start with a basic caching, forwarding DNS server. It continues on with adding lookup zones for your LAN hosts. Finally, it gives a peek at setting up ad blocking. You can work through as much or as little as you like depending on your DNS needs.&lt;br /&gt;
&lt;br /&gt;
It should be noted, this document focuses on quick deployment and ease of use for a &#039;&#039;trusted network behind a firewall&#039;&#039;. Do not deploy this configuration on a host that allows DNS queries from the internet.&lt;br /&gt;
&lt;br /&gt;
== Install the Package ==&lt;br /&gt;
&lt;br /&gt;
The usual Alpine apk installation method can be used to install bind9. This will install the named DNS server as well as nslookup and other utilities.&lt;br /&gt;
&lt;br /&gt;
 # apk update&lt;br /&gt;
 # apk add bind&lt;br /&gt;
&lt;br /&gt;
== Configure as a Forwarding DNS Server ==&lt;br /&gt;
&lt;br /&gt;
When configured as a forwarding server, the local DNS server will cache the results of query replies. Queries not found in cache are forwarded to a public DNS server (or your ISP).&lt;br /&gt;
&lt;br /&gt;
The example below uses public DNS servers 1.1.1.1 and 8.8.8.8. You may substitute your ISP’s DNS servers or any other trusted DNS server.&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; named.conf&lt;br /&gt;
 &lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 };&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
After writing the configuration, run named-checkconf to verify it’s correct. Fix any errors before moving on.&lt;br /&gt;
&lt;br /&gt;
=== Start the DNS Server ===&lt;br /&gt;
&lt;br /&gt;
 # service named start&lt;br /&gt;
 # rc-update add named&lt;br /&gt;
&lt;br /&gt;
=== Test Queries Locally ===&lt;br /&gt;
&lt;br /&gt;
First, run nslookup on your Alpine host and set the server to your Alpine host’s IP address. Then, query some internet DNS name and IP addresses. You should see IP addresses and domain names in the reply.&lt;br /&gt;
&lt;br /&gt;
If you see an error, like &#039;&#039;** server can’t find example.com: NXDOMAIN&#039;&#039;, check the configuration in named.conf.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; 1.1.1.1&lt;br /&gt;
 1.1.1.1.in-addr.arpa    name = one.one.one.one.&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you’ll want to configure your host’s /etc/resolv.conf to use its own IP address for DNS lookups.&lt;br /&gt;
&lt;br /&gt;
=== Test Queries from a LAN Client ===&lt;br /&gt;
&lt;br /&gt;
Repeat the test, but from another machine on your network. Be sure to use the Alpine host’s IP address for the nslookup server.&lt;br /&gt;
&lt;br /&gt;
If you see an error like &#039;&#039;*** [192.168.1.100] can’t find example.com: Query refused&#039;&#039;, check your named.conf. Verify there is a line for &#039;&#039;recursion yes;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Here’s a sample of a successful test on a Windows client.&lt;br /&gt;
&lt;br /&gt;
 C:\&amp;gt; nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:  [192.168.1.100]&lt;br /&gt;
 Address:  192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:    example.com&lt;br /&gt;
 Addresses:  2600:1406:bc00:53::b81e:94ce&lt;br /&gt;
           23.215.0.136&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you can configure your DHCP server to use the Alpine host’s IP address for primary DNS.&lt;br /&gt;
&lt;br /&gt;
== Optionally Add LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
So far, only well-known internet hosts are able to be queried. Sometimes it’s useful to have hosts on your own network be available in DNS as well. This requires setting up a zone file.&lt;br /&gt;
&lt;br /&gt;
Creatig a zone file is a little more complex than the configuration thus far, but not insurmountable. There are many examples of zone files to be found on the internet, including [https://bind9.readthedocs.io/en/latest/chapter3.html#example-com-base-zone-file the BIND9 documentation], [https://en.wikipedia.org/wiki/Zone_file#Example_file a Wikipedia article], and [https://wiki.alpinelinux.org/wiki/Setting_up_nsd_DNS_server#Configure another Alpine Wiki DNS howto]. All these can be used as references.&lt;br /&gt;
&lt;br /&gt;
=== Create the Zone File ===&lt;br /&gt;
&lt;br /&gt;
The example below is for a simple home network using the reserved private top-level domain name of &#039;&#039;.home&#039;&#039;. The top half of the file contains details about the domain itself. The bottom half is where individual hosts and their addresses are listed. You will need to adjust names and IP addresses for your network configuration.&lt;br /&gt;
&lt;br /&gt;
 # mkdir /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/bind/zones/home&lt;br /&gt;
 &lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Be sure to check the file using named-checkzone and fix any errors before continuing. The positional parameters are &#039;&#039;zone name&#039;&#039; and &#039;&#039;file name&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
 # named-checkzone home /etc/bind/zone/home&lt;br /&gt;
 zone home/IN: loaded serial 1&lt;br /&gt;
 OK&lt;br /&gt;
&lt;br /&gt;
If you do encounter errors in the output, there is a line number included that will help you track it down.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone File in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Edit /etc/bind/named.conf and append the following lines:&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;home&amp;quot; {&lt;br /&gt;
     type master;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/home&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Validate the configuration with the command: named-checkconf. Fix any errors before continuing.&lt;br /&gt;
&lt;br /&gt;
=== Inform the DNS Server of the New Configuration ===&lt;br /&gt;
&lt;br /&gt;
Use the usual Alpine service command to reload the configuration.&lt;br /&gt;
&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
If there are errors, use the named-checkconf and named-checkzone commands to help narrow down the cause.&lt;br /&gt;
&lt;br /&gt;
=== Do Some Test Queries ===&lt;br /&gt;
&lt;br /&gt;
As a final check, revisit the tests using nslookup that were used to verify the forwarding DNS server. This time, in addition to looking up internet hosts, try some queries for the hosts in your zone file.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; router.home&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Name:   router.home&lt;br /&gt;
 Address: 192.168.1.1&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
== Add Zones for localhost ==&lt;br /&gt;
&lt;br /&gt;
To make the configuration complete, there should be a zone for the localhost name so the DNS server will return the familiar 127.0.0.1 address when queried. The DNS server should also respond with &#039;&#039;localhost&#039;&#039; when queried for the IP address &#039;&#039;127.0.0.1&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The process for creating the forward lookup zone is the same as is was for creating the &#039;&#039;home&#039;&#039; zone. What’s new in this step is the concept of reverse lookup zones. This is simply the DNS server returning a name when asked about an IP address.&lt;br /&gt;
&lt;br /&gt;
Here are the steps:&lt;br /&gt;
# Create the zone file&lt;br /&gt;
# Reference the zone in named.conf&lt;br /&gt;
# Reload the configuration&lt;br /&gt;
&lt;br /&gt;
Don’t forget to test with named-checkzone, named-checkconf, and nslookup as you go.&lt;br /&gt;
&lt;br /&gt;
=== Create the Forward Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The zone file for localhost is fairly simple, with only one A record. An example is show below. Create a new file with the path /etc/bind/zones/localhost and copy the contents of the example into it.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 @       IN  A     127.0.0.1&lt;br /&gt;
&lt;br /&gt;
=== Create the Reverse Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The reverse lookup zone file is nearly the same as the forward lookup, but has a PTR record instead of an A record on the last line. Create a new file with the path /etc/bind/zones/1.0.0.127.in-addr.arpa and copy the contents from below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 1       IN  PTR   localhost.     &lt;br /&gt;
&lt;br /&gt;
The rather strange looking naming convention of the file (and the zone itself) is simply the IP address of the reverse zone with its octets in reverse order and the suffix .in-addr.arpa tacked on the end. You can actually name it whatever you want provided it matches the configuration in named.conf. Some examples will use localhost.rev for the reverse lookup filename.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone Files in named.conf ===&lt;br /&gt;
&lt;br /&gt;
After checking the new zone files with named-checkzone, append a reference to them in the named.conf file. The configuration to be added is shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;localhost&amp;quot; {&lt;br /&gt;
     type master;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/localhost&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 zone &amp;quot;1.0.0.127.in-addr.arpa&amp;quot; {&lt;br /&gt;
     type master;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/1.0.0.127.in-addr.arpa&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
If named-checkconf does not raise any errors, the next step is to reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
== Reverse Lookup Zone for LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
If you created a zone file for hosts on your local network, you should create a reverse lookup zone for completeness. The process is very similar to the creation of the localhost reverse lookup zone. A shortcut method is to copy the forward lookup zone file to a new filename of the IP of your LAN and then replace the A records with their corresponding PTR records.&lt;br /&gt;
&lt;br /&gt;
Following the example given in the forward lookup, the reverse zone would look like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
&lt;br /&gt;
=== On-Going Maintenance of LAN Hosts ===&lt;br /&gt;
&lt;br /&gt;
When using DNS for your own network’s hosts, there are a few steps to keep in mind when you add or remove hosts.&lt;br /&gt;
&lt;br /&gt;
# Increment the serial number on the zone file.&lt;br /&gt;
# Test the zone file with named-checkzone&lt;br /&gt;
# Test the configuration with named-checkconf&lt;br /&gt;
# Reload the named service to make the changes active.&lt;br /&gt;
&lt;br /&gt;
== Blocking Ads ==&lt;br /&gt;
&lt;br /&gt;
The Response Policy Zone (RPZ) feature of BIND9 makes it easy to block access to an unwanted domain by returning a domain not found response instead of an IP address. Three steps are required to get this working.&lt;br /&gt;
&lt;br /&gt;
# Enable to RPZ feature in the options section of named.conf&lt;br /&gt;
# Create a zone file lising unwanted domains.&lt;br /&gt;
# Reference the zone file in named.conf&lt;br /&gt;
&lt;br /&gt;
=== Enable RPZ in named.conf options ===&lt;br /&gt;
&lt;br /&gt;
Below is the options section of named.conf used in all the examples so far, but with the addition of response policy zones. New lines for RPZ appear following the &#039;&#039;recursion yes;&#039;&#039; directive. The remainder of named.conf has been omitted for brevity.&lt;br /&gt;
&lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 &lt;br /&gt;
     response-policy {&lt;br /&gt;
         zone &amp;quot;rpz&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After making the changes, run named-checkconf to ensure there are no problems with the file.&lt;br /&gt;
&lt;br /&gt;
=== Create an RPZ File ===&lt;br /&gt;
&lt;br /&gt;
The RPZ zone file looks a lot like a regular zone file. One way to create it quickly is to start by copying the localhost zone file and then appending the hosts to be blocked.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cp localhost rpz&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt;&amp;gt; rpz&lt;br /&gt;
 example.com    CNAME .&lt;br /&gt;
 *.example.com  CNAME .&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
The CNAME . record instructs BIND9 to return an NXDOMAIN (domain not found) response when the listed domain is queried. You probably wont want to block example.com, but it works well for demonstration purposes.&lt;br /&gt;
&lt;br /&gt;
Check the file for errors by running named-checkzone rpz /etc/bind/zone/rpz and fix any errors before moving on to the next step.&lt;br /&gt;
&lt;br /&gt;
=== Reference the RPZ file in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Just like the instructions for adding localhost and LAN host zones, adding the RPZ zone file involves appending a few lines to named.conf and running named-checkconf before reloading the service.&lt;br /&gt;
&lt;br /&gt;
The format for a new zone should be familiar by now. It looks like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;rpz&amp;quot; {&lt;br /&gt;
     type master;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/rpz&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After appending this to named.conf, be sure to run named-checkconf. Then reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
=== Test RPZ Blocking ===&lt;br /&gt;
&lt;br /&gt;
To test, use nslookup just like before when testing the forwarding configuration, LAN hosts, etc. Except this time, you’re hoping to see an error message.&lt;br /&gt;
&lt;br /&gt;
Below an example showing the successful configuration to block example.com.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 ** server can&#039;t find example.com: NXDOMAIN&lt;br /&gt;
&lt;br /&gt;
Continue testing with some other domains that should be allowed just to make sure it’s being blocked by the RPZ policy and not because the server is misconfigured.&lt;br /&gt;
&lt;br /&gt;
=== Maintaining the RPZ File ===&lt;br /&gt;
&lt;br /&gt;
Manually adding blocked domains to the RPZ zone file can quickly become tedious, but with this simple test involving example.com, you can see how it’s done. There are some folks on the internet who curate and maintain blocklists. One such source is https://github.com/hagezi/dns-blocklists&lt;br /&gt;
&lt;br /&gt;
To use an ad blocking RPZ you’ll want to perform the following steps:&lt;br /&gt;
&lt;br /&gt;
# Download the file from the source location.&lt;br /&gt;
# Check the file’s validity with named-checkzone&lt;br /&gt;
# Replace the existing /etc/bind/zones/rpz file with the downloaded one.&lt;br /&gt;
# Reload the configuration by running service named reload&lt;br /&gt;
&lt;br /&gt;
New ad domains pop up all the time. The trick is automating the download of new block lists when they come out. A shell script like the one below can help.&lt;br /&gt;
&lt;br /&gt;
 #! /bin/sh&lt;br /&gt;
 &lt;br /&gt;
 cd /etc/bind/zones || exit 1&lt;br /&gt;
 curl -Os https://raw.githubusercontent.com/hagezi/dns-blocklists/main/rpz/multi.txt || exit 2&lt;br /&gt;
 named-checkzone rpz ./multi.txt || exit 3&lt;br /&gt;
 cp rpz rpz~ &amp;amp;&amp;amp; mv multi.txt rpz&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
== Next Steps ==&lt;br /&gt;
&lt;br /&gt;
This document has taken you through the basics of setting up BIND9 on your Alpine server. There are many more features that haven’t been covered. Some of the interesting ones include:&lt;br /&gt;
&lt;br /&gt;
* Wildcard subdomains&lt;br /&gt;
* IPv6 domains&lt;br /&gt;
* Secondary DNS servers&lt;br /&gt;
* DNSSEC encryption&lt;br /&gt;
&lt;br /&gt;
Whichever you choose to pursue is up to you. See the [https://bind9.readthedocs.io BIND9 documentation] for more information.&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28901</id>
		<title>Small-Time DNS with BIND9</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Small-Time_DNS_with_BIND9&amp;diff=28901"/>
		<updated>2025-02-02T15:48:50Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: Created page with &amp;quot;= Small-Time DNS Server with BIND9 =  This document shows how to configure a basic installation of the ISC DNS server, BIND9, for Alpine Linux. This is useful when you want to have a DNS server for your home or home office network. The instructions start with a basic caching, forwarding DNS server. It continues on with adding lookup zones for your LAN hosts. Finally, it gives a peek at setting up ad blocking. You can work through as much or as little as you like dependin...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Small-Time DNS Server with BIND9 =&lt;br /&gt;
&lt;br /&gt;
This document shows how to configure a basic installation of the ISC DNS server, BIND9, for Alpine Linux. This is useful when you want to have a DNS server for your home or home office network. The instructions start with a basic caching, forwarding DNS server. It continues on with adding lookup zones for your LAN hosts. Finally, it gives a peek at setting up ad blocking. You can work through as much or as little as you like depending on your DNS needs.&lt;br /&gt;
&lt;br /&gt;
It should be noted, this document focuses on quick deployment and ease of use for a &#039;&#039;trusted network behind a firewall&#039;&#039;. Do not deploy this configuration on a host that allows DNS queries from the internet.&lt;br /&gt;
&lt;br /&gt;
== Install the Package ==&lt;br /&gt;
&lt;br /&gt;
The usual Alpine apk installation method can be used to install bind9. This will install the named DNS server as well as nslookup and other utilities.&lt;br /&gt;
&lt;br /&gt;
 apk update&lt;br /&gt;
 apk add bind&lt;br /&gt;
&lt;br /&gt;
== Configure as a Forwarding DNS Server ==&lt;br /&gt;
&lt;br /&gt;
When configured as a forwarding server, the local DNS server will cache the results of query replies. Queries not found in cache are forwarded to a public DNS server (or your ISP).&lt;br /&gt;
&lt;br /&gt;
The example below uses public DNS servers 1.1.1.1 and 8.8.8.8. You may substitute your ISP’s DNS servers or any other trusted DNS server.&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; named.conf&lt;br /&gt;
 &lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 };&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
After writing the configuration, run named-checkconf to verify it’s correct. Fix any errors before moving on.&lt;br /&gt;
&lt;br /&gt;
=== Start the DNS Server ===&lt;br /&gt;
&lt;br /&gt;
 service named start&lt;br /&gt;
 rc-update add named&lt;br /&gt;
&lt;br /&gt;
=== Test Queries Locally ===&lt;br /&gt;
&lt;br /&gt;
First, run nslookup on your Alpine host and set the server to your Alpine host’s IP address. Then, query some internet DNS name and IP addresses. You should see IP addresses and domain names in the reply.&lt;br /&gt;
&lt;br /&gt;
If you see an error, like &#039;&#039;** server can’t find example.com: NXDOMAIN&#039;&#039;, check the configuration in named.conf.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; 1.1.1.1&lt;br /&gt;
 1.1.1.1.in-addr.arpa    name = one.one.one.one.&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you’ll want to configure your host’s /etc/resolv.conf to use its own IP address for DNS lookups.&lt;br /&gt;
&lt;br /&gt;
=== Test Queries from a LAN Client ===&lt;br /&gt;
&lt;br /&gt;
Repeat the test, but from another machine on your network. Be sure to use the Alpine host’s IP address for the nslookup server.&lt;br /&gt;
&lt;br /&gt;
If you see an error like &#039;&#039;*** [192.168.1.100] can’t find example.com: Query refused&#039;&#039;, check your named.conf. Verify there is a line for &#039;&#039;recursion yes;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Here’s a sample of a successful test on a Windows client.&lt;br /&gt;
&lt;br /&gt;
 C:\&amp;gt; nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:  [192.168.1.100]&lt;br /&gt;
 Address:  192.168.1.100&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:    example.com&lt;br /&gt;
 Addresses:  2600:1406:bc00:53::b81e:94ce&lt;br /&gt;
           23.215.0.136&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
If the test is successful, you can configure your DHCP server to use the Alpine host’s IP address for primary DNS.&lt;br /&gt;
&lt;br /&gt;
== Optionally Add LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
So far, only well-known internet hosts are able to be queried. Sometimes it’s useful to have hosts on your own network be available in DNS as well. This requires setting up a zone file.&lt;br /&gt;
&lt;br /&gt;
Creatig a zone file is a little more complex than the configuration thus far, but not insurmountable. There are many examples of zone files to be found on the internet, including [https://bind9.readthedocs.io/en/latest/chapter3.html#example-com-base-zone-file the BIND9 documentation], [https://en.wikipedia.org/wiki/Zone_file#Example_file a Wikipedia article], and [https://wiki.alpinelinux.org/wiki/Setting_up_nsd_DNS_server#Configure another Alpine Wiki DNS howto]. All these can be used as references.&lt;br /&gt;
&lt;br /&gt;
=== Create the Zone File ===&lt;br /&gt;
&lt;br /&gt;
The example below is for a simple home network using the reserved private top-level domain name of &#039;&#039;.home&#039;&#039;. The top half of the file contains details about the domain itself. The bottom half is where individual hosts and their addresses are listed. You will need to adjust names and IP addresses for your network configuration.&lt;br /&gt;
&lt;br /&gt;
 # mkdir /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/bind/zones/home&lt;br /&gt;
 &lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Be sure to check the file using named-checkzone and fix any errors before continuing. The positional parameters are &#039;&#039;zone name&#039;&#039; and &#039;&#039;file name&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
 # named-checkzone home /etc/bind/zone/home&lt;br /&gt;
 zone home/IN: loaded serial 1&lt;br /&gt;
 OK&lt;br /&gt;
&lt;br /&gt;
If you do encounter errors in the output, there is a line number included that will help you track it down.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone File in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Edit /etc/bind/named.conf and append the following lines:&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;home&amp;quot; {&lt;br /&gt;
     type master;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/home&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
Validate the configuration with the command: named-checkconf. Fix any errors before continuing.&lt;br /&gt;
&lt;br /&gt;
=== Inform the DNS Server of the New Configuration ===&lt;br /&gt;
&lt;br /&gt;
Use the usual Alpine service command to reload the configuration.&lt;br /&gt;
&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
If there are errors, use the named-checkconf and named-checkzone commands to help narrow down the cause.&lt;br /&gt;
&lt;br /&gt;
=== Do Some Test Queries ===&lt;br /&gt;
&lt;br /&gt;
As a final check, revisit the tests using nslookup that were used to verify the forwarding DNS server. This time, in addition to looking up internet hosts, try some queries for the hosts in your zone file.&lt;br /&gt;
&lt;br /&gt;
Here’s an example of a successful test.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; server 192.168.1.100&lt;br /&gt;
 Default server: 192.168.1.100&lt;br /&gt;
 Address: 192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Non-authoritative answer:&lt;br /&gt;
 Name:   example.com&lt;br /&gt;
 Address: 23.215.0.136&lt;br /&gt;
 &lt;br /&gt;
 &amp;gt; router.home&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 Name:   router.home&lt;br /&gt;
 Address: 192.168.1.1&lt;br /&gt;
&lt;br /&gt;
Note: Output has been truncated for brevity.&lt;br /&gt;
&lt;br /&gt;
== Add Zones for localhost ==&lt;br /&gt;
&lt;br /&gt;
To make the configuration complete, there should be a zone for the localhost name so the DNS server will return the familiar 127.0.0.1 address when queried. The DNS server should also respond with &#039;&#039;localhost&#039;&#039; when queried for the IP address &#039;&#039;127.0.0.1&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The process for creating the forward lookup zone is the same as is was for creating the &#039;&#039;home&#039;&#039; zone. What’s new in this step is the concept of reverse lookup zones. This is simply the DNS server returning a name when asked about an IP address.&lt;br /&gt;
&lt;br /&gt;
Here are the steps:&lt;br /&gt;
# Create the zone file&lt;br /&gt;
# Reference the zone in named.conf&lt;br /&gt;
# Reload the configuration&lt;br /&gt;
&lt;br /&gt;
Don’t forget to test with named-checkzone, named-checkconf, and nslookup as you go.&lt;br /&gt;
&lt;br /&gt;
=== Create the Forward Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The zone file for localhost is fairly simple, with only one A record. An example is show below. Create a new file with the path /etc/bind/zones/localhost and copy the contents of the example into it.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 @       IN  A     127.0.0.1&lt;br /&gt;
&lt;br /&gt;
=== Create the Reverse Lookup Zone File ===&lt;br /&gt;
&lt;br /&gt;
The reverse lookup zone file is nearly the same as the forward lookup, but has a PTR record instead of an A record on the last line. Create a new file with the path /etc/bind/zones/1.0.0.127.in-addr.arpa and copy the contents from below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   localhost.  root.localhost. (&lt;br /&gt;
                                             1    ; Serial - increment after modifying&lt;br /&gt;
                                        604800    ; Refresh&lt;br /&gt;
                                         86400    ; Retry&lt;br /&gt;
                                       2419200    ; Expire&lt;br /&gt;
                                        604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    localhost.&lt;br /&gt;
 1       IN  PTR   localhost.     &lt;br /&gt;
&lt;br /&gt;
The rather strange looking naming convention of the file (and the zone itself) is simply the IP address of the reverse zone with its octets in reverse order and the suffix .in-addr.arpa tacked on the end. You can actually name it whatever you want provided it matches the configuration in named.conf. Some examples will use localhost.rev for the reverse lookup filename.&lt;br /&gt;
&lt;br /&gt;
=== Reference the Zone Files in named.conf ===&lt;br /&gt;
&lt;br /&gt;
After checking the new zone files with named-checkzone, append a reference to them in the named.conf file. The configuration to be added is shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;localhost&amp;quot; {&lt;br /&gt;
     type master;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/localhost&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
 zone &amp;quot;1.0.0.127.in-addr.arpa&amp;quot; {&lt;br /&gt;
     type master;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/1.0.0.127.in-addr.arpa&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
If named-checkconf does not raise any errors, the next step is to reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
== Reverse Lookup Zone for LAN Hosts ==&lt;br /&gt;
&lt;br /&gt;
If you created a zone file for hosts on your local network, you should create a reverse lookup zone for completeness. The process is very similar to the creation of the localhost reverse lookup zone. A shortcut method is to copy the forward lookup zone file to a new filename of the IP of your LAN and then replace the A records with their corresponding PTR records.&lt;br /&gt;
&lt;br /&gt;
Following the example given in the forward lookup, the reverse zone would look like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 $TTL 3600&lt;br /&gt;
 @       IN  SOA   ns1.home.  root.home. (&lt;br /&gt;
                                       1    ; Serial - increment after modifying&lt;br /&gt;
                                  604800    ; Refresh&lt;br /&gt;
                                   86400    ; Retry&lt;br /&gt;
                                 2419200    ; Expire&lt;br /&gt;
                                  604800 )  ; Negative Cache TTL&lt;br /&gt;
 ;&lt;br /&gt;
 &lt;br /&gt;
 @       IN  NS    ns1&lt;br /&gt;
 @       IN  A     192.168.1.1&lt;br /&gt;
 router  IN  A     192.168.1.1&lt;br /&gt;
 ns1     IN  A     192.168.1.100&lt;br /&gt;
 alpine  IN  A     192.168.1.100&lt;br /&gt;
 media   IN  A     192.168.1.101&lt;br /&gt;
&lt;br /&gt;
=== On-Going Maintenance of LAN Hosts ===&lt;br /&gt;
&lt;br /&gt;
When using DNS for your own network’s hosts, there are a few steps to keep in mind when you add or remove hosts.&lt;br /&gt;
&lt;br /&gt;
# Increment the serial number on the zone file.&lt;br /&gt;
# Test the zone file with named-checkzone&lt;br /&gt;
# Test the configuration with named-checkconf&lt;br /&gt;
# Reload the named service to make the changes active.&lt;br /&gt;
&lt;br /&gt;
== Blocking Ads ==&lt;br /&gt;
&lt;br /&gt;
The Response Policy Zone (RPZ) feature of BIND9 makes it easy to block access to an unwanted domain by returning a domain not found response instead of an IP address. Three steps are required to get this working.&lt;br /&gt;
&lt;br /&gt;
# Enable to RPZ feature in the options section of named.conf&lt;br /&gt;
# Create a zone file lising unwanted domains.&lt;br /&gt;
# Reference the zone file in named.conf&lt;br /&gt;
&lt;br /&gt;
=== Enable RPZ in named.conf options ===&lt;br /&gt;
&lt;br /&gt;
Below is the options section of named.conf used in all the examples so far, but with the addition of response policy zones. New lines for RPZ appear following the &#039;&#039;recursion yes;&#039;&#039; directive. The remainder of named.conf has been omitted for brevity.&lt;br /&gt;
&lt;br /&gt;
 options {&lt;br /&gt;
     directory &amp;quot;/var/bind&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     listen-on { any; };&lt;br /&gt;
     listen-on-v6 { none; };&lt;br /&gt;
 &lt;br /&gt;
     dnssec-validation no;&lt;br /&gt;
 &lt;br /&gt;
     forwarders {&lt;br /&gt;
         1.1.1.1;&lt;br /&gt;
         8.8.8.8;&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     recursion yes;&lt;br /&gt;
 &lt;br /&gt;
     response-policy {&lt;br /&gt;
         zone &amp;quot;rpz&amp;quot;;&lt;br /&gt;
     };&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After making the changes, run named-checkconf to ensure there are no problems with the file.&lt;br /&gt;
&lt;br /&gt;
=== Create an RPZ File ===&lt;br /&gt;
&lt;br /&gt;
The RPZ zone file looks a lot like a regular zone file. One way to create it quickly is to start by copying the localhost zone file and then appending the hosts to be blocked.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
 # cd /etc/bind/zones&lt;br /&gt;
 &lt;br /&gt;
 # cp localhost rpz&lt;br /&gt;
 &lt;br /&gt;
 # cat &amp;lt;&amp;lt; EOF &amp;gt;&amp;gt; rpz&lt;br /&gt;
 example.com    CNAME .&lt;br /&gt;
 *.example.com  CNAME .&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
The CNAME . record instructs BIND9 to return an NXDOMAIN (domain not found) response when the listed domain is queried. You probably wont want to block example.com, but it works well for demonstration purposes.&lt;br /&gt;
&lt;br /&gt;
Check the file for errors by running named-checkzone rpz /etc/bind/zone/rpz and fix any errors before moving on to the next step.&lt;br /&gt;
&lt;br /&gt;
=== Reference the RPZ file in named.conf ===&lt;br /&gt;
&lt;br /&gt;
Just like the instructions for adding localhost and LAN host zones, adding the RPZ zone file involves appending a few lines to named.conf and running named-checkconf before reloading the service.&lt;br /&gt;
&lt;br /&gt;
The format for a new zone should be familiar by now. It looks like what’s shown below.&lt;br /&gt;
&lt;br /&gt;
 zone &amp;quot;rpz&amp;quot; {&lt;br /&gt;
     type master;&lt;br /&gt;
     file &amp;quot;/etc/bind/zones/rpz&amp;quot;;&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
After appending this to named.conf, be sure to run named-checkconf. Then reload the configuration with service named reload&lt;br /&gt;
&lt;br /&gt;
=== Test RPZ Blocking ===&lt;br /&gt;
&lt;br /&gt;
To test, use nslookup just like before when testing the forwarding configuration, LAN hosts, etc. Except this time, you’re hoping to see an error message.&lt;br /&gt;
&lt;br /&gt;
Below an example showing the successful configuration to block example.com.&lt;br /&gt;
&lt;br /&gt;
 $ nslookup&lt;br /&gt;
 &amp;gt; example.com&lt;br /&gt;
 Server:         192.168.1.100&lt;br /&gt;
 Address:        192.168.1.100#53&lt;br /&gt;
 &lt;br /&gt;
 ** server can&#039;t find example.com: NXDOMAIN&lt;br /&gt;
&lt;br /&gt;
Continue testing with some other domains that should be allowed just to make sure it’s being blocked by the RPZ policy and not because the server is misconfigured.&lt;br /&gt;
&lt;br /&gt;
=== Maintaining the RPZ File ===&lt;br /&gt;
&lt;br /&gt;
Manually adding blocked domains to the RPZ zone file can quickly become tedious, but with this simple test involving example.com, you can see how it’s done. There are some folks on the internet who curate and maintain blocklists. One such source is https://github.com/hagezi/dns-blocklists&lt;br /&gt;
&lt;br /&gt;
To use an ad blocking RPZ you’ll want to perform the following steps:&lt;br /&gt;
&lt;br /&gt;
# Download the file from the source location.&lt;br /&gt;
# Check the file’s validity with named-checkzone&lt;br /&gt;
# Replace the existing /etc/bind/zones/rpz file with the downloaded one.&lt;br /&gt;
# Reload the configuration by running service named reload&lt;br /&gt;
&lt;br /&gt;
New ad domains pop up all the time. The trick is automating the download of new block lists when they come out. A shell script like the one below can help.&lt;br /&gt;
&lt;br /&gt;
 #! /bin/sh&lt;br /&gt;
 &lt;br /&gt;
 cd /etc/bind/zones || exit 1&lt;br /&gt;
 curl -Os https://raw.githubusercontent.com/hagezi/dns-blocklists/main/rpz/multi.txt || exit 2&lt;br /&gt;
 named-checkzone rpz ./multi.txt || exit 3&lt;br /&gt;
 cp rpz rpz~ &amp;amp;&amp;amp; mv multi.txt rpz&lt;br /&gt;
 service named reload&lt;br /&gt;
&lt;br /&gt;
== Next Steps ==&lt;br /&gt;
&lt;br /&gt;
This document has taken you through the basics of setting up BIND9 on your Alpine server. There are many more features that haven’t been covered. Some of the interesting ones include:&lt;br /&gt;
&lt;br /&gt;
* Wildcard subdomains&lt;br /&gt;
* IPv6 domains&lt;br /&gt;
* Secondary DNS servers&lt;br /&gt;
* DNSSEC encryption&lt;br /&gt;
&lt;br /&gt;
Whichever you choose to pursue is up to you. See the [https://bind9.readthedocs.io BIND9 documentation] for more information.&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
	<entry>
		<id>https://wiki.alpinelinux.org/w/index.php?title=Tutorials_and_Howtos&amp;diff=28900</id>
		<title>Tutorials and Howtos</title>
		<link rel="alternate" type="text/html" href="https://wiki.alpinelinux.org/w/index.php?title=Tutorials_and_Howtos&amp;diff=28900"/>
		<updated>2025-02-02T15:00:57Z</updated>

		<summary type="html">&lt;p&gt;DavesCodeMusings: /* DNS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Image:package_edutainment.svg|right|link=]]&lt;br /&gt;
{{TOC left}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Welcome to Tutorials and Howtos, a place of basic and advanced configuration tasks for your Alpine Linux.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Howtos are smaller articles&#039;&#039;&#039; explaining how to perform a particular task with Alpine Linux, that expects a minimal knowledge from reader to perform actions. Howto&#039;s have been organized in the below page based on the topics.  &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The [[#Tutorials|tutorials]] are hands-on&#039;&#039;&#039; and the reader is expected to try and achieve the goals described in each step, possibly with the help of a good example. The output in one step is the starting point for the following step.&lt;br /&gt;
&lt;br /&gt;
{{Note|&lt;br /&gt;
* Contributors are requested to refer to [[Help:Editing]] first and make use of resources like [[How to write a HOWTO]].&lt;br /&gt;
* Contributions must be complete articles. &lt;br /&gt;
* Don&#039;t override already made contributions, unless there is a mistake. &lt;br /&gt;
* If you want to request a topic, please add your request in this page&#039;s [[Talk:Tutorials_and_Howtos|Discussion]].}}&lt;br /&gt;
&lt;br /&gt;
== Desktop ==&lt;br /&gt;
&lt;br /&gt;
* {{:Daily driver guide}}&lt;br /&gt;
=== Power management ===&lt;br /&gt;
&lt;br /&gt;
* [[Configure action when power-button is pressed]]&lt;br /&gt;
* [[Suspend on LID close]]&lt;br /&gt;
* [[Configure Wake-on-LAN]]&lt;br /&gt;
&lt;br /&gt;
=== Networking ===&lt;br /&gt;
&lt;br /&gt;
* [[Bluetooth]] - Instructions for installing and configuring Bluetooth&lt;br /&gt;
* [[Bonding]] - Bond (or aggregate) multiple ethernet interfaces&lt;br /&gt;
* [[Bridge]] - Configuring a network bridge&lt;br /&gt;
** [[Bridge wlan0 to eth0]]&lt;br /&gt;
* [[Configure Networking]]&lt;br /&gt;
* [[How to configure static routes]]&lt;br /&gt;
* Modem&lt;br /&gt;
** [[Using HSDPA modem]]&lt;br /&gt;
** [[Using serial modem]]&lt;br /&gt;
* [[mDNS]] - Howto implement multicast DNS resolution in Alpine. &lt;br /&gt;
* [[Multi ISP]] &#039;&#039;(Dual-ISP setup with load-balancing and automatic failover)&#039;&#039;&lt;br /&gt;
* [[PXE boot]]&lt;br /&gt;
* Wi-Fi&lt;br /&gt;
** [[Wi-Fi|Connecting to a wireless access point]]&lt;br /&gt;
** [[How to setup a wireless access point]] &#039;&#039;(Setting up Secure Wireless AP w/ WPA encryption with bridge to wired network)&#039;&#039;&lt;br /&gt;
* [[VLAN]]&lt;br /&gt;
&lt;br /&gt;
=== Security ===&lt;br /&gt;
&lt;br /&gt;
* [[Securing Alpine Linux]] How to Secure Alpine Linux using Security Technical Implementation Guides (STIGs)&lt;br /&gt;
* Understand [[UEFI]] and enable [[UEFI Secure Boot]]&lt;br /&gt;
&lt;br /&gt;
=== Backup and data migration ===&lt;br /&gt;
&lt;br /&gt;
* [[Migrating data]]&lt;br /&gt;
* [[Rsnapshot]] - setting up periodic backups&lt;br /&gt;
&lt;br /&gt;
=== Other topics ===&lt;br /&gt;
&lt;br /&gt;
* [[Gaming on Alpine]]&lt;br /&gt;
* [[Remote Desktop Server]]&lt;br /&gt;
* [[Default applications|How to change default application]]&lt;br /&gt;
* [[CPU frequency scaling]]&lt;br /&gt;
* [[Mimalloc]]&lt;br /&gt;
* [[Enable Serial Console on Boot]]&lt;br /&gt;
* [[How to build the Alpine Linux kernel]]&lt;br /&gt;
* [[Nextcloud]] &#039;&#039;(Self hostable cloud suite - Dropbox Alternative)&#039;&#039;&lt;br /&gt;
* [[Setting up lm_sensors]]&lt;br /&gt;
* [[Desktop environments and Window managers|List of supported Desktop environments and Window managers]]&lt;br /&gt;
&lt;br /&gt;
== Diskless ==&lt;br /&gt;
&lt;br /&gt;
* [[Alpine local backup|Alpine local backup (lbu)]] &#039;&#039;(Permanently store your modifications in case your box needs reboot)&#039;&#039;&lt;br /&gt;
** [[Back Up a Flash Memory Installation]]&lt;br /&gt;
** [[Manually editing a existing apkovl]]&lt;br /&gt;
&lt;br /&gt;
== Other Architectures ==&lt;br /&gt;
&lt;br /&gt;
=== ARM ===&lt;br /&gt;
&lt;br /&gt;
* [[Alpine on ARM]]&lt;br /&gt;
&lt;br /&gt;
==== Raspberry Pi ====&lt;br /&gt;
&lt;br /&gt;
* [[Raspberry Pi Bluetooth Speaker|Raspberry Pi - Bluetooth Speaker]]&lt;br /&gt;
* [[Raspberry Pi|Raspberry Pi - Installation]]&lt;br /&gt;
* [[Linux Router with VPN on a Raspberry Pi|Raspberry Pi - Router with VPN]]&lt;br /&gt;
* [[Linux Router with VPN on a Raspberry Pi (IPv6)|Raspberry Pi - Router with VPN (IPv6)]]&lt;br /&gt;
* [[Classic install or sys mode on Raspberry Pi|Raspberry Pi - Sys mode install]]&lt;br /&gt;
* [[Raspberry Pi LVM on LUKS|Raspberry Pi - Sys mode install - LVM on LUKS]]&lt;br /&gt;
* [[RPI Video Receiver|Raspberry Pi - Video Receiver]] &#039;&#039;(network video decoder using Rasperry Pi and omxplayer)&#039;&#039;&lt;br /&gt;
* [[Raspberry Pi 3 - Browser Client]] - kiosk or digital sign&lt;br /&gt;
* [[Raspberry Pi 3 - Configuring it as wireless access point -AP Mode]]&lt;br /&gt;
* [[Raspberry Pi 3 - Setting Up Bluetooth]]&lt;br /&gt;
* [[Raspberry Pi 4 - Persistent system acting as a NAS and Time Machine]]&lt;br /&gt;
* [[How to set up Alpine as a wireless router|Raspberry Pi Zero W - Wireless router]] &#039;&#039;(Setting up a firewalled, Wireless AP with wired network on a Pi Zero W)&#039;&#039;&lt;br /&gt;
* [[RPI Video Receiver]]&lt;br /&gt;
&lt;br /&gt;
=== IBM Z (IBM z Systems) ===&lt;br /&gt;
&lt;br /&gt;
* [[s390x|s390x - Installation]]&lt;br /&gt;
&lt;br /&gt;
=== PowerPC ===&lt;br /&gt;
&lt;br /&gt;
* [[Ppc64le|Powerpc64le - Installation]]&lt;br /&gt;
&lt;br /&gt;
== Services == &lt;br /&gt;
&lt;br /&gt;
{{Note| Services are arranged in alphabetical order.}}&lt;br /&gt;
&lt;br /&gt;
=== Content management systems ===&lt;br /&gt;
&lt;br /&gt;
* [[DokuWiki]]&lt;br /&gt;
* [[Drupal]] &#039;&#039;(Content Management System (CMS) written in PHP)&#039;&#039;&lt;br /&gt;
* [[Kopano]] &#039;&#039;(Microsoft Outlook compatible Groupware)&#039;&#039;&lt;br /&gt;
* [[Mahara]] &#039;&#039;(E-portfolio and social networking system)&#039;&#039;&lt;br /&gt;
* [[MediaWiki]] &#039;&#039;(Free web-based wiki software application)&#039;&#039;&lt;br /&gt;
* [[Pastebin]] &#039;&#039;(Pastebin software application)&#039;&#039;&lt;br /&gt;
* [[WordPress]] &#039;&#039;(Web software to create website or blog)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Database === &lt;br /&gt;
&lt;br /&gt;
* [[MySQL|MySQL]]&lt;br /&gt;
&lt;br /&gt;
=== DNS ===&lt;br /&gt;
&lt;br /&gt;
* [[DNSCrypt-Proxy]] &#039;&#039;Encrypt and authenticate DNS calls from your system&#039;&#039;&lt;br /&gt;
* [[Setting up nsd DNS server]]&lt;br /&gt;
* [[Setting up unbound DNS server]]&lt;br /&gt;
* [[Small-Time DNS with BIND9]] &#039;&#039;(A simple configuration with ad blocking for your home network)&#039;&#039;&lt;br /&gt;
* [[TinyDNS Format]]&lt;br /&gt;
&lt;br /&gt;
=== File server ===&lt;br /&gt;
&lt;br /&gt;
* [[Setting up an NFS server|nfs-server]]&lt;br /&gt;
* [[Setting up a Samba server|samba-server]] &#039;&#039;(standard file sharing)&#039;&#039;&lt;br /&gt;
* [[Setting up a samba-ad-dc|samba-ad-dc]] &#039;&#039;(Active Directory compatible domain controller)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Firewall and VPN ===&lt;br /&gt;
&lt;br /&gt;
* Alpine Wall &#039;&#039;(a new firewall management framework)&#039;&#039;&lt;br /&gt;
** [[Alpine Wall]]&lt;br /&gt;
** [https://git.alpinelinux.org/awall/about/ Alpine Wall User&#039;s Guide]&lt;br /&gt;
** [[How-To Alpine Wall]]&lt;br /&gt;
* [[Freeradius Active Directory Integration]]&lt;br /&gt;
* [[GNUnet]]&lt;br /&gt;
* [[Setting up a OpenVPN server|OpenVPN server]] &#039;&#039;(Allowing single users or devices to remotely connect to your network)&#039;&#039;&lt;br /&gt;
* [[OpenVSwitch]]&lt;br /&gt;
* [[Using Alpine on Windows domain with IPSEC isolation]]&lt;br /&gt;
* [[Configure a Wireguard interface (wg)|Wireguard]]&lt;br /&gt;
* [[IGMPproxy]]&lt;br /&gt;
&lt;br /&gt;
=== HTTP and web services ===&lt;br /&gt;
&lt;br /&gt;
* [[Apache]]&lt;br /&gt;
** [[Apache with php-fpm]]&lt;br /&gt;
** [[Setting Up Apache with PHP]]&lt;br /&gt;
** [[Apache authentication: NTLM Single Signon]]&lt;br /&gt;
* [[Darkhttpd]]&lt;br /&gt;
* [[Lighttpd]]&lt;br /&gt;
** [[Lighttpd Advanced security]]&lt;br /&gt;
** [[Setting Up Lighttpd With FastCGI]]&lt;br /&gt;
** [[Production Web server: Lighttpd|Production web server: Lighttpd‎‎]]&lt;br /&gt;
* [[Nginx]]&lt;br /&gt;
** [[Nginx as reverse proxy with acme (letsencrypt)]]&lt;br /&gt;
** [[Nginx with PHP]]&lt;br /&gt;
* Squid Proxy&lt;br /&gt;
** [[Obtaining user information via SNMP]] &#039;&#039;(Using squark-auth-snmp as a Squid authentication helper)&#039;&#039; &amp;lt;!-- Networking and Server, &amp;lt;== Using squark-auth-snmp --&amp;gt;&lt;br /&gt;
** [[Setting up Explicit Squid Proxy]]&lt;br /&gt;
** [[Setting up Transparent Squid Proxy]] &#039;&#039;(Covers Squid proxy and URL Filtering system)&#039;&#039;&lt;br /&gt;
** [[SqStat]] &#039;&#039;(Script to look at active squid users connections)&#039;&#039;&lt;br /&gt;
* [[Tomcat]]&lt;br /&gt;
** [[Production LAMP system: Lighttpd + PHP + MySQL‎‎]]&lt;br /&gt;
&lt;br /&gt;
=== IRC ===&lt;br /&gt;
&lt;br /&gt;
* [[NgIRCd]] &#039;&#039;(Server for Internet Relay Chat/IRC)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Mail ===&lt;br /&gt;
&lt;br /&gt;
* [[Hosting services on Alpine]] &#039;&#039;(Hosting mail, webservices and other services)&#039;&#039;&lt;br /&gt;
* [[Hosting Web/Email services on Alpine]]&lt;br /&gt;
* Exim/Dovecot&lt;br /&gt;
** [[Small-Time Email with Exim and Dovecot]] &#039;&#039;(A simple configuration for your home network.)&lt;br /&gt;
** [[Setting up dovecot with imap and tls]]&lt;br /&gt;
* [[relay email to gmail (msmtp, mailx, sendmail]]&lt;br /&gt;
* [[relay email (nullmailer)]]&lt;br /&gt;
* [[Roundcube]] &#039;&#039;(Webmail system)&#039;&#039;&lt;br /&gt;
* [[Setting up postfix with virtual domains]]&lt;br /&gt;
* Server protection&lt;br /&gt;
** [[Setting up clamsmtp]]&lt;br /&gt;
&lt;br /&gt;
=== Monitoring ===&lt;br /&gt;
&lt;br /&gt;
* [[Awstats]] &#039;&#039;(Free log file analyzer)&#039;&#039;&lt;br /&gt;
* [[Cacti: traffic analysis and monitoring network]] &#039;&#039;(Front-end for rrdtool networking monitor)&#039;&#039;&lt;br /&gt;
* [[Cvechecker]] &#039;&#039;(Compare installed packages for Common Vulnerabilities Exposure)&#039;&#039; &amp;lt;!-- Monitoring and Security --&amp;gt;&lt;br /&gt;
* [[Linfo]]&lt;br /&gt;
* [[Obtaining user information via SNMP]] &#039;&#039;(Using squark-auth-snmp as a Squid authentication helper)&#039;&#039; &amp;lt;!-- Networking and Server, &amp;lt;== Using squark-auth-snmp --&amp;gt;&lt;br /&gt;
* [[PhpSysInfo]] &#039;&#039;(A simple application that displays information about the host it&#039;s running on)&#039;&#039;&lt;br /&gt;
* [[Logcheck]] &#039;&#039;(log file monitoring tool)&#039;&#039;&lt;br /&gt;
* [[Matomo]] &#039;&#039;(A real time web analytics software program)&#039;&#039;&lt;br /&gt;
* [[Rasdaemon]] &#039;&#039;(Platform Reliability, Availability and Serviceability monitoring tool)&#039;&#039;&lt;br /&gt;
* [[Setting up A Network Monitoring and Inventory System]] &#039;&#039;(Nagios + OpenAudit and related components)&#039;&#039; &amp;lt;!-- draft, solution, Networking and Monitoring and Server --&amp;gt;&lt;br /&gt;
** [[Setting up NRPE daemon]] &#039;&#039;(Performs remote Nagios checks)&#039;&#039; &amp;lt;!-- Networking and Monitoring --&amp;gt;&lt;br /&gt;
* [[Setting Up Fprobe And Ntop|Ntop]] &#039;&#039;(NetFlow collection and analysis using a remote fprobe instance; for alpine 3.10-3.12 only)&#039;&#039; &amp;lt;!-- Networking and Monitoring --&amp;gt;&lt;br /&gt;
* [[SqStat]] &#039;&#039;(Script to look at active squid users connections)&#039;&#039;&lt;br /&gt;
* [[Traffic monitoring]] &amp;lt;!-- Networking and Monitoring --&amp;gt;&lt;br /&gt;
** [[Setting up monitoring using rrdtool (and rrdcollect)]]&lt;br /&gt;
** [[Setting up traffic monitoring using rrdtool (and snmp)]] &amp;lt;!-- Monitoring --&amp;gt;&lt;br /&gt;
* [[Zabbix|Zabbix - the professional complete manager]] &#039;&#039;(Monitor and track the status of network services and hardware)&#039;&#039;&lt;br /&gt;
* [[ZoneMinder video camera security and surveillance]]&lt;br /&gt;
&lt;br /&gt;
=== Remote Administration ===&lt;br /&gt;
&lt;br /&gt;
* ACF&lt;br /&gt;
** [[Changing passwords for ACF|ACF - changing passwords]]&lt;br /&gt;
** [[Generating SSL certs with ACF]] &amp;lt;!-- Generating SSL certs with ACF 1.9 --&amp;gt;&lt;br /&gt;
** [[setup-acf| ACF - setup]] &#039;&#039;(Configures ACF (webconfiguration/webmin) so you can manage your box through https)&#039;&#039;&lt;br /&gt;
* [[Setting up a SSH server]] &#039;&#039;(Using ssh is a good way to administer your box remotely)&#039;&#039;&lt;br /&gt;
** [[HOWTO OpenSSH 2FA with password and Google Authenticator |OpenSSH 2FA]] &#039;&#039;(A simple two factor setup for OpenSSH)&#039;&#039;&lt;br /&gt;
* [[OpenVCP]] &#039;&#039;(VServer Control Panel)&#039;&#039;&lt;br /&gt;
* [[PhpMyAdmin]] &#039;&#039;(Web-based administration tool for MYSQL)&#039;&#039;&lt;br /&gt;
* [[PhpPgAdmin]] &#039;&#039;(Web-based administration tool for PostgreSQL)&#039;&#039;&lt;br /&gt;
* [[Webmin]] &#039;&#039;(A web-based interface for Linux system)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Telephony ===&lt;br /&gt;
&lt;br /&gt;
* [[FreePBX|FreePBX on Alpine Linux]]&lt;br /&gt;
* [[Setting up Zaptel/Asterisk on Alpine]]&lt;br /&gt;
* [[Kamailio]] &#039;&#039;(SIP Server, formerly OpenSER)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Other Servers ===&lt;br /&gt;
&lt;br /&gt;
* [[apcupsd]] &#039;&#039;(UPS Monitoring with apcupsd)&#039;&#039;&lt;br /&gt;
* [[Chrony and GPSD | Chrony, gpsd, and a garmin LVC 18 as a Stratum 1 NTP source ]]&lt;br /&gt;
* [[Glpi]] &#039;&#039;(Manage inventory of technical resources)&#039;&#039;&lt;br /&gt;
* [[How to setup a Alpine Linux mirror]]&lt;br /&gt;
* [[nut-ups|NUT UPS]] &#039;&#039;(UPS Monitoring with Network UPS Tools)&#039;&#039;&lt;br /&gt;
* [[Odoo]]&lt;br /&gt;
* [[Configure OpenLDAP | OpenLDAP]] &#039;&#039;(Installing and configuring the Alpine package for OpenLDAP)&#039;&#039;&lt;br /&gt;
* [[Setting up a LLDAP server|lldap-server]] &#039;&#039;(Directory Server)&#039;&#039;&lt;br /&gt;
* [[Setting up Transmission (bittorrent) with Clutch WebUI]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Software development ==&lt;br /&gt;
&lt;br /&gt;
* [[Cgit]]&lt;br /&gt;
* [[OsTicket]] &#039;&#039;(Ticket system)&#039;&#039;&lt;br /&gt;
* [[Patchwork]] &#039;&#039;(Patch review management system)&#039;&#039;&lt;br /&gt;
* [[Redmine]] &#039;&#039;(Project management system)&#039;&#039;&lt;br /&gt;
* [[Request Tracker]] &#039;&#039;(Ticket system)&#039;&#039;&lt;br /&gt;
* [[Setting up trac wiki|Trac]] &#039;&#039;(Enhanced wiki and issue tracking system for software development projects)&#039;&#039;&lt;br /&gt;
* [[Ansible]] &#039;&#039;(Configuration management)&#039;&#039;&lt;br /&gt;
* [[Installing Oracle Java|Oracle Java (installation)]]&lt;br /&gt;
&lt;br /&gt;
== Storage ==&lt;br /&gt;
&lt;br /&gt;
* [[Setting up disks manually|Manual partitioning]]&lt;br /&gt;
* [[Disk Replication with DRBD|DRBD: Disk Replication]]&lt;br /&gt;
* [[Filesystems]]&lt;br /&gt;
** [[Burning ISOs]]&lt;br /&gt;
* [[Setting up iSCSI|iSCSI Setup]]&lt;br /&gt;
** [[iSCSI Raid and Clustered File Systems]]&lt;br /&gt;
** [[Linux iSCSI Target (TCM)|iSCSI Target (TCM)/LinuxIO (LIO)]]&lt;br /&gt;
** [[Linux iSCSI Target (tgt)|User space iSCSI Target (tgt)]]&lt;br /&gt;
* [[Setting up Logical Volumes with LVM|LVM Setup]]&lt;br /&gt;
** [[Setting up LVM on GPT-labeled disks|LVM on GPT-labeled disks]]&lt;br /&gt;
** [[Installing on GPT LVM|LVM on GPT-labeled disks (updated)]]&lt;br /&gt;
** [[LVM on LUKS]]&lt;br /&gt;
* RAID&lt;br /&gt;
** [[Raid Administration]]&lt;br /&gt;
** [[Setting up a software RAID array]]&lt;br /&gt;
* ZFS&lt;br /&gt;
** [[Root on ZFS with native encryption]]&lt;br /&gt;
** [[Setting up ZFS on LUKS]]&lt;br /&gt;
** [[Setting up ZFS with native encryption]]&lt;br /&gt;
** [[ZFS scrub and trim]]&lt;br /&gt;
* [[CEPH|CEPH]]&lt;br /&gt;
&lt;br /&gt;
== Virtualization ==&lt;br /&gt;
&lt;br /&gt;
* [[Docker]]&lt;br /&gt;
* [[Installing Alpine in a virtual machine]]&lt;br /&gt;
** [[Install Alpine on VMware ESXi]]&lt;br /&gt;
* [[KVM]] &#039;&#039;(Setting up Alpine as a KVM hypervisor)&#039;&#039;&lt;br /&gt;
* [[LXC]] &#039;&#039;(Setting up a Linux container in Alpine Linux)&#039;&#039;&lt;br /&gt;
* [[QEMU]]&lt;br /&gt;
* Xen&lt;br /&gt;
** [[Xen Dom0]] &#039;&#039;(Setting up Alpine as a dom0 for Xen hypervisor)&#039;&#039;&lt;br /&gt;
** [[Xen Dom0 on USB or SD]]&lt;br /&gt;
** [[Create Alpine Linux PV DomU|Xen DomU (paravirtualized)]]&lt;br /&gt;
** [[Xen LiveCD]]&lt;br /&gt;
** [[Xen PCI Passthrough]]&lt;br /&gt;
** [[K8s]] Building a K8s Kubernetes Cluster on Alpine Linux&lt;br /&gt;
&lt;br /&gt;
== Tutorials ==&lt;br /&gt;
&lt;br /&gt;
* [[TTY_Autologin|TTY Autologin]]&lt;br /&gt;
* [[Kexec|Faster rebooting with kexec]]&lt;br /&gt;
* [[Dynamic Multipoint VPN (DMVPN)]] combined with [[Small Office Services]]&lt;br /&gt;
* [[DIY Fully working Alpine Linux for Allwinner and Other ARM SOCs]]&lt;br /&gt;
* [[Fault Tolerant Routing with Alpine Linux]]&lt;br /&gt;
* [[High Availability High Performance Web Cache]] &#039;&#039;(uCarp + HAProxy for High Availability Services such as Squid web proxy)&#039;&#039;&lt;br /&gt;
* [[Linux iSCSI Target (TCM)]]&lt;br /&gt;
* [[ISP Mail Server 3.x HowTo]] &#039;&#039;(Postfix+PostfixAdmin+DoveCot+Roundcube+ClamAV+Spamd - A full-service ISP mail server)&#039;&#039;&lt;br /&gt;
* [[Grommunio Mail Server]] &#039;&#039;(Mariadb+Postfix+Rspamd+Grommunio - Full-service mail server as MS exchange replacement)&#039;&#039;&lt;br /&gt;
* [[Replacing non-Alpine Linux with Alpine remotely]]&lt;br /&gt;
* [[Setting up A Network Monitoring and Inventory System]] &#039;&#039;(Nagios + OpenAudit and related components)&#039;&#039; &amp;lt;!-- draft --&amp;gt;&lt;br /&gt;
* [[Streaming Security Camera Video with VLC]]&lt;br /&gt;
* [[Install Alpine on a btrfs filesystem with refind as boot manager]]&lt;br /&gt;
* [[Compile software from source|How to Compile a software from source in Alpine Linux]]&lt;/div&gt;</summary>
		<author><name>DavesCodeMusings</name></author>
	</entry>
</feed>