<?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>Forem: SAHIL</title>
    <description>The latest articles on Forem by SAHIL (@sahillearninglinux).</description>
    <link>https://forem.com/sahillearninglinux</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%2F2613933%2Fcec3db38-ccb4-4dc7-a592-ba1f68281d19.jpg</url>
      <title>Forem: SAHIL</title>
      <link>https://forem.com/sahillearninglinux</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sahillearninglinux"/>
    <language>en</language>
    <item>
      <title>1: The Problems/Errors I Faced While Writing BashScripts And The Solutions also</title>
      <dc:creator>SAHIL</dc:creator>
      <pubDate>Sun, 12 Apr 2026 12:07:23 +0000</pubDate>
      <link>https://forem.com/sahillearninglinux/1-the-problemserrors-i-faced-while-writing-bashscripting-and-the-solutions-also-3kpe</link>
      <guid>https://forem.com/sahillearninglinux/1-the-problemserrors-i-faced-while-writing-bashscripting-and-the-solutions-also-3kpe</guid>
      <description>&lt;h2&gt;
  
  
  1. Automated Logging with exec
&lt;/h2&gt;

&lt;p&gt;Logging every line of a script manually is tedious. Using exec redirects the entire script's output stream.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem Without It&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Error&lt;/strong&gt;: Without global redirection, you have to append &amp;gt;&amp;gt; logfile.txt 2&amp;gt;&amp;amp;1 to every single command. If you forget one, that output is lost to the terminal and never recorded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The "Read" Conflict&lt;/strong&gt;: Once you redirect stdin (standard input), the read command starts looking at your log file or pipe for input instead of your keyboard. The script will either hang or crash because it can't find the "input" it needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Solution&lt;/strong&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;exec&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"script.log"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; 2&amp;gt;&amp;amp;1

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it works&lt;/strong&gt;: It uses Process Substitution. It sends stdout (1) and stderr (2) into a pipe that tee reads. tee then writes to the file and back to the terminal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Thought Process&lt;/strong&gt;: To fix the read issue, you must explicitly tell the script to look at the physical terminal for input:
&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;read&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Enter Name: "&lt;/span&gt; username &amp;lt; /dev/tty

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it helps&lt;/strong&gt;: It ensures 100% of errors are caught in the log without sacrificing the ability to have an interactive UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Processing Files: while read vs. for loop
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Problem Without It&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Error&lt;/strong&gt;: Using for line in $(cat file.txt) breaks if a line contains a space. The for loop treats spaces as delimiters, so a line like "John Doe" becomes two separate iterations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Thought Process&lt;/strong&gt;: We need a tool that respects the Newline character \n specifically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Solution&lt;/strong&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="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; line&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Processing: &lt;/span&gt;&lt;span class="nv"&gt;$line&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt; &amp;lt; file.txt

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How it helps:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;while&lt;/code&gt; read processes the file line-by-line. The &lt;code&gt;-r&lt;/code&gt; flag prevents backslashes from being interpreted as escape characters, preserving the data exactly as it exists in the file.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Non-Interactive Password Updates
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Problem Without It&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Error&lt;/strong&gt;: The standard passwd command is interactive. If you run it in a script, it pauses and waits for a human to type the password twice. This hangs an automated deployment script.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Thought Process&lt;/strong&gt;: We need a way to "pipe" the credentials directly into the system's authentication database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Solution&lt;/strong&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;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | chpasswd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it helps&lt;/strong&gt;: chpasswd is designed specifically for batch processing. It accepts user:pass strings from stdin, making it perfect for loops and automation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Clean Archiving
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Error&lt;/strong&gt;: If you 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;tar&lt;/span&gt; &lt;span class="nt"&gt;-cvf&lt;/span&gt; backup.tar /home/user/data/file.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;when you extract it, tar will recreate the entire folder structure &lt;code&gt;/home/user/data/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution&lt;/strong&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;tar&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; /home/user/data/ &lt;span class="nt"&gt;-cvf&lt;/span&gt; backup.tar file.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How it helps&lt;/strong&gt;: The -C (change directory) flag tells tar to "step into" that folder before arching, so the metadata only contains the filename.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using basename&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Thought Process&lt;/strong&gt;: If you have a full path like /var/logs/app/error.log, but you only want the string error.log for a backup name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Command&lt;/strong&gt;: &lt;code&gt;FILE_NAME=$(basename "/var/logs/app/error.log")&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How it helps&lt;/strong&gt;: It strips the directory path, allowing you to create clean, dynamic labels for your backups.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Reliability over $?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Problem with $?&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;The Error&lt;/strong&gt;: $? (the exit status) only captures the result of the last command executed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Risk&lt;/strong&gt;: If you call a function that checks a service, but the function has a small echo or cleanup command at the very end, $? will return the status of the echo, not the service check. You might think the service is running when it actually failed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution&lt;/strong&gt;: Direct Boolean Logic&lt;br&gt;
Instead of checking the number, use the command directly in an if statement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Avoid&lt;/strong&gt;: &lt;code&gt;systemctl is-active service; status=$?; if [ $status -eq 0 ]...&lt;br&gt;
&lt;/code&gt; &lt;br&gt;
&lt;strong&gt;Better&lt;/strong&gt;: &lt;code&gt;if systemctl is-active --quiet service; then ...&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it works&lt;/strong&gt;: In Bash, an if statement evaluates the exit code of the command following it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it helps&lt;/strong&gt;: It eliminates the "middleman" variable. It is cleaner, less prone to being overwritten by an accidental command in between, and more readable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  6. Short-Circuiting
&lt;/h2&gt;

&lt;p&gt;In Bash, &amp;amp;&amp;amp; represents AND. For an "AND" statement to be true, both sides must be true. If the first part (the condition) fails, Bash doesn't even bother looking at the second part—it just stops.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem with the &lt;code&gt;if&lt;/code&gt; Block&lt;/strong&gt;&lt;br&gt;
The standard if statement is visually heavy for simple tasks:&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="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"root"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Access granted."&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Access denied."&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Issue&lt;/strong&gt;: It takes 6 lines to perform one simple check. In a long script, this creates "visual noise" that makes it harder to spot the actual logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Solution&lt;/strong&gt;: Grouped Commands&lt;/p&gt;

&lt;p&gt;To run multiple commands (like an echo followed by an exit) on a single line, you must group them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A&lt;/strong&gt;: Using Parentheses ( )&lt;br&gt;
This runs the commands in a subshell.&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; &lt;span class="nv"&gt;$USER&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"root"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Error: Must be root"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Catch&lt;/strong&gt;: Because it’s a subshell, the exit command will exit the subshell, not your main script. Avoid this if you actually want the script to stop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option B&lt;/strong&gt;: Using Curly Braces { } (Recommended)&lt;br&gt;
This runs the commands in the current shell context.&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; &lt;span class="nv"&gt;$USER&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"root"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Error: Must be root"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Crucial Syntax&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There must be a space after the opening {.&lt;/li&gt;
&lt;li&gt;Each command inside must end with a semicolon ;.&lt;/li&gt;
&lt;li&gt;There must be a space before the closing }.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Handling the "Else" (The Ternary Style)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to emulate an &lt;code&gt;if/else&lt;/code&gt; on one line, you can chain &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; and &lt;code&gt;||&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="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"config.txt"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Found it"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Missing file"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The "Thought Process" &amp;amp; Common Errors&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The "Unexpected Exit" Error&lt;/strong&gt;: If you write [[ condition ]] &amp;amp;&amp;amp; echo "Success" || exit 1, and for some reason the echo fails (e.g., the disk is full or stdout is closed), the exit 1 will trigger even if the condition was true.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Fix&lt;/strong&gt;: Using the grouped { } after the &amp;amp;&amp;amp; ensures that the "Success" logic and the "Failure" logic stay strictly separated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So that wraps up the errors I faced and concepts I used to troubleshoot them. All the scripts are currently in my Github account&lt;br&gt;
(&lt;a href="https://github.com/sahil0907/BashScripting" rel="noopener noreferrer"&gt;https://github.com/sahil0907/BashScripting&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Feel free to share your insights and if there are any inputs I would love to hear over my LinkedIn &lt;br&gt;
(&lt;a href="https://www.linkedin.com/in/sahil0907/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sahil0907/&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Have a nice day and Keep Learning.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>cli</category>
      <category>linux</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Advanced Dockerfiles and the Build Process</title>
      <dc:creator>SAHIL</dc:creator>
      <pubDate>Mon, 08 Dec 2025 03:41:49 +0000</pubDate>
      <link>https://forem.com/sahillearninglinux/advanced-dockerfiles-and-the-build-process-1gmf</link>
      <guid>https://forem.com/sahillearninglinux/advanced-dockerfiles-and-the-build-process-1gmf</guid>
      <description>&lt;p&gt;In Part 1, we learned that the Dockerfile is the essential, reproducible "source code" for your Docker image. Now, we dive into the docker build command and explore advanced instructions that help you create production-ready, highly efficient images.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Build Process&lt;/strong&gt;: The docker build Command&lt;br&gt;
The docker build command is what executes the instructions in your Dockerfile and creates the image.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command Part&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;docker build&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The command to start the image creation process.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker build .&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;.&lt;/code&gt; (Context)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The &lt;strong&gt;build context&lt;/strong&gt;. This is the directory containing the Dockerfile and all files needed for the build (e.g., application code).&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker build .&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;-t&lt;/code&gt; (Tag)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Assigns a &lt;strong&gt;name and optional tag&lt;/strong&gt; to the final image. Essential for identification and pushing to registries.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker build -t myapp/backend:v1.0 .&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;-f &amp;lt;file&amp;gt;&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Specifies an alternative &lt;strong&gt;Dockerfile name or path&lt;/strong&gt;. Useful if you have multiple Dockerfiles in one directory.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker build -f Dockerfile.dev .&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;--no-cache&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Forces Docker to ignore the build cache and run every instruction.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker build --no-cache .&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. The Power of the Build Context&lt;/strong&gt;&lt;br&gt;
The build context (the directory you specify, often .) is critical.&lt;/p&gt;

&lt;p&gt;When you run docker build, Docker first bundles the entire contents of the context directory and sends it to the Docker Daemon.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;COPY&lt;/strong&gt; and &lt;strong&gt;ADD&lt;/strong&gt; instructions can only reference files within this context. They cannot access files outside of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using .dockerignore&lt;/strong&gt;&lt;br&gt;
To prevent sending large, unnecessary files (like node_modules, .git folders, or local environment files) to the Docker Daemon, you use a .dockerignore file.&lt;/p&gt;

&lt;p&gt;This file works exactly like &lt;strong&gt;.gitignore&lt;/strong&gt;. It lists files and directories that should be excluded from the build context sent to the daemon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;: Smaller build context means faster builds and avoids accidentally copying sensitive local files into your image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Advanced Dockerfile Instructions&lt;/strong&gt;&lt;br&gt;
We covered the basics (FROM, RUN, CMD) in Part 1. These instructions provide more control over image size and container execution:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Instruction&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Creates Layer?&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;ENTRYPOINT&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Configures a container to run as an &lt;strong&gt;executable&lt;/strong&gt;. It sets the main program that will always run when the container starts.&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ENTRYPOINT ["/usr/bin/python3"]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;ADD&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Similar to &lt;code&gt;COPY&lt;/code&gt;, but it can automatically extract compressed archives (e.g., &lt;code&gt;.tar&lt;/code&gt;, &lt;code&gt;.zip&lt;/code&gt;) from the source URL or local path into the destination.&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ADD https://example.com/app.tar.gz /tmp/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;ARG&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Defines &lt;strong&gt;build-time variables&lt;/strong&gt; that users can pass during the build process using the &lt;code&gt;--build-arg&lt;/code&gt; flag.&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ARG VERSION=1.0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;ENV&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sets persistent &lt;strong&gt;environment variables&lt;/strong&gt; inside the resulting image (and container). These variables persist after the build and during runtime.&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ENV PORT=8080&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;USER&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sets the &lt;strong&gt;username or UID&lt;/strong&gt; to be used when running the container and for subsequent instructions like &lt;code&gt;CMD&lt;/code&gt; or &lt;code&gt;RUN&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;USER appuser&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Understanding CMD vs. ENTRYPOINT&lt;/strong&gt;&lt;br&gt;
This is a common point of confusion:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CMD&lt;/strong&gt;: Defines the default arguments for the ENTRYPOINT. If no ENTRYPOINT is defined, CMD sets the executable. It is easily overridden by arguments passed to docker run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ENTRYPOINT&lt;/strong&gt;: Defines the main executable. Arguments passed to docker run are appended to the ENTRYPOINT command.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;&lt;code&gt;ENTRYPOINT&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;CMD&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Effective Command on Run&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Shell App&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not set&lt;/td&gt;
&lt;td&gt;&lt;code&gt;["/bin/bash"]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/bin/bash&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Server App&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;["java", "-jar", "app.jar"]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not set&lt;/td&gt;
&lt;td&gt;&lt;code&gt;java -jar app.jar&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Executable/Arguments&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;["nginx"]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;["-g", "daemon off;"]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nginx -g daemon off;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Override Example&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;["echo"]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;["Hello"]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;echo Hello&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Override with &lt;code&gt;docker run world&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;["echo"]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;["Hello"]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;echo world&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;4. Best Practice: Multi-Stage Builds&lt;/strong&gt;&lt;br&gt;
The biggest challenge in image building is keeping the final image small. Tools needed for building (compilers, SDKs, development dependencies) often result in large image sizes.&lt;/p&gt;

&lt;p&gt;Multi-Stage Builds solve this by using multiple FROM statements in a single Dockerfile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 1 (Builder)&lt;/strong&gt;: Uses a large base image (e.g., golang:latest) to compile the application. This stage contains all the unnecessary build tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 2 (Final)&lt;/strong&gt;: Uses a small, minimal base image (e.g., scratch or alpine). It only copies the final, compiled executable artifact from the Builder stage.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Base Image Example&lt;/th&gt;
&lt;th&gt;Contents&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Builder (Stage 1)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;FROM node:20 as build&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All source code, NPM, Webpack, etc.&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;To Compile&lt;/strong&gt; the application.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Final (Stage 2)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;FROM nginx:alpine&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Only the static HTML/CSS/JS files.&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;To Serve&lt;/strong&gt; the application.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The Result&lt;/strong&gt;: The final image size is drastically reduced because the entire build environment is discarded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Pushing Your Image to a Registry&lt;/strong&gt;&lt;br&gt;
Once your image is built, the final step is sharing it. A Container Registry (like Docker Hub, AWS ECR, or GitHub Packages) stores your images securely.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authenticate&lt;/strong&gt;: Log into your registry using your CLI credentials.
&lt;code&gt;docker login&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tag the Image&lt;/strong&gt;: Ensure your image is tagged with the full registry path (e.g., username/repository:tag).
&lt;code&gt;docker tag myapp/backend:v1.0 myregistry.com/myusername/myapp:v1.0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Push the Image&lt;/strong&gt;: Upload the image and its layers to the remote registry.
&lt;code&gt;docker push myregistry.com/myusername/myapp:v1.0&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You have now completed the entire image lifecycle!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example Dockerfile:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ----------------------------------
# STAGE 1: THE BUILDER STAGE
# This stage compiles, bundles, and installs dependencies.
# We use a large, full Node image (node:20) for all the necessary tools.
# ----------------------------------
FROM node:20-alpine AS build

# Set build arguments (can be passed with --build-arg during 'docker build')
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}

# Set the working directory inside the container for all subsequent commands
WORKDIR /app

# Copy package.json and package-lock.json first. 
# This leverages Docker's cache: if dependencies haven't changed, 
# Docker won't re-run 'npm install'.
COPY package*.json ./

# Install application dependencies
RUN npm install

# Copy the rest of the application source code
COPY . .

# Run the build process (e.g., if you have a React or Angular front-end)
# RUN npm run build

# ----------------------------------
# STAGE 2: THE FINAL PRODUCTION STAGE
# This stage takes only the necessary runtime files from the build stage.
# We use a tiny base image (alpine) for a small final size.
# ----------------------------------
FROM alpine:latest

# Define environment variables (runtime settings)
ENV HOST=0.0.0.0
ENV PORT=3000

# Set the user to a non-root user (good security practice)
RUN addgroup -S appgroup &amp;amp;&amp;amp; adduser -S appuser -G appgroup
USER appuser

# Set the final working directory
WORKDIR /usr/src/app

# Copy ONLY the node executable and the necessary files from the 'build' stage
# Note the '--from=build' flag
COPY --from=build /usr/local/bin/node /usr/local/bin/
COPY --from=build /usr/local/lib/node_modules /usr/local/lib/node_modules
COPY --from=build /app ./
# The above copies could be replaced by just copying the final executable files or artifacts
# For a simple Node app, we copy the app files and hope the Node runtime is available.

# The EXPOSE instruction documents the port the application listens on.
EXPOSE 3000

# ENTRYPOINT is the main executable command (the application runner)
ENTRYPOINT ["node"]

# CMD provides the default arguments for the ENTRYPOINT (the app file to run)
CMD ["index.js"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key points and why we used it:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Instruction&lt;/th&gt;
&lt;th&gt;Purpose in this Demo&lt;/th&gt;
&lt;th&gt;Concept Highlighted&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;FROM node:20-alpine AS build&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Starts the build stage and names it &lt;code&gt;build&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Multi-Stage Build&lt;/strong&gt; (Stage Naming)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;ARG/ENV&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Defines environment settings for build and runtime.&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Build-Time vs. Runtime&lt;/strong&gt; variables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;WORKDIR /app&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ensures consistency for subsequent file operations.&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Filesystem Context&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;COPY package*.json ./&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Separates dependency files for &lt;strong&gt;Cache Optimization&lt;/strong&gt;.&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Layer Caching&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;RUN npm install&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Executes shell commands to install software (creates a layer).&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Image Layering&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;COPY --from=build /app ./&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Transfers only the necessary files between stages.&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Multi-Stage Build&lt;/strong&gt; (Efficiency)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;EXPOSE 3000&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Documents the port required by the application.&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Port Documentation&lt;/strong&gt; (Not actual mapping)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;USER appuser&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Drops root privileges for better security.&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Security Best Practice&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;ENTRYPOINT ["node"]&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sets the application's main executable.&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Container Execution&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;CMD ["index.js"]&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sets the default file/arguments for the executable.&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Overridable Defaults&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
    </item>
    <item>
      <title>Building Images: From Manual Commits to the Dockerfile Revolution</title>
      <dc:creator>SAHIL</dc:creator>
      <pubDate>Mon, 08 Dec 2025 03:27:41 +0000</pubDate>
      <link>https://forem.com/sahillearninglinux/building-images-from-manual-commits-to-the-dockerfile-revolution-548c</link>
      <guid>https://forem.com/sahillearninglinux/building-images-from-manual-commits-to-the-dockerfile-revolution-548c</guid>
      <description>&lt;p&gt;In our previous posts, we learned the commands to manage images and containers. Now, let's dive into image creation. There are two main ways to build an image, and understanding the older method shows you why the modern standard is essential.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Manual Way: Building Images with docker commit&lt;/strong&gt;&lt;br&gt;
Before Dockerfiles became standard, the most straightforward way to create an image was by modifying a running container and then "committing" those changes to a new image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A. How docker commit Works&lt;/strong&gt;&lt;br&gt;
Start a Base Container: Run an image, often with shell access for interaction.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run -it --name my_sandbox ubuntu:latest bash&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make Manual Changes&lt;/strong&gt;: Inside the container, perform installations or configurations. For example, installing Nginx.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;apt-get update &amp;amp;&amp;amp; apt-get install -y nginx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exit the Container&lt;/strong&gt;: Type exit to stop the container (preserving the changes in the container's read-write layer).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Commit the Changes&lt;/strong&gt;: Use docker commit to save the container's current state as a new, immutable image.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker commit &amp;lt;container_name&amp;gt; &amp;lt;new_image_name&amp;gt;:&amp;lt;tag&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;code&gt;docker commit my_sandbox my_custom_nginx:v1.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B. Upgrading a Committed Image&lt;/strong&gt;&lt;br&gt;
To "upgrade" this image, you would repeat the process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start a new container from your my_custom_nginx:v1.0 image.&lt;/li&gt;
&lt;li&gt;Make further manual changes (e.g., update the Nginx configuration).&lt;/li&gt;
&lt;li&gt;Commit the changes again, tagging it with v2.0.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;docker commit &amp;lt;new_container_name&amp;gt; my_custom_nginx:v2.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The Limitations of docker commit&lt;/strong&gt;&lt;br&gt;
While docker commit is simple, it quickly becomes unmanageable for production use due to several major drawbacks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limitation&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;No Traceability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;There is &lt;strong&gt;no record&lt;/strong&gt; of the commands that were run inside the container. You don't know &lt;em&gt;why&lt;/em&gt; a file exists or &lt;em&gt;how&lt;/em&gt; a package was installed.&lt;/td&gt;
&lt;td&gt;Makes auditing, debugging, and security checks nearly impossible.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Non-Reproducible&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;If you delete the image, you have to manually repeat the exact shell commands in the exact order to rebuild it.&lt;/td&gt;
&lt;td&gt;Prevents consistent development and deployment across different environments.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Large Images&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;docker commit&lt;/code&gt; often captures unnecessary files (like temporary install cache) in the image layer.&lt;/td&gt;
&lt;td&gt;Leads to bloated images that are slow to pull and consume more disk space.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security Risk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You cannot easily verify the contents or history of the image layers.&lt;/td&gt;
&lt;td&gt;Increases the risk of hidden vulnerabilities.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;3. The Dockerfile Revolution&lt;/strong&gt;&lt;br&gt;
The Dockerfile was created specifically to eliminate the limitations of docker commit. A Dockerfile is a simple, plain text file that contains a series of instructions (commands) that Docker executes sequentially to build an image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Use a Dockerfile?&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Automation&lt;/strong&gt;: The entire build process is fully automated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Traceability:&lt;/strong&gt; Every command is explicitly listed, creating a transparent, auditable history of the image's creation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reproducibility:&lt;/strong&gt; Anyone with the Dockerfile can rebuild the exact same image consistently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it Removes the Limitations:&lt;/strong&gt;&lt;br&gt;
The Dockerfile is the source code for the image. It allows you to automatically generate images that adhere to best practices for size and security, guaranteeing a reproducible and version-controlled build.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Essential Dockerfile Instructions (Part 1)&lt;/strong&gt;&lt;br&gt;
While the full building process is covered in Part 2, let's introduce the core instructions that form the backbone of nearly every Dockerfile.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Instruction&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Creates Layer?&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;FROM&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Specifies the &lt;strong&gt;base image&lt;/strong&gt; for the build (the starting point). &lt;strong&gt;Must be the first instruction.&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;FROM node:18-alpine&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;RUN&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Executes any command in a new layer on top of the current image. Used for installing packages, making directories, etc.&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RUN apk add --no-cache git&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;WORKDIR&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sets the &lt;strong&gt;working directory&lt;/strong&gt; for any subsequent &lt;code&gt;RUN&lt;/code&gt;, &lt;code&gt;CMD&lt;/code&gt;, &lt;code&gt;ENTRYPOINT&lt;/code&gt;, &lt;code&gt;COPY&lt;/code&gt;, or &lt;code&gt;ADD&lt;/code&gt; instructions.&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;WORKDIR /app&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;COPY&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Copies files or directories from the &lt;strong&gt;host machine&lt;/strong&gt; (where the build is running) into the new image filesystem.&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;COPY package.json /app&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;CMD&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provides the default command for an &lt;strong&gt;executing container&lt;/strong&gt;. This command is typically overwritten when the container starts. &lt;strong&gt;Only one &lt;code&gt;CMD&lt;/code&gt; is allowed.&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CMD ["node", "server.js"]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;EXPOSE&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Informs Docker that the container listens on the specified network ports at runtime. &lt;strong&gt;It does not actually publish the port.&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;EXPOSE 8080&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Understanding CMD vs. RUN&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RUN&lt;/strong&gt; executes a command during the image build (e.g., installing software).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CMD&lt;/strong&gt; executes a command when the container is started (e.g., launching the application).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Small Explanations on Omitted Topics&lt;/strong&gt;&lt;br&gt;
We haven't fully covered Networking and Volumes, but here is how they relate to the Dockerfile:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Networking:&lt;/strong&gt; The EXPOSE instruction is the only networking configuration typically done in a Dockerfile. It simply documents which ports the application inside the container uses. The actual port mapping (e.g., -p 8080:80) is done using the docker run command, not the Dockerfile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Volumes:&lt;/strong&gt; Volumes are for data persistence and are usually defined using the docker run -v command or Docker Compose. Occasionally, the VOLUME instruction is used in a Dockerfile to mark a mount point, but it's often better practice to manage volumes outside the image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's Next?&lt;/strong&gt;&lt;br&gt;
You now understand the critical necessity of the Dockerfile! In Part 2 of this topic, we will dive into the full build process using the docker build command, cover advanced instructions like ENTRYPOINT and best practices like multi-stage builds, and officially put our image on a registry.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>🛠️ Mastering Docker Commands: Your Daily Toolkit</title>
      <dc:creator>SAHIL</dc:creator>
      <pubDate>Mon, 08 Dec 2025 03:13:07 +0000</pubDate>
      <link>https://forem.com/sahillearninglinux/post-6-mastering-docker-commands-your-daily-toolkit-519h</link>
      <guid>https://forem.com/sahillearninglinux/post-6-mastering-docker-commands-your-daily-toolkit-519h</guid>
      <description>&lt;p&gt;You've learned the what, why, and how behind Docker's architecture and filesystem. Now, let's get deeply practical with the commands you'll use every single day to interact with Docker. This post will be your go-to reference for managing images, containers, and your Docker environment.&lt;/p&gt;

&lt;p&gt;We've organized the essential commands into categories for easy lookup:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. 🔍 Docker System &amp;amp; Information Commands&lt;/strong&gt;&lt;br&gt;
These commands provide overall status and management of your Docker installation.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Displays the &lt;strong&gt;Docker client version&lt;/strong&gt;.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker --version&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker info&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Provides detailed system-wide information about your Docker installation.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker info&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker system df&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shows disk space usage by Docker objects (images, containers, volumes).&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker system df&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker system prune&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Removes unused Docker data (stopped containers, unused networks, dangling images).&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker system prune&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. 🖼️ Image Management Commands&lt;/strong&gt;&lt;br&gt;
Images are the blueprints. These commands help you find, download, list, and remove them.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker pull&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Downloads an image from a registry (default is &lt;strong&gt;Docker Hub&lt;/strong&gt;) to your local machine.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker pull ubuntu:latest&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;docker images&lt;/code&gt; (or &lt;code&gt;docker image ls&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Lists all images stored locally on your machine.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker images&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Searches Docker Hub for images based on a keyword.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker search nginx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker inspect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Displays detailed JSON configuration information about a Docker object.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker inspect nginx:latest&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker rmi&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Removes one or more images.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker rmi ubuntu:latest&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;3. 🚢 Container Lifecycle Commands&lt;/strong&gt;&lt;br&gt;
These are the workhorses for creating, starting, stopping, and managing individual containers.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;docker run&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Creates and starts&lt;/strong&gt; a new container from an image.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker run -it --name my-alpine alpine sh&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker create&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Creates a container but &lt;strong&gt;does not start it&lt;/strong&gt;.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker create --name my-db postgres&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Starts one or more stopped containers.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker start my-db&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker stop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stops one or more running containers &lt;strong&gt;gracefully&lt;/strong&gt;.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker stop my-web-server&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker restart&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Restarts one or more containers.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker restart my-db&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker kill&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Kills one or more running containers &lt;strong&gt;forcefully&lt;/strong&gt; (sends &lt;code&gt;SIGKILL&lt;/code&gt;).&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker kill my-db&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;docker ps&lt;/code&gt; (or &lt;code&gt;docker container ls&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Lists running containers. Add &lt;code&gt;-a&lt;/code&gt; or &lt;code&gt;--all&lt;/code&gt; to list all containers.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker ps -a&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker rm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Removes one or more stopped containers. Use &lt;code&gt;-f&lt;/code&gt; to force removal of a running container.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker rm my-alpine&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;4. ✨ docker run Options (Flags)&lt;/strong&gt;&lt;br&gt;
The flexibility of docker run comes from its flags. Here are the most important ones and their meanings:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Example Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-it&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Interactive Mode.&lt;/strong&gt; Stands for &lt;code&gt;-i&lt;/code&gt; (interactive) and &lt;code&gt;-t&lt;/code&gt; (TTY). Essential for shell access.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker run -it alpine sh&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Detached Mode.&lt;/strong&gt; Runs the container in the background.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker run -d nginx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-p &amp;lt;host&amp;gt;:&amp;lt;container&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Port Mapping.&lt;/strong&gt; Publishes a container's port to a host port.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker run -p 8080:80 nginx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--name &amp;lt;name&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Assigns a memorable name to the container.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker run --name my-app ...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--rm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatically &lt;strong&gt;removes the container when it exits&lt;/strong&gt;. Great for temporary tasks.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker run --rm alpine ...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-v &amp;lt;source&amp;gt;:&amp;lt;dest&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Volume Mount.&lt;/strong&gt; Mounts a host path or named volume for data persistence.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker run -v my-data:/data ...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;5. 🔬 Container Interaction &amp;amp; Monitoring Commands&lt;/strong&gt;&lt;br&gt;
Once a container is running, these commands help you interact with it, monitor performance, and debug issues.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;docker exec&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Executes a command &lt;strong&gt;inside a running container&lt;/strong&gt;.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker exec -it my-app sh&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;docker logs&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fetches the logs of a container. Use &lt;code&gt;-f&lt;/code&gt; to stream logs in real-time.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker logs -f my-web-server&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;docker top&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Displays the &lt;strong&gt;running processes&lt;/strong&gt; within a container.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker top my-web-server&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;docker stats&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Displays a live stream of resource usage (CPU, memory, I/O) for running containers.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker stats&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;docker cp&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Copies files/folders &lt;strong&gt;between a container and the local filesystem&lt;/strong&gt;.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker cp my-app:/app/config.ini .&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker attach&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Attaches your terminal to a running container's streams (use with caution).&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker attach my-alpine&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;What's Next?&lt;/strong&gt;&lt;br&gt;
You now have a robust toolkit and reference guide for managing every aspect of a container's life.&lt;/p&gt;

&lt;p&gt;In our next post, we will finally use the command-line knowledge to build custom images. We'll dive into the architecture of a Dockerfile and practice writing efficient instructions!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Docker Filesystem and the Power of Copy-on-Write (CoW)</title>
      <dc:creator>SAHIL</dc:creator>
      <pubDate>Mon, 08 Dec 2025 03:03:16 +0000</pubDate>
      <link>https://forem.com/sahillearninglinux/docker-filesystem-and-the-power-of-copy-on-write-cow-6a</link>
      <guid>https://forem.com/sahillearninglinux/docker-filesystem-and-the-power-of-copy-on-write-cow-6a</guid>
      <description>&lt;p&gt;We've discussed how containers are fast because they share the host OS kernel and use Namespaces and cgroups for isolation. But what about disk space and file operations? The secret here lies in Docker's efficient Filesystem and the Copy-on-Write (CoW) strategy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Container's Filesystem Structure&lt;/strong&gt;&lt;br&gt;
As we touched on, a running container's filesystem is composed of two primary parts, layered on top of each other using a Union File System (like Overlay2):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Read-Only Image Layers (Base):&lt;/strong&gt; These layers form the foundation of the container. They contain everything from the operating system base to the application binaries and dependencies. Multiple containers derived from the same image share these same read-only layers. This is the shared, immutable part.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Read-Write Container Layer (Top):&lt;/strong&gt; This thin, final layer is unique to the running container. Any data created, deleted, or modified while the container is running is written only to this top layer. This is the unique, ephemeral part.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The Copy-on-Write (CoW) Principle&lt;/strong&gt;&lt;br&gt;
The magic happens when a running container tries to modify a file that exists in one of the read-only image layers below it.&lt;/p&gt;

&lt;p&gt;The Copy-on-Write (CoW) principle ensures that the shared base layers are never directly altered. It works like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;CoW Principle Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reading a File&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The container reads the file directly from the shared, read-only layer (very fast and efficient).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Modifying or Deleting a File&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Docker &lt;strong&gt;copies&lt;/strong&gt; the file from its original read-only layer into the top read-write layer. The container then modifies this new copy. The original file in the base layer remains untouched for other containers to use.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Why CoW is Essential:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Disk Efficiency&lt;/strong&gt;: Since all containers share the base layers, you don't waste disk space by storing multiple copies of the same OS files or libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed and Immutability:&lt;/strong&gt; File reads are instantaneous (no copying needed). Furthermore, the original image is preserved (it's immutable), guaranteeing that every new container starts from a clean, known state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast Boot Times:&lt;/strong&gt; Containers start quickly because they only need to create the thin, empty writable layer on top, not duplicate the entire image filesystem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Understanding Ephemeral Data&lt;/strong&gt;&lt;br&gt;
Because changes are written to the top, thin, writable layer, this data is ephemeral.&lt;/p&gt;

&lt;p&gt;Ephemeral means it exists only as long as the container does. If you run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker rm &amp;lt;container_name&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;em&gt;...the writable layer is destroyed, and all the data written to it is gone forever.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is a key architectural design point: containers are designed to be stateless and disposable. For data that must persist across container restarts or deletions (like a database's contents or application logs), you must use Docker Volumes, which we will cover in a dedicated post on data persistence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's Next?&lt;/strong&gt;&lt;br&gt;
We've covered the theoretical foundations: the why (Post 1), the what (Images and Containers), the how (Architecture and Runtime), and now the efficiency (Filesystem and CoW).&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Container Architecture and Runtime Explained</title>
      <dc:creator>SAHIL</dc:creator>
      <pubDate>Mon, 08 Dec 2025 02:54:35 +0000</pubDate>
      <link>https://forem.com/sahillearninglinux/container-architecture-and-runtime-explained-354n</link>
      <guid>https://forem.com/sahillearninglinux/container-architecture-and-runtime-explained-354n</guid>
      <description>&lt;p&gt;We've explored what containers are and how they use layered images. Now, let's look at the plumbing: how your operating system (OS) isolates these containers and the software that manages their lifecycle—the Container Runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Core Concept: OS-Level Virtualization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Unlike Virtual Machines (VMs), which virtualize the entire hardware stack and require a full guest OS, Docker uses OS-level virtualization. This means the containers run directly on the host OS's kernel.&lt;/p&gt;

&lt;p&gt;This is the source of Docker's speed and lightweight nature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key OS Technologies Used for Isolation:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Containers achieve isolation using two fundamental features built into the Linux Kernel (and mirrored/virtualized on Windows/macOS):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Namespaces&lt;/strong&gt;: These isolate the container's view of the operating system. Each container gets its own segregated slice of resources, including:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PID Namespace&lt;/strong&gt;: Containers only see their own processes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Net Namespace&lt;/strong&gt;: Containers have their own network interfaces, ports, and routing tables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mount Namespace&lt;/strong&gt;: Containers have their own root filesystem (based on the image layers).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Control Groups (cgroups)&lt;/strong&gt;: These limit the amount of resources a container can consume. They act as resource controllers, allowing you to cap a container's access to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CPU&lt;/strong&gt;: Limit the percentage of processor time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory&lt;/strong&gt;: Set hard limits on RAM usage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Block I/O&lt;/strong&gt;: Control disk input/output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In short&lt;/strong&gt;: Namespaces isolate what a container sees (its view), and cgroups limit what a container uses (its resources).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The Engine: Docker Daemon vs. Container Runtime&lt;/strong&gt;&lt;br&gt;
When you run a command like docker run, several pieces of software work together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A. The Docker Daemon (dockerd)&lt;/strong&gt;&lt;br&gt;
The Docker Daemon is the server component that runs in the background. It is responsible for the heavy lifting, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building images.&lt;/li&gt;
&lt;li&gt;Pulling and pushing images to registries (like Docker Hub).&lt;/li&gt;
&lt;li&gt;Managing storage (volumes) and networking.&lt;/li&gt;
&lt;li&gt;Receiving commands from the CLI (your docker run commands) and passing them to the appropriate runtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;B. The Container Runtime&lt;/strong&gt;&lt;br&gt;
The Container Runtime is the low-level component that executes the essential tasks of running and managing a container process. It interacts directly with the Linux kernel's Namespaces and cgroups.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There are two main types of runtimes:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;High-Level Runtime (e.g., containerd):&lt;/strong&gt; This manages the entire container lifecycle: image transfer, mounting the root filesystem, setting up networking, and logging. The Docker Daemon uses containerd to manage its containers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Low-Level Runtime (e.g., runc):&lt;/strong&gt; This is the executable that actually creates and runs the container process. It is the final component that interfaces directly with the kernel features (Namespaces and cgroups) to enforce isolation. runc is the reference implementation of the OCI Runtime Specification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Chain of Command:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You type: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run ...&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Docker CLI sends the command to the Docker Daemon (dockerd).&lt;/li&gt;
&lt;li&gt;The Docker Daemon prepares the image and passes the request to the High-Level Runtime (containerd).&lt;/li&gt;
&lt;li&gt;containerd extracts the container configuration and hands it off to the Low-Level Runtime (runc).&lt;/li&gt;
&lt;li&gt;runc uses Namespaces and cgroups to create and run the isolated container process on the host OS kernel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. OCI: The Open Container Initiative&lt;/strong&gt;&lt;br&gt;
You'll often hear the term OCI. This is a project that created standardized specifications for the core components of container technology:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image Specification&lt;/strong&gt;: Defines what a container image must look like (e.g., structure, layers, manifest).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtime Specification&lt;/strong&gt;: Defines how a container runtime (like runc) must be configured and executed.&lt;/p&gt;

&lt;p&gt;The OCI standards ensure that images built by one tool (e.g., Docker) can be run by another compliant tool (e.g., Podman or Kubernetes' Kubelet), promoting portability and preventing vendor lock-in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's Next?&lt;/strong&gt;&lt;br&gt;
Understanding these low-level concepts is crucial. Now we know how containers work and what software makes them run. In next post we will learn about Filesystem used in Docker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Thank You.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Understanding Docker Images and Layers</title>
      <dc:creator>SAHIL</dc:creator>
      <pubDate>Sun, 07 Dec 2025 16:09:52 +0000</pubDate>
      <link>https://forem.com/sahillearninglinux/understanding-docker-images-and-layers-4c4k</link>
      <guid>https://forem.com/sahillearninglinux/understanding-docker-images-and-layers-4c4k</guid>
      <description>&lt;p&gt;In our last post, you ran your very first container. You saw how quickly Docker could start an &lt;strong&gt;Nginx&lt;/strong&gt; web server. But what makes containers so fast and lightweight? The answer lies in how Docker builds and manages its core components: Images and Layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Relationship: Image vs. Container&lt;/strong&gt;&lt;br&gt;
Think of it like programming:&lt;/p&gt;

&lt;p&gt;A Docker Image is the class (the blueprint). It's a static, read-only set of instructions and components.&lt;/p&gt;

&lt;p&gt;A Docker Container is the object (the instance). It's the running environment created from that image, complete with a thin, writable layer on top.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Nature&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Image&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Static, Read-Only&lt;/td&gt;
&lt;td&gt;The template for building a container.&lt;/td&gt;
&lt;td&gt;Stored on disk.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Container&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dynamic, Read/Write&lt;/td&gt;
&lt;td&gt;The isolated, running instance of an image.&lt;/td&gt;
&lt;td&gt;Running in memory.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. The Magic: The Layered Filesystem&lt;/strong&gt;&lt;br&gt;
The core efficiency of Docker comes from its layered structure.&lt;/p&gt;

&lt;p&gt;Docker Images are not monolithic files; they are built up from a stack of read-only layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How layers are created&lt;/strong&gt;: Every instruction in a &lt;em&gt;Dockerfile&lt;/em&gt; (which we'll cover in the next post) generally creates a new layer. For example, installing a package or copying a file creates a layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Union File System:&lt;/strong&gt; Docker uses a Union File System (like &lt;strong&gt;Overlay2&lt;/strong&gt;) to merge all these read-only layers together, making it look like a single, complete filesystem to the user and the running application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The Efficiency: Image Caching&lt;/strong&gt;&lt;br&gt;
This layering system enables incredible efficiency through caching and sharing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sharing Base Images:&lt;/strong&gt; If you have 10 different applications that all use the same base operating system (e.g., Alpine Linux), the base OS layer is only stored once on your system, even though 10 different images reference it. This saves significant disk space.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content-Addressable Storage:&lt;/strong&gt; Every layer is identified by a unique cryptographic hash (SHA256). Docker checks this hash to see if the layer already exists locally. If it does, Docker reuses it instead of pulling it again from the registry. This is the power of image caching.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fast Updates:&lt;/strong&gt; When you rebuild an image, Docker only rebuilds the layers after the first command you change. All previous, unchanged layers are pulled directly from the cache, making iteration and rebuilding incredibly fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. The Final Piece:&lt;/strong&gt; The Container's Writable Layer&lt;br&gt;
When you run an image using docker run, Docker places a final, writable layer on top of the stack of read-only image layers.&lt;/p&gt;

&lt;p&gt;Any changes made by the running container (e.g., creating a log file, modifying a setting) are written only to this top writable layer.&lt;/p&gt;

&lt;p&gt;This ensures the original image layers remain untouched (immutable). If you stop the container and start a new one, the new container starts with a clean, fresh writable layer, guaranteeing consistency.&lt;/p&gt;

&lt;p&gt;The writable layer is ephemeral by default. If you delete the container, you lose the data in this layer. This is why we need Volumes (covered in a future post) for persistent data storage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Inspecting the Layers&lt;/strong&gt;&lt;br&gt;
You can easily see the stack of layers used to build any image on your system using the docker history command.&lt;/p&gt;

&lt;p&gt;Let's inspect the nginx image we used previously:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker history nginx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You will see output showing the different layers, the size of each, and the command that was executed to create that layer. This gives you direct insight into the image's construction process, from the base Linux distribution up to the final &lt;em&gt;Nginx&lt;/em&gt; configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s Next?&lt;/strong&gt;&lt;br&gt;
Now that we understand what an image is and how its efficient, layered structure works, we are ready for the most important part of building applications with Docker: writing our own images!&lt;/p&gt;

&lt;p&gt;In Post 4, we will dive deep into the &lt;strong&gt;Dockerfile&lt;/strong&gt; and learn the commands necessary to create efficient, small, and secure images for your own applications.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Getting Started: Your First Container🐋</title>
      <dc:creator>SAHIL</dc:creator>
      <pubDate>Sat, 06 Dec 2025 14:33:21 +0000</pubDate>
      <link>https://forem.com/sahillearninglinux/getting-started-your-first-container-4fcc</link>
      <guid>https://forem.com/sahillearninglinux/getting-started-your-first-container-4fcc</guid>
      <description>&lt;p&gt;In our first post, we explored why Docker matters. Now, let's get our hands dirty and learn how to use it. By the end of this post, you'll have Docker installed and be running your very own web server in a container!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Setting Up Docker Desktop:&lt;/strong&gt;&lt;br&gt;
The easiest way to start is by installing Docker Desktop. This package includes the Docker Engine, Docker CLI (Command Line Interface), Docker Compose, and a user-friendly GUI for Windows, macOS, and Linux.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;: Go to the official Docker website and download Docker Desktop for your operating system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation Note&lt;/strong&gt;: Follow the default installation steps. You will likely need to restart your computer once the installation is complete.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verification&lt;/strong&gt;: Once installed, open your terminal (Command Prompt, PowerShell, or Bash) and run the following command to ensure Docker is running correctly:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker --version&lt;/code&gt;&lt;br&gt;
You should see an output indicating the version of the Docker client you have installed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The Core Concept: Image vs. Container&lt;/strong&gt;&lt;br&gt;
Before running anything, let's briefly review the two most important terms:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Image&lt;/strong&gt;: This is the static blueprint. It's a read-only template that contains the application code, dependencies, libraries, and configuration needed for your application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Container&lt;/strong&gt;: This is the running instance of an image. When you run an image, you create a container—a lightweight, isolated environment that is executable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Your First Command: Pulling an Image&lt;/strong&gt;&lt;br&gt;
When you tell Docker to run a container, it first needs the blueprint (the image). It looks for the image locally. If it doesn't find it, it automatically pulls it from a Container Registry, with the default being Docker Hub.&lt;/p&gt;

&lt;p&gt;Let's pull the official Nginx web server image:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker pull nginx:latest&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;docker pull&lt;/strong&gt;: The command to download an image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;nginx&lt;/strong&gt;: The name of the repository (the image).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;:latest&lt;/strong&gt;: The tag, which specifies the version. latest is the default if no tag is specified.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will see output showing Docker downloading the image in layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Running Your First Container (The Web Server)&lt;/strong&gt;&lt;br&gt;
Now for the magic! We will launch an instance of that Nginx image, which will run as an isolated web server.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run -d -p 8080:80 --name my-nginx-server nginx&lt;/code&gt;&lt;br&gt;
Let's break down this powerful command:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Flag&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;docker run&lt;/td&gt;
&lt;td&gt;This is the main command to create a new container and run a command in it.&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-d&lt;/td&gt;
&lt;td&gt;Stands for "detached" mode. This runs the container in the background, freeing up your terminal.&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-p&lt;/td&gt;
&lt;td&gt;Stands for "publish" or "port mapping." This links a port on your local machine (the host) to a port inside the container.&lt;/td&gt;
&lt;td&gt;8080:80 means: Host Port 8080 $\rightarrow$ Container Port 80 (Nginx's default).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;--name&lt;/td&gt;
&lt;td&gt;Assigns a human-readable name to your container.&lt;/td&gt;
&lt;td&gt;my-nginx-server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nginx&lt;/td&gt;
&lt;td&gt;The image you want to run (Docker assumes :latest if no tag is specified).&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;Open your web browser.&lt;/p&gt;

&lt;p&gt;Navigate to &lt;strong&gt;&lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You should see the "Welcome to nginx!" default page. Congratulations! You are running a full web server inside a lightweight, isolated container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Managing Your Running Containers&lt;/strong&gt;&lt;br&gt;
Since your container is running in the background, you need commands to interact with it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A. Checking Container Status&lt;/strong&gt;&lt;br&gt;
Use docker ps to see a list of all currently running containers:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker ps&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You will see details like the Container ID, the image used, the ports mapped, and the status.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B. Viewing Container Logs&lt;/strong&gt;&lt;br&gt;
If you want to see what the container is printing (like server access logs or errors), use docker logs:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker logs my-nginx-server&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C. Stopping and Removing the Container&lt;/strong&gt;&lt;br&gt;
A container takes up resources while running, so let's shut it down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stop the Container&lt;/strong&gt;: This sends a signal to the container to shut down gracefully.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker stop my-nginx-server&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remove the Container&lt;/strong&gt;: A stopped container is still on your system. To completely delete the instance, use docker rm.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker rm my-nginx-server&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: You must stop a container before you can remove it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Cleaning Up the Image&lt;/strong&gt;&lt;br&gt;
If you no longer need the Nginx image itself, you can remove it from your local system cache:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker rmi nginx&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;rmi&lt;/strong&gt; stands for "remove image."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A word of caution&lt;/strong&gt;: You cannot remove an image if any containers (even stopped ones) are still referencing it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s Next?&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;You’ve successfully installed Docker&lt;/strong&gt; and navigated the basic commands to run and manage your first container. In the next post, we’ll dive deeper into Docker Images and Layers to understand why these containers are so fast and efficient, which is crucial knowledge before we start building our own images!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>🐳 Docker: The Container Revolution for Developers</title>
      <dc:creator>SAHIL</dc:creator>
      <pubDate>Tue, 18 Nov 2025 15:05:15 +0000</pubDate>
      <link>https://forem.com/sahillearninglinux/docker-the-container-revolution-for-developers-49jd</link>
      <guid>https://forem.com/sahillearninglinux/docker-the-container-revolution-for-developers-49jd</guid>
      <description>&lt;p&gt;Welcome to the world of Docker! If you're a developer or just getting started in tech, you've probably heard the term. This post will demystify Docker, explain the problems it solved, and show you why it's become an essential tool in modern software development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Docker?&lt;/strong&gt;&lt;br&gt;
At its core, Docker is a platform that allows you to develop, ship, and run applications in lightweight, isolated environments called containers.&lt;/p&gt;

&lt;p&gt;Think of a container like a shipping container . Just as a physical shipping container can hold any kind of cargo (furniture, electronics, etc.) and be moved consistently between a truck, train, or ship, a Docker container holds everything your application needs to run-code, runtime, system tools, libraries, and settings-and runs consistently on any machine that has Docker installed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image&lt;/strong&gt;: A static, read-only template with instructions for creating a container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Container&lt;/strong&gt;: A runnable instance of an image.&lt;/p&gt;

&lt;p&gt;🤯 &lt;strong&gt;The Scenario Before Docker (The Problem)&lt;/strong&gt;&lt;br&gt;
Before containerization became widespread, developers faced a notorious problem: "It works on my machine!"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Environment Setup Headache&lt;/strong&gt;&lt;br&gt;
Setting up a new development environment was often a manual, time-consuming process. You might have needed specific versions of Node.js, Python, MongoDB, and a certain Linux distribution. This led to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency Conflicts:&lt;/strong&gt; Installing a new project might break an old one due to conflicting library versions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inconsistent Environments:&lt;/strong&gt; Your local machine, the testing server, and the production server would inevitably have slightly different configurations, leading to unexpected bugs when deploying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Virtual Machine (VM) Overhead&lt;/strong&gt;&lt;br&gt;
The alternative was using Virtual Machines (VMs), but they are resource-intensive:&lt;/p&gt;

&lt;p&gt;VMs require a full guest operating system (OS) (like a whole installation of Ubuntu or Windows) on top of the host OS.&lt;/p&gt;

&lt;p&gt;Each VM takes up a lot of disk space and requires its own dedicated chunk of CPU and RAM. This makes them slow to start and heavy to run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✨ The Scenario After Docker (The Solution)&lt;/strong&gt;&lt;br&gt;
Docker changed the game by offering lightweight virtualization through containers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Consistency and Isolation&lt;/strong&gt;&lt;br&gt;
Containers share the host machine's OS kernel but keep their own isolated file system and process space. This provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"&lt;strong&gt;Ship it and forget it&lt;/strong&gt;": The application runs exactly the same way everywhere (from your laptop to the cloud).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation&lt;/strong&gt;: Your application and its dependencies are neatly packaged, preventing conflicts with other applications running on the same host.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Speed and Efficiency&lt;/strong&gt;&lt;br&gt;
Unlike VMs, containers don't boot an entire OS; they just start the necessary application processes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast Startup&lt;/strong&gt;: Containers typically start in seconds, not minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimal Overhead&lt;/strong&gt;: They require far less disk space and consume resources more efficiently.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Benefit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rapid Deployment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Quickly deploy new features or roll back to older versions with confidence.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Portability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Run the same container image on any major OS (Linux, Windows, macOS) and any cloud provider.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Microservices&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Easily package and manage individual services independently, which is crucial for modern microservices architectures.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Resource Efficiency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Run far more containers on a single host than you could run VMs, maximizing hardware utilization.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🌍 &lt;strong&gt;Where is Docker Used?&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Docker&lt;/strong&gt; is now a fundamental tool in the entire software development lifecycle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Development&lt;/strong&gt;: Local development environments that perfectly mirror production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing&lt;/strong&gt;: Creating consistent, throwaway environments for running automated tests (CI/CD pipelines).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous Integration/Continuous Deployment (CI/CD):&lt;/strong&gt; Building and deploying applications to staging and production servers automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production&lt;/strong&gt;: Running highly scalable, reliable, and fault-tolerant applications, often managed by orchestration tools like Kubernetes (which builds directly on the container concept!).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Wrapping Up&lt;/strong&gt;&lt;br&gt;
Docker truly solved the "works on my machine" problem and streamlined the journey of code from a developer's laptop to a global-scale production environment. Containers have become the standard unit of deployment, and understanding Docker is a must-have skill today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Ready to dive deeper? In the next post, we'll look at the basic Docker commands...&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Dynamic Host Configuration Protocol (DHCP)</title>
      <dc:creator>SAHIL</dc:creator>
      <pubDate>Sat, 04 Oct 2025 07:03:57 +0000</pubDate>
      <link>https://forem.com/sahillearninglinux/dynamic-host-configuration-protocol-dhcp-1lk3</link>
      <guid>https://forem.com/sahillearninglinux/dynamic-host-configuration-protocol-dhcp-1lk3</guid>
      <description>&lt;p&gt;&lt;strong&gt;What is DHCP?&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;DHCP&lt;/strong&gt; stands for Dynamic Host Configuration Protocol. It's a network management protocol used on Internet Protocol (IP) networks for automatically assigning and dynamically allocating IP addresses and other network configuration parameters to devices connected to the network.&lt;/p&gt;

&lt;p&gt;In simple terms, instead of manually setting the IP address, subnet mask, default gateway, and DNS servers on every single computer, you let a DHCP server do it for you, automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Use a DHCP Server?&lt;/strong&gt;&lt;br&gt;
Using a DHCP server provides several significant advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Centralized Management and Efficiency&lt;/strong&gt;: It eliminates the time-consuming and error-prone process of manually configuring network settings on every host. This is especially critical in large networks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preventing IP Address Conflicts&lt;/strong&gt;: The DHCP server tracks which IP addresses are in use. It ensures that every device gets a unique IP address for a specific period (called a lease), preventing two devices from trying to use the same address.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portability and Mobility&lt;/strong&gt;: Devices can easily move between different network segments (subnets) and automatically receive the correct configuration for their new location without manual changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: It makes adding new devices to the network trivial; they just boot up and get their configuration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The DHCP Process (DORA)&lt;/strong&gt;&lt;br&gt;
The core communication process between a client (a device joining the network) and the DHCP server is often remembered using the acronym DORA:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Discover&lt;/strong&gt;: The client broadcasts a DHCP Discover message on the network to find any available DHCP servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offer&lt;/strong&gt;: All DHCP servers that receive the Discover message respond with a DHCP Offer, proposing an IP address and lease time to the client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request&lt;/strong&gt;: The client receives the offers and broadcasts a DHCP Request message, formally requesting the use of the IP address offered by a specific server (and implicitly declining the others).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Acknowledgment&lt;/strong&gt;: The chosen DHCP server sends a DHCP Acknowledgment (ACK) to the client, confirming the lease of the IP address and providing the rest of the configuration parameters (subnet mask, gateway, DNS, etc.).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key DHCP Components and Terminology&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Term&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scope/Pool&lt;/td&gt;
&lt;td&gt;A range of IP addresses that the DHCP server is allowed to assign to clients on a particular subnet.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lease&lt;/td&gt;
&lt;td&gt;The duration for which a client is allowed to use an assigned IP address. Clients must renew their lease before it expires.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reservation&lt;/td&gt;
&lt;td&gt;A specific IP address permanently reserved for a specific client, identified by its MAC address. This ensures the device always gets the same IP.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DHCP Relay&lt;/td&gt;
&lt;td&gt;A component (often a router) that forwards DHCP broadcast messages between clients and DHCP servers located on different subnets.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bootp&lt;/td&gt;
&lt;td&gt;An older, simpler protocol that DHCP evolved from.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;DHCP on Linux&lt;/strong&gt;&lt;br&gt;
On Linux, the most common software package used to implement a DHCP server is ISC DHCP Server, now often superseded by the Kea DHCP server, developed by the Internet Systems Consortium (ISC).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ISC DHCP Server (often called dhcpd)&lt;/strong&gt;: The traditional, highly mature, and widely used DHCP server for Linux.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kea DHCP&lt;/strong&gt;: A newer, high-performance, and modular DHCP server designed to handle the demands of very large networks.&lt;/p&gt;

&lt;p&gt;When we move to the practical part, we'll likely focus on configuring one of these services!&lt;/p&gt;

&lt;p&gt;Let's dive into the practical setup of a DHCP server on Linux, focusing on the traditional and widely used ISC DHCP Server (&lt;strong&gt;dhcpd&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical DHCP Server Setup (ISC dhcpd)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1. Key Files, Ports, and Daemons&lt;/strong&gt;&lt;br&gt;
The following are the essential components you'll interact with when configuring and running a DHCP server on a Linux distribution like Debian or CentOS/RHEL:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Daemon/Service&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;dhcpd&lt;/code&gt; or &lt;code&gt;isc-dhcp-server&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;The main background process (daemon) that runs the DHCP server.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration File&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/etc/dhcp/dhcpd.conf&lt;/code&gt; (or &lt;code&gt;/etc/dhcpd.conf&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;The primary file where all the server settings, pools, and reservations are defined. This is the most important file.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Leases File&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/var/lib/dhcp/dhcpd.leases&lt;/code&gt; (location may vary)&lt;/td&gt;
&lt;td&gt;A dynamic file where the server stores a record of every IP address it has assigned (leased) and to which client (MAC address).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Port&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;UDP Port 67&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The standard destination port used by the DHCP server to listen for client requests.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Port&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;UDP Port 68&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The standard source port used by the DHCP client when sending requests to the server.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. Basic Configuration Setup&lt;/strong&gt;&lt;br&gt;
The goal is to configure the dhcpd.conf file and ensure the DHCP server is listening on the correct network interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.1 Installation&lt;/strong&gt;&lt;br&gt;
First, you need to install the DHCP server package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;On Debian/Ubuntu
sudo apt update
sudo apt install isc-dhcp-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; On RHEL/CentOS/Fedora
sudo dnf install dhcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.2 Editing /etc/dhcp/dhcpd.conf&lt;/strong&gt;&lt;br&gt;
This file defines the scope (the range of IPs) and the network options. You need to configure a subnet declaration that matches the network interface the server is running on.&lt;/p&gt;

&lt;p&gt;Here is a template for a basic configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Global Parameters (apply to all subnets)
# Default lease time is the minimum time a client keeps an IP (in seconds)
default-lease-time 600;

# Max lease time is the longest time a client can hold an IP (in seconds)
max-lease-time 7200;

# Set the authoritative flag to prevent the server from answering requests for networks it doesn't serve
authoritative;

# Subnet Declaration (This MUST match the network the server is connected to)
# Example: Server's interface IP is 192.168.1.1/24

subnet 192.168.1.0 netmask 255.255.255.0 {
    # The range of addresses DHCP can assign
    range 192.168.1.100 192.168.1.150;

    # Network options to push to clients:
    # Option 3: Default Gateway/Router
    option routers 192.168.1.1;

    # Option 6: Domain Name Servers (e.g., Google's public DNS)
    option domain-name-servers 8.8.8.8, 8.8.4.4;

    # Option 15: Domain Name
    option domain-name "mylocaldomain.lan";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Dive Deep&lt;/strong&gt;: The server itself must have a static IP address (e.g., 192.168.1.1 in this example) within the subnet. It cannot rely on DHCP for its own configuration. The IP range defined in the range statement must not include the server's static IP or any other static IPs you've assigned manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.3 Interface Configuration&lt;/strong&gt;&lt;br&gt;
On some Linux distributions, you must tell the DHCP daemon which network interface to listen on.&lt;/p&gt;

&lt;p&gt;In older versions, you might edit a file like &lt;code&gt;/etc/default/isc-dhcp-server&lt;/code&gt; and define the interface:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;On modern systems using systemd, this is often handled automatically or configured via network management tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.4 Starting the Service&lt;/strong&gt;&lt;br&gt;
After configuring, restart or enable the service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Reload the configuration and start the server
sudo systemctl restart isc-dhcp-server
# or
sudo systemctl restart dhcpd

# Check the status to ensure it's running without errors
sudo systemctl status isc-dhcp-server

# Check logs for detailed information
sudo journalctl -u isc-dhcp-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Dynamic IP Usage by Clients&lt;/strong&gt;&lt;br&gt;
Once the server is running, any client configured for DHCP (the default for most devices) on that same physical network will automatically follow the DORA process:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Client Boot&lt;/strong&gt;: A client (e.g., a laptop or phone) boots up and sends a broadcast DHCP Discover request from its network interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server Response&lt;/strong&gt;: The Linux DHCP server running dhcpd receives the request and replies with a DHCP Offer proposing an IP address from its defined range (e.g., 192.168.1.101).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Client Acceptance&lt;/strong&gt;: After the ACK, the client configures its network interface with the leased IP address (192.168.1.101), the subnet mask (255.255.255.0), the default gateway (192.168.1.1), and the DNS servers (8.8.8.8, 8.8.4.4).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lease Renewal&lt;/strong&gt;:&lt;br&gt;
 At T.lease/2 (half the lease time), the client will attempt to renew the lease with the DHCP server to keep the IP address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Advanced: Making a Reservation&lt;/strong&gt;&lt;br&gt;
You can ensure a specific device always receives the same IP address by creating a static mapping or reservation based on the device's MAC address (Hardware Ethernet Address). This is often used for printers or servers.&lt;/p&gt;

&lt;p&gt;Add this block inside the subnet declaration in &lt;code&gt;/etc/dhcp/dhcpd.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;host printer1 {
    hardware ethernet aa:bb:cc:11:22:33; # The MAC address of the printer
    fixed-address 192.168.1.200;       # The reserved IP address (outside the dynamic range is best)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After making this change, restart the dhcpd service again. The client with that specific MAC address will now receive 192.168.1.200.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Firewall Considerations&lt;/strong&gt;&lt;br&gt;
Crucially, the Linux machine running the DHCP server must allow traffic on UDP Port 67. You need to configure your firewall (e.g., firewalld or ufw) to permit incoming requests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Using UFW (Uncomplicated Firewall - common on Ubuntu)
sudo ufw allow 67/udp

# Using firewalld (common on CentOS/RHEL/Fedora)
sudo firewall-cmd --add-service=dhcp --permanent
sudo firewall-cmd --reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This completes the deep dive into the practical setup! You now have a working framework for a DHCP server on Linux.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Thanks for reading and leave a like and your wonderful insights on dhcp.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Samba Mastery: The Definitive Guide to Cross-Platform File Sharing (Theory, Setup, &amp; Permanent Mounts)</title>
      <dc:creator>SAHIL</dc:creator>
      <pubDate>Sat, 04 Oct 2025 06:38:31 +0000</pubDate>
      <link>https://forem.com/sahillearninglinux/samba-mastery-the-definitive-guide-to-cross-platform-file-sharing-theory-setup-permanent-4aka</link>
      <guid>https://forem.com/sahillearninglinux/samba-mastery-the-definitive-guide-to-cross-platform-file-sharing-theory-setup-permanent-4aka</guid>
      <description>&lt;p&gt;💻 &lt;strong&gt;Understanding Samba: Theory and Purpose&lt;/strong&gt;&lt;br&gt;
Samba is a free and open-source re-implementation of the Server Message Block (SMB) networking protocol.&lt;/p&gt;

&lt;p&gt;📜 &lt;strong&gt;Core Theory: SMB/CIFS&lt;/strong&gt;&lt;br&gt;
Samba's foundation lies in the SMB protocol (which was also referred to as Common Internet File System - CIFS in some older versions).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it is&lt;/strong&gt;: SMB is an application-layer network protocol primarily used for providing shared access to files, printers, and serial ports between nodes on a network. It is the core networking protocol used by Microsoft Windows for file and print sharing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem it Solves&lt;/strong&gt;: Windows clients (desktops, laptops, servers) are designed to talk to other Windows machines for file sharing using the SMB protocol. Unix-like systems (Linux, macOS) use their own native file sharing protocols (like NFS). Samba acts as a protocol translator/server that allows Unix/Linux machines to speak the SMB language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it Works (The Role of Samba)&lt;/strong&gt;: Samba runs on a Unix/Linux host and makes the host appear to Windows clients as a native Windows file and print server. This creates a seamless, cross-platform file-sharing environment.&lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;Why Samba is Used (Key Use Cases)&lt;/strong&gt;&lt;br&gt;
Samba is indispensable in heterogeneous networks (those containing both Windows and Unix/Linux machines).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cross-Platform File Sharing&lt;/td&gt;
&lt;td&gt;The primary use: enables Linux/Unix servers to share directories (shares) with Windows clients,&lt;br&gt;and vice versa.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Print Services&lt;/td&gt;
&lt;td&gt;Allows Windows clients to print to printers attached to a Linux/Unix server.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain Services&lt;/td&gt;
&lt;td&gt;Samba can function as a &lt;strong&gt;Primary Domain Controller (PDC)&lt;/strong&gt; or a member server in a Windows domain&lt;br&gt;or &lt;strong&gt;Active Directory (AD)&lt;/strong&gt; environment (using Samba 4.x), managing user authentication and group policies.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Home Directory Access&lt;/td&gt;
&lt;td&gt;Allows users to access their Linux home directory as a network share&lt;br&gt;when they log in from a Windows client.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;p&gt;⚙️ &lt;strong&gt;Samba Components, Ports, and Installation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🛠️ &lt;strong&gt;Key Samba Daemons (Services)&lt;/strong&gt;&lt;br&gt;
Samba is typically implemented by two main background services, or "&lt;strong&gt;daemons&lt;/strong&gt;," on the server.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Daemon (Service Name)&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;smbd&lt;/code&gt; (Samba Daemon)&lt;/td&gt;
&lt;td&gt;Provides the file and print sharing services. It handles the actual SMB/CIFS connections, authentication, and resource sharing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;nmbd&lt;/code&gt; (NetBIOS Name Daemon)&lt;/td&gt;
&lt;td&gt;Provides the NetBIOS-to-IP-address name service (similar to a local DNS for legacy Windows networks). It handles network browsing (NetBIOS over TCP/IP). This is less critical with modern networks using DNS/WSD but is still part of the suite.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;p&gt;🔌 &lt;strong&gt;Port Numbers&lt;/strong&gt;&lt;br&gt;
Samba uses the standard ports for the SMB protocol, which need to be opened on the server's firewall:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Port&lt;/th&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TCP 139&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;TCP&lt;/td&gt;
&lt;td&gt;Used for the NetBIOS Session Service (older SMB traffic).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UDP 137&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;UDP&lt;/td&gt;
&lt;td&gt;Used for the NetBIOS Name Service.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UDP 138&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;UDP&lt;/td&gt;
&lt;td&gt;Used for the NetBIOS Datagram Service (browsing).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TCP 445&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;TCP&lt;/td&gt;
&lt;td&gt;Used for SMB over TCP/IP (Direct host communication without NetBIOS). &lt;strong&gt;Primary port for modern SMB/CIFS traffic.&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;p&gt;📦 &lt;strong&gt;Package Name and Installation&lt;/strong&gt;&lt;br&gt;
The package name for the Samba server software is usually just &lt;code&gt;samba&lt;/code&gt;. Installation commands vary by Linux distribution:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Distribution&lt;/th&gt;
&lt;th&gt;Installation Command (Server)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Debian/Ubuntu&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt install samba&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RHEL/CentOS/Fedora&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;sudo dnf install samba samba-common&lt;/code&gt; or &lt;code&gt;sudo yum install samba samba-common&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;After installation, the services must be started and enabled to start automatically on boot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl start smbd nmbd

sudo systemctl enable smbd nmbd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;📝 &lt;strong&gt;Key Configuration Files and Syntax&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;📁 &lt;strong&gt;Main Configuration File&lt;/strong&gt;&lt;br&gt;
The heart of Samba configuration is the &lt;em&gt;smb.conf&lt;/em&gt; file.&lt;/p&gt;

&lt;p&gt;Location: Typically found at &lt;strong&gt;/etc/samba/smb.conf or /etc/smb.conf.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Syntax&lt;/strong&gt;: The file is structured into sections enclosed in square brackets ([]), each defining a shared resource or a global setting. Inside each section, parameters are defined using name = value.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Section&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[global]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Defines overall server settings, like workgroup name, security mode, logging, and other default behaviors.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;workgroup = WORKGROUP&lt;/code&gt;&lt;br&gt;&lt;code&gt;security = user&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[share_name]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Defines a specific shared resource (a file share or a printer). Replace &lt;code&gt;share_name&lt;/code&gt; with your desired name (e.g., &lt;code&gt;[PublicDocs]&lt;/code&gt;).&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;[PublicDocs]&lt;/code&gt;&lt;br&gt;&lt;code&gt;path = /srv/samba/public&lt;/code&gt;&lt;br&gt;&lt;code&gt;read only = No&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[homes]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A special section that automatically creates a private share for each authenticated user, mapping to their Unix home directory (&lt;code&gt;/home/username&lt;/code&gt;).&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;[homes]&lt;/code&gt;&lt;br&gt;&lt;code&gt;comment = Home Directories&lt;/code&gt;&lt;br&gt;&lt;code&gt;browseable = No&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[printers]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A special section for printer sharing.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;[printers]&lt;/code&gt;&lt;br&gt;&lt;code&gt;printable = yes&lt;/code&gt;&lt;br&gt;&lt;code&gt;path = /var/spool/samba&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;p&gt;🛡️ &lt;strong&gt;Essential Global Parameters&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;workgroup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;e.g., &lt;code&gt;MYNETWORK&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;The NetBIOS workgroup or domain name the server will belong to. Must match the clients.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;security&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;user&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Most common mode: Client must provide a valid username and Samba password (usually matched to a Unix account).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;encrypt passwords&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;yes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Critical:&lt;/strong&gt; Must be set to &lt;code&gt;yes&lt;/code&gt; for modern Windows clients.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;map to guest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Bad User&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ensures that connection attempts with invalid users are treated as a guest connection (if guest access is allowed).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;p&gt;📂 &lt;strong&gt;Essential Share Parameters (Example for a Read/Write Share)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[PublicData]
   comment = General Shared Folder
   path = /srv/samba/public
   browseable = yes
   writeable = yes
   guest ok = no  ; Requires a valid user/password
   valid users = @staff myuser
   create mask = 0664
   directory mask = 0775
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;🧑‍💻 &lt;strong&gt;Server Configuration Steps (The "How-To")&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Create the Shared Directory&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mkdir -p /srv/samba/public
sudo chown nobody:nogroup /srv/samba/public # Set initial ownership
sudo chmod 770 /srv/samba/public            # Set permissions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;em&gt;You may also need to configure SELinux or AppArmor to allow Samba access to the shared path&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Edit the Configuration File&lt;/strong&gt;&lt;br&gt;
Use your preferred editor (nano, vi) to modify                         &lt;code&gt;/etc/samba/smb.conf&lt;/code&gt; and add your share section (like the  [PublicData] example above).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create Samba Users&lt;/strong&gt;&lt;br&gt;
A user must have a regular Unix account first, then a separate Samba password.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo adduser myuser         # 1. Create a standard Unix user
sudo smbpasswd -a myuser    # 2. Add and set a Samba-specific password for the user
sudo systemctl restart smbd nmbd # 3. Restart services to load changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Test the Configuration&lt;/strong&gt;
Use the built-in utility to check for syntax errors:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;testparm&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Configure Firewall&lt;/strong&gt;
Allow the necessary Samba ports through your firewall.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Using firewalld (RHEL/Fedora/CentOS)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo firewall-cmd --permanent --add-service=samba
sudo firewall-cmd --reload

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Using ufw (Debian/Ubuntu)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ufw allow samba
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;🌐 &lt;strong&gt;Permanent Client Mount (Linux Client)&lt;/strong&gt;&lt;br&gt;
To permanently access a Samba share on a Linux client (not the server), you typically use the cifs-utils package and the &lt;code&gt;/etc/fstab file&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;📦 &lt;strong&gt;Client Package Name&lt;/strong&gt;&lt;br&gt;
The package for the Samba client utility and mounting tools is usually &lt;code&gt;cifs-utils&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Installation (e.g., Ubuntu/Debian): sudo apt install cifs-utils&lt;/p&gt;

&lt;p&gt;🔧 &lt;strong&gt;Syntax for /etc/fstab&lt;/strong&gt;&lt;br&gt;
The /etc/fstab file is used to define file systems that should be mounted automatically at boot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a Mount Point&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo mkdir /mnt/samba_share&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a Credential File (for security)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Store your username and password in a secure file (e.g., /etc/samba/credentials.txt) and restrict its permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;username=myuser
password=my_samba_password
sudo chmod 600 /etc/samba/credentials.txt

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Add Entry to /etc/fstab&lt;/strong&gt;&lt;br&gt;
Add the following line to &lt;code&gt;/etc/fstab&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**Syntax**:
//SAMBA_SERVER_IP/ShareName  /mount/point  cifs  credentials=/path/to/credentials,uid=local_user,gid=local_group,iocharset=utf8,vers=3.0  0  0

//192.168.1.100/PublicData  /mnt/samba_share  cifs  credentials=/etc/samba/credentials.txt,uid=1000,gid=1000,iocharset=utf8,vers=3.0  0  0

//192.168.1.100/PublicData: The network location (//server_ip_or_name/share_name).

/mnt/samba_share: The local mount directory.

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;cifs&lt;/strong&gt;: The file system type (for mounting Samba/SMB shares).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;credentials=...&lt;/code&gt;: Points to the secure file with the Samba user and password.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;uid=1000,gid=1000&lt;/code&gt;: Sets the ownership of all files on the mounted share to the local user with UID 1000 (usually the first non-root user).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vers=3.0&lt;/code&gt;: Specifies the SMB protocol version (3.0 is a common modern, secure version).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mount the Share&lt;/strong&gt;&lt;br&gt;
Mount the new entry without rebooting:&lt;br&gt;
&lt;/p&gt;

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

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

&lt;/div&gt;



&lt;p&gt;If successful, you should see the contents of the share in &lt;code&gt;/mnt/samba_share&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Thank you so much for reading. &lt;br&gt;
Leave a like and anything you want to add or improve.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Ultimate Guide to vsftpd: Configuration Files, Commands, and Secure SFTP Migration</title>
      <dc:creator>SAHIL</dc:creator>
      <pubDate>Tue, 30 Sep 2025 07:54:55 +0000</pubDate>
      <link>https://forem.com/sahillearninglinux/ultimate-guide-to-vsftpd-configuration-files-commands-and-secure-sftp-migration-170m</link>
      <guid>https://forem.com/sahillearninglinux/ultimate-guide-to-vsftpd-configuration-files-commands-and-secure-sftp-migration-170m</guid>
      <description>&lt;p&gt;The &lt;strong&gt;File Transfer Protocol (FTP)&lt;/strong&gt; is a foundational network protocol used to transfer files between a client and a server on a computer network. It operates on the client-server model and is defined in RFC 959.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.1 The Two Connection Channels&lt;/strong&gt;&lt;br&gt;
FTP is unique because it uses two separate TCP connections for a single session:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Control Connection&lt;/strong&gt; (TCP Port 21):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Handles commands, replies, authentication (username/password), and session management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nature&lt;/strong&gt;: Stays open for the entire duration of the session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Format&lt;/strong&gt;: Uses NVT ASCII (Network Virtual Terminal ASCII) for commands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Connection&lt;/strong&gt; (TCP Port 20 or Variable):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Transfers the actual file data and directory listing contents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nature&lt;/strong&gt;: Is transient—it opens for a single transfer (upload or download) and immediately closes afterward.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;1.2 Data Transfer Modes&lt;/strong&gt;&lt;br&gt;
The most complex part of FTP is how the Data Connection is established, which is governed by the connection mode:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Data Connection Initiator&lt;/th&gt;
&lt;th&gt;Control Channel Command&lt;/th&gt;
&lt;th&gt;Data Channel Port&lt;/th&gt;
&lt;th&gt;Firewall Complexity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Active Mode&lt;/td&gt;
&lt;td&gt;The Server connects back to the Client.&lt;/td&gt;
&lt;td&gt;PORT&lt;/td&gt;
&lt;td&gt;Server uses Port 20 (source).&lt;/td&gt;
&lt;td&gt;Difficult for clients behind a firewall.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Passive Mode&lt;/td&gt;
&lt;td&gt;The Client connects to the Server.&lt;/td&gt;
&lt;td&gt;PASV&lt;/td&gt;
&lt;td&gt;Server opens a random high port (e.g., 40000+).&lt;/td&gt;
&lt;td&gt;Easier for clients; essential for servers to define a port range.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. vsftpd: The Daemon and Its Files&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;vsftpd&lt;/strong&gt; (&lt;em&gt;Very Secure FTP Daemon&lt;/em&gt;) is the most popular, stable, and security-focused FTP server software for Linux systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.1 Daemon and Service&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Daemon&lt;/strong&gt;: vsftpd (the executable program running in the background).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Default Service Port&lt;/strong&gt;: TCP 21 (for the Control Channel).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Management&lt;/strong&gt;: On modern Linux distributions (like Ubuntu, CentOS 7+), it is managed by systemd.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start/Stop&lt;/strong&gt;: sudo systemctl start vsftpd&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Status Check&lt;/strong&gt;: sudo systemctl status vsftpd&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enable at Boot&lt;/strong&gt;: sudo systemctl enable vsftpd&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.2 Core Configuration Files&lt;/strong&gt;&lt;br&gt;
The primary file is a simple list of directive=value settings.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File Path&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;/etc/vsftpd.conf&lt;/td&gt;
&lt;td&gt;Main Configuration File. Controls all server behavior, ports, user access, and security policies.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/etc/ftpusers&lt;/td&gt;
&lt;td&gt;A list of users that are explicitly denied access to the FTP server (often includes root and other system accounts).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/etc/vsftpd.userlist&lt;/td&gt;
&lt;td&gt;A configurable list of users that can either be allowed or denied access, depending on a directive in &lt;code&gt;vsftpd.conf&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/var/log/vsftpd.log&lt;/td&gt;
&lt;td&gt;The default location for connection and activity logs (file transfers, login attempts).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Practical vsftpd Configuration Examples&lt;/strong&gt;&lt;br&gt;
To configure a basic, working FTP server for local Linux users:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3.1&lt;/strong&gt;: Enabling Basic Access and Writes&lt;br&gt;
In the &lt;code&gt;/etc/vsftpd.conf&lt;/code&gt; file, ensure these lines are set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Start the server in standalone mode (not run by inetd)
listen=YES


# Deny anonymous login
anonymous_enable=NO

# Allow local system users (from /etc/passwd) to log in
local_enable=YES

# Allow users to upload, delete, and create files/directories
write_enable=YES
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3.2: Implementing Security (Chroot Jail)&lt;/strong&gt;&lt;br&gt;
The &lt;strong&gt;Chroot Jail&lt;/strong&gt; is paramount. It locks users into their home directories, preventing them from navigating the rest of the server's file system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# **CRITICAL SECURITY STEP:** Chroot all local users to their home directories
chroot_local_user=YES

# Required on some newer vsftpd versions when chroot is enabled and write_enable=YES
# This allows the jailed user's home directory to be writable
allow_writeable_chroot=YES
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3.3: Configuring Passive Mode (for Firewall Compatibility)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Passive Mode&lt;/strong&gt; is standard today. It requires defining a range of high ports to be opened on your server's firewall.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Enable Passive Mode
pasv_enable=YES

# Define the minimum port for the data connection
pasv_min_port=40000

# Define the maximum port for the data connection
pasv_max_port=50000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Action Required&lt;/strong&gt;: You must ensure your server's firewall (e.g., iptables, firewalld, ufw) permits inbound TCP traffic on Port 21 and the entire range of Ports 40000-50000.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;4. Security and Other Advanced Aspects&lt;/strong&gt;&lt;br&gt;
Once the server is configured and working, you must focus on security.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.1 Security Level 1: Hardening vsftpd&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;vsftpd Directive&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;User Listing&lt;/td&gt;
&lt;td&gt;userlist_enable=YES userlist_deny=NO userlist_file=/etc/vsftpd.userlist&lt;/td&gt;
&lt;td&gt;This creates an allow list: only users listed in /etc/vsftpd.userlist can log in, greatly restricting access.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Rate&lt;/td&gt;
&lt;td&gt;local_max_rate=500000&lt;/td&gt;
&lt;td&gt;Limits the transfer speed for local users to 500 KB/s to prevent resource starvation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timeouts&lt;/td&gt;
&lt;td&gt;idle_session_timeout=300&lt;/td&gt;
&lt;td&gt;Disconnects inactive clients after 300 seconds (5 minutes) to free resources.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logging&lt;/td&gt;
&lt;td&gt;xferlog_enable=YES xferlog_file=/var/log/vsftpd.log&lt;/td&gt;
&lt;td&gt;Ensures all file transfers are logged, crucial for auditing and security monitoring.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;4.2 Security Level 2: Mandatory Encryption (The Upgrade)&lt;/strong&gt;&lt;br&gt;
Plain FTP is a massive risk. The immediate security upgrade is to require encryption:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FTPS (FTP over TLS/SSL)&lt;/strong&gt;: This is the native, encrypted mode supported directly by vsftpd. It uses certificates to encrypt the communication on both the control and data channels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup&lt;/strong&gt;: Requires generating or installing an SSL/TLS certificate and setting directives like ssl_enable=YES and force_local_logins_ssl=YES in vsftpd.conf.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drawback&lt;/strong&gt;: It is still based on the complex two-channel architecture, making firewall management difficult.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SFTP (Secure File Transfer Protocol)&lt;/strong&gt;: This is the preferred modern standard. It is an entirely different protocol that runs over the single-port SSH connection (Port 22).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup&lt;/strong&gt;: Requires no additional software if you already run SSH (sshd).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages&lt;/strong&gt;: Single port (Port 22) simplifies firewalls, and it is inherently more secure, leveraging SSH's strong encryption and key-based authentication methods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.3 Other Theoretical Aspects&lt;/strong&gt;&lt;br&gt;
FTP Commands: The interaction is based on command verbs (e.g., USER, PASS, RETR, STOR, LIST) sent over the control channel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Representation&lt;/strong&gt;: You define the file type using the TYPE command: ASCII (for text files, handling newline conversion) or IMAGE/BINARY (for all other files).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anonymous FTP&lt;/strong&gt;: A historical practice that allows public access with the username anonymous and any email address as the password. This is generally disabled on private servers (anonymous_enable=NO).&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Server Setup&lt;/strong&gt;: VSFTPD Installation and Configuration&lt;br&gt;
We'll install vsftpd and configure it to allow a local user to log in and upload files, while being secured by the Chroot Jail.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Action on Server (Linux Shell)&lt;/th&gt;
&lt;th&gt;Command/Explanation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Install&lt;/td&gt;
&lt;td&gt;Install the vsftpd package.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt install vsftpd&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Backup Config&lt;/td&gt;
&lt;td&gt;Create a safety copy of the default config file.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.orig&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Create User&lt;/td&gt;
&lt;td&gt;Create a dedicated system user for FTP access (e.g., &lt;code&gt;ftpuser&lt;/code&gt;).&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo adduser ftpuser&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Configure VSFTPD&lt;/td&gt;
&lt;td&gt;Open the configuration file for editing.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo nano /etc/vsftpd.conf&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Apply Core Settings&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Core Directives (Add/Change):&lt;/strong&gt;&lt;br&gt;&lt;br&gt;• &lt;code&gt;anonymous_enable=NO&lt;/code&gt;&lt;br&gt;• &lt;code&gt;local_enable=YES&lt;/code&gt;&lt;br&gt;• &lt;code&gt;write_enable=YES&lt;/code&gt;&lt;br&gt;• &lt;code&gt;chroot_local_user=YES&lt;/code&gt;&lt;br&gt;• &lt;code&gt;allow_writeable_chroot=YES&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Ensure these directives are set (or uncomment/change existing ones).&lt;br&gt;&lt;br&gt;🔒 &lt;strong&gt;Jail users&lt;/strong&gt; to their home directory and allow writes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6. Set Passive Ports&lt;/td&gt;
&lt;td&gt;Define the port range for the data connection.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pasv_min_port=40000 pasv_max_port=50000&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7. Restart Service&lt;/td&gt;
&lt;td&gt;Apply the configuration changes.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo systemctl restart vsftpd&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8. Firewall&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Open Ports:&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;sudo ufw allow 20,21/tcp&lt;/code&gt;&lt;br&gt;&lt;code&gt;sudo ufw allow 40000:50000/tcp&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9. Test File&lt;/td&gt;
&lt;td&gt;Create a test file inside the user's home directory.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo -u ftpuser touch /home/ftpuser/README.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Client Interaction: Getting Files via FTP
Now, from a separate client machine on the same network, we will connect to the server and download the file. (Assume your server's IP is 192.168.1.100).&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Action on Client (Any System Shell)&lt;/th&gt;
&lt;th&gt;Command and Expected Output/Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Initiate Connection&lt;/td&gt;
&lt;td&gt;Use the standard ftp client command with the server's IP address.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ftp 192.168.1.100&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Login&lt;/td&gt;
&lt;td&gt;Enter the username and password created on the server.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Connected to 192.168.1.100. Name (192.168.1.100:user): ftpuser&lt;/code&gt;&lt;br&gt;&lt;code&gt;Password: (Input password here)&lt;/code&gt;&lt;br&gt;&lt;code&gt;230 Login successful.&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Check Directory&lt;/td&gt;
&lt;td&gt;Use the LS command to see the contents of the remote directory.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ftp&amp;gt; LS&lt;/code&gt;&lt;br&gt;&lt;code&gt;200 PORT command successful. 150 Here comes the directory listing.&lt;/code&gt;&lt;br&gt;&lt;code&gt;README.txt 226 Directory send okay.&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Set Transfer Mode&lt;/td&gt;
&lt;td&gt;Specify &lt;strong&gt;Binary&lt;/strong&gt; mode (best practice for any file type).&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ftp&amp;gt; BINARY&lt;/code&gt;&lt;br&gt;&lt;code&gt;200 Type set to I.&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Download File&lt;/td&gt;
&lt;td&gt;Use the &lt;strong&gt;GET&lt;/strong&gt; command to download the test file.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ftp&amp;gt; GET README.txt&lt;/code&gt;&lt;br&gt;&lt;code&gt;200 PORT command successful. 150 Opening BINARY mode data connection for README.txt&lt;/code&gt;&lt;br&gt;&lt;code&gt;226 Transfer complete.&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6. Verification&lt;/td&gt;
&lt;td&gt;Use the local shell command (&lt;code&gt;!&lt;/code&gt;) to check if the file is now on your client machine.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ftp&amp;gt; ! ls&lt;/code&gt;&lt;br&gt;&lt;code&gt;README.txt&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7. Cleanup&lt;/td&gt;
&lt;td&gt;End the FTP session.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ftp&amp;gt; QUIT&lt;/code&gt;&lt;br&gt;&lt;code&gt;221 Goodbye.&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Thanks for reading the post. Please share your experiences and do like it.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
