<?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: Sai Shanmukkha Surapaneni</title>
    <description>The latest articles on DEV Community by Sai Shanmukkha Surapaneni (@saishanmukkha).</description>
    <link>https://dev.to/saishanmukkha</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%2F1238051%2F7c70d4f1-99ff-4cc8-81f7-87502734c500.jpeg</url>
      <title>DEV Community: Sai Shanmukkha Surapaneni</title>
      <link>https://dev.to/saishanmukkha</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/saishanmukkha"/>
    <language>en</language>
    <item>
      <title>Part 1: Mastering Dynamic Programming — 5 Steps to Solve It (Longest Increasing Subsequence Using Tabulation / Bottom-Up)</title>
      <dc:creator>Sai Shanmukkha Surapaneni</dc:creator>
      <pubDate>Sat, 15 Nov 2025 19:06:40 +0000</pubDate>
      <link>https://dev.to/saishanmukkha/part-1-mastering-dynamic-programming-5-steps-to-solve-it-longest-increasing-sequence-using-5hm4</link>
      <guid>https://dev.to/saishanmukkha/part-1-mastering-dynamic-programming-5-steps-to-solve-it-longest-increasing-sequence-using-5hm4</guid>
      <description>&lt;p&gt;Dynamic Programming (DP) has a reputation for being one of the trickiest topics in algorithms. Many learners struggle not because DP is inherently complex, but because they lack a structured approach to reasoning about problems. In this blog, we’ll break DP down into &lt;strong&gt;five simple steps&lt;/strong&gt; that you can apply to most problems.&lt;/p&gt;

&lt;p&gt;To make things concrete, we’ll use the &lt;strong&gt;Longest Increasing Subsequence (LIS)&lt;/strong&gt; problem as our running example.&lt;/p&gt;




&lt;h2&gt;
  
  
  ## &lt;strong&gt;🧠 5-Step Framework to Solve DP Problems&lt;/strong&gt;
&lt;/h2&gt;




&lt;h2&gt;
  
  
  ### &lt;strong&gt;1. Visualize Examples (Think in Terms of a DAG)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Almost all DP problems can be imagined as paths in a &lt;strong&gt;Directed Acyclic Graph (DAG)&lt;/strong&gt;. Each state represents a choice, and edges represent transitions to future states.&lt;/p&gt;

&lt;p&gt;Let’s take our example array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try to imagine all sequences that can be formed by picking numbers in increasing order.&lt;br&gt;
Visualizing a few example sequences helps greatly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Starting at &lt;strong&gt;3&lt;/strong&gt; → [3, 8] or [3, 5]&lt;/li&gt;
&lt;li&gt;Starting at &lt;strong&gt;1&lt;/strong&gt; → [1, 8], [1, 2, 5]&lt;/li&gt;
&lt;li&gt;Starting at &lt;strong&gt;8&lt;/strong&gt; → [8]&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each number can go to any number &lt;strong&gt;greater than it&lt;/strong&gt; that appears later in the list — this is your DAG.&lt;/p&gt;


&lt;h2&gt;
  
  
  ### &lt;strong&gt;2. Find an Appropriate Subproblem&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A good DP solution boils down to defining the right subproblem.&lt;/p&gt;

&lt;p&gt;For LIS, a natural subproblem is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What is the longest increasing subsequence starting at index &lt;code&gt;i&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or more commonly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What is the LIS ending at index &lt;code&gt;i&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s define:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dp[i] = length of the longest increasing subsequence ending at index i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ### &lt;strong&gt;3. Find Relationships Among Subproblems&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that we have &lt;code&gt;dp[i]&lt;/code&gt;, how do we compute it?&lt;/p&gt;

&lt;p&gt;For each index &lt;code&gt;i&lt;/code&gt;, look at all previous indices &lt;code&gt;j &amp;lt; i&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;arr[j] &amp;lt; arr[i]&lt;/code&gt;, then we can extend the subsequence ending at &lt;code&gt;j&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dp[i] = 1 + max(dp[j]) over all j &amp;lt; i where arr[j] &amp;lt; arr[i]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If no such &lt;code&gt;j&lt;/code&gt; exists, then &lt;code&gt;dp[i] = 1&lt;/code&gt; (the element itself).&lt;/p&gt;




&lt;h2&gt;
  
  
  ### &lt;strong&gt;4. Generalize the Relationship&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Combining everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dp[i] = 1 + max(dp[j] for all valid j)
otherwise dp[i] = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is our &lt;strong&gt;recurrence relation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The final LIS answer is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;max(dp[i] for all i)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ### &lt;strong&gt;5. Implement by Solving Subproblems in Order&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We fill the &lt;code&gt;dp&lt;/code&gt; array from left to right, ensuring all &lt;code&gt;dp[j]&lt;/code&gt; values needed for &lt;code&gt;dp[i]&lt;/code&gt; have already been computed.&lt;/p&gt;

&lt;p&gt;Here’s a full implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;LIS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="c1"&gt;# Every element is a subsequence of length 1
&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Testing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LIS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Output: 3  (The subsequence is [1, 2, 5])
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Nice, let’s zoom all the way in on this array and see exactly what’s happening:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's go step-by-step:&lt;/p&gt;

&lt;h3&gt;
  
  
  0. What does &lt;code&gt;dp[i]&lt;/code&gt; mean?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;dp[i]&lt;/code&gt; = length of the &lt;strong&gt;Longest Increasing Subsequence that ends exactly at index i&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So for each position &lt;code&gt;i&lt;/code&gt;, we assume &lt;code&gt;arr[i]&lt;/code&gt; is the &lt;strong&gt;last element&lt;/strong&gt; of the subsequence.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step-by-step for &lt;code&gt;[3, 1, 8, 2, 5]&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Indexing:&lt;br&gt;
&lt;code&gt;i = 0  1  2  3  4&lt;/code&gt;&lt;br&gt;
&lt;code&gt;arr = [3, 1, 8, 2, 5]&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Initial state
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&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;/div&gt;


&lt;p&gt;Why all 1’s?&lt;br&gt;
Because every single element alone is a subsequence of length 1.&lt;/p&gt;


&lt;h3&gt;
  
  
  i = 0  → element = 3
&lt;/h3&gt;

&lt;p&gt;For &lt;code&gt;i = 0&lt;/code&gt;, the loops don’t run (no &lt;code&gt;j &amp;lt; 0&lt;/code&gt;), so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;dp[0]&lt;/code&gt; stays &lt;strong&gt;1&lt;/strong&gt; → subsequence &lt;code&gt;[3]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Current:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&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;/div&gt;






&lt;h3&gt;
  
  
  i = 1 → element = 1
&lt;/h3&gt;

&lt;p&gt;We look at all &lt;code&gt;j &amp;lt; 1&lt;/code&gt; → only &lt;code&gt;j = 0&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;j = 0&lt;/code&gt; → compare &lt;code&gt;arr[0] &amp;lt; arr[1]&lt;/code&gt; → &lt;code&gt;3 &amp;lt; 1&lt;/code&gt;? ❌ No.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So there is &lt;strong&gt;no previous smaller element&lt;/strong&gt; that can come before &lt;code&gt;1&lt;/code&gt; in an increasing subsequence.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;dp[1]&lt;/code&gt; stays &lt;strong&gt;1&lt;/strong&gt; → subsequence &lt;code&gt;[1]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Current:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&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;/div&gt;



&lt;p&gt;Subproblems so far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LIS ending at index 0 is 1 (&lt;code&gt;[3]&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;LIS ending at index 1 is 1 (&lt;code&gt;[1]&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  i = 2 → element = 8
&lt;/h3&gt;

&lt;p&gt;We look at all &lt;code&gt;j &amp;lt; 2&lt;/code&gt; → &lt;code&gt;j = 0, 1&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  j = 0:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;arr[0] &amp;lt; arr[2]&lt;/code&gt; → &lt;code&gt;3 &amp;lt; 8&lt;/code&gt; ✅
We can extend the subsequence ending at index 0.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Candidate length if we extend:&lt;br&gt;
&lt;code&gt;dp[0] + 1 = 1 + 1 = 2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Update:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&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;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  j = 1:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;arr[1] &amp;lt; arr[2]&lt;/code&gt; → &lt;code&gt;1 &amp;lt; 8&lt;/code&gt; ✅
We can also extend the subsequence ending at index 1.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Candidate length:&lt;br&gt;
&lt;code&gt;dp[1] + 1 = 1 + 1 = 2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Update:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the best we can do for subsequences &lt;strong&gt;ending at 8&lt;/strong&gt; is length 2:&lt;br&gt;
Either &lt;code&gt;[3, 8]&lt;/code&gt; or &lt;code&gt;[1, 8]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Current:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&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;/div&gt;






&lt;h3&gt;
  
  
  i = 3 → element = 2
&lt;/h3&gt;

&lt;p&gt;We look at all &lt;code&gt;j &amp;lt; 3&lt;/code&gt; → &lt;code&gt;j = 0, 1, 2&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  j = 0:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;arr[0] &amp;lt; arr[3]&lt;/code&gt; → &lt;code&gt;3 &amp;lt; 2&lt;/code&gt;? ❌ No.
Can't put 2 after 3 in an increasing sequence.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  j = 1:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;arr[1] &amp;lt; arr[3]&lt;/code&gt; → &lt;code&gt;1 &amp;lt; 2&lt;/code&gt; ✅
We &lt;em&gt;can&lt;/em&gt; extend the subsequence ending at &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Candidate length:&lt;br&gt;
&lt;code&gt;dp[1] + 1 = 1 + 1 = 2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Update:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&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;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This corresponds to subsequence &lt;code&gt;[1, 2]&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  j = 2:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;arr[2] &amp;lt; arr[3]&lt;/code&gt; → &lt;code&gt;8 &amp;lt; 2&lt;/code&gt;? ❌ No.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So best subsequence &lt;strong&gt;ending at 2&lt;/strong&gt; has length 2 → &lt;code&gt;[1, 2]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Current:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&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;/div&gt;






&lt;h3&gt;
  
  
  i = 4 → element = 5
&lt;/h3&gt;

&lt;p&gt;We look at all &lt;code&gt;j &amp;lt; 4&lt;/code&gt; → &lt;code&gt;j = 0, 1, 2, 3&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  j = 0:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;arr[0] &amp;lt; arr[4]&lt;/code&gt; → &lt;code&gt;3 &amp;lt; 5&lt;/code&gt; ✅
Extend subsequence ending at index 0 (which is &lt;code&gt;[3]&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Candidate length:&lt;br&gt;
&lt;code&gt;dp[0] + 1 = 1 + 1 = 2&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, one candidate subsequence is &lt;code&gt;[3, 5]&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  j = 1:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;arr[1] &amp;lt; arr[4]&lt;/code&gt; → &lt;code&gt;1 &amp;lt; 5&lt;/code&gt; ✅
Extend subsequence ending at index 1 (&lt;code&gt;[1]&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Candidate:&lt;br&gt;
&lt;code&gt;dp[1] + 1 = 1 + 1 = 2&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;   &lt;span class="c1"&gt;# no change
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So &lt;code&gt;[1, 5]&lt;/code&gt; is another subsequence of length 2.&lt;/p&gt;

&lt;h4&gt;
  
  
  j = 2:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;arr[2] &amp;lt; arr[4]&lt;/code&gt; → &lt;code&gt;8 &amp;lt; 5&lt;/code&gt;? ❌ No.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We cannot put 5 after 8.&lt;/p&gt;

&lt;h4&gt;
  
  
  j = 3:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;arr[3] &amp;lt; arr[4]&lt;/code&gt; → &lt;code&gt;2 &amp;lt; 5&lt;/code&gt; ✅
Extend subsequence ending at index 3 (which was &lt;code&gt;[1, 2]&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Candidate:&lt;br&gt;
&lt;code&gt;dp[3] + 1 = 2 + 1 = 3&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we’ve found a better subsequence ending at 5:&lt;br&gt;
&lt;code&gt;[1, 2, 5]&lt;/code&gt; of length &lt;strong&gt;3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Final &lt;code&gt;dp&lt;/code&gt; array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Final Answer
&lt;/h2&gt;

&lt;p&gt;The LIS length is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And one actual &lt;strong&gt;longest increasing subsequence&lt;/strong&gt; is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(There’s no longer one in this example.)&lt;/p&gt;




&lt;h2&gt;
  
  
  How this is DP (subproblem view)
&lt;/h2&gt;

&lt;p&gt;Each &lt;code&gt;dp[i]&lt;/code&gt; depends on &lt;strong&gt;smaller indices&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To compute &lt;code&gt;dp[4]&lt;/code&gt; (LIS ending at 5),
we reused solutions to earlier subproblems: &lt;code&gt;dp[0], dp[1], dp[2], dp[3]&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the subproblem is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“What’s the length of the longest increasing subsequence that &lt;strong&gt;ends at index i&lt;/strong&gt;?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You solve that for &lt;code&gt;i = 0, 1, 2, 3, 4&lt;/code&gt; in order → &lt;strong&gt;bottom-up tabulation DP&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ## &lt;strong&gt;💡 Final Thoughts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Dynamic Programming becomes much easier when you approach it &lt;em&gt;systematically&lt;/em&gt;.&lt;br&gt;
By following these 5 steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visualize examples&lt;/li&gt;
&lt;li&gt;Identify subproblems&lt;/li&gt;
&lt;li&gt;Find relationships&lt;/li&gt;
&lt;li&gt;Generalize&lt;/li&gt;
&lt;li&gt;Implement in order&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;—you can confidently tackle even the most intimidating DP problems.&lt;/p&gt;

</description>
      <category>dsa</category>
      <category>python</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Set Up n8n Workflow Automation Tool From Scratch and Make It Accessible via Domain</title>
      <dc:creator>Sai Shanmukkha Surapaneni</dc:creator>
      <pubDate>Mon, 11 Aug 2025 06:28:44 +0000</pubDate>
      <link>https://dev.to/saishanmukkha/how-to-set-up-n8n-workflow-automation-tool-from-scratch-and-make-it-accessible-via-domain-n48</link>
      <guid>https://dev.to/saishanmukkha/how-to-set-up-n8n-workflow-automation-tool-from-scratch-and-make-it-accessible-via-domain-n48</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Fhbig6cup0xsgyfhcqel0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fhbig6cup0xsgyfhcqel0.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;n8n&lt;/strong&gt; is a powerful open-source workflow automation tool, enabling you to automate repetitive tasks by connecting different apps and services. In this guide, you’ll learn how to set up n8n from zero on any cloud provider or even a bare-metal server, and expose it securely through your own custom domain — all in a cloud-agnostic way.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Use n8n?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Open-source and self-hostable&lt;/li&gt;
&lt;li&gt;Highly customizable workflows&lt;/li&gt;
&lt;li&gt;Supports over 200 apps natively&lt;/li&gt;
&lt;li&gt;Extendable with custom nodes&lt;/li&gt;
&lt;li&gt;Free to run on your own infrastructure&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Overview of What We’ll Cover
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Setting Up a Server&lt;/li&gt;
&lt;li&gt;Installing Docker and Docker Compose&lt;/li&gt;
&lt;li&gt;Running n8n with Docker&lt;/li&gt;
&lt;li&gt;Setting Up a Reverse Proxy with HTTPS using Caddy&lt;/li&gt;
&lt;li&gt;Pointing Your Domain and Configuring DNS&lt;/li&gt;
&lt;li&gt;Securing and Managing Your Setup&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A server (cloud VM or bare-metal) running Linux (Ubuntu recommended)&lt;/li&gt;
&lt;li&gt;A domain name you own and control DNS records for&lt;/li&gt;
&lt;li&gt;Basic command line and SSH access knowledge&lt;/li&gt;
&lt;li&gt;Docker and Docker Compose installed (we’ll install them in the guide)&lt;/li&gt;
&lt;li&gt;Optional: An Elastic IP or static IP on your server for consistent access&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Setting Up Your Server
&lt;/h2&gt;

&lt;p&gt;Choose any cloud provider (AWS, Google Cloud, Azure, DigitalOcean, Linode, Vultr, Hetzner, etc.) or your own Linux server.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ubuntu 20.04 or 22.04 LTS is preferred.&lt;/li&gt;
&lt;li&gt;Make sure ports &lt;strong&gt;80&lt;/strong&gt; and &lt;strong&gt;443&lt;/strong&gt; are open for HTTP/HTTPS traffic.&lt;/li&gt;
&lt;li&gt;SSH into your server to run the commands.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Install Docker &amp;amp; Docker Compose
&lt;/h2&gt;

&lt;p&gt;Docker makes deployment straightforward and consistent. Run these commands on your server:&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="nb"&gt;sudo &lt;/span&gt;apt-get update &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; docker.io docker-compose unzip curl

&lt;span class="c"&gt;# Enable and start Docker&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;docker
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start docker

&lt;span class="c"&gt;# Verify Docker installed correctly&lt;/span&gt;
docker &lt;span class="nt"&gt;--version&lt;/span&gt;
docker-compose &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Run n8n Using Docker Compose
&lt;/h2&gt;

&lt;p&gt;Create a project directory and define your Docker Compose 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="nb"&gt;mkdir&lt;/span&gt; ~/n8n
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/n8n
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a file named &lt;code&gt;docker-compose.yaml&lt;/code&gt; with this content:&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="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;n8n&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker.n8n.io/n8nio/n8n&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5678:5678"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GENERIC_TIMEZONE=America/Chicago&lt;/span&gt;  &lt;span class="c1"&gt;# Change timezone as needed&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TZ=America/Chicago&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;N8N_PROTOCOL=http&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;N8N_HOST=yourdomain.com&lt;/span&gt;            &lt;span class="c1"&gt;# Replace with your domain&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;N8N_PORT=5678&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;n8n_data:/home/node/.n8n&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;n8n_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then start your container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&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;/div&gt;



&lt;p&gt;You should now be able to reach n8n on &lt;code&gt;http://your-server-ip:5678&lt;/code&gt; (replace with your actual IP).&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Setup Reverse Proxy and HTTPS with Caddy
&lt;/h2&gt;

&lt;p&gt;To make your n8n instance accessible securely via HTTPS and your domain, we use &lt;strong&gt;Caddy&lt;/strong&gt; — an automatic HTTPS reverse proxy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a &lt;code&gt;Caddyfile&lt;/code&gt; in the same directory:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yourdomain.com {
    reverse_proxy n8n:5678
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update your &lt;code&gt;docker-compose.yaml&lt;/code&gt; to add Caddy service:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;n8n&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker.n8n.io/n8nio/n8n&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;n8n&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GENERIC_TIMEZONE=America/Chicago&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TZ=America/Chicago&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;N8N_PROTOCOL=http&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;N8N_HOST=yourdomain.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;N8N_PORT=5678&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;n8n_data:/home/node/.n8n&lt;/span&gt;

  &lt;span class="na"&gt;caddy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;caddy:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;caddy&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;443:443"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./Caddyfile:/etc/caddy/Caddyfile&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;caddy_data:/data&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;caddy_config:/config&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;n8n&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;n8n_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;caddy_data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;caddy_config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart the services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose down
docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Point Your Domain DNS
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create an &lt;strong&gt;A record&lt;/strong&gt; in your domain's DNS management panel pointing your domain (e.g., &lt;code&gt;yourdomain.com&lt;/code&gt;) to your server's &lt;strong&gt;public IP address&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If using a cloud provider with Elastic IPs or static IPs, make sure this IP doesn’t change.&lt;/li&gt;
&lt;li&gt;It may take some time for DNS changes to propagate.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  7. Secure and Manage Your Setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Caddy automatically provisions SSL certificates via Let's Encrypt.&lt;/li&gt;
&lt;li&gt;Your n8n is now accessible securely at &lt;code&gt;https://yourdomain.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;docker logs caddy&lt;/code&gt; or &lt;code&gt;docker logs n8n&lt;/code&gt; to debug if necessary.&lt;/li&gt;
&lt;li&gt;Backup your &lt;code&gt;/home/node/.n8n&lt;/code&gt; data volume regularly.&lt;/li&gt;
&lt;li&gt;Consider setting up firewall rules to restrict access.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You now have a self-hosted n8n workflow automation instance running behind a secure HTTPS domain — all set up in a cloud-provider-agnostic way! This setup allows full control over your automation workflows with no vendor lock-in.&lt;/p&gt;

&lt;p&gt;If you want to scale or add databases like Postgres, n8n supports that too with minor config changes.&lt;/p&gt;

&lt;p&gt;Happy automating! 🚀&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.n8n.io/" rel="noopener noreferrer"&gt;n8n Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;Docker Compose Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://caddyserver.com/docs/" rel="noopener noreferrer"&gt;Caddy Server Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://letsencrypt.org/" rel="noopener noreferrer"&gt;Let's Encrypt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>cloud</category>
      <category>ai</category>
    </item>
    <item>
      <title>Automate Everything: Why Bash Scripting is a Must-Learn Skill</title>
      <dc:creator>Sai Shanmukkha Surapaneni</dc:creator>
      <pubDate>Wed, 12 Mar 2025 16:08:23 +0000</pubDate>
      <link>https://dev.to/saishanmukkha/automate-everything-why-bash-scripting-is-a-must-learn-skill-3n37</link>
      <guid>https://dev.to/saishanmukkha/automate-everything-why-bash-scripting-is-a-must-learn-skill-3n37</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Have you ever wished you could automate boring, repetitive tasks on your computer? Whether you're managing files, monitoring servers, or just simplifying everyday tasks, Bash scripting can be a game-changer. If you're working with Linux, macOS, or even Windows (using tools like Git Bash), learning Bash scripting is a must-have skill that can make your life easier and your workflow more efficient.&lt;/p&gt;

&lt;p&gt;Let’s dive into why Bash scripting is so important and why you should start learning it today!&lt;/p&gt;




&lt;h3&gt;
  
  
  Why Bash Scripting is Important
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Automating Repetitive Tasks&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency:&lt;/strong&gt; Instead of manually running the same commands over and over, write a script once and let your computer do the work for you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; Ensure tasks are executed exactly the same way every time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Examples:&lt;/strong&gt; File management, backups, log monitoring, and software deployment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;System Administration Made Easy&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server Management:&lt;/strong&gt; Bash scripts can manage users, monitor disk usage, and keep systems updated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduled Tasks:&lt;/strong&gt; Use cron jobs to run scripts automatically at specific intervals (e.g., cleaning temp files daily).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data Processing and File Manipulation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Handling Text Files:&lt;/strong&gt; Use grep, awk, and sed to filter and manipulate data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Processing Logs:&lt;/strong&gt; Analyze logs and extract useful insights.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch Processing:&lt;/strong&gt; Rename, move, or modify multiple files with just one script.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Boosting Productivity and Speed&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Speed:&lt;/strong&gt; Automate tasks that would take hours manually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customization:&lt;/strong&gt; Create scripts tailored to your specific needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example:&lt;/strong&gt; Write a script to back up your work folder every night.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cost-Effective and Built-In&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No Extra Software Needed:&lt;/strong&gt; Bash comes pre-installed on most Linux and macOS systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Platform:&lt;/strong&gt; Works on Linux, macOS, and Windows (via WSL or Git Bash).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Essential for DevOps and Cloud Computing&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automate Deployments:&lt;/strong&gt; Bash is widely used in CI/CD pipelines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure Management:&lt;/strong&gt; Write scripts for AWS, Google Cloud, and Azure automation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Career Growth and Opportunities&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In-Demand Skill:&lt;/strong&gt; System administrators, DevOps engineers, and software developers all need Bash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency at Work:&lt;/strong&gt; Companies love employees who can automate tasks and improve workflows.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  How to Learn Bash Scripting &lt;strong&gt;(Roadmap)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Ready to start? Follow this roadmap to master Bash scripting!&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before diving into Bash scripting, make sure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Basic knowledge of Linux/Unix command-line&lt;/strong&gt;: Familiarity with common commands like &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cd&lt;/code&gt;, &lt;code&gt;cp&lt;/code&gt;, &lt;code&gt;mv&lt;/code&gt;, &lt;code&gt;cat&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understanding of text editors&lt;/strong&gt;: Learn how to use editors like &lt;code&gt;nano&lt;/code&gt;, &lt;code&gt;vim&lt;/code&gt;, or &lt;code&gt;emacs&lt;/code&gt; for writing scripts.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Basic Concepts
&lt;/h3&gt;

&lt;p&gt;Start by learning the foundational aspects of Bash scripting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bash Basics&lt;/strong&gt;: Understand what a Bash script is and how to run one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing a simple script (e.g., &lt;code&gt;hello.sh&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Running a script with &lt;code&gt;bash script_name.sh&lt;/code&gt; or making it executable with &lt;code&gt;chmod +x script_name.sh&lt;/code&gt; and running it directly.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Shebang (&lt;code&gt;#!/bin/bash&lt;/code&gt;)&lt;/strong&gt;: Learn about the shebang and why it's used to specify the shell for script execution.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Variables&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Declaring variables and using them (&lt;code&gt;var_name=value&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Accessing variables (&lt;code&gt;$var_name&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;User Input&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;read&lt;/code&gt; to get input from the user.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Control Flow and Conditional Statements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;If Statements&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;else&lt;/code&gt;, &lt;code&gt;elif&lt;/code&gt; for decision-making.&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;if [ $a -gt $b ]; then echo "a is greater"; fi&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Comparison Operators&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand numerical and string comparisons (&lt;code&gt;-eq&lt;/code&gt;, &lt;code&gt;-gt&lt;/code&gt;, &lt;code&gt;-lt&lt;/code&gt;, &lt;code&gt;-ne&lt;/code&gt;, &lt;code&gt;=&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Case Statements&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;case&lt;/code&gt; for multiple conditions.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Logical Operators&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; (and), &lt;code&gt;||&lt;/code&gt; (or), and &lt;code&gt;!&lt;/code&gt; (not).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Looping Constructs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;For Loops&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn both simple loops and loops with a range or list of values.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;While and Until Loops&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;while&lt;/code&gt; and &lt;code&gt;until&lt;/code&gt; for repeating commands until a condition is met.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Nested Loops&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn how to nest loops for more complex logic.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  5. Functions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Defining Functions&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn how to define and call functions within your script.&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;function_name() { ... }&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Passing Arguments to Functions&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accessing function arguments using &lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Returning Values from Functions&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;return&lt;/code&gt; and &lt;code&gt;echo&lt;/code&gt; to return values.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  6. Working with Files and Directories
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;File Manipulation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using commands like &lt;code&gt;cp&lt;/code&gt;, &lt;code&gt;mv&lt;/code&gt;, &lt;code&gt;rm&lt;/code&gt;, &lt;code&gt;touch&lt;/code&gt;, &lt;code&gt;cat&lt;/code&gt;, and &lt;code&gt;echo&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;File Permissions&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;chmod&lt;/code&gt;, &lt;code&gt;chown&lt;/code&gt;, &lt;code&gt;chgrp&lt;/code&gt; to modify file permissions and ownership.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Directory Manipulation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigating directories (&lt;code&gt;cd&lt;/code&gt;, &lt;code&gt;ls&lt;/code&gt;), and creating/removing directories (&lt;code&gt;mkdir&lt;/code&gt;, &lt;code&gt;rmdir&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Redirecting Input/Output&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn about &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; for redirection.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;|&lt;/code&gt; (pipe) for chaining commands.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  7. Text Processing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Text Utilities&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Master &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt;, &lt;code&gt;cut&lt;/code&gt;, &lt;code&gt;sort&lt;/code&gt;, &lt;code&gt;uniq&lt;/code&gt; for text processing.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Regular Expressions&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn basic and advanced regular expressions for pattern matching in files and strings.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;String Manipulation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn string manipulation techniques like substring extraction, replacement, and case conversion.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  8. Arrays and Associative Arrays
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Arrays&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating and accessing indexed arrays.&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;array=(1 2 3)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Associative Arrays&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn about hashmaps/dictionaries (available in Bash 4.0+).&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;declare -A map&lt;/code&gt; for associative arrays.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  9. Error Handling and Debugging
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Exit Status&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn how to handle the exit status (&lt;code&gt;$?&lt;/code&gt;) of commands and scripts.&lt;/li&gt;
&lt;li&gt;Understand success (&lt;code&gt;0&lt;/code&gt;) vs failure (&lt;code&gt;non-zero&lt;/code&gt; exit codes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Using &lt;code&gt;set&lt;/code&gt; for Debugging&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;set -x&lt;/code&gt; for tracing script execution.&lt;/li&gt;
&lt;li&gt;Learn &lt;code&gt;set -e&lt;/code&gt; to exit the script if a command fails.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Logging Errors&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;2&amp;gt;&lt;/code&gt; for redirecting errors to a file.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  10. Advanced Topics
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Processes and Job Control&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn how to manage background processes (&lt;code&gt;bg&lt;/code&gt;, &lt;code&gt;fg&lt;/code&gt;, &lt;code&gt;jobs&lt;/code&gt;, &lt;code&gt;disown&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;wait&lt;/code&gt; to wait for a process to finish.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Command Substitution&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn command substitution with backticks or &lt;code&gt;$(...)&lt;/code&gt; for embedding command output.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Scheduling Tasks&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learn how to use &lt;code&gt;cron&lt;/code&gt; to schedule jobs and &lt;code&gt;at&lt;/code&gt; for one-time tasks.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Scripting Best Practices&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing clean, maintainable scripts (use comments, consistent naming conventions).&lt;/li&gt;
&lt;li&gt;Making scripts portable and secure.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  11. Putting It All Together
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Project Ideas&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automating system backups.&lt;/li&gt;
&lt;li&gt;Writing a script to manage log files.&lt;/li&gt;
&lt;li&gt;Creating a system monitoring script.&lt;/li&gt;
&lt;li&gt;Building a script for file organization or batch renaming.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Refactoring Code&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Refactor large scripts into smaller functions and better-organized components.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  12. Resources and Learning Materials
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Books&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;"Learning the Bash Shell"&lt;/em&gt; by Cameron Newham&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"Bash Cookbook"&lt;/em&gt; by Carl Albing, JP Vossen, and Cameron Newham&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Online Tutorials&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/bash/manual/" rel="noopener noreferrer"&gt;GNU Bash Manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.tldp.org/LDP/abs/html/" rel="noopener noreferrer"&gt;Bash Scripting Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Interactive Learning&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://linuxcommand.org/" rel="noopener noreferrer"&gt;LinuxCommand.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bash.academy/" rel="noopener noreferrer"&gt;Bash Academy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Practice&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Try coding exercises on platforms like &lt;a href="https://exercism.io/tracks/bash" rel="noopener noreferrer"&gt;Exercism.io&lt;/a&gt; and &lt;a href="https://www.hackerrank.com/domains/tutorials/10-days-of-bash" rel="noopener noreferrer"&gt;Hackerrank&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Mastering Bash scripting involves consistent practice. Start with small, simple scripts, and gradually take on more complex tasks. Always challenge yourself with real-world problems like automation, system management, and creating custom utilities. The more you script, the more efficient and comfortable you'll become!&lt;/p&gt;

</description>
      <category>linux</category>
      <category>bash</category>
      <category>devops</category>
      <category>programming</category>
    </item>
    <item>
      <title>Understanding Networking in Oracle's Virtualbox - NAT Network Adapter</title>
      <dc:creator>Sai Shanmukkha Surapaneni</dc:creator>
      <pubDate>Mon, 03 Mar 2025 19:44:13 +0000</pubDate>
      <link>https://dev.to/saishanmukkha/understanding-networking-in-oracles-virtualbox-nat-network-adapter-2m0j</link>
      <guid>https://dev.to/saishanmukkha/understanding-networking-in-oracles-virtualbox-nat-network-adapter-2m0j</guid>
      <description>&lt;p&gt;Oracle VirtualBox provides several network adapter modes to help virtual machines (VMs) connect to external networks, such as the internet. These adapters include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;NAT&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NAT Network&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Bridged Adapter&lt;/li&gt;
&lt;li&gt;Internal Network&lt;/li&gt;
&lt;li&gt;Host-only Adapter
(Plus a few experimental options.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this post, we’ll focus on the NAT (Network Address Translation) Network adapter, which is the default mode for newly created VMs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NAT Network is different from the NAT Adapter.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Among these, &lt;code&gt;NAT Network&lt;/code&gt; is often confused with &lt;code&gt;NAT Adapter&lt;/code&gt;, but they serve different purposes. In this post, we'll break down how NAT Network works, why you might use it, and how to configure it for optimal DevOps workflows.&lt;/p&gt;




&lt;h3&gt;
  
  
  What is NAT Network in VirtualBox?
&lt;/h3&gt;

&lt;p&gt;The NAT Network adapter in VirtualBox acts as a private network for multiple VMs, allowing them to communicate with each other while still having access to the external internet through the host.&lt;/p&gt;




&lt;h3&gt;
  
  
  Key Features of NAT Network:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inter-VM Communication&lt;/strong&gt; – VMs connected to the same NAT Network can talk to each other.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internet Access&lt;/strong&gt; – Each VM can access the internet via the host machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port Forwarding&lt;/strong&gt; – Allows specific ports to be forwarded from the host to the VM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DHCP Support&lt;/strong&gt; – VirtualBox provides automatic IP assignment through DHCP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network Isolation&lt;/strong&gt; – The VMs in a NAT Network cannot be directly accessed by the host or other external devices, increasing security.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Can Multiple VMs Communicate with Each Other?
&lt;/h2&gt;

&lt;p&gt;Not with NAT Adapter, but yes with NAT Network.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NAT Adapter isolates VMs; they cannot talk to each other.&lt;/li&gt;
&lt;li&gt;NAT Network allows multiple VMs on the same virtual network to communicate while still having internet access.&lt;/li&gt;
&lt;li&gt;If you need both internet access and inter-VM communication, you should use NAT Network instead of the NAT Adapter.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What's the difference?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;NAT Adapter is best when you just need a single VM to have internet access without network visibility.&lt;/li&gt;
&lt;li&gt;NAT Network is useful when multiple VMs need to talk to each other while maintaining external internet access.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  NAT Network Diagram
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fakxw4admqpkukxkwvr24.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fakxw4admqpkukxkwvr24.jpg" alt="NAT Network Diagram" width="800" height="1018"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both VM1 and VM2 can communicate within the NAT Network.&lt;/li&gt;
&lt;li&gt;The VirtualBox NAT engine handles internet access for all VMs.&lt;/li&gt;
&lt;li&gt;Port forwarding enables external access if needed.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Setting Up NAT Network with a Custom Subnet in VirtualBox&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Yes! You can set up a &lt;strong&gt;NAT Network&lt;/strong&gt; in VirtualBox with a custom subnet from the &lt;strong&gt;10.x.x.x private IP range&lt;/strong&gt;. This allows you to define the IP addressing scheme and ensures &lt;strong&gt;VM-to-VM communication within the NAT Network&lt;/strong&gt;, while still allowing internet access.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1: Create a NAT Network with a Custom Subnet&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;VirtualBox&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Press (Ctrl+H) or Navigate to &lt;strong&gt;Tools&lt;/strong&gt; -&amp;gt; &lt;strong&gt;File&lt;/strong&gt; → &lt;strong&gt;Tools&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Network Manager&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;NAT Networks&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add New NAT Network&lt;/strong&gt; (green + icon).&lt;/li&gt;
&lt;li&gt;Select the new network and click &lt;strong&gt;Edit&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Configure the following:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Network Name:&lt;/strong&gt; &lt;code&gt;MyCustomNATNetwork&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable DHCP:&lt;/strong&gt; ✅ (Optional, if you want automatic IP assignment)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subnet CIDR:&lt;/strong&gt; &lt;code&gt;10.10.10.0/24&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;OK&lt;/strong&gt; and close the Preferences window.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2: Attach VMs to the NAT Network&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For each VM:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select a &lt;strong&gt;VM&lt;/strong&gt; in VirtualBox.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Settings&lt;/strong&gt; → &lt;strong&gt;Network&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Adapter 1&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Attached to:&lt;/strong&gt; &lt;code&gt;NAT Network&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Select the NAT Network you created (&lt;code&gt;MyCustomNATNetwork&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Save the settings and start the VM.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each VM will now receive an IP address in the &lt;code&gt;10.10.10.x&lt;/code&gt; range.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VM1:&lt;/strong&gt; &lt;code&gt;10.10.10.10&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VM2:&lt;/strong&gt; &lt;code&gt;10.10.10.11&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These VMs can now communicate &lt;strong&gt;directly with each other&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3: Configure Port Forwarding for Inbound Traffic (Internet → VM)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;By default, VirtualBox blocks inbound traffic from the internet. To access a VM from an external machine, &lt;strong&gt;port forwarding&lt;/strong&gt; is required.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Enable Port Forwarding for SSH (Example)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;VirtualBox&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;VM&lt;/strong&gt; you want to access.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Settings&lt;/strong&gt; → &lt;strong&gt;Network&lt;/strong&gt; → &lt;strong&gt;Advanced&lt;/strong&gt; → &lt;strong&gt;Port Forwarding&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add a new rule:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; &lt;code&gt;SSH&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protocol:&lt;/strong&gt; &lt;code&gt;TCP&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Host IP:&lt;/strong&gt; &lt;code&gt;0.0.0.0&lt;/code&gt; (Or &lt;code&gt;your_host_IP&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Host Port:&lt;/strong&gt; &lt;code&gt;2222&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guest IP:&lt;/strong&gt; &lt;code&gt;10.10.10.10&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guest Port:&lt;/strong&gt; &lt;code&gt;22&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Save and restart the VM.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, you can SSH into the VM from the internet using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-p&lt;/span&gt; 2222 user@your_host_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: &lt;code&gt;0.0.0.0&lt;/code&gt; will listen on all network interfaces of the host. If you want to limit access to a specific interface, use &lt;code&gt;your_host_IP&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;NAT Network Traffic Flow (10.x.x.x Subnet)&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Outbound Traffic (VM → Internet)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;VM1 (10.10.10.10)&lt;/strong&gt; sends a request to &lt;code&gt;google.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;VirtualBox NAT Engine&lt;/strong&gt; replaces the VM’s &lt;strong&gt;private IP&lt;/strong&gt; (&lt;code&gt;10.10.10.10&lt;/code&gt;) with the &lt;strong&gt;host’s public IP&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The request is sent to the internet.&lt;/li&gt;
&lt;li&gt;The external website (Google) responds to the &lt;strong&gt;host’s public IP&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VirtualBox identifies the VM that made the request&lt;/strong&gt; and forwards the response to &lt;strong&gt;VM1 (10.10.10.10)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;➡️ &lt;strong&gt;VM1 and VM2 can access the internet but are not directly reachable from the internet unless port forwarding is configured.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Inbound Traffic (Internet → VM in NAT Network)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;By default, &lt;strong&gt;NAT Network blocks unsolicited inbound traffic&lt;/strong&gt;. However, &lt;strong&gt;port forwarding&lt;/strong&gt; allows selective traffic to be forwarded.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Example: SSH Access from the Internet to VM1&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;An external user runs:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   ssh &lt;span class="nt"&gt;-p&lt;/span&gt; 2222 user@your_host_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;request reaches the host machine&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;VirtualBox NAT engine&lt;/strong&gt; checks the &lt;strong&gt;port forwarding rules&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The request is &lt;strong&gt;forwarded to VM1 (10.10.10.10:22)&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;SSH connection is established&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;➡️ &lt;strong&gt;Only explicitly forwarded ports allow inbound traffic; all other traffic is blocked.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Inter-VM Traffic (VM1 ↔ VM2 within NAT Network)&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;VM1 (10.10.10.10)&lt;/strong&gt; pings &lt;strong&gt;VM2 (10.10.10.11)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The request &lt;strong&gt;remains inside the NAT Network&lt;/strong&gt; (&lt;strong&gt;does not go through the host or internet&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VM2 receives the request&lt;/strong&gt; and responds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VM1 gets the response&lt;/strong&gt;, completing the communication.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;➡️ &lt;strong&gt;VMs within the same NAT Network communicate directly without port forwarding.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Practices for Using NAT Network in DevOps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use NAT Network for Multi-VM Setups&lt;/strong&gt; – Ideal for running clusters (e.g., Kubernetes, Docker Swarm).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable Port Forwarding for Remote Access&lt;/strong&gt; – Allows SSH and web services to be accessible from the host.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combine with Bridged Adapters if Needed&lt;/strong&gt; – If external devices need to reach the VM directly, consider adding a second adapter in Bridged Mode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Static IPs for Stability&lt;/strong&gt; – Manually assign static IPs to VMs within the NAT Network to avoid conflicts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DHCP Lease Considerations&lt;/strong&gt; - Be aware that DHCP leases will expire, and while VirtualBox will attempt to reassign the same IP, it is not guaranteed. For long term stability, static IPs are recommended.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Best Practices&lt;/strong&gt; - Remember that even with network isolation, it is important to maintain security best practices on the host OS. Keep the host OS up to date with security patches, and use strong passwords.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The NAT Network Adapter in VirtualBox is a powerful and flexible option for virtual machine networking, enabling inter-VM communication while maintaining external internet access. By understanding how to configure it properly, you can optimize your development, testing, and DevOps workflows.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>computerscience</category>
      <category>network</category>
      <category>virtualmachine</category>
    </item>
    <item>
      <title>Understanding SSH Socket-Based Activation in Ubuntu 24.04</title>
      <dc:creator>Sai Shanmukkha Surapaneni</dc:creator>
      <pubDate>Thu, 20 Feb 2025 01:52:02 +0000</pubDate>
      <link>https://dev.to/saishanmukkha/understanding-ssh-socket-based-activation-in-ubuntu-2404-28m</link>
      <guid>https://dev.to/saishanmukkha/understanding-ssh-socket-based-activation-in-ubuntu-2404-28m</guid>
      <description>&lt;p&gt;With Ubuntu 24.04 LTS, Canonical has continued its trend of optimizing system resources, particularly with how SSH (OpenSSH) is handled. If you've been configuring SSH for a while, you might have noticed that starting from Ubuntu 22.10, SSH uses &lt;code&gt;systemd&lt;/code&gt; socket-based activation instead of running as a standalone service by default.&lt;/p&gt;

&lt;p&gt;While this change improves memory efficiency (especially for VMs and containers), it can also be a bit confusing if you're trying to configure SSH ports or listen addresses. In this article, I'll try to break it all down and show you how to manage SSH the way you want!&lt;/p&gt;

&lt;p&gt;I have faced this issue when I launched Ubuntu instances in AWS Cloud and tried to enable password authentication in &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;, but it didn't work. I then started researching online to understand what was happening.&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s Changed with SSH?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Socket-Based Activation by Default
&lt;/h3&gt;

&lt;p&gt;Ubuntu now uses socket-based activation for SSH. This means that sshd doesn’t start until an incoming connection request is received. The benefits? Lower memory usage, especially in cloud and containerized environments, as SSH is only active when needed. &lt;/p&gt;

&lt;p&gt;Instead of the traditional SSH service (&lt;code&gt;ssh.service&lt;/code&gt;), &lt;code&gt;ssh.socket&lt;/code&gt; is now responsible for listening on &lt;code&gt;port 22&lt;/code&gt;. When a connection attempt is made, &lt;code&gt;ssh.socket&lt;/code&gt; directly starts &lt;code&gt;sshd&lt;/code&gt; to handle the session, without starting &lt;code&gt;ssh.service&lt;/code&gt; persistently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Configuring a Custom SSH Port
&lt;/h2&gt;

&lt;p&gt;Previously, to change the SSH port, you'd edit &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; and set:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;However, with socket-based activation, &lt;code&gt;systemd&lt;/code&gt; intercepts port configurations and defaults to &lt;code&gt;port 22&lt;/code&gt; unless explicitly changed. Ubuntu 24.04 dynamically pulls port settings from &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;, eliminating the need to manually migrate configurations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edit &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;, for example:
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Reload &lt;code&gt;systemd&lt;/code&gt; and restart &lt;code&gt;ssh.socket&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&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 daemon-reload
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart ssh.socket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it! The new port setting should now be active.&lt;/p&gt;




&lt;h2&gt;
  
  
  What If You Don’t Like This Change?
&lt;/h2&gt;

&lt;p&gt;If you prefer the traditional method where SSH starts at boot and isn’t dependent on &lt;code&gt;systemd&lt;/code&gt; sockets, you can disable socket-based activation and restore the classic behavior.&lt;/p&gt;

&lt;p&gt;Run:&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="nb"&gt;sudo &lt;/span&gt;systemctl disable &lt;span class="nt"&gt;--now&lt;/span&gt; ssh.socket
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; ssh.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stop socket-based activation (ssh.socket)&lt;/li&gt;
&lt;li&gt;Enable ssh.service to run at boot&lt;/li&gt;
&lt;li&gt;Allow &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; to fully control SSH settings (including ports and listen addresses)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Avoiding SSH Listening on Multiple Ports
&lt;/h2&gt;

&lt;p&gt;By default, when using socket-based activation and adding a custom port, SSH may end up listening on both the new port and the default &lt;code&gt;port 22&lt;/code&gt;. If you only want SSH to listen on one specific port, you must explicitly clear previous settings.&lt;/p&gt;

&lt;p&gt;To make SSH listen only on &lt;code&gt;port 5463&lt;/code&gt;:&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="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /etc/systemd/system/ssh.socket.d
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/systemd/system/ssh.socket.d/listen.conf &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
[Socket]
ListenStream=
ListenStream=5463
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then reload &lt;code&gt;systemd&lt;/code&gt; and restart &lt;code&gt;ssh.socket&lt;/code&gt;:&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="nb"&gt;sudo &lt;/span&gt;systemctl daemon-reload
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart ssh.socket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now SSH will only listen on port 5463.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;While &lt;code&gt;systemd&lt;/code&gt; socket activation for SSH can be an adjustment, it ultimately provides better efficiency. That said, Ubuntu still allows you to revert to traditional SSH behavior if needed. Understanding these changes ensures you have full control over your system’s SSH configuration.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you’re fine with the new socket-based activation, just edit &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; and restart ssh.socket.&lt;/li&gt;
&lt;li&gt;If you want SSH to run traditionally (like in Ubuntu 20.04 or before), disable ssh.socket and enable ssh.service.&lt;/li&gt;
&lt;li&gt;To ensure SSH only listens on a custom port, clear previous socket settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have any thoughts or experiences with this change, feel free to share them in the comments!&lt;/p&gt;

</description>
      <category>linux</category>
      <category>ubuntu</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Understanding Networking in Oracle's VirtualBox - NAT Adapter</title>
      <dc:creator>Sai Shanmukkha Surapaneni</dc:creator>
      <pubDate>Sun, 02 Feb 2025 22:52:22 +0000</pubDate>
      <link>https://dev.to/saishanmukkha/networking-in-virtualbox-nat-adapter-3pf0</link>
      <guid>https://dev.to/saishanmukkha/networking-in-virtualbox-nat-adapter-3pf0</guid>
      <description>&lt;p&gt;Oracle VirtualBox provides several network adapter modes to help virtual machines (VMs) connect to external networks, such as the internet. These adapters include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;NAT&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;NAT Network&lt;/li&gt;
&lt;li&gt;Bridged Adapter&lt;/li&gt;
&lt;li&gt;Internal Network&lt;/li&gt;
&lt;li&gt;Host-only Adapter
(Plus a few experimental options.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this post, we’ll focus on the &lt;strong&gt;NAT (Network Address Translation) adapter&lt;/strong&gt;, which is the default mode for newly created VMs.&lt;/p&gt;




&lt;h3&gt;
  
  
  What Is a NAT Adapter?
&lt;/h3&gt;

&lt;p&gt;A NAT (Network Address Translation) adapter creates a separate subnetwork for each VM and uses NAT to connect the VM to the internet, keeping it isolated from the host’s local network. In other words, any request from the VM appears to come from the host machine. Although the VM can access the host, the host cannot directly access the VM unless you set up port forwarding or other configurations.&lt;/p&gt;




&lt;h3&gt;
  
  
  Can Multiple VMs Communicate With Each Other?
&lt;/h3&gt;

&lt;p&gt;By default, multiple VMs using the NAT adapter cannot communicate with each other. One workaround is to use port forwarding for each VM. Another option is to use the specialized host IP address 10.0.2.2 (for example, 10.0.2.2:) to allow some level of communication. However, this can get tricky for multiple VMs, so you may want to explore other adapter modes if you need direct VM-to-VM communication.&lt;/p&gt;




&lt;h3&gt;
  
  
  How Does NAT Work?
&lt;/h3&gt;

&lt;p&gt;When a VM is set to use NAT, VirtualBox creates a virtual router that manages network traffic for that VM. The VM receives a private IP address from VirtualBox’s built-in DHCP server, and all outbound traffic is translated (NATed) before reaching external networks (like the internet).&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.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%2Fsx4kqzz2jjwbq5kq60rs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fsx4kqzz2jjwbq5kq60rs.jpg" alt="NAT Diagram" width="800" height="829"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the figure above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VM1 and VM2 each use their own NAT table (NAT1 and NAT2).&lt;/li&gt;
&lt;li&gt;Both connect to the host machine’s network interface card (NIC).&lt;/li&gt;
&lt;li&gt;Each VM is on its own isolated subnetwork, so they cannot directly reach each other’s IP addresses.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Step-by-Step NAT Traffic Flow
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  Outbound Traffic (VM → Internet)
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;The VM sends a request (e.g., visiting google.com).&lt;/li&gt;
&lt;li&gt;The NAT engine replaces the VM’s private IP (e.g., 10.0.2.15) with the host’s public IP.&lt;/li&gt;
&lt;li&gt;The request is sent to the internet.&lt;/li&gt;
&lt;li&gt;The response from the external site returns to the host machine.&lt;/li&gt;
&lt;li&gt;VirtualBox forwards the response back to the VM.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;




&lt;blockquote&gt;
&lt;h4&gt;
  
  
  Inbound Traffic (Internet → VM)
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Because the VM is behind NAT, unsolicited inbound traffic is dropped.&lt;/li&gt;
&lt;li&gt;Only traffic forwarded via port forwarding rules can reach the VM.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The NAT adapter is a simple and secure way to provide internet access to your VMs without exposing them directly on the host network. If you need more control over network configurations or VM-to-VM communication, consider exploring other VirtualBox network adapters like Bridged or Host-only.&lt;/p&gt;

</description>
      <category>network</category>
      <category>computerscience</category>
      <category>virtualmachine</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
