<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: budiantoip</title>
    <description>The latest articles on DEV Community by budiantoip (@budiantoip).</description>
    <link>https://dev.to/budiantoip</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F927016%2F1e165e4f-6e70-4874-8b65-5931068f3930.jpeg</url>
      <title>DEV Community: budiantoip</title>
      <link>https://dev.to/budiantoip</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/budiantoip"/>
    <language>en</language>
    <item>
      <title>Configure Email Clients</title>
      <dc:creator>budiantoip</dc:creator>
      <pubDate>Tue, 28 May 2024 09:50:35 +0000</pubDate>
      <link>https://dev.to/budiantoip/configure-email-clients-43f2</link>
      <guid>https://dev.to/budiantoip/configure-email-clients-43f2</guid>
      <description>&lt;p&gt;This part will guide you on how to configure email clients, such as &lt;a href="https://www.thunderbird.net/en-US/"&gt;Mozilla Thunderbird&lt;/a&gt;, &lt;a href="https://www.icloud.com/mail"&gt;Apple Mail&lt;/a&gt;, and &lt;a href="https://www.microsoft.com/en-us/microsoft-365/outlook/email-and-calendar-software-microsoft-outlook"&gt;Microsoft Outlook&lt;/a&gt;. Further details will be explained in each section.&lt;/p&gt;

&lt;h2&gt;
  
  
  IMAP or POP
&lt;/h2&gt;

&lt;p&gt;Before we begin, since we will be presented with the option to choose between IMAP and POP when configuring mail clients, let us review the differences between the two.&lt;/p&gt;

&lt;h3&gt;
  
  
  IMAP
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Server-Based Storage
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Emails are stored on the mail server and synchronized across all devices.&lt;/li&gt;
&lt;li&gt;Actions like reading, deleting, or organizing emails are mirrored on all devices.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Accessibility:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Allows access to email from multiple devices (computers, smartphones, tablets) while keeping everything synchronized.&lt;/li&gt;
&lt;li&gt;Ideal for users who check their email from various locations or devices.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Real-Time Updates:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Changes made in the mail client are reflected immediately on the server and other devices.&lt;/li&gt;
&lt;li&gt;Supports folder organization and maintains the structure across devices.
#### Offline Access:&lt;/li&gt;
&lt;li&gt;You can choose to download emails for offline access, but changes made offline will be updated on the server once reconnected.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Space Management:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Email is stored on the server, potentially occupying server space if not managed properly.&lt;/li&gt;
&lt;li&gt;Typically used by those with large mail quotas or those who manage emails regularly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  POP
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Local Storage:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Emails are downloaded from the server to a single device and typically deleted from the server (though some settings allow copies to remain on the server).&lt;/li&gt;
&lt;li&gt;Actions on one device (like deleting or moving emails) do not affect other devices.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Single-Device Focus:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Best suited for users who access their email from one device.&lt;/li&gt;
&lt;li&gt;Less suitable for multi-device access since synchronization across devices is not inherently supported.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Offline Access:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Since emails are downloaded and stored locally, they are accessible offline.&lt;/li&gt;
&lt;li&gt;Changes made (like organizing or deleting emails) are local to that device only.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Space Management:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Frees up server space since emails are typically removed from the server after download.&lt;/li&gt;
&lt;li&gt;Useful for users with limited server storage or who prefer keeping a local archive.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Which One to Choose?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;IMAP is generally recommended if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access your email from multiple devices.&lt;/li&gt;
&lt;li&gt;Want real-time synchronization of your email and folders across all devices.&lt;/li&gt;
&lt;li&gt;Prefer server-based storage and management of your emails.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;POP might be suitable if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mainly access your email from a single device.&lt;/li&gt;
&lt;li&gt;Prefer to download and store emails locally.&lt;/li&gt;
&lt;li&gt;Want to minimize server storage usage.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mozilla Thunderbird
&lt;/h2&gt;

&lt;p&gt;Mozilla Thunderbird is free and open-source email client software that also functions as a full personal information manager with a calendar and contact book and an RSS feed reader, chat client, and news client.&lt;/p&gt;

&lt;p&gt;To download the application file, head over to &lt;a href="https://www.thunderbird.net/en-US/"&gt;this page&lt;/a&gt; and then click the Download button at the top right. Once downloaded, install the application.&lt;/p&gt;

&lt;p&gt;To configure email on Mozilla Thunderbird, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Mozilla Thunderbird.&lt;/li&gt;
&lt;li&gt;Open the Account Settings, and add a Mail Account.&lt;/li&gt;
&lt;li&gt;You will be presented with this form:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fubji5z5b0x4kmaeso4jb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fubji5z5b0x4kmaeso4jb.png" alt="Set Up Email Address" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enter your full name, email address, and password.&lt;/li&gt;
&lt;li&gt;Ensure the Remember password option is checked.&lt;/li&gt;
&lt;li&gt;Click continue and the application will try to get the email server configuration automatically.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If the process runs successfully, you will see a message like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnp2zdnndzr6e6regspt5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnp2zdnndzr6e6regspt5.png" alt="Configuration Found" width="800" height="83"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You will be presented with two configurations, IMAP and POP3.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once you choose the config you want, click Done.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After that you will be presented with the "Account successfully created" message.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click Finish, and you will be redirected to your email inbox. From there you can send and receive emails.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Apple Mail
&lt;/h2&gt;

&lt;p&gt;Apple Mail is available on MacOS.&lt;/p&gt;

&lt;p&gt;To configure email on apple mail, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the apple mail application.&lt;/li&gt;
&lt;li&gt;Click the Mail menu on top left, near the apple icon. Then click Accounts.&lt;/li&gt;
&lt;li&gt;An "Internet Accounts" window will be opened.&lt;/li&gt;
&lt;li&gt;Click the Add Account button at the bottom, then choose Add Other Account...&lt;/li&gt;
&lt;li&gt;Choose Mail account.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You will be presented with a form like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3jplbfmo38lovnaedvlb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3jplbfmo38lovnaedvlb.png" alt="Add a mail account form" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enter your name, email address, and password. Then click Sign in&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After that, the form will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fro4cf15ca6039qae97bt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fro4cf15ca6039qae97bt.png" alt="Mail settings" width="800" height="577"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pick an Account Type, IMAP or POP&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enter &lt;strong&gt;mail.domain.com&lt;/strong&gt; on both Incoming and Outgoing Mail Servers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once done, click Sign in again.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It might take a while for it to process. Once done, open up your Apple Mail application, and you will see your mailbox there. From there you can send and receive emails.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Microsoft Outlook
&lt;/h2&gt;

&lt;p&gt;Microsoft Outlook can be obtained by purchasing a Microsoft 365 subscription. For more information, refer to &lt;a href="https://www.microsoft.com/en-us/microsoft-365/outlook/email-and-calendar-software-microsoft-outlook"&gt;this page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To configure email on Microsoft Outlook, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Microsoft Outlook.&lt;/li&gt;
&lt;li&gt;Go to Settings.&lt;/li&gt;
&lt;li&gt;Choose Accounts.&lt;/li&gt;
&lt;li&gt;Add an account.&lt;/li&gt;
&lt;li&gt;Enter your email address.&lt;/li&gt;
&lt;li&gt;Choose IMAP/POP as the provider.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The form will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhnx3hl89o0ozsrisl9i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkhnx3hl89o0ozsrisl9i.png" alt="Set Up Your Email" width="800" height="964"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Important!&lt;/strong&gt; Remove &lt;strong&gt;@domain.com&lt;/strong&gt; from Username.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enter your email password.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Type &lt;strong&gt;mail.domain.com&lt;/strong&gt; as both Incoming and Outgoing Servers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click Add Account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You will then see a message like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;email-test@domain.com has been added&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Close the window and go back to your Microsoft Outlook.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You should now be able to send and receive emails.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>email</category>
      <category>exim</category>
      <category>almalinux</category>
    </item>
    <item>
      <title>How to Build Email Server with Exim on Alma Linux 9</title>
      <dc:creator>budiantoip</dc:creator>
      <pubDate>Sat, 20 Apr 2024 07:59:22 +0000</pubDate>
      <link>https://dev.to/budiantoip/how-to-build-email-server-with-exim-on-alma-linux-9-568e</link>
      <guid>https://dev.to/budiantoip/how-to-build-email-server-with-exim-on-alma-linux-9-568e</guid>
      <description>&lt;h2&gt;
  
  
  Cloud Provider Consideration
&lt;/h2&gt;

&lt;p&gt;Before we continue, be mindful when choosing the cloud provider in which your email server will be launched. Not all cloud providers open the email-sending port, e.g., 25, hence blocking your email-sending capabilities. You will need to request them to open the port, and they will ask for some information before they can approve your request. Some providers I have known like these close their email-sending port:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Digital Ocean&lt;/li&gt;
&lt;li&gt;Vultr&lt;/li&gt;
&lt;li&gt;Linode&lt;/li&gt;
&lt;li&gt;AWS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can host your email server at Contabo or Kamatera or even build it on your on-premise server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server Consideration
&lt;/h2&gt;

&lt;p&gt;Installing from a new server is highly recommended, as it will avoid any unnecessary dependency conflict.&lt;/p&gt;

&lt;h2&gt;
  
  
  Screen Installation
&lt;/h2&gt;

&lt;p&gt;First, we will install the &lt;code&gt;screen&lt;/code&gt; package. The package is helpful if we get disconnected during the build session, we can reconnect to the session and continue what we left off.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; epel-release
&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; screen


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, start a screen session.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

screen &lt;span class="nt"&gt;-U&lt;/span&gt; &lt;span class="nt"&gt;-S&lt;/span&gt; email-server-build


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Later, when you get disconnected from the ssh session, run this command to resume the session:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

screen &lt;span class="nt"&gt;-R&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To list active screen sessions, run this command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

screen &lt;span class="nt"&gt;-ls&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To terminate current screen session, run:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;exit&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Setup Hostname
&lt;/h2&gt;

&lt;p&gt;We will set up a hostname to identify the server uniquely.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

hostnamectl set-hostname &amp;lt;server_name&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

hostnamectl set-hostname mail.domain.com


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, verify the change by running this command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;hostname&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The output should look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

mail.domain.com


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, update the hosts file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

vim /etc/hosts


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Change an entry like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

x.x.x.x vmi123456.server.net vmi123456


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Note that, &lt;code&gt;x.x.x.x&lt;/code&gt; is the server's IP address.&lt;br&gt;
To this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

x.x.x.x vmi123456.server.net vmi123456 mail.domain.com


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Reboot the server to apply the changes.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

shutdown &lt;span class="nt"&gt;-r&lt;/span&gt; now


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  System Update and Dependencies Installation
&lt;/h2&gt;

&lt;p&gt;We need to update the existing packages.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf update


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, install vim as our text editor. You can install your own preferred text editor, e.g. nano. And, install &lt;code&gt;tar&lt;/code&gt; and &lt;code&gt;socat&lt;/code&gt; as they are required by &lt;code&gt;acme.sh&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install &lt;/span&gt;vim &lt;span class="nb"&gt;tar &lt;/span&gt;socat &lt;span class="nt"&gt;-y&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Acme.sh Installation
&lt;/h2&gt;

&lt;p&gt;Next, we will install &lt;code&gt;acme.sh&lt;/code&gt;, a command-line tool for managing SSL/TLS certificates. I prefer &lt;code&gt;acme.sh&lt;/code&gt; over &lt;code&gt;certbot&lt;/code&gt;, as it does not depend on the OS version. For more details about &lt;code&gt;acme.sh&lt;/code&gt;, check its GitHub repo &lt;a href="https://github.com/acmesh-official/acme.sh" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, install &lt;code&gt;acme.sh&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

curl https://get.acme.sh | sh &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nv"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my@example.com


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Note that change &lt;code&gt;my@example.com&lt;/code&gt; accordingly.&lt;br&gt;
Create an alias for the acme.sh command so we can run &lt;code&gt;acme.sh&lt;/code&gt; directly without specifying its full path.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'alias acme.sh="/root/.acme.sh/acme.sh"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.bash_aliases
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bash_aliases


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Before we issue an SSL certificate, we must configure the DNS record properly. I will use &lt;code&gt;mail.domain.com&lt;/code&gt; in this tutorial, and its A and MX records has already been configured. Refer to the &lt;code&gt;DNS Record Configuration&lt;/code&gt; section at the end of this article to get more details.&lt;/p&gt;

&lt;p&gt;After that, let us start issuing a staging SSL certificate. This certificate cannot be used on production servers and is used primarily to test certificate generation. Note that generating a live LetsEncrypt certificate is limited to 50 per week, for more info check &lt;a href="https://letsencrypt.org/docs/rate-limits/#:~:text=You%20can%20create%20a%20maximum,produced%20in%20each%20certificate%20request." rel="noopener noreferrer"&gt;this documentation&lt;/a&gt;. If it works, we can continue issuing a live SSL certificate.&lt;/p&gt;

&lt;p&gt;Before we issue the SSL certificate, let us create a folder to store the generated certificates.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /etc/pki/tls/certs/staging
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /etc/pki/tls/certs/live


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To issue a staging SSL certificate, run this command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

acme.sh &lt;span class="nt"&gt;--issue&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"mail.domain.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--cert-home&lt;/span&gt; /etc/pki/tls/certs/staging &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--standalone&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--debug&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--staging&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Some notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-d&lt;/code&gt;: the domain name we want to issue the certificate for&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--cert-home&lt;/code&gt;: the folder path where we want the generated certificate files to be stored.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--standalone&lt;/code&gt;: this assumes we do not have a web server capable of serving web files, e.g. apache or nginx&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;debug&lt;/code&gt;: display all information. Useful for tracing issues&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;staging&lt;/code&gt;: generate a staging certificate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If things go well, you will see an output like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="o"&gt;[&lt;/span&gt;Sun Mar 24 04:08:19 UTC 2024] Your cert is &lt;span class="k"&gt;in&lt;/span&gt;: /etc/pki/tls/certs/staging/mail.domain.com_ecc/mail.domain.com.cer
&lt;span class="o"&gt;[&lt;/span&gt;Sun Mar 24 04:08:19 UTC 2024] Your cert key is &lt;span class="k"&gt;in&lt;/span&gt;: /etc/pki/tls/certs/staging/mail.domain.com_ecc/mail.domain.com.key
&lt;span class="o"&gt;[&lt;/span&gt;Sun Mar 24 04:08:19 UTC 2024] The intermediate CA cert is &lt;span class="k"&gt;in&lt;/span&gt;: /etc/pki/tls/certs/staging/mail.domain.com_ecc/ca.cer
&lt;span class="o"&gt;[&lt;/span&gt;Sun Mar 24 04:08:19 UTC 2024] And the full chain certs is there: /etc/pki/tls/certs/staging/mail.domain.com_ecc/fullchain.cer
&lt;span class="o"&gt;[&lt;/span&gt;Sun Mar 24 04:08:19 UTC 2024] _on_issue_success


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, let us issue a live certificate:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

acme.sh &lt;span class="nt"&gt;--issue&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"mail.domain.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--cert-home&lt;/span&gt; /etc/pki/tls/certs/live &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--standalone&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--debug&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This time we removed the &lt;code&gt;--staging&lt;/code&gt; parameter, and changed the certificate home folder.&lt;/p&gt;

&lt;p&gt;The output will look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="o"&gt;[&lt;/span&gt;Sun Mar 24 04:35:12 UTC 2024] Your cert is &lt;span class="k"&gt;in&lt;/span&gt;: /etc/pki/tls/certs/live/mail.mail.domain.com_ecc/mail.mail.domain.com.cer
&lt;span class="o"&gt;[&lt;/span&gt;Sun Mar 24 04:35:12 UTC 2024] Your cert key is &lt;span class="k"&gt;in&lt;/span&gt;: /etc/pki/tls/certs/live/mail.mail.domain.com_ecc/mail.mail.domain.com.key
&lt;span class="o"&gt;[&lt;/span&gt;Sun Mar 24 04:35:12 UTC 2024] The intermediate CA cert is &lt;span class="k"&gt;in&lt;/span&gt;: /etc/pki/tls/certs/live/mail.mail.domain.com_ecc/ca.cer
&lt;span class="o"&gt;[&lt;/span&gt;Sun Mar 24 04:35:12 UTC 2024] And the full chain certs is there: /etc/pki/tls/certs/live/mail.mail.domain.com_ecc/fullchain.cer
&lt;span class="o"&gt;[&lt;/span&gt;Sun Mar 24 04:35:12 UTC 2024] _on_issue_success


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, we need to change the future SSL generation configured via crontab. Run this command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vim crontab &lt;span class="nt"&gt;-e&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Replace the following cron:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

11 16 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="s2"&gt;"/root/.acme.sh"&lt;/span&gt;/acme.sh &lt;span class="nt"&gt;--cron&lt;/span&gt; &lt;span class="nt"&gt;--home&lt;/span&gt; &lt;span class="s2"&gt;"/root/.acme.sh"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

11 16 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /root/.acme.sh/acme.sh &lt;span class="nt"&gt;--cron&lt;/span&gt; &lt;span class="nt"&gt;--home&lt;/span&gt; /root/.acme.sh &lt;span class="nt"&gt;--cert-home&lt;/span&gt; /etc/pki/tls/certs/live &lt;span class="nt"&gt;--standalone&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Configure Firewall
&lt;/h2&gt;

&lt;p&gt;We will use firewalld to protect our email server. First, install the firewalld package.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; firewalld


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, enable and start firewalld on server startup.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;firewalld
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start firewalld


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, configure firewall rules.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;public &lt;span class="nt"&gt;--permanent&lt;/span&gt; &lt;span class="nt"&gt;--add-service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http
&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;public &lt;span class="nt"&gt;--permanent&lt;/span&gt; &lt;span class="nt"&gt;--add-service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https
&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;public &lt;span class="nt"&gt;--add-service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pop3 &lt;span class="nt"&gt;--permanent&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;public &lt;span class="nt"&gt;--add-service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pop3s &lt;span class="nt"&gt;--permanent&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;public &lt;span class="nt"&gt;--add-service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;smtp &lt;span class="nt"&gt;--permanent&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;public &lt;span class="nt"&gt;--add-service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;smtps &lt;span class="nt"&gt;--permanent&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;public &lt;span class="nt"&gt;--add-service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;imap &lt;span class="nt"&gt;--permanent&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;public &lt;span class="nt"&gt;--add-service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;imaps &lt;span class="nt"&gt;--permanent&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--reload&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Validate the result by checking the configured firewall rules.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;public &lt;span class="nt"&gt;--list-all&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The output should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7chddpnrar8iv16xvpr4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7chddpnrar8iv16xvpr4.png" alt="Firewall Rule List"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Exim Installation and Configuration
&lt;/h2&gt;

&lt;p&gt;We will install Exim, a mail transfer agent used to deliver and receive emails.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; exim


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Before configuring exim, we need to back up the existing config file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /etc/exim/exim.conf&lt;span class="o"&gt;{&lt;/span&gt;,.orig&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will copy &lt;code&gt;exim.conf&lt;/code&gt; to &lt;code&gt;exim.conf.orig&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After that, we can safely configure exim.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

vim /etc/exim/exim.conf


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Adjust the existing exim configuration so they look like these:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

primary_hostname = mail.domain.com
domainlist local_domains = @ : domain.com
tls_advertise_hosts = *
tls_certificate = /etc/pki/tls/certs/live/mail.domain.com_ecc/mail.domain.com.cer
tls_privatekey = /etc/pki/tls/certs/live/mail.domain.com_ecc/mail.domain.com.key
auth_advertise_hosts = *


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, find &lt;code&gt;ROUTERS CONFIGURATION&lt;/code&gt; section, and then find &lt;code&gt;localuser:&lt;/code&gt; block.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh6ed2rmft7lnh1r2ebag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh6ed2rmft7lnh1r2ebag.png" alt="localuser block"&gt;&lt;/a&gt;&lt;br&gt;
Adjust the whole block so it will look like these:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

localuser:
  driver = redirect
  check_local_user
  file_transport = local_delivery
  reply_transport = local_delivery_autoreply
  data = /home/${local_part_data}/Maildir


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, find the &lt;code&gt;TRANSPORTS CONFIGURATION&lt;/code&gt; section and then find &lt;code&gt;local_delivery:&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctu7lsrqltxtx69674m0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctu7lsrqltxtx69674m0.png" alt="local_delivery block"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Adjust the whole block so it will look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

local_delivery:
  driver = appendfile
  directory = $home/Maildir
  maildir_format
  maildir_use_size_file
  delivery_date_add
  envelope_to_add
  return_path_add


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And add this block right after the &lt;code&gt;local_delivery:&lt;/code&gt; block.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

local_delivery_autoreply:
   driver = autoreply
   headers = Content-Type: text/plain; charset=utf-8\nContent-Transfer-Encoding: base64
   to = ${sender_address}
   from = ${$local_part}@${$domain}
   debug_print = "T: auto reply for $local_part@$domain"
   once_file_size = 500K
   log = /var/log/exim/sieve_autoreply.log



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The autoreply transport will generate a new email message as an automatic reply to the incoming message. It is useful to generate an automatic email when we are on a vacation or out-of-office. We will utilize this later in Roundcube. For more details on autoreply, refer to the doc &lt;a href="https://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_autoreply_transport.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, find &lt;code&gt;AUTHENTICATION CONFIGURATION&lt;/code&gt; section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F711m0rlg9uo4j1n5731o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F711m0rlg9uo4j1n5731o.png" alt="Authentication Configuration section"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, add these blocks at the end of the section.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

dovecot_login:
  driver = dovecot
  public_name = LOGIN
  server_socket = /var/run/dovecot/auth-client
  server_set_id = $auth1

dovecot_plain:
  driver = dovecot
  public_name = PLAIN
  server_socket = /var/run/dovecot/auth-client
  server_set_id = $auth1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Save all the changes and then quit.&lt;/p&gt;

&lt;p&gt;Start exim service, and automatically start the service on server startup.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start exim
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;exim
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status exim


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Test the &lt;code&gt;local_delivery&lt;/code&gt; transport and ensure there is no warning or error message.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

exim &lt;span class="nt"&gt;-d&lt;/span&gt;+all &lt;span class="nt"&gt;-bP&lt;/span&gt; transport local_delivery


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, change the certificate folder's ownership so that Exim will be able to access the certificates later.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; exim:exim /etc/pki/tls/certs/staging
&lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; exim:exim /etc/pki/tls/certs/live


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Dovecot Installation and Configuration
&lt;/h2&gt;

&lt;p&gt;We will use &lt;code&gt;dovecot&lt;/code&gt;, an open-source IMAP and POP3 server. It takes responsibility for connecting your email client (Thunderbird, etc.) to your mail box.&lt;/p&gt;

&lt;p&gt;Run this command to install dovecot.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; dovecot


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  SSL Configuration
&lt;/h3&gt;

&lt;p&gt;Configure SSL in dovecot.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

vim /etc/dovecot/conf.d/10-ssl.conf


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then adjust the existing config to this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

ssl = yes
ssl_cert = &amp;lt;/etc/pki/tls/certs/live/mail.domain.com_ecc/fullchain.cer
ssl_key = &amp;lt;/etc/pki/tls/certs/live/mail.domain.com_ecc/mail.domain.com.key


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Note that, ensure the file paths are prefixed by &lt;code&gt;&amp;lt;&lt;/code&gt;. Otherwise, it will trigger an error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plain Authentication
&lt;/h3&gt;

&lt;p&gt;Allow plain authentication in dovecot.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

vim /etc/dovecot/conf.d/10-auth.conf


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Adjust the existing config.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

disable_plaintext_auth = no
auth_mechanisms = plain login


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Mailbox Location
&lt;/h3&gt;

&lt;p&gt;Configure mailbox location.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

vim /etc/dovecot/conf.d/10-mail.conf


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Adjust the existing config.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

mail_location = maildir:~/Maildir


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Allow Exim to Authenticate
&lt;/h3&gt;

&lt;p&gt;Set up dovecot to allow Exim to use its authentication system.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

vim /etc/dovecot/conf.d/10-master.conf


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Find the &lt;code&gt;unix_listener auth-userdb&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr06uthr5karn2zqd08pn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr06uthr5karn2zqd08pn.png" alt="unix_listener auth-userdb block"&gt;&lt;/a&gt;&lt;br&gt;
Then, fully comment the block, and add this block beneath it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

unix_listener auth-client {
    mode = 0660
    user = exim
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The final changes should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsg18znexjlx96gkv4x2b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsg18znexjlx96gkv4x2b.png" alt="unix_listener auth-client"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Start dovecot service, and automatically start the service on server startup.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start dovecot
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;dovecot
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status dovecot


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Create an Email Address
&lt;/h2&gt;

&lt;p&gt;We will create an email address, say &lt;a href="mailto:email-test@domain.com"&gt;email-test@domain.com&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

useradd &lt;span class="nt"&gt;-m&lt;/span&gt; email-test


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Set its password.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

passwd email-test


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Create info user (optional).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

useradd &lt;span class="nt"&gt;-m&lt;/span&gt; info
passwd info


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Note that, when sending an email to &lt;a href="mailto:info@domain.com"&gt;info@domain.com&lt;/a&gt;, you might encounter a problem, this is because &lt;a href="mailto:info@domain.com"&gt;info@domain.com&lt;/a&gt; is considered a root user. To fix the issue, remove it from the aliases list.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

vim /etc/aliases


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, comment this line by prefixing the line with &lt;code&gt;#&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# info:          postmaster


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Test the email user routing, and ensure there is no error or warning message.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

exim &lt;span class="nt"&gt;-bt&lt;/span&gt; email-test@domain.com


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The output should look like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

email-test@domain.com -&amp;gt; /home/email-test/Maildir
  transport &lt;span class="o"&gt;=&lt;/span&gt; local_delivery


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And the other user.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

exim &lt;span class="nt"&gt;-bt&lt;/span&gt; info@domain.com


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The output should look like this:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;p&gt;&lt;a href="mailto:info@domain.com"&gt;info@domain.com&lt;/a&gt; -&amp;gt; /home/info/Maildir&lt;br&gt;
  transport &lt;span class="o"&gt;=&lt;/span&gt; local_delivery&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  DNS Record Configuration&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Before we can send and receive emails, ensure to have these records on your DNS Control Panel:&lt;br&gt;
A record:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0cilzgkdagwl1zr45gk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0cilzgkdagwl1zr45gk.png" alt="A Record"&gt;&lt;/a&gt;&lt;br&gt;
Change &lt;code&gt;1.2.3.4&lt;/code&gt; with the IP Address of your email server.&lt;/p&gt;

&lt;p&gt;MX record:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxi6uvp64o5hbdt252c5u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxi6uvp64o5hbdt252c5u.png" alt="MX Record"&gt;&lt;/a&gt;&lt;br&gt;
The MX record indicates it will point to your email server.&lt;/p&gt;

</description>
      <category>email</category>
      <category>exim</category>
      <category>almalinux</category>
    </item>
    <item>
      <title>Introduction</title>
      <dc:creator>budiantoip</dc:creator>
      <pubDate>Sat, 20 Apr 2024 07:58:18 +0000</pubDate>
      <link>https://dev.to/budiantoip/introduction-3peh</link>
      <guid>https://dev.to/budiantoip/introduction-3peh</guid>
      <description>&lt;p&gt;This workshop will guide you through building an email server, powered with Exim and Dovecot on top of AlmaLinux 9.&lt;/p&gt;

&lt;p&gt;The workshop will be divided into parts, and they are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Part 1: Build the email server&lt;/p&gt;

&lt;p&gt;We will build the email server from scratch here.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Part 2: Configure email clients&lt;/p&gt;

&lt;p&gt;We will configure email clients to send and receive emails. We will configure &lt;a href="https://www.thunderbird.net/en-US/"&gt;Mozilla Thunderbird&lt;/a&gt;, &lt;a href="https://www.icloud.com/mail"&gt;Apple Mail&lt;/a&gt;, and &lt;a href="https://www.microsoft.com/en-us/microsoft-365/outlook/email-and-calendar-software-microsoft-outlook"&gt;Microsoft Outlook&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Part 3: Configure webmails&lt;/p&gt;

&lt;p&gt;We will configure several webmails. We will install and configure &lt;a href="https://roundcube.net/"&gt;RoundCube&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Part 4: Configure spam protection&lt;/p&gt;

&lt;p&gt;We will install and configure SpamAssassin.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Part 5: Configure Email Deliverability&lt;/p&gt;

&lt;p&gt;We will configure SPF, DKIM, and DMARC records to increase email deliverability.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some parts require some time to write since I have to work on them in my spare time. But hopefully, I can finish all of them soon.&lt;/p&gt;

</description>
      <category>email</category>
      <category>exim</category>
      <category>almalinux</category>
    </item>
    <item>
      <title>How to Setup TLS connection in SQL Anywhere 11</title>
      <dc:creator>budiantoip</dc:creator>
      <pubDate>Thu, 21 Dec 2023 09:20:41 +0000</pubDate>
      <link>https://dev.to/budiantoip/how-to-setup-tls-connection-in-sql-anywhere-11-j0b</link>
      <guid>https://dev.to/budiantoip/how-to-setup-tls-connection-in-sql-anywhere-11-j0b</guid>
      <description>&lt;p&gt;In this article, we will learn how to setup a TLS connection in SQL Anywhere 11.&lt;br&gt;
The connection will be like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c_jXgEwM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dlzs6mkk7fokkom0hn7c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c_jXgEwM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dlzs6mkk7fokkom0hn7c.png" alt="TLS Connection diagram" width="800" height="257"&gt;&lt;/a&gt;&lt;br&gt;
A client device, e.g. laptop, connects to a server. Communications between the two will be encrypted and sent over a TLS protocol.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Both client and server use &lt;code&gt;Windows Operating System&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;SQL Anywhere 11&lt;/code&gt; is installed on both&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;telnet&lt;/code&gt; utility is installed on the client device&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Boundary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The client device should be able to connect to the server. We will test it using the telnet utility&lt;/li&gt;
&lt;li&gt;I use SQL Anywhere 11 here, but the steps described here should be applicable to version 9+&lt;/li&gt;
&lt;li&gt;The server should allow inbound connections to port 2638&lt;/li&gt;
&lt;li&gt;The scenario has been tested on Windows 10&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Server Setup
&lt;/h2&gt;

&lt;p&gt;We will now setup the TLS connection on the server. We will do these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a TLS certificate&lt;/li&gt;
&lt;li&gt;Run DB server&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Create a TLS certificate
&lt;/h3&gt;

&lt;p&gt;Before going further, make sure the SQL Anywhere 11 has been installed on the server already. We will use the &lt;code&gt;createcert&lt;/code&gt; utility here.&lt;/p&gt;

&lt;p&gt;Also, we first need to create a &lt;code&gt;certs&lt;/code&gt; folder. The certificate files created will be stored in this folder. To create the folder, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open up Command Prompt&lt;/li&gt;
&lt;li&gt;Type: &lt;code&gt;mkdir c:\Users\Public\Documents\certs&lt;/code&gt;, and hit enter&lt;/li&gt;
&lt;li&gt;Type: &lt;code&gt;dir c:\Users\Public\Documents\certs&lt;/code&gt;, and hit enter. There should be no error message, and the folder contents will be displayed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To create the TLS certificate, simply login to your server, and follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open up Powershell&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;cd "C:\Program Files (x86)\SQL Anywhere 11\Bin32"&lt;/code&gt; and then press enter&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;createcert.exe&lt;/code&gt; and then press enter. Note that, you may adjust the values accordingly.

&lt;ol&gt;
&lt;li&gt;Enter RSA key length (512-16384): 4096&lt;/li&gt;
&lt;li&gt;Country Code: ID&lt;/li&gt;
&lt;li&gt;State/Province: DKI Jakarta&lt;/li&gt;
&lt;li&gt;Locality: Indonesian&lt;/li&gt;
&lt;li&gt;Organization: My Organization&lt;/li&gt;
&lt;li&gt;Organizational Unit: Engineering&lt;/li&gt;
&lt;li&gt;Common name: my-organization.com&lt;/li&gt;
&lt;li&gt;Enter file path of signer's certificate: (leave this empty, and hit enter)&lt;/li&gt;
&lt;li&gt;Serial number [generate GUID]: (leave this empty, and hit enter)&lt;/li&gt;
&lt;li&gt;Certificate valid for how many years (1-100): 1&lt;/li&gt;
&lt;li&gt;Certificate Authority (Y/N) [N]: N

&lt;ol&gt;
&lt;li&gt; Digital Signature&lt;/li&gt;
&lt;li&gt; Nonrepudiation&lt;/li&gt;
&lt;li&gt; Key Encipherment&lt;/li&gt;
&lt;li&gt; Data Encipherment&lt;/li&gt;
&lt;li&gt; Key Agreement&lt;/li&gt;
&lt;li&gt; Certificate Signing&lt;/li&gt;
&lt;li&gt; CRL Signing&lt;/li&gt;
&lt;li&gt; Encipher Only&lt;/li&gt;
&lt;li&gt; Decipher Only&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Key Usage [3,4,5]: (leave this empty, and hit enter)&lt;/li&gt;
&lt;li&gt;Enter file path to save certificate: C:\Users\Public\Documents\certs\my-organization.com.pem&lt;/li&gt;
&lt;li&gt;Enter file path to save private key: C:\Users\Public\Documents\certs\my-organization.com.key&lt;/li&gt;
&lt;li&gt;Enter password to protect private key: my-password&lt;/li&gt;
&lt;li&gt;Enter file path to save identity: C:\Users\Public\Documents\certs\my-organization.com.id.pem
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--srjRgAG9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yvcekkrbvke49pozb7gk.png" alt="Create Certificate" width="800" height="366"&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After this, 3 certificate files will be created in &lt;code&gt;C:\Users\Public\Documents\certs&lt;/code&gt;, and they are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;my-organization.com.pem (we will use this on the client device later)&lt;/li&gt;
&lt;li&gt;my-organization.com.id.pem (we will use this on the server later)&lt;/li&gt;
&lt;li&gt;my-organization.com.key&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Run DB server
&lt;/h3&gt;

&lt;p&gt;Before we run the DB server, copy the SQL Anywhere database, e.g. &lt;code&gt;DEMO2022.db&lt;/code&gt; to &lt;code&gt;C:\Users\Public\Documents&lt;/code&gt;.&lt;br&gt;
To run the DB server, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open up Windows Explorer, then go to C:\Program Files (x86)\SQL Anywhere 11\Bin32&lt;/li&gt;
&lt;li&gt;Find &lt;code&gt;dbsrv11.exe&lt;/code&gt;, and double click it.&lt;/li&gt;
&lt;li&gt;Once an application loaded, fill in the form as follow:

&lt;ol&gt;
&lt;li&gt;Database: &lt;code&gt;C:\Users\Public\Documents\Demo2022.db&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Server name: &lt;code&gt;DEMO2022&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Options: &lt;code&gt;-ec TLS(TLS_TYPE=RSA;IDENTITY=c:\Users\Public\Documents\certs\my-organization.com.id.pem;IDENTITY_PASSWORD=my-password) -x tcpip&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Hit the OK button
The database server will now run at port 2638. If no error message is shown, the database server runs correctly.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KQC4qmTS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m20a948b3rcokknzgnql.png" alt="DB Server" width="459" height="310"&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setup Client
&lt;/h2&gt;

&lt;p&gt;Before going further, make sure the SQL Anywhere 11 has been installed on the server already.&lt;/p&gt;

&lt;p&gt;Also, we will use telnet to test the client connection to the server. If the telnet has not been installed yet, open up Powershell (run it as Administrator), and then run this command:&lt;br&gt;
&lt;code&gt;Enable-WindowsOptionalFeature -Online -FeatureName TelnetClient&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you receive an error message when running the command, make sure you are connected to the internet, and then re-run the command.&lt;/p&gt;

&lt;p&gt;Now let's assume each of the device's ip addresses are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Client: 192.168.0.9&lt;/li&gt;
&lt;li&gt;Server: 192.168.0.10&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To test the client-to-server connection, Open up Command Prompt, and then run this command:&lt;br&gt;
&lt;code&gt;telnet 192.168.0.10 2638&lt;/code&gt;&lt;br&gt;
Hit enter, and then you will see a blank output, it means the connection goes through and the client can connect to the server successfully. Otherwise, if you see an error message, fix it first until you can connect to the server successfully.&lt;/p&gt;

&lt;p&gt;Now, we need to copy the certificate files we created on the server to the client device, specifically at C:\Users\Public\Documents\certs (create the &lt;code&gt;certs&lt;/code&gt; folder first).&lt;/p&gt;

&lt;p&gt;Now, we will setup the ODBC connection. Open up Start Menu, and then type "ODBC", and then click "ODBC Data Sources (64-bit)". Make sure you choose the &lt;code&gt;64-bit&lt;/code&gt; option. Once it is opened, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hit the "System DSN" tab. We will create a system-wide ODBC configuration&lt;/li&gt;
&lt;li&gt;Hit the "Add" button&lt;/li&gt;
&lt;li&gt;Choose "SQL Anywhere 11". If the option does not appear, you need to install the SQL Anywhere 11 first

&lt;ol&gt;
&lt;li&gt;At the ODBC tab, fill in the following:

&lt;ol&gt;
&lt;li&gt;Data source name: Demo&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;At the Login tab, if your database requires a login:

&lt;ol&gt;
&lt;li&gt;Choose "Supply user ID and password"&lt;/li&gt;
&lt;li&gt;Fill in User ID and Password&lt;/li&gt;
&lt;li&gt;Tick the "Encrypt password" option&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;At the Database tab, fill in the following:

&lt;ol&gt;
&lt;li&gt;Server name: Demo2022 (we specify this name when running the DB server before)&lt;/li&gt;
&lt;li&gt;Untick "Stop database after last disconnect". This will make sure the DB server will always run on the server&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;At the Network tab, fill in the following:

&lt;ol&gt;
&lt;li&gt;Untick the "Shared memory" option. This option is enabled when we run the DB server locally&lt;/li&gt;
&lt;li&gt;Tick the "TCP/IP" option, and set the value to this:
&lt;code&gt;"HOST=192.168.0.10;PORT=2638"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click the "TLS" option, and then click the Edit button

&lt;ol&gt;
&lt;li&gt;For the "Trusted certificates", click the Browse button and then point it to the &lt;code&gt;my-organization.com.pem&lt;/code&gt;. If you cannot see the certificate files, choose the "All Files" option, and then you should be able to see them. Or, directly set the value to this:
&lt;code&gt;C:\Users\Public\Documents\certs\my-organization.com.pem&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;TLS Type: RSA&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Lastly, go back to the ODBC tab, and hit the "Test Connection" button. And you should see a "Connection successful" message.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5_1FTxa7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eokyg5s2ove095dgt6mc.png" alt="Connection Successful" width="340" height="473"&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, you can use the created ODBC Data Source in your application. Happy coding!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.help.sqlanywhere.11.0.1/dbadmin_en11/ec-database-dbserver.html"&gt;Database Server Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dcx.sap.com/1101/en/dbadmin_en11/ec-database-dbserver.html"&gt;Starting the database server with transport-layer security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dcx.sap.com/1101/en/dbadmin_en11/ml-tls-s-3283969.html"&gt;Transport Layer Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dcx.sap.com/1101/en/dbadmin_en11/gencert-ml-ref1.html"&gt;Certificate Creation utility&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>sqlanywhere</category>
      <category>windows</category>
      <category>odbc</category>
      <category>powerbuilder</category>
    </item>
    <item>
      <title>How to Enable Slow Query Logging on MariaDB</title>
      <dc:creator>budiantoip</dc:creator>
      <pubDate>Mon, 20 Nov 2023 22:32:07 +0000</pubDate>
      <link>https://dev.to/budiantoip/how-to-enable-slow-query-logging-on-mariadb-20k5</link>
      <guid>https://dev.to/budiantoip/how-to-enable-slow-query-logging-on-mariadb-20k5</guid>
      <description>&lt;p&gt;MariaDB is one of the most popular open source relational databases. It’s made by the original developers of MySQL and guaranteed to stay open source. It is part of most cloud offerings and the default in most Linux distributions.&lt;/p&gt;

&lt;p&gt;Many websites use MariaDB to store its data. When a website is launched, it may run fast. But the data grows from time to time, especially when it's getting more traffic from day to day. There are times when websites become slow. Many factors can be involved, but one of them is because of slow queries. Slow queries happen when many, e.g. millions of records are in one or multiple tables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Slow queries
&lt;/h2&gt;

&lt;p&gt;Slow queries are queries that run more than a specific time limit, e.g. 5 seconds. Imagine if a webpage executes 10 queries, and each of them runs for at least 5 seconds. In addition to how many asset files are loaded, plus other processing, including but not limited to executing a third-party API call, sending email notifications, and lastly, imagine if you have thousands of people that are using your website, that 5 seconds will surely make your website look slow.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to identify slow queries
&lt;/h2&gt;

&lt;p&gt;MariaDB provides a way for us to log slow queries. In the previous example, we specified queries run at least 5 seconds are considered slow. MariaDB will log those slow queries to a log file or table. More instructions will be provided later in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before we begin
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The instructions have been tested on MariaDB 10.7.8. The DDL file in this article uses the UUID data type, which is only available starting from this MariaDB version.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.docker.com/engine/install/" rel="noopener noreferrer"&gt;Docker Engine&lt;/a&gt; or &lt;a href="https://www.docker.com/products/docker-desktop/" rel="noopener noreferrer"&gt;Docker Desktop&lt;/a&gt; installed&lt;/li&gt;
&lt;li&gt;A sample of a large dataset is used to experiment with the slow queries. You can get it by cloning my repository &lt;a href="https://github.com/budiantoip-it/mariadb-slow-query.git" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Note that the dataset file size is 644 MB. It may take a while for the &lt;code&gt;git clone&lt;/code&gt; to finish.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once the repository is cloned, run this command on your terminal at the project level to initialize the container:&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will take a while for the container to initialize as it has to extract the compressed dataset file, but you can monitor the process by running this command:&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs &lt;span class="nt"&gt;-f&lt;/span&gt; mariadb_slow_query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wait until you read this line: &lt;code&gt;Finished initializing the container&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once the container is fully initialized, you can run all the commands in this article inside the container. To get inside the container, run this command:&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; mariadb_slow_query /bin/bash
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Slow query logging
&lt;/h2&gt;

&lt;p&gt;There are 2 ways to enable slow query logging, and they are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;By modifying the MariaDB configuration file&lt;/p&gt;

&lt;p&gt;You can use this approach to enable slow query logging permanently. Note that this approach requires us to restart the MariaDB service. Restarting MariaDB service can be dangerous. Imagine if visitors to your website are trying to make payments, and the payment processes are suddenly terminated. This may cause corrupted data stored in your database. And, slow query logging should be enabled temporarily, as it can make your disk space full in no time. When the disk space is fully occupied, it can corrupt your MariaDB, rendering it completely inoperable. So, be very super careful when taking this approach.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;By modifying some of the MariaDB system variables&lt;/p&gt;

&lt;p&gt;I prefer this approach because it does not require us to restart the MariaDB service. We will use this approach in this article.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Logging Type
&lt;/h2&gt;

&lt;p&gt;There are two slow query logging types, and they are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;File logging&lt;/p&gt;

&lt;p&gt;To enable slow query logging and store the result in a log file, follow these steps:&lt;br&gt;
a. Login to MySQL console, and select the appropriate database&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcdu8xnpm14x2gpfncet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcdu8xnpm14x2gpfncet.png" alt="MySQL console login"&gt;&lt;/a&gt;&lt;br&gt;
b. Run this query to find out which filename the slow query log will be written to:&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;@@&lt;/span&gt;&lt;span class="n"&gt;slow_query_log_file&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the output is a filename, not a fullpath, e.g. showing folder location, it means it will be written to a file, and the file by default is stored to &lt;code&gt;/var/lib/mysql&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feuvg0ksmrof8f6l6sc5e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feuvg0ksmrof8f6l6sc5e.png" alt="Filename"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjrv6vg1qovi9ji6emzp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjrv6vg1qovi9ji6emzp.png" alt="File location"&gt;&lt;/a&gt;&lt;br&gt;
If we want to store the file to a new filename, we can run this query:&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;slow_query_log_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'slow.log'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The old file is preserved, and a new file will be created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbfwkw5lzh2krrs91uo44.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbfwkw5lzh2krrs91uo44.png" alt="File location 2"&gt;&lt;/a&gt; &lt;br&gt;
If we want to store the file in a specific folder, for example &lt;code&gt;/var/log/mysql&lt;/code&gt;, we can run this query:&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;slow_query_log_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/var/log/mysql/slow.log'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvi51chsm6hgks7rvid8k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvi51chsm6hgks7rvid8k.png" alt="File location 3"&gt;&lt;/a&gt;&lt;br&gt;
b. Next, we need to change the time limit. We can change the time limit to 1 second, which means any queries run at least 1 second will be considered slow queries. By default, it's configured to 10 seconds. We can change it by running this query:&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;long_query_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;c. Lastly, we need to see whether the slow query logging has been enabled or not by running this command:&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;@@&lt;/span&gt;&lt;span class="n"&gt;slow_query_log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;if it returns 0, it means it's disabled. We can enable it by running this query:&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;slow_query_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To disable it back, run this query:&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;slow_query_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Table logging&lt;br&gt;
The slow queries can be recorded in a table by following these steps:&lt;br&gt;
a. Login to MySQL console, and select the appropriate database&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcdu8xnpm14x2gpfncet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcdu8xnpm14x2gpfncet.png" alt="MySQL console login"&gt;&lt;/a&gt;&lt;br&gt;
b. First, let's check the current logging type by running this query:&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;@@&lt;/span&gt;&lt;span class="n"&gt;log_output&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default, it will return FILE. We can change it to table logging, by running this query:&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;log_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'table'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the above query will be applied to slow and general query logging. General query logging will log all types of queries. By default, general query logging is disabled.&lt;br&gt;
The slow query logging will be recorded to &lt;code&gt;slow_query&lt;/code&gt; table within the &lt;code&gt;mysql&lt;/code&gt; database. Meanwhile, the general query logging will be recorded to &lt;code&gt;general_log&lt;/code&gt; table within the &lt;code&gt;mysql&lt;/code&gt; database.&lt;br&gt;
c. Change the time limit, e.g. 1 second. Any query that runs at least 1 second will be considered a slow query. We can change the time limit by running this command:&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;long_query_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;d. Enable the slow query logging by running this query:&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;slow_query_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To disable it back, run this query:&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;slow_query_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;e. Check the slow query log by running this query:&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slow_log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Run some tests
&lt;/h2&gt;

&lt;p&gt;Now, we need to generate the slow query logs, either by running the website or by running some queries that are believed to be slow.&lt;br&gt;
For example, using the above large dataset, run these queries:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;askubuntu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt; &lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;askubuntu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;askubuntu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;Where&lt;/span&gt; &lt;span class="nb"&gt;Text&lt;/span&gt; &lt;span class="k"&gt;Like&lt;/span&gt; &lt;span class="s1"&gt;'%aptitude%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ViewCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnswerCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommentCount&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerUserId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%ubuntu%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, let's check the slow query logs.&lt;br&gt;
If you choose file logging, run this command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; LOG_FILE_LOCATION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Note that, change LOG_FILE_LOCATION accordingly, e.g. &lt;code&gt;/var/log/mysql/slow.log&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctfcqlc4zxf5cjsy865b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctfcqlc4zxf5cjsy865b.png" alt="File logging"&gt;&lt;/a&gt;&lt;br&gt;
If you choose table logging, run this query:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;query_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rows_sent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rows_examined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sql_text&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slow_log&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;query_time&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6br279iqprcbi46zmlm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6br279iqprcbi46zmlm.png" alt="Table logging"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mariadb.org/" rel="noopener noreferrer"&gt;MariaDB official site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/slow-query-log-overview/" rel="noopener noreferrer"&gt;Slow Query Log Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/_/mariadb" rel="noopener noreferrer"&gt;MariaDB Docker Image&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>mariadb</category>
      <category>slowquery</category>
      <category>logging</category>
    </item>
    <item>
      <title>How to Reboot AWS Lightsail Instance for a Beginner (With Images)</title>
      <dc:creator>budiantoip</dc:creator>
      <pubDate>Tue, 14 Nov 2023 13:00:19 +0000</pubDate>
      <link>https://dev.to/budiantoip/how-to-reboot-aws-lightsail-instance-for-a-beginner-with-images-189c</link>
      <guid>https://dev.to/budiantoip/how-to-reboot-aws-lightsail-instance-for-a-beginner-with-images-189c</guid>
      <description>&lt;p&gt;This article is intended for non-technical people who want to know how to reboot an AWS Lightsail instance via the AWS Console.&lt;/p&gt;

&lt;p&gt;AWS Lightsail is a Virtual Private Server (VPS) provider. Lightsail includes everything you need to launch your project quickly – virtual machines, containers, databases, CDN, load balancers, DNS management, etc. People love Lightsail because of its simplicity.&lt;/p&gt;

&lt;p&gt;AWS Lightsail is a lightweight version of EC2, with limited features compared to EC2. It has a low and relatively stable monthly price. And it is a good entrance for beginners who want to use VPS on AWS.&lt;/p&gt;

&lt;p&gt;AWS Console is a web application to navigate and manage AWS services.&lt;/p&gt;

&lt;p&gt;To reboot your AWS Lightsail instance, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Login to the AWS console (&lt;a href="https://console.aws.amazon.com/"&gt;https://console.aws.amazon.com/&lt;/a&gt;). After that, you will be redirected to the sign-in page. From here, you have two options, and they are:

&lt;ol&gt;
&lt;li&gt;Login as root. Enter your email, and then enter your password on the next page. Lastly, you might be asked to enter an MFA code.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n_ZYrEM4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3vuedbr9qjc8qbx0pbc.png" alt="Root Login" width="800" height="402"&gt;
&lt;/li&gt;
&lt;li&gt;Login as an IAM user. You can enter your Account ID here and then your IAM username and password on the next page. Lastly, you might be asked to enter an MFA code.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w23otTdz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/397pg64oyvr8452qxbck.png" alt="IAM user Login" width="800" height="412"&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Once logged in, you will be redirected to the home page. There are two important sections here. The first is the "Search Bar". You can search for anything from here. The other is the "Recently Visited" section, listing any recently visited AWS services.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O06ua_pM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dppoh4w0rogwjrdchzb2.png" alt="AWS Console" width="800" height="412"&gt;
&lt;/li&gt;
&lt;li&gt;You can hit the Lightsail link in the "Recently Visited" section or type lightsail in the "Search Bar" and then hit the Lightsail result under the Services section.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mv4IBFN8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pjwap9cx0enqzxruyqz3.png" alt="Console Search" width="800" height="412"&gt;
&lt;/li&gt;
&lt;li&gt;Now, you will be redirected to the AWS Lightsail page. The page will show how many instances you have. In my case, it shows 2 instances, Staging and Production. We will reboot the Production instance, so click the "Production" instance and we will be redirected to the instance details page.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iQ7IS_Eb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jv5x2nmzzmhksealkx1y.png" alt="Lightsail Page" width="800" height="412"&gt;
&lt;/li&gt;
&lt;li&gt;The instance details page shows detailed information regarding your instance. To reboot the instance, click the Reboot button on the top right.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I_T72UzC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/loncoke7eihmxg4jviyo.png" alt="Producton Instance" width="800" height="412"&gt;
&lt;/li&gt;
&lt;li&gt;It will take some time for the instance to finish rebooting. Wait about 3-5 minutes, then use &lt;a href="https://semonto.com/tools/website-reachability-check"&gt;this online tool&lt;/a&gt; to test your website reachability. The tool will try to load your website from different server locations.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sYxsWH2E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wuiwahw0qpo4pfyfs3kf.png" alt="Website Reachability Check" width="800" height="412"&gt;
&lt;/li&gt;
&lt;li&gt;Enter your website URL, and then hit the "Check Reachability" button. It may take some time for it to return results. If the result shows a green-colored message like this, it means your server has finished rebooting and your website is fully operational:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;[Your website URL] is looking good! See below for more details.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O8KeLUO1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qfqksw2n1tin6t2midg7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O8KeLUO1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qfqksw2n1tin6t2midg7.png" alt="Website Reachability Check Result" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/lightsail/faq/"&gt;AWS Lightsail FAQ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/concepts.html"&gt;What is Amazon EC2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/awsconsolehelpdocs/latest/gsg/learn-whats-new.html"&gt;What is the AWS Management Console?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to connect with me on LinkedIn:&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/budiantoip/"&gt;https://www.linkedin.com/in/budiantoip/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>lightsail</category>
      <category>devops</category>
    </item>
    <item>
      <title>How to migrate a Mongo Database with Ansible Playbook</title>
      <dc:creator>budiantoip</dc:creator>
      <pubDate>Tue, 31 Oct 2023 03:15:19 +0000</pubDate>
      <link>https://dev.to/budiantoip/how-to-migrate-a-mongo-database-with-ansible-playbook-2fha</link>
      <guid>https://dev.to/budiantoip/how-to-migrate-a-mongo-database-with-ansible-playbook-2fha</guid>
      <description>&lt;p&gt;Recently, a client tasked me with migrating MongoDB from &lt;a href="https://www.mongodb.com/atlas/database"&gt;MongoDB Atlas&lt;/a&gt; to &lt;a href="https://www.digitalocean.com/products/managed-databases-mongodb"&gt;Digital Ocean managed MongoDB service&lt;/a&gt;. He had 2 reasons, one was to manage everything in Digital Ocean since the application server was in Digital Ocean, and two was to minimize the network latency, the client wanted to have the MongoDB in the same VPC as the application server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.mongodb.com/docs/database-tools/installation/installation/"&gt;Database Tools&lt;/a&gt; (The package includes mongodump and mongorestore)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html"&gt;Ansible&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migration Concept
&lt;/h2&gt;

&lt;p&gt;To migrate the mongo database, we will use the backup (&lt;em&gt;mongodump&lt;/em&gt;) and restore (&lt;em&gt;mongorestore&lt;/em&gt;) utilities. In my case, I ran both commands from my application server in Digital Ocean. We will then use the Ansible Playbook to create a template to run it as many times as we need. In my case, the client wanted to run it twice. First, he wanted me to migrate the DB to a staging environment, and once everything worked correctly, he asked me to migrate the DB to a production environment. Ansible Playbook also provides time calculation, giving you an idea of how long the live Mongodb migration will take.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backup
&lt;/h2&gt;

&lt;p&gt;We will back up the MongoDB from MongoDB Atlas using the &lt;em&gt;mongodump&lt;/em&gt; utility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Syntax and Example
&lt;/h3&gt;

&lt;p&gt;To backup your existing database, the mongodump syntax will be like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongodump &lt;span class="nt"&gt;--username&lt;/span&gt; DB_USERNAME &lt;span class="nt"&gt;--out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;TARGET_FOLDER &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mongodump.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;username&lt;/strong&gt; is the username we use to authenticate to our mongo DB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;out&lt;/strong&gt; is the target folder to store our mongo DB backup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;config&lt;/strong&gt; is the config file that will be used by mongodump.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mongodump.cfg contains these configurations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;password: PASSWORD
uri: mongodb+srv://HOSTNAME.mongodb.net/DATABASE_NAME?retryWrites&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&amp;amp;w&lt;span class="o"&gt;=&lt;/span&gt;majority
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change PASSWORD, HOSTNAME, and DATABASE_NAME accordingly. &lt;em&gt;retryWrites=true&amp;amp;w=majority&lt;/em&gt; are connection parameters used by mongo DB Atlas, so leave them as they are.&lt;/p&gt;

&lt;h2&gt;
  
  
  Restore
&lt;/h2&gt;

&lt;p&gt;We will restore the MongoDB to Digital Ocean managed mongo DB service using the &lt;em&gt;mongorestore&lt;/em&gt; utility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Syntax and Example
&lt;/h3&gt;

&lt;p&gt;To restore to a database, the mongorestore syntax will be like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongorestore &lt;span class="nt"&gt;--ssl&lt;/span&gt; &lt;span class="nt"&gt;--tlsInsecure&lt;/span&gt; &lt;span class="nt"&gt;--username&lt;/span&gt; USERNAME &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mongorestore.cfg &lt;span class="nt"&gt;--nsInclude&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;DATABASE_NAME TARGET_FOLDER/DATABASE_NAME/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ssl&lt;/strong&gt; means we will connect to mongo DB via TLS/SSL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;tlsInsecure&lt;/strong&gt; will disable the certificate validations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;config&lt;/strong&gt; is the config file that will be used by mongorestore.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;nsInclude&lt;/strong&gt; specifies the namespace pattern. Since we will restore the whole database, we will use DATABASE_NAME (change this with your database name).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mongorestore.cfg contains these configurations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uri: mongodb+srv://HOSTNAME.mongo.ondigitalocean.com/DATABASE_NAME?authSource&lt;span class="o"&gt;=&lt;/span&gt;admin
password: PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change PASSWORD, HOSTNAME, and DATABASE_NAME accordingly.&lt;br&gt;
&lt;em&gt;authSource=admin&lt;/em&gt; is a connection parameter used by Digital Ocean managed mongo DB service, so leave it as it is.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ansible Playbook
&lt;/h2&gt;

&lt;p&gt;We will now use Ansible Playbook. First create a file named &lt;code&gt;playbook.yml&lt;/code&gt;, and then put these in the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# How to run: ansible-playbook playbook.yaml&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Migrate mongodb&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost&lt;/span&gt;
  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Remove backup folder if exists&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/root/mongorestore/backup&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;absent&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Mongodump from mongodb atlas&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongodump --username USERNAME --out=backup/mongodb --config=mongodump.cfg&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Mongorestore to Digital Ocean managed database - mongodb&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongorestore --ssl --tlsInsecure --username USERNAME --config=mongorestore.cfg --nsInclude=DATABASE_NAME backup/mongodb/DATABASE_NAME/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change USERNAME and DATABASE_NAME accordingly.&lt;br&gt;
The ansible playbook contains 3 tasks, and they are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first task will remove the backup folder if it exists. Since we will run the ansible playbook many times, we need to do this to ensure there is no trace of the previous backup&lt;/li&gt;
&lt;li&gt;The 2nd task will dump mongo DB&lt;/li&gt;
&lt;li&gt;The last task will restore mongo DB&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next, we need to create a file named &lt;code&gt;mongodump.cfg&lt;/code&gt;, and then put these in the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;password: PASSWORD
uri: mongodb+srv://HOSTNAME.mongodb.net/DATABASE_NAME?retryWrites&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&amp;amp;w&lt;span class="o"&gt;=&lt;/span&gt;majority
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to change PASSWORD, HOSTNAME, and DATABASE_NAME accordingly.&lt;/p&gt;

&lt;p&gt;Then create a file named &lt;code&gt;mongorestore.cfg&lt;/code&gt;, and then put these in the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uri: mongodb+srv://HOSTNAME.mongo.ondigitalocean.com/DATABASE_NAME?authSource&lt;span class="o"&gt;=&lt;/span&gt;admin
password: PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we will configure Ansible to display the time calculation to know how much time we need to run all the 3 tasks. According to the doc &lt;a href="https://docs.ansible.com/ansible/latest/reference_appendices/config.html#the-configuration-file"&gt;here&lt;/a&gt;, there are 4 ways that we can configure (pick one), and they are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;ANSIBLE_CONFIG&lt;/code&gt; environment variable&lt;/li&gt;
&lt;li&gt;Create a file named &lt;code&gt;ansible.cfg&lt;/code&gt; and put it in the same folder as the playbook.yml resides&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/.ansible.cfg&lt;/code&gt;, if you are logged in as &lt;code&gt;root&lt;/code&gt;, the file will be stored in &lt;code&gt;/root&lt;/code&gt;. If you are logged in another user, e.g. &lt;code&gt;ubuntu&lt;/code&gt;, it will be stored in &lt;code&gt;/home/ubuntu&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Modify the file in &lt;code&gt;/etc/ansible/ansible.cfg&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's say we create a file named &lt;code&gt;ansible.cfg&lt;/code&gt;. Once created, put these in the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;defaults]
callback_whitelist &lt;span class="o"&gt;=&lt;/span&gt; profile_tasks, profile_roles, timer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use &lt;code&gt;callback_whitelist&lt;/code&gt; to allow some plugins to run during the playbook execution. For ansible version older than 2.0, refer to &lt;a href="https://github.com/jlafon/ansible-profile#usage-in-ansible-1x"&gt;here&lt;/a&gt; to find out how to display the time calculation. &lt;a href="https://docs.ansible.com/ansible/2.9/plugins/callback/profile_tasks.html"&gt;profile_tasks&lt;/a&gt;, &lt;a href="https://docs.ansible.com/ansible/2.9/plugins/callback/profile_roles.html"&gt;profile_roles&lt;/a&gt;, and &lt;a href="https://docs.ansible.com/ansible/2.9/plugins/callback/timer.html"&gt;timer&lt;/a&gt; will display a detailed information of the executed tasks.&lt;/p&gt;

&lt;p&gt;Before we run the ansible playbook, we need to create a new terminal session so that when our SSH connection is accidentally closed, the command will continue to run in the background. Run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;screen &lt;span class="nt"&gt;-S&lt;/span&gt; mongodb_migration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To connect to the terminated terminal session, run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;screen -R
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once everything is fully setup, run the ansible playbook with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ansible-playbook playbook.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@docker-ubuntu:~/mongodb-migration# ansible-playbook playbook.yml
&lt;span class="o"&gt;[&lt;/span&gt;WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match &lt;span class="s1"&gt;'all'&lt;/span&gt;

PLAY &lt;span class="o"&gt;[&lt;/span&gt;Migrate mongodb] &lt;span class="k"&gt;****************************************************************************************************************************************************&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Gathering Facts] &lt;span class="k"&gt;****************************************************************************************************************************************************&lt;/span&gt;
Tuesday 31 October 2023  03:00:31 +0000 &lt;span class="o"&gt;(&lt;/span&gt;0:00:00.042&lt;span class="o"&gt;)&lt;/span&gt;       0:00:00.042 &lt;span class="k"&gt;*******&lt;/span&gt;
Tuesday 31 October 2023  03:00:31 +0000 &lt;span class="o"&gt;(&lt;/span&gt;0:00:00.041&lt;span class="o"&gt;)&lt;/span&gt;       0:00:00.041 &lt;span class="k"&gt;*******&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;localhost]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Remove backup folder &lt;span class="k"&gt;if &lt;/span&gt;exists] &lt;span class="k"&gt;*************************************************************************************************************************************&lt;/span&gt;
Tuesday 31 October 2023  03:00:32 +0000 &lt;span class="o"&gt;(&lt;/span&gt;0:00:01.770&lt;span class="o"&gt;)&lt;/span&gt;       0:00:01.812 &lt;span class="k"&gt;*******&lt;/span&gt;
Tuesday 31 October 2023  03:00:32 +0000 &lt;span class="o"&gt;(&lt;/span&gt;0:00:01.770&lt;span class="o"&gt;)&lt;/span&gt;       0:00:01.812 &lt;span class="k"&gt;*******&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;localhost]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Mongodump from mongodb atlas] &lt;span class="k"&gt;***************************************************************************************************************************************&lt;/span&gt;
Tuesday 31 October 2023  03:00:33 +0000 &lt;span class="o"&gt;(&lt;/span&gt;0:00:00.608&lt;span class="o"&gt;)&lt;/span&gt;       0:00:02.420 &lt;span class="k"&gt;*******&lt;/span&gt;
Tuesday 31 October 2023  03:00:33 +0000 &lt;span class="o"&gt;(&lt;/span&gt;0:00:00.607&lt;span class="o"&gt;)&lt;/span&gt;       0:00:02.420 &lt;span class="k"&gt;*******&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;localhost]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Mongorestore to Digital Ocean managed database - mongodb] &lt;span class="k"&gt;***********************************************************************************************************&lt;/span&gt;
Tuesday 31 October 2023  03:04:34 +0000 &lt;span class="o"&gt;(&lt;/span&gt;0:04:01.372&lt;span class="o"&gt;)&lt;/span&gt;       0:04:03.793 &lt;span class="k"&gt;*******&lt;/span&gt;
Tuesday 31 October 2023  03:04:34 +0000 &lt;span class="o"&gt;(&lt;/span&gt;0:04:01.373&lt;span class="o"&gt;)&lt;/span&gt;       0:04:03.793 &lt;span class="k"&gt;*******&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;localhost]

PLAY RECAP &lt;span class="k"&gt;****************************************************************************************************************************************************************&lt;/span&gt;
localhost                  : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4    &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3    &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;skipped&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;rescued&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

Tuesday 31 October 2023  03:09:43 +0000 &lt;span class="o"&gt;(&lt;/span&gt;0:05:08.507&lt;span class="o"&gt;)&lt;/span&gt;       0:09:12.300 &lt;span class="k"&gt;*******&lt;/span&gt;
&lt;span class="o"&gt;===============================================================================&lt;/span&gt;
shell &lt;span class="nt"&gt;-----------------------------------------------------------------&lt;/span&gt; 549.88s
gather_facts &lt;span class="nt"&gt;------------------------------------------------------------&lt;/span&gt; 1.77s
ansible.builtin.file &lt;span class="nt"&gt;----------------------------------------------------&lt;/span&gt; 0.61s
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
total &lt;span class="nt"&gt;-----------------------------------------------------------------&lt;/span&gt; 552.26s
Tuesday 31 October 2023  03:09:43 +0000 &lt;span class="o"&gt;(&lt;/span&gt;0:05:08.508&lt;span class="o"&gt;)&lt;/span&gt;       0:09:12.301 &lt;span class="k"&gt;*******&lt;/span&gt;
&lt;span class="o"&gt;===============================================================================&lt;/span&gt;
Mongorestore to Digital Ocean managed database - mongodb &lt;span class="nt"&gt;---------------------------------------------------------------------------------------------------------&lt;/span&gt; 308.51s
Mongodump from mongodb atlas &lt;span class="nt"&gt;-------------------------------------------------------------------------------------------------------------------------------------&lt;/span&gt; 241.37s
Gathering Facts &lt;span class="nt"&gt;----------------------------------------------------------------------------------------------------------------------------------------------------&lt;/span&gt; 1.77s
Remove backup folder &lt;span class="k"&gt;if &lt;/span&gt;exists &lt;span class="nt"&gt;-------------------------------------------------------------------------------------------------------------------------------------&lt;/span&gt; 0.61s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have uploaded the ansible files to a repository &lt;a href="https://github.com/budiantoip-it/mongodb-migration"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Feel free to connect with me on LinkedIn:&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/budiantoip/"&gt;https://www.linkedin.com/in/budiantoip/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>atlas</category>
      <category>digitalocean</category>
      <category>ansible</category>
    </item>
  </channel>
</rss>
