<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Christophe Avonture</title>
    <description>The latest articles on DEV Community by Christophe Avonture (@cavo789).</description>
    <link>https://dev.to/cavo789</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%2F388906%2Ff4f5a7d8-40d7-41b2-b75a-6870a8541b4d.jpg</url>
      <title>DEV Community: Christophe Avonture</title>
      <link>https://dev.to/cavo789</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cavo789"/>
    <language>en</language>
    <item>
      <title>Linux Makefile - Adding a help screen</title>
      <dc:creator>Christophe Avonture</dc:creator>
      <pubDate>Mon, 25 Dec 2023 16:56:55 +0000</pubDate>
      <link>https://dev.to/cavo789/linux-makefile-adding-a-help-screen-3hhj</link>
      <guid>https://dev.to/cavo789/linux-makefile-adding-a-help-screen-3hhj</guid>
      <description>&lt;p&gt;By using a makefile, you know it already, you can gather in one place a lot of &lt;em&gt;actions&lt;/em&gt; like &lt;code&gt;make bash&lt;/code&gt;, &lt;code&gt;make build&lt;/code&gt;, &lt;code&gt;make deploy&lt;/code&gt;, ... just like I do when working on this blog (see my makefile on &lt;a href="https://github.com/cavo789/blog/blob/main/makefile" rel="noopener noreferrer"&gt;https://github.com/cavo789/blog/blob/main/makefile&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;What's really nice is being able to type &lt;code&gt;make&lt;/code&gt; at the command line without any other options and then get a screen with lists of existing commands and a short one-line explanation.&lt;/p&gt;

&lt;p&gt;That's what we'll be looking at in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites - Install GNU Make if needed
&lt;/h2&gt;

&lt;p&gt;We will use &lt;code&gt;GNU make&lt;/code&gt; so you need to have it.&lt;/p&gt;

&lt;p&gt;Please run &lt;code&gt;which make&lt;/code&gt; in your Linux console to check if &lt;code&gt;make&lt;/code&gt; is already installed. If so, you will get f.i. &lt;code&gt;/usr/bin/make&lt;/code&gt; as result.&lt;/p&gt;

&lt;p&gt;If you got &lt;code&gt;make not found&lt;/code&gt;, please run &lt;code&gt;sudo apt-get update &amp;amp;&amp;amp; sudo apt-get -y install make&lt;/code&gt; to install it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites - Create a sample file
&lt;/h2&gt;

&lt;p&gt;For the demo, please start a Linux shell and run &lt;code&gt;mkdir -p /tmp/makefile &amp;amp;&amp;amp; cd $_&lt;/code&gt; to create a folder called &lt;code&gt;makefile&lt;/code&gt; in your Linux temporary folder and jump in it.&lt;/p&gt;

&lt;p&gt;Please create a new file called &lt;code&gt;makefile&lt;/code&gt; with this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;SHELL&lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;bash

&lt;span class="nv"&gt;COLOR_YELLOW&lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;33

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;bash&lt;/span&gt;
&lt;span class="nl"&gt;bash&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
 &lt;span class="err"&gt;@printf&lt;/span&gt; &lt;span class="s2"&gt;"\e[1;${COLOR_YELLOW}m%s\e[0m\n\n"&lt;/span&gt; &lt;span class="s2"&gt;"Start an interactive shell in the Docker container; type exit to quit"&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;code&lt;/span&gt;
&lt;span class="nl"&gt;code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
 &lt;span class="err"&gt;@printf&lt;/span&gt; &lt;span class="s2"&gt;"\e[1;${COLOR_YELLOW}m%s\e[0m\n\n"&lt;/span&gt; &lt;span class="s2"&gt;"Open the blog in Visual Studio Code"&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;
&lt;span class="nl"&gt;build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
 &lt;span class="err"&gt;@printf&lt;/span&gt; &lt;span class="s2"&gt;"\e[1;${COLOR_YELLOW}m%s\e[0m\n\n"&lt;/span&gt; &lt;span class="s2"&gt;"Generate a newer version of the build directory"&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;deploy&lt;/span&gt;
&lt;span class="nl"&gt;deploy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;
 &lt;span class="err"&gt;@printf&lt;/span&gt; &lt;span class="s2"&gt;"\e[1;${COLOR_YELLOW}m%s\e[0m\n\n"&lt;/span&gt; &lt;span class="s2"&gt;"Deploy static pages to the webserver"&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;install&lt;/span&gt;
&lt;span class="nl"&gt;install&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
 &lt;span class="err"&gt;@printf&lt;/span&gt; &lt;span class="s2"&gt;"\e[1;${COLOR_YELLOW}m%s\e[0m\n\n"&lt;/span&gt; &lt;span class="s2"&gt;"Generate a newer version of the build directory"&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;
&lt;span class="nl"&gt;start&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
 &lt;span class="nl"&gt;@printf "\e[1;${COLOR_YELLOW}m%s\e[0m\n\n" "Open the blog (http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//localhost:3000)"&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;watch&lt;/span&gt;
&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
 &lt;span class="nl"&gt;@printf "\e[1;${COLOR_YELLOW}m%s\e[0m\n\n" "Run Docusaurus watcher and open the blog on the localhost. When done, just start a browser and surf to http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//localhost:3000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The indentation in a makefile &lt;strong&gt;SHOULD BE&lt;/strong&gt; made using tabs and not spaces, this is crucial. So please make sure, if your file didn't work, you know what to do.&lt;/p&gt;

&lt;p&gt;That file contains a few &lt;em&gt;targets&lt;/em&gt; (=actions) and a simple &lt;code&gt;printf&lt;/code&gt; statement to display a text. Except echoing something into the console that &lt;code&gt;makefile&lt;/code&gt; does nothing.&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;ls&lt;/span&gt; &lt;span class="nt"&gt;-alh&lt;/span&gt;

total 920K
drwxr-xr-x  2 christophe christophe 4.0K Dec  10 12:19 &lt;span class="nb"&gt;.&lt;/span&gt;
drwxrwxrwt 17 root       root       908K Dec  10 12:19 ..
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;  1 christophe christophe 1.4K Dec  10 12:19 makefile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding the default action
&lt;/h2&gt;

&lt;p&gt;We're ready to start our implementation.&lt;/p&gt;

&lt;p&gt;We have to do three things for this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a &lt;code&gt;default: help&lt;/code&gt; action&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;help:&lt;/code&gt; target (a target is, in the Make terminology an action)&lt;/li&gt;
&lt;li&gt;Edit each target and add a small description.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 1 - Adding the default action
&lt;/h3&gt;

&lt;p&gt;In the absence of a &lt;code&gt;default:&lt;/code&gt; action defined in the file, like in your example, the first action will be executed.&lt;/p&gt;

&lt;p&gt;So, right now, if you run &lt;code&gt;make&lt;/code&gt; (without any other arguments), you'll get the &lt;em&gt;Start an interactive shell...&lt;/em&gt; message, that's the result of the &lt;code&gt;bash:&lt;/code&gt; target; the first in the file&lt;br&gt;
&lt;/p&gt;

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

Start an interactive shell &lt;span class="k"&gt;in &lt;/span&gt;the Docker container&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;type exit &lt;/span&gt;to quit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please edit the file and add the highlighted line below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;SHELL&lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;bash

&lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;highlight-next-line&lt;/span&gt;
&lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;help&lt;/span&gt;

&lt;span class="nv"&gt;COLOR_YELLOW&lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;33

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;bash&lt;/span&gt;
&lt;span class="nl"&gt;bash&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
 &lt;span class="err"&gt;@printf&lt;/span&gt; &lt;span class="s2"&gt;"\e[1;${COLOR_YELLOW}m%s\e[0m\n\n"&lt;/span&gt; &lt;span class="s2"&gt;"Start an interactive shell in the Docker container; type exit to quit"&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2 - Adding the help target
&lt;/h3&gt;

&lt;p&gt;Still in your editor, please add the highlighted block below; the position where you'll copy/paste it is not important but, logically, let's put this new action as the first since it's the one that will be executed by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;SHELL&lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;bash

&lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;help&lt;/span&gt;

&lt;span class="nv"&gt;COLOR_YELLOW&lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;33

&lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;highlight-next-line&lt;/span&gt;
&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;help&lt;/span&gt;
&lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;highlight-next-line&lt;/span&gt;
&lt;span class="nl"&gt;help&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Show the help with the list of commands&lt;/span&gt;
    // highlight-next-line
 &lt;span class="err"&gt;@clear&lt;/span&gt;
    &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;highlight-next-line&lt;/span&gt; 
 &lt;span class="nl"&gt;@awk 'BEGIN {FS = "&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;.*&lt;/span&gt;&lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt;"; printf "&lt;/span&gt;\n&lt;span class="nf"&gt;Usage:&lt;/span&gt;\n&lt;span class="nf"&gt;  make &lt;/span&gt;\0&lt;span class="nf"&gt;33[36m&amp;lt;target&amp;gt;&lt;/span&gt;\0&lt;span class="nf"&gt;33[0m&lt;/span&gt;\n\n&lt;span class="nf"&gt;"} /^[a-zA-Z_-]+:.*?&lt;/span&gt;&lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt;/ { printf "  &lt;/span&gt;\0&lt;span class="nf"&gt;33[36m%-20s&lt;/span&gt;\0&lt;span class="nf"&gt;33[0m %s&lt;/span&gt;\n&lt;span class="nf"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; $$1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; $$2 } /^&lt;/span&gt;&lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt;@/ { printf "&lt;/span&gt;\n\0&lt;span class="nf"&gt;33[0;33m%s&lt;/span&gt;\0&lt;span class="nf"&gt;33[0m&lt;/span&gt;\n&lt;span class="nf"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; substr($$0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; 5) } ' $(MAKEFILE_LIST)&lt;/span&gt;
    // highlight-next-line
 &lt;span class="err"&gt;@echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Right now, if you type &lt;code&gt;make&lt;/code&gt; on your console, you'll get this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Usage:
  make &amp;lt;target&amp;gt;

  &lt;span class="nb"&gt;help                  &lt;/span&gt;Show the &lt;span class="nb"&gt;help &lt;/span&gt;with the list of commands
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3 - Add a description for each target
&lt;/h3&gt;

&lt;p&gt;Take a look on your new &lt;code&gt;help&lt;/code&gt; target: the description &lt;em&gt;Show the help with the list of commands&lt;/em&gt; is prefixed by a double &lt;code&gt;#&lt;/code&gt;. This is how to add a description.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;highlight-next-line&lt;/span&gt;
&lt;span class="nl"&gt;help&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Show the help with the list of commands&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, you've to edit your makefile for the last time, and, for each target, add a &lt;code&gt;## a small, one line, description&lt;/code&gt; text; like below, our final file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;SHELL&lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;bash

&lt;span class="nv"&gt;COLOR_YELLOW&lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;33

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;help&lt;/span&gt;
&lt;span class="nl"&gt;help&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Show the help with the list of commands&lt;/span&gt;
 &lt;span class="err"&gt;@clear&lt;/span&gt;
 &lt;span class="nl"&gt;@awk 'BEGIN {FS = "&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;.*&lt;/span&gt;&lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt;"; printf "&lt;/span&gt;\n&lt;span class="nf"&gt;Usage:&lt;/span&gt;\n&lt;span class="nf"&gt;  make &lt;/span&gt;\0&lt;span class="nf"&gt;33[36m&amp;lt;target&amp;gt;&lt;/span&gt;\0&lt;span class="nf"&gt;33[0m&lt;/span&gt;\n\n&lt;span class="nf"&gt;"} /^[a-zA-Z_-]+:.*?&lt;/span&gt;&lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt;/ { printf "  &lt;/span&gt;\0&lt;span class="nf"&gt;33[36m%-20s&lt;/span&gt;\0&lt;span class="nf"&gt;33[0m %s&lt;/span&gt;\n&lt;span class="nf"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; $$1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; $$2 } /^&lt;/span&gt;&lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt;@/ { printf "&lt;/span&gt;\n\0&lt;span class="nf"&gt;33[0;33m%s&lt;/span&gt;\0&lt;span class="nf"&gt;33[0m&lt;/span&gt;\n&lt;span class="nf"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; substr($$0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; 5) } ' $(MAKEFILE_LIST)&lt;/span&gt;
 &lt;span class="err"&gt;@echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;bash&lt;/span&gt;
&lt;span class="nl"&gt;bash&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Open an interactive shell in the Docker container&lt;/span&gt;
 &lt;span class="err"&gt;@printf&lt;/span&gt; &lt;span class="s2"&gt;"\e[1;${COLOR_YELLOW}m%s\e[0m\n\n"&lt;/span&gt; &lt;span class="s2"&gt;"Start an interactive shell in the Docker container; type exit to quit"&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;code&lt;/span&gt;
&lt;span class="nl"&gt;code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Open Visual Studio Code&lt;/span&gt;
 &lt;span class="err"&gt;@printf&lt;/span&gt; &lt;span class="s2"&gt;"\e[1;${COLOR_YELLOW}m%s\e[0m\n\n"&lt;/span&gt; &lt;span class="s2"&gt;"Open the blog in Visual Studio Code"&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;
&lt;span class="nl"&gt;build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Generate a newer version of the build directory&lt;/span&gt;
 &lt;span class="err"&gt;@printf&lt;/span&gt; &lt;span class="s2"&gt;"\e[1;${COLOR_YELLOW}m%s\e[0m\n\n"&lt;/span&gt; &lt;span class="s2"&gt;"Generate a newer version of the build directory"&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;deploy&lt;/span&gt;
&lt;span class="nl"&gt;deploy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;build &lt;/span&gt;&lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Deploy static pages to the webserver&lt;/span&gt;
 &lt;span class="err"&gt;@printf&lt;/span&gt; &lt;span class="s2"&gt;"\e[1;${COLOR_YELLOW}m%s\e[0m\n\n"&lt;/span&gt; &lt;span class="s2"&gt;"Deploy static pages to the webserver"&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;install&lt;/span&gt;
&lt;span class="nl"&gt;install&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; The very first time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; after having cloned this blog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; you need to install Docusaurus before using it.&lt;/span&gt;
 &lt;span class="err"&gt;@printf&lt;/span&gt; &lt;span class="s2"&gt;"\e[1;${COLOR_YELLOW}m%s\e[0m\n\n"&lt;/span&gt; &lt;span class="s2"&gt;"Generate a newer version of the build directory"&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;
&lt;span class="nl"&gt;start&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Start the local webserver and open the webpage&lt;/span&gt;
 &lt;span class="nl"&gt;@printf "\e[1;${COLOR_YELLOW}m%s\e[0m\n\n" "Open the blog (http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//localhost:3000)"&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;watch&lt;/span&gt;
&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Start the Docusaurus watcher. Listen any changes to a .md file and reflect the change onto the website&lt;/span&gt;
 &lt;span class="nl"&gt;@printf "\e[1;${COLOR_YELLOW}m%s\e[0m\n\n" "Run Docusaurus watcher and open the blog on the localhost. When done, just start a browser and surf to http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//localhost:3000"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, by running &lt;code&gt;make&lt;/code&gt; you'll get a nice help screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Usage:
  make &amp;lt;target&amp;gt;

  help                  Show the help with the list of commands
  bash                  Open an interactive shell in the Docker container
  code                  Open Visual Studio Code
  build                 Generate a newer version of the build directory
  deploy                Deploy static pages to the webserver
  install               The very first time, after having cloned this blog, you need to install Docusaurus before using it.
  start                 Start the local webserver and open the webpage
  watch                 Start the Docusaurus watcher. Listen any changes to a .md file and reflect the change onto the website
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the order of targets respect the order in your file. &lt;code&gt;help&lt;/code&gt; is displayed first because it's the first target in the file so, think to reorder targets in your file based on your logic (f.i. alphabetically).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 - Add a subtitle between each "main section"
&lt;/h2&gt;

&lt;p&gt;Imagine you have dozens of shares... It would be nice to group them into sections: everything concerning your application, everything relating to your database, actions of the Code Analysis type, and so on.&lt;/p&gt;

&lt;p&gt;To do this, simply add a line with this syntax: &lt;code&gt;##@ My project&lt;/code&gt; as illustrated below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;SHELL&lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;bash

&lt;span class="nv"&gt;COLOR_YELLOW&lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;33

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;help&lt;/span&gt;
&lt;span class="nl"&gt;help&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Show the help with the list of commands&lt;/span&gt;
 &lt;span class="err"&gt;@clear&lt;/span&gt;
 &lt;span class="nl"&gt;@awk 'BEGIN {FS = "&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;.*&lt;/span&gt;&lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt;"; printf "&lt;/span&gt;\n&lt;span class="nf"&gt;Usage:&lt;/span&gt;\n&lt;span class="nf"&gt;  make &lt;/span&gt;\0&lt;span class="nf"&gt;33[36m&amp;lt;target&amp;gt;&lt;/span&gt;\0&lt;span class="nf"&gt;33[0m&lt;/span&gt;\n\n&lt;span class="nf"&gt;"} /^[a-zA-Z_-]+:.*?&lt;/span&gt;&lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt;/ { printf "  &lt;/span&gt;\0&lt;span class="nf"&gt;33[36m%-20s&lt;/span&gt;\0&lt;span class="nf"&gt;33[0m %s&lt;/span&gt;\n&lt;span class="nf"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; $$1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; $$2 } /^&lt;/span&gt;&lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt;@/ { printf "&lt;/span&gt;\n\0&lt;span class="nf"&gt;33[0;33m%s&lt;/span&gt;\0&lt;span class="nf"&gt;33[0m&lt;/span&gt;\n&lt;span class="nf"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; substr($$0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nf"&gt; 5) } ' $(MAKEFILE_LIST)&lt;/span&gt;
 &lt;span class="err"&gt;@echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;

&lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;highlight-next-line&lt;/span&gt;
&lt;span class="c"&gt;##@ My project              Helpers to work with the application
&lt;/span&gt;
&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;bash&lt;/span&gt;
&lt;span class="nl"&gt;bash&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Open an interactive shell in the Docker container&lt;/span&gt;
    &lt;span class="c"&gt;# [...]&lt;/span&gt;

&lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;highlight-next-line&lt;/span&gt;
&lt;span class="c"&gt;##@ Data quality            Code analysis tools
&lt;/span&gt;
&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;phan&lt;/span&gt;
&lt;span class="nl"&gt;phan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Run phan analysis&lt;/span&gt;
    &lt;span class="c"&gt;# [...]&lt;/span&gt;

&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;php-cs-fixer&lt;/span&gt;
&lt;span class="nl"&gt;php-cs-fixer&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Run php-cs-fixer&lt;/span&gt;
    &lt;span class="c"&gt;# [...]&lt;/span&gt;

&lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;highlight-next-line&lt;/span&gt;
&lt;span class="c"&gt;##@ Database management     Working with the database
&lt;/span&gt;
&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;phpmyadmin&lt;/span&gt;
&lt;span class="nl"&gt;phpmyadmin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Run phpmyadmin web interface&lt;/span&gt;
    &lt;span class="c"&gt;# [...]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is the final result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Usage:
  make &amp;lt;target&amp;gt;

  help                  Show the help with the list of commands

My project              Helpers to work with the application
  bash                  Open an interactive shell in the Docker container

Data quality            Code analysis tools
  phan                  Run phan analysis
  php-cs-fixer          Run php-cs-fixer

Database management     Working with the database
  phpmyadmin            Run phpmyadmin web interface
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have a clear grouping of actions. Much better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take a look on mine, for this blog
&lt;/h2&gt;

&lt;p&gt;This blog is maintained using such makefile, you can get a copy here: &lt;a href="https://github.com/cavo789/blog/blob/main/makefile" rel="noopener noreferrer"&gt;https://github.com/cavo789/blog/blob/main/makefile&lt;/a&gt;&lt;/p&gt;

</description>
      <category>makefile</category>
    </item>
    <item>
      <title>Running Quarto Markdown in Docker</title>
      <dc:creator>Christophe Avonture</dc:creator>
      <pubDate>Fri, 22 Dec 2023 19:39:45 +0000</pubDate>
      <link>https://dev.to/cavo789/running-quarto-markdown-in-docker-4igj</link>
      <guid>https://dev.to/cavo789/running-quarto-markdown-in-docker-4igj</guid>
      <description>&lt;p&gt;&lt;a href="https://quarto.org/" rel="noopener noreferrer"&gt;Quarto&lt;/a&gt; is a tool for producing PDF, Word document, HTML web pages, ePub files, slideshows and many, many more output based on a Markdown file.&lt;/p&gt;

&lt;p&gt;Using Quarto, you can render any markdown content to a new PDF f.i.&lt;/p&gt;

&lt;p&gt;Quarto supports a very large number of features, to which are added extensions from its community, making it a really practical tool for anyone wishing to produce documentation.&lt;/p&gt;

&lt;p&gt;Personally, I haven't used a Word-type word processor for several years; nor have I used PowerPoint since, I don't even know when the last time was.&lt;/p&gt;

&lt;p&gt;And yet, I produce a great deal of documentation and slideshows. I write everything in markdown and generate pdfs or slideshows from the same content.&lt;/p&gt;

&lt;p&gt;Until recently, I'd been using &lt;a href="https://pandoc.org/" rel="noopener noreferrer"&gt;pandoc&lt;/a&gt; but, having taken the time to look around Quarto, it's a hell of a lot more powerful.&lt;/p&gt;

&lt;p&gt;Like always on this blog, you will not install Quarto the old-fashioned way. Instead, you'll create our own Docker image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's play
&lt;/h2&gt;

&lt;p&gt;As usual, you will now create a temporary folder for your experiments. Please start a Linux shell and run &lt;code&gt;mkdir -p /tmp/docker-quarto &amp;amp;&amp;amp; cd $_&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create your own Docker image
&lt;/h3&gt;

&lt;p&gt;Create a new file called &lt;code&gt;Dockerfile&lt;/code&gt; (there is no extension) with this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Based on https://github.com/analythium/quarto-docker-examples/blob/main/Dockerfile.base&lt;/span&gt;

&lt;span class="c"&gt;# Version number of Quarto to download and use&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; QUARTO_VERSION="1.4.529"&lt;/span&gt;

&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; OS_USERNAME=quarto&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; UID=1000&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; GID=1000&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; eddelbuettel/r2u:20.04&lt;/span&gt;

&lt;span class="c"&gt;# librsvg2-bin is to allow SVG conversion when rendering a PDF file&lt;/span&gt;
&lt;span class="c"&gt;# (will install the rsvg-view binary)&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    pandoc &lt;span class="se"&gt;\
&lt;/span&gt;    pandoc-citeproc &lt;span class="se"&gt;\
&lt;/span&gt;    curl &lt;span class="se"&gt;\
&lt;/span&gt;    gdebi-core &lt;span class="se"&gt;\
&lt;/span&gt;    librsvg2-bin &lt;span class="se"&gt;\
&lt;/span&gt;    python3.8 python3-pip &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get clean &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    install.r shiny jsonlite ggplot2 htmltools remotes renv knitr rmarkdown quarto

&lt;span class="c"&gt;# Download and install Quarto&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; QUARTO_VERSION&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    curl &lt;span class="nt"&gt;-o&lt;/span&gt; quarto-linux-amd64.deb &lt;span class="nt"&gt;-L&lt;/span&gt; https://github.com/quarto-dev/quarto-cli/releases/download/v&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;QUARTO_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/quarto-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;QUARTO_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-linux-amd64&lt;/span&gt;.deb &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; gdebi &lt;span class="nt"&gt;--non-interactive&lt;/span&gt; quarto-linux-amd64.deb &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; quarto-linux-amd64.deb

&lt;span class="c"&gt;# Should be done for the user; won't work if done for root&lt;/span&gt;
&lt;span class="c"&gt;# (quarto will say that "tinytex is not installed")&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; OS_USERNAME&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; UID&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; GID&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    groupadd &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$GID&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OS_USERNAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    useradd &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nv"&gt;$UID&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nv"&gt;$GID&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /bin/bash &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OS_USERNAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; "${OS_USERNAME}"&lt;/span&gt;

&lt;span class="c"&gt;# Install tools like tinytex to allow conversion to PDF&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    quarto &lt;span class="nb"&gt;install &lt;/span&gt;tool tinytex &lt;span class="nt"&gt;--update-path&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\e&lt;/span&gt;&lt;span class="s2"&gt;[0;105m%s&lt;/span&gt;&lt;span class="se"&gt;\e&lt;/span&gt;&lt;span class="s2"&gt;[0;0m&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"Run tlmgr update"&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ~/.TinyTeX/bin/x86_64-linux/tlmgr update &lt;span class="nt"&gt;--self&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    ~/.TinyTeX/bin/x86_64-linux/fmtutil-sys &lt;span class="nt"&gt;--all&lt;/span&gt;

&lt;span class="c"&gt;# See https://github.com/rstudio/tinytex/issues/426 for explanation&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\e&lt;/span&gt;&lt;span class="s2"&gt;[0;105m%s&lt;/span&gt;&lt;span class="se"&gt;\e&lt;/span&gt;&lt;span class="s2"&gt;[0;0m&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"Run tlmgr install for a few tinyText packages (needed for PDF conversion)"&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ~/.TinyTeX/bin/x86_64-linux/tlmgr &lt;span class="nb"&gt;install &lt;/span&gt;fvextra footnotebackref pagecolor sourcesanspro sourcecodepro titling

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; root&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /input

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; "${OS_USERNAME}"&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This done, please run &lt;code&gt;docker build -t cavo789/quarto .&lt;/code&gt; and after something like three minutes the first time, you'll get your own Docker image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker build &lt;span class="nt"&gt;-t&lt;/span&gt; cavo789/quarto &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;+] Building 208.2s &lt;span class="o"&gt;(&lt;/span&gt;13/13&lt;span class="o"&gt;)&lt;/span&gt; FINISHED                  docker:default
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;internal] load .dockerignore                     0.0s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; transferring context: 2B                       0.0s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;internal] load build definition from Dockerfile  0.0s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; transferring dockerfile: 2.08kB                0.0s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;internal] load metadata &lt;span class="k"&gt;for &lt;/span&gt;docker.io/eddelbuettel/r2u:20.04  3.4s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; CACHED &lt;span class="o"&gt;[&lt;/span&gt; 1/10] FROM docker.io/eddelbuettel/r2u:20.04@sha256:133b40653e0ad564d348f94ad72c753b97fb28941c072e69bb6e03c3b8d6c06e 0.0s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; 2/10] RUN &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt;     pandoc     pandoc-citeproc     curl     gdebi-core     librsvg2-bin     python3.8   47.6s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; 3/10] RUN &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; install.r shiny jsonlite ggplot2 htmltools remotes renv knitr rmarkdown quarto                                                                       27.2s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; 4/10] RUN &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; curl &lt;span class="nt"&gt;-o&lt;/span&gt; quarto-linux-amd64.deb &lt;span class="nt"&gt;-L&lt;/span&gt; https://github.com/quarto-dev/quarto-cli/releases/download/v1.4.529/quarto-1.4.529-linux-amd64.deb     &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; gdebi -  12.1s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; 5/10] RUN &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; groupadd &lt;span class="nt"&gt;-g&lt;/span&gt; 1000 &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"quarto"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; useradd &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; 1000 &lt;span class="nt"&gt;-g&lt;/span&gt; 1000 &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /bin/bash &lt;span class="s2"&gt;"quarto"&lt;/span&gt;                                                               0.5s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; 6/10] RUN &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; quarto &lt;span class="nb"&gt;install &lt;/span&gt;tool tinytex &lt;span class="nt"&gt;--update-path&lt;/span&gt;                                   23.0s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; 7/10] RUN &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\e&lt;/span&gt;&lt;span class="s2"&gt;[0;105m%s&lt;/span&gt;&lt;span class="se"&gt;\e&lt;/span&gt;&lt;span class="s2"&gt;[0;0m&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"Run tlmgr update"&lt;/span&gt;     &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ~/.TinyTeX/bin/x86_64-linux/tlmgr update &lt;span class="nt"&gt;--self&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ~/.TinyTeX/bin/x86_64-linux/fm  77.9s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; 8/10] RUN &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\e&lt;/span&gt;&lt;span class="s2"&gt;[0;105m%s&lt;/span&gt;&lt;span class="se"&gt;\e&lt;/span&gt;&lt;span class="s2"&gt;[0;0m&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"Run tlmgr install for a few tinyText packages (needed for PDF conversion)"&lt;/span&gt;     &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ~/.TinyTeX/bin/x86_64-linux/tlmgr   11.7s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; 9/10] RUN &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /input                   0.5s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; exporting to image               4.0s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; exporting layers              4.0s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; writing image sha256:fe1d20bd71a66eb574ba1f5b35c988ace57c2c30f93159caa4d5de2f8c490eb0                  0.0s
 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; naming to docker.io/cavo789/quarto                                                                     0.0s

What&lt;span class="s1"&gt;'s Next?
  View summary of image vulnerabilities and recommendations → docker scout quickview
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous instruction &lt;code&gt;docker build -t cavo789/quarto .&lt;/code&gt; has created an image called &lt;code&gt;cavo789/quarto&lt;/code&gt;. You can for sure choose a different name without any impact on the image.&lt;/p&gt;

&lt;p&gt;You can quickly check the size of your image; quite huge but except you're very low in memory / disk space; this is really not a big deal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker image list | &lt;span class="nb"&gt;grep &lt;/span&gt;quarto

cavo789/quarto  latest  fe1d20bd71a6  10 minutes ago  2.14GB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using Quarto and generate a PDF file
&lt;/h3&gt;

&lt;p&gt;Create a new &lt;code&gt;test.md&lt;/code&gt; file in your &lt;code&gt;/tmp/docker-quarto&lt;/code&gt; folder with this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# What's is Quarto? Explain like I'm five&lt;/span&gt;

Imagine you want to write a story or a report, but instead of using a fancy computer program, you use plain text. That's kind of like Markdown, a simple language that lets you format your text without getting too complicated.

Now, Quarto is like a super-powered writing tool that understands Markdown and can also help you write code in different languages, like R or Python. It's like having a helper in your writing process, making things easier and more fun.

So, if you want to create documents, presentations, or even books, Quarto and Markdown can be your friends. They'll help you organize your thoughts, add cool features, and even share your work with the world.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, back to your Linux console and you'll convert that file to a pdf. &lt;strong&gt;Please refers to the official documentation of &lt;a href="https://quarto.org/" rel="noopener noreferrer"&gt;Quarto&lt;/a&gt; to get in-depth information about it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To convert to a PDF, the instruction to fire is &lt;code&gt;quarto render test.md --to pdf&lt;/code&gt;. But since you're using Quarto from a Docker image, the instruction becomes &lt;code&gt;docker run -it --rm -v ${PWD}:/input -w /input -u $(id -u):$(id -g) cavo789/quarto quarto render test.md --to pdf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As a reminder, the used Docker run command are (almost always the same):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-it&lt;/code&gt; to start Docker interactively, this will allow the script running in the container to ask you for some prompts f.i.,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--rm&lt;/code&gt; to ask Docker to kill and remove the container as soon as the script has been executed (otherwise you'll have a lot of exited but not removed Docker containers; you can check this by not using the &lt;code&gt;--rm&lt;/code&gt; flag then running &lt;code&gt;docker container list&lt;/code&gt; on the console),&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-v ${PWD}:/input&lt;/code&gt; to share your current folder with a folder called &lt;code&gt;/input&lt;/code&gt; in the Docker container,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-w /input&lt;/code&gt; to tell Docker that the current directory, in the container, will be the &lt;code&gt;/app&lt;/code&gt; folder,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-u $(id -u):$(id -g)&lt;/code&gt; ask Docker to reuse our local credentials so when a file is updated/created in the container, the file will be owned by you,&lt;/li&gt;
&lt;li&gt;then &lt;code&gt;cavo789/quarto&lt;/code&gt; which is the name of your Quarto Docker image, and, finally,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;quarto render test.md --to pdf&lt;/code&gt; i.e. the command line to start within the container.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, let's convert to PDF and run &lt;code&gt;docker run -it --rm -v ${PWD}:/input -w /input -u $(id -u):$(id -g) cavo789/quarto quarto render test.md --to pdf&lt;/code&gt; in your console.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:/input &lt;span class="nt"&gt;-w&lt;/span&gt; /input &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; cavo789/quarto quarto render test.md &lt;span class="nt"&gt;--to&lt;/span&gt; pdf&lt;span class="sb"&gt;`&lt;/span&gt;

pandoc
  to: latex
  output-file: test.tex
  standalone: &lt;span class="nb"&gt;true
  &lt;/span&gt;pdf-engine: xelatex
  variables:
    graphics: &lt;span class="nb"&gt;true
    &lt;/span&gt;tables: &lt;span class="nb"&gt;true
  &lt;/span&gt;default-image-extension: pdf

metadata
  documentclass: scrartcl
  classoption:
    - &lt;span class="nv"&gt;DIV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;11
    - &lt;span class="nv"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;noendperiod
  papersize: letter
  header-includes:
    - &lt;span class="s1"&gt;'\KOMAoption{captions}{tableheading}'&lt;/span&gt;
  block-headings: &lt;span class="nb"&gt;true

&lt;/span&gt;Rendering PDF
running xelatex - 1
  This is XeTeX, Version 3.141592653-2.6-0.999995 &lt;span class="o"&gt;(&lt;/span&gt;TeX Live 2023&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;preloaded &lt;span class="nv"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xelatex&lt;span class="o"&gt;)&lt;/span&gt;
   restricted &lt;span class="se"&gt;\w&lt;/span&gt;rite18 enabled.
  entering extended mode

running xelatex - 2
  This is XeTeX, Version 3.141592653-2.6-0.999995 &lt;span class="o"&gt;(&lt;/span&gt;TeX Live 2023&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;preloaded &lt;span class="nv"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xelatex&lt;span class="o"&gt;)&lt;/span&gt;
   restricted &lt;span class="se"&gt;\w&lt;/span&gt;rite18 enabled.
  entering extended mode

Output created: test.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Add the &lt;code&gt;--log-level warning&lt;/code&gt; CLI argument to Quarto to ask him to show only warning (and error) messages. Non-essential output will be hidden and you'll keep a clean console. The new command to use is thus &lt;code&gt;docker run -it --rm -v ${PWD}:/input -w /input -u $(id -u):$(id -g) cavo789/quarto quarto render test.md --to pdf --log-level warning&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Quarto and generate a HTML file
&lt;/h3&gt;

&lt;p&gt;Simply modify the &lt;code&gt;--to&lt;/code&gt; argument and replace &lt;code&gt;pdf&lt;/code&gt; by &lt;code&gt;html&lt;/code&gt; and run the command: &lt;code&gt;docker run -it --rm -v ${PWD}:/input -w /input -u $(id -u):$(id -g) cavo789/quarto quarto render test.md --to html --log-level warning&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, you've a &lt;code&gt;test.html&lt;/code&gt; file in your directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Quarto and generate a revealjs slideshow
&lt;/h3&gt;

&lt;p&gt;This time, the &lt;code&gt;--to&lt;/code&gt; argument should be set to &lt;code&gt;revealjs&lt;/code&gt;: &lt;code&gt;docker run -it --rm -v ${PWD}:/input -w /input -u $(id -u):$(id -g) cavo789/quarto quarto render test.md --to revealjs --log-level warning&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Open the &lt;code&gt;test.html&lt;/code&gt; file and you'll get this:&lt;/p&gt;

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

&lt;p&gt;Ok, you've just one slide now. Reopen the &lt;code&gt;test.md&lt;/code&gt; file and you'll insert &lt;em&gt;slide breaks&lt;/em&gt;. This can be done using the &lt;code&gt;----&lt;/code&gt; syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# What's is Quarto? Explain like I'm five&lt;/span&gt;

Imagine you want to write a story or a report, but instead of using a fancy computer program, you use plain text. That's kind of like Markdown, a simple language that lets you format your text without getting too complicated.
&lt;span class="p"&gt;
----
&lt;/span&gt;
Now, Quarto is like a super-powered writing tool that understands Markdown and can also help you write code in different languages, like R or Python. It's like having a helper in your writing process, making things easier and more fun.
&lt;span class="p"&gt;
----
&lt;/span&gt;
So, if you want to create documents, presentations, or even books, Quarto and Markdown can be your friends. They'll help you organize your thoughts, add cool features, and even share your work with the world.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rerun &lt;code&gt;docker run -it --rm -v ${PWD}:/input -w /input -u $(id -u):$(id -g) cavo789/quarto quarto render test.md --to revealjs --log-level warning&lt;/code&gt; and now your slideshow will have three slides (press space or arrow keys for navigation):&lt;/p&gt;

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

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

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

&lt;p&gt;The nice thing now is that your slideshow is ready to be deployed on your remote server. Copy the html file and the associated folder (in our use case here, file &lt;code&gt;test.html&lt;/code&gt; and folder &lt;code&gt;test_files&lt;/code&gt;) to your FTP server f.i. and your website can be publicly accessed. Nice, isn't it?&lt;/p&gt;

</description>
      <category>quarto</category>
      <category>docker</category>
      <category>markdown</category>
    </item>
    <item>
      <title>Encrypt sensitive data using SSL and Docker</title>
      <dc:creator>Christophe Avonture</dc:creator>
      <pubDate>Mon, 11 Dec 2023 15:58:20 +0000</pubDate>
      <link>https://dev.to/cavo789/encrypt-sensitive-data-using-ssl-and-docker-54kk</link>
      <guid>https://dev.to/cavo789/encrypt-sensitive-data-using-ssl-and-docker-54kk</guid>
      <description>&lt;p&gt;For 1,000 reasons or more, you want to encrypt a file containing text. Which software should you install? Well ... none other than Docker!&lt;/p&gt;

&lt;p&gt;By using a &lt;a href="https://hub.docker.com/r/alpine/openssl" rel="noopener noreferrer"&gt;Docker Alpine/OpenSSL&lt;/a&gt; image, it's so easy to encrypt/decrypt files using OpenSSL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linux scripts
&lt;/h2&gt;

&lt;p&gt;Create a new file on your disk with this content. This is the &lt;code&gt;encrypt.sh&lt;/code&gt; script.&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="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;MY_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ThisIsMyLongPasswordNobodyWillBeAbleToCrackIt"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:/data &lt;span class="nt"&gt;-w&lt;/span&gt; /data &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; alpine/openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="nt"&gt;-salt&lt;/span&gt; &lt;span class="nt"&gt;-pbkdf2&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-in&lt;/span&gt; /data/secrets.md &lt;span class="nt"&gt;-out&lt;/span&gt; /data/secrets_encrypted.md &lt;span class="nt"&gt;-k&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MY_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is the &lt;code&gt;decrypt.sh&lt;/code&gt; script:&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="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;MY_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ThisIsMyLongPasswordNobodyWillBeAbleToCrackIt"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:/data &lt;span class="nt"&gt;-w&lt;/span&gt; /data &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; alpine/openssl enc &lt;span class="nt"&gt;-aes-256-cbc&lt;/span&gt; &lt;span class="nt"&gt;-salt&lt;/span&gt; &lt;span class="nt"&gt;-pbkdf2&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-in&lt;/span&gt; /data/secrets_encrypted.md &lt;span class="nt"&gt;-out&lt;/span&gt; //data/secrets_decrypted.md &lt;span class="nt"&gt;-k&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MY_PASSWORD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the &lt;code&gt;MY_PASSWORD&lt;/code&gt; variable in both scripts to use yours.&lt;/p&gt;

&lt;h2&gt;
  
  
  DOS scripts
&lt;/h2&gt;

&lt;p&gt;For the illustration purpose, the DOS encryption script, &lt;code&gt;encrypt.cmd&lt;/code&gt;, will ask you for a password (since the &lt;code&gt;-k&lt;/code&gt; parameter is not part of the instruction). If the encrypted file has been created, the original one will be removed from your disk.&lt;/p&gt;

&lt;p&gt;Here is the content of the &lt;code&gt;encrypt.cmd&lt;/code&gt; DOS script:&lt;br&gt;
&lt;/p&gt;

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

cls

docker run --rm -it -v %CD%:/data -w /data alpine/openssl enc -aes-256-cbc -salt -pbkdf2 -a -in /data/secrets.md -out /data/secrets.encrypted

# Put this part in comment if you want to keep the original, unencrypted, file.
IF EXIST secrets.encrypted (
  del secrets.md
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The decryption script, &lt;code&gt;decrypt.cmd&lt;/code&gt; will ask you for the password and will display the decrypted content on the console (since the &lt;code&gt;-out&lt;/code&gt; parameter is not part of the instruction).&lt;/p&gt;

&lt;p&gt;Here is the content of the &lt;code&gt;decrypt.cmd&lt;/code&gt; DOS script:&lt;br&gt;
&lt;/p&gt;

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

cls

docker run --rm -it -v C:\temp:/data -w /data alpine/openssl enc -aes-256-cbc -salt -pbkdf2 -a -d -in /data/secrets.encrypted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use case
&lt;/h2&gt;

&lt;p&gt;In addition to simple encryption need, one use case is to store confidential files in online systems, e.g. a versioning system such as Github, or on cloud disks (e.g. Google drive).&lt;/p&gt;

&lt;h2&gt;
  
  
  Command line arguments
&lt;/h2&gt;

&lt;p&gt;The openssl &lt;code&gt;enc&lt;/code&gt; command accepts those arguments:&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;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;enc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Encoding with Ciphers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-aes-256-cbc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The encryption cipher to be used&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-salt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Adds strength to the encryption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-pbkdf2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate a PBKDF2 key derivation of a supplied password&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Encrypted data should be in Base64 and not binary&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;Decrypt action (if &lt;code&gt;-d&lt;/code&gt; is missing, action is encryt)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-in&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Specifies the input file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-out&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Specifies the output file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-k&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Provide the password to use&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Decrypt on the console, don't write a file
&lt;/h2&gt;

&lt;p&gt;Edit the &lt;code&gt;decrypt.sh&lt;/code&gt; (or &lt;code&gt;decrypt.cmd&lt;/code&gt;) script and search for &lt;code&gt;-out /data/secrets_decrypted.md&lt;/code&gt;. Remove that part.&lt;/p&gt;

&lt;p&gt;Now, when you'll run &lt;code&gt;decrypt.sh&lt;/code&gt; the decrypted content will be displayed on the console only, nothing will be written on the disk. Your secrets are safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Imagine a text file like &lt;code&gt;secrets.md&lt;/code&gt; with this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# My password&lt;/span&gt;

&lt;span class="gu"&gt;## My secret site&lt;/span&gt;

&lt;span class="gu"&gt;### FTP server&lt;/span&gt;
&lt;span class="p"&gt;
*&lt;/span&gt; Name: &lt;span class="sb"&gt;`127.0.0.1`&lt;/span&gt;
&lt;span class="p"&gt;*&lt;/span&gt; Login: &lt;span class="sb"&gt;`admin`&lt;/span&gt;
&lt;span class="p"&gt;*&lt;/span&gt; Password: &lt;span class="sb"&gt;`admin`&lt;/span&gt;

&lt;span class="gu"&gt;### Admin interface&lt;/span&gt;
&lt;span class="p"&gt;
*&lt;/span&gt; URL: &lt;span class="sb"&gt;`https://..../admin`&lt;/span&gt;
&lt;span class="p"&gt;*&lt;/span&gt; Login: &lt;span class="sb"&gt;`admin`&lt;/span&gt;
&lt;span class="p"&gt;*&lt;/span&gt; Password: &lt;span class="sb"&gt;`admin`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By running the &lt;code&gt;encrypt.sh&lt;/code&gt; script, the file &lt;code&gt;secrets_encrypted.md&lt;/code&gt; will be created on your disk and will have this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;U2FsdGVkX18jyyHAiaDcwolgvrCmB9SutNFhOFosDZvYA+t/8F5PWsxU+YIb0xLj
/0swl1Mvh9XBcg3FwpQn5CGm5ltb3zKiExPO8WoTuYOmlJj2PN5eLJv3GWVVJ8/t
q31xBBAlbI0k+a3pWiETl1qEmh4hwc4jeC5NOByYSAojiIdCNF0W5+VVkUlBeKGb
sv8tpDWEb/dgHrfFPtZD5MqeNQw71/ndORZC1ZDIT/Ju6O7a6rd9ph0aQuPz49PU
SzDUePUgn9wbR0tZvNM1JA1LkN1kDaguJ940TdKns+Q=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From now, you can remove &lt;code&gt;secrets.md&lt;/code&gt; since you've the encrypted version.&lt;/p&gt;

&lt;p&gt;To retrieve the original content, just run the &lt;code&gt;decrypt.sh&lt;/code&gt; script.&lt;/p&gt;

&lt;p&gt;By running that command (or by running &lt;code&gt;decrypt.sh&lt;/code&gt;), you'll decrypt the file &lt;code&gt;secrets_encrypted.md&lt;/code&gt; and get a newer one called &lt;code&gt;secrets_decrypted.md&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>ssl</category>
    </item>
    <item>
      <title>Self-hosted monitoring tool using Docker Uptime Kuma</title>
      <dc:creator>Christophe Avonture</dc:creator>
      <pubDate>Wed, 06 Dec 2023 09:08:21 +0000</pubDate>
      <link>https://dev.to/cavo789/self-hosted-monitoring-tool-using-docker-uptime-kuma-49gk</link>
      <guid>https://dev.to/cavo789/self-hosted-monitoring-tool-using-docker-uptime-kuma-49gk</guid>
      <description>&lt;p&gt;Imagine you're a web developer or you work in a web agency and you'd like to keep an eye on the sites you've developed for your clients, free of charge. Are these sites online now, or are they down?&lt;/p&gt;

&lt;p&gt;This work is carried out by site monitoring platforms. Could you install one on your computer? Of course!&lt;/p&gt;

&lt;p&gt;There are tons of self-hosted monitoring tools; one of them is Uptime Kuma. You can play with the demo website here: &lt;a href="https://demo.uptime.kuma.pet:27000/" rel="noopener noreferrer"&gt;https://demo.uptime.kuma.pet:27000/&lt;/a&gt;. Just create an admin account (for free) and you're ready to add your first websites.&lt;/p&gt;

&lt;p&gt;As read in the official documentation, you can easily start it using the command below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;always &lt;span class="nt"&gt;-p&lt;/span&gt; 3001:3001 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:/app/data &lt;span class="nt"&gt;--name&lt;/span&gt; uptime-kuma louislam/uptime-kuma:1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The -v ${PWD}:/app/data flag is important if you want to keep track of the sites you'll add to the dashboard (i.e. if you restart the tool). If you wish, only, play once with the interface first, you can omit it so nothing will be written on the disk.&lt;/p&gt;

&lt;p&gt;In the setting page, site by site, you can define a lot of actions like what the monitoring tool should do when the site is down. For instance, send you a notification on Mattermost or an email or ...&lt;/p&gt;

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

&lt;p&gt;On top of configuration items site by site, you'll also find in the Profile -&amp;gt; Settings page, a large number of global settings like the choice of the language's interface (French is available).&lt;/p&gt;

</description>
      <category>docker</category>
      <category>monitoring</category>
      <category>uptime</category>
    </item>
    <item>
      <title>Create your Joomla website using Docker</title>
      <dc:creator>Christophe Avonture</dc:creator>
      <pubDate>Tue, 28 Nov 2023 14:06:09 +0000</pubDate>
      <link>https://dev.to/cavo789/create-your-joomla-website-using-docker-4joh</link>
      <guid>https://dev.to/cavo789/create-your-joomla-website-using-docker-4joh</guid>
      <description>&lt;p&gt;In this article, we will learn how to use Docker to install Joomla on your localhost and start a new website &lt;strong&gt;in seconds&lt;/strong&gt; &lt;em&gt;(don't want to wait? Jump to the Final docker-compose.yml chapter)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I will use a Linux console &lt;em&gt;(I'm running WSL on my Windows computer and I have chosen Ubuntu for my distribution)&lt;/em&gt; but since Docker can also be used on Windows, you can perfectly run, exactly, the same commands in an MS-DOS / Powershell console.&lt;/p&gt;

&lt;p&gt;If you don't have Docker yet, please consult my "&lt;a href="https://www.avonture.be/blog/install-docker" rel="noopener noreferrer"&gt;Install Docker and play with PHP&lt;/a&gt;" article to get more information about Docker and an easy introduction guide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We will assume in this article that you have Docker, and you're working under Linux or using WSL.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Before starting
&lt;/h2&gt;

&lt;p&gt;As you know, to be able to run a CMS like Joomla we need three things + 1:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We need a webserver like &lt;strong&gt;Apache&lt;/strong&gt; or &lt;strong&gt;nginx&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;We need a database service like &lt;strong&gt;MySQL&lt;/strong&gt;, &lt;strong&gt;MariaDB&lt;/strong&gt; or &lt;strong&gt;PostgreSQL&lt;/strong&gt; or any other supported databases and&lt;/li&gt;
&lt;li&gt;We need &lt;strong&gt;PHP&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And, of course, we need &lt;strong&gt;Joomla&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In terms of Docker: we need three services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker compose
&lt;/h2&gt;

&lt;p&gt;When you need many services (Apache should be able to communicate with PHP and PHP should be able to request data from MySQL), you need to configure a special file called &lt;code&gt;docker-compose.yml&lt;/code&gt;. That file should be placed in the root of the project and will define the list of services required and how they will collaborate together.&lt;/p&gt;

&lt;p&gt;You will find an example of the &lt;code&gt;docker-compose.yml&lt;/code&gt; file on the Joomla image description page: &lt;a href="https://hub.docker.com/_/joomla" rel="noopener noreferrer"&gt;https://hub.docker.com/_/joomla&lt;/a&gt; &lt;em&gt;search for &lt;code&gt;docker-compose&lt;/code&gt; on this page.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The Docker Joomla image is built on PHP and Apache&lt;br&gt;
It's for sure too technical now but if you click on the&lt;br&gt;
&lt;a href="https://github.com/joomla-docker/docker-joomla/blob/8cac4ff7ae88b9274870a95f5e22ea3c32f01fd7/5.0/php8.1/apache/Dockerfile#L8" rel="noopener noreferrer"&gt;https://github.com/joomla-docker/docker-joomla/blob/8cac4ff7ae88b9274870a95f5e22ea3c32f01fd7/5.0/php8.1/apache/Dockerfile#L8&lt;/a&gt; link, you can see that the Docker image for Joomla 5.0.0 is built on a &lt;code&gt;php:8.1-apache&lt;/code&gt; image. This means that using this image, you will get PHP, Apache and Joomla, altogether in a single image.&lt;/p&gt;
&lt;h2&gt;
  
  
  Download images
&lt;/h2&gt;

&lt;p&gt;Please create on your disk, let us say in the &lt;code&gt;/tmp/joomla&lt;/code&gt; folder a file called &lt;code&gt;docker-compose.yml&lt;/code&gt; with this content (you can retrieve that file on &lt;a href="https://hub.docker.com/_/joomla" rel="noopener noreferrer"&gt;https://hub.docker.com/_/joomla&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;joomla&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;joomla&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8080:80&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;JOOMLA_DB_HOST=joomladb&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;JOOMLA_DB_PASSWORD=example&lt;/span&gt;

  &lt;span class="na"&gt;joomladb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:8.0.13&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_ROOT_PASSWORD=example&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You want MariaDB, not MySQL?&lt;br&gt;
Nothing could be simpler! In the &lt;code&gt;docker-compose.yml&lt;/code&gt; file, replace the line &lt;code&gt;image: mysql:8.0.13&lt;/code&gt; with &lt;code&gt;image: mariadb:11.1.2&lt;/code&gt; and save your change. That's it. It's piece of cake no?&lt;/p&gt;

&lt;p&gt;To make things as clear as possible, here is my temporary folder content:&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;pwd&lt;/span&gt;
/tmp/joomla

❯ &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-alh&lt;/span&gt;
Permissions Size User       Group      Date Modified    Name
drwxr-xr-x     - christophe christophe 2023-11-04 09:32  &lt;span class="nb"&gt;.&lt;/span&gt;
drwxrwxrwt     - christophe christophe 2023-11-04 09:32 ..
.rw-r--r--   325 christophe christophe 2023-11-04 09:32 docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, I just have one file, and this is the newly, created, &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Now, if needed, please start a Linux console, and go to your joomla folder (i.e. &lt;code&gt;cd /tmp/joomla&lt;/code&gt;). From there, run the command below:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;docker compose up --detach&lt;/code&gt;&lt;br&gt;
That command is one of the most important to know. It asks Docker to proceed the &lt;code&gt;docker-compose.yml&lt;/code&gt; file and run services. &lt;strong&gt;In short: run your website&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Docker will start downloading &lt;code&gt;joomla&lt;/code&gt; and &lt;code&gt;joomladb&lt;/code&gt;, the two services mentioned in the &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;joomla&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;joomladb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will obtain something like this, please wait until everything is downloaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker compose up &lt;span class="nt"&gt;--detach&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;+] Running 16/35
 ⠹ joomladb 12 layers &lt;span class="o"&gt;[&lt;/span&gt;⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀]    0B/0B  Pulling  19.3s
   ⠧ 177e7ef0df69 Waiting   15.8s
   ⠧ cac25352c4c8 Waiting   15.8s
   ⠧ 8585afabb40a Waiting   15.8s
   &lt;span class="o"&gt;[&lt;/span&gt;...]
 ⠹ joomla 21 layers &lt;span class="o"&gt;[&lt;/span&gt;⣿⣿⣦⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣿⣿⣿⣿⣀⠀⠀] 94.59MB/155.9MB Pulling  19.3s
   ✔ 578acb154839 Pull &lt;span class="nb"&gt;complete  &lt;/span&gt;11.3s
   ✔ c053f6f43c12 Pull &lt;span class="nb"&gt;complete  &lt;/span&gt;11.9s
   ⠋ 65cebbf4d847 Downloading &lt;span class="o"&gt;[==============&amp;gt;&lt;/span&gt;         &lt;span class="o"&gt;]&lt;/span&gt;  68.41MB/104.4MB  16.1s
   ✔ 34045bc93960 Download &lt;span class="nb"&gt;complete  &lt;/span&gt;1.0s
   &lt;span class="o"&gt;[&lt;/span&gt;...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the end, once images have been downloaded, the console will show something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker compose up &lt;span class="nt"&gt;--detach&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;+] Running 35/35
 ✔ joomladb 12 layers &lt;span class="o"&gt;[&lt;/span&gt;⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿]  0B/0B   Pulled  84.9s
   ✔ 177e7ef0df69 Pull &lt;span class="nb"&gt;complete  &lt;/span&gt;26.9s
   ✔ cac25352c4c8 Pull &lt;span class="nb"&gt;complete  &lt;/span&gt;27.5s
   ✔ 8585afabb40a Pull &lt;span class="nb"&gt;complete  &lt;/span&gt;28.2s
   &lt;span class="o"&gt;[&lt;/span&gt;...]
 ✔ joomla 21 layers &lt;span class="o"&gt;[&lt;/span&gt;⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿] 0B/0B  Pulled  146.4s
   ✔ 578acb154839 Pull &lt;span class="nb"&gt;complete   &lt;/span&gt;11.3s
   ✔ c053f6f43c12 Pull &lt;span class="nb"&gt;complete   &lt;/span&gt;11.9s
   ✔ 65cebbf4d847 Pull &lt;span class="nb"&gt;complete   &lt;/span&gt;31.2s
   &lt;span class="o"&gt;[&lt;/span&gt;...]
&lt;span class="o"&gt;[&lt;/span&gt;+] Running 3/3
 ✔ Network joomla_default       Created  0.3s
 ✔ Container joomla-joomladb-1  Started  52.9s
 ✔ Container joomla-joomla-1    Started  38.8s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, the two images have been downloaded then,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;a &lt;code&gt;joomla_default&lt;/code&gt; network is created,&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;joomla-joomladb-1&lt;/code&gt; container is created (this is your database server) and&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;joomla-joomla-1&lt;/code&gt; container is created too (this is your Joomla service).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At this stage, your site is already being installed. Go to the URL &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt; to view it (make sure to use the &lt;code&gt;http&lt;/code&gt; protocol and not &lt;code&gt;https&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Not yet ready&lt;br&gt;
You may get an error page &lt;code&gt;ERR_EMPTY_RESPONSE&lt;/code&gt;; this is because, for example, MySQL is not yet fully loaded and Joomla has to wait for it before it can display the installation page. In this case, please wait a little longer ... or read the rest of this article.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why joomla-joomlaxxx names?
&lt;/h3&gt;

&lt;p&gt;We didn't give your project a name, we just created a &lt;code&gt;docker-compose.yml&lt;/code&gt; file in your &lt;code&gt;/tmp/joomla&lt;/code&gt; folder. So, Docker has named your project using the folder name (&lt;code&gt;joomla&lt;/code&gt;) concatenated to service name (refers to the &lt;code&gt;docker-compose.yml&lt;/code&gt; file, we have two services, one called &lt;code&gt;joomladb&lt;/code&gt; and one called &lt;code&gt;joomla&lt;/code&gt;). That is why...&lt;/p&gt;

&lt;p&gt;Let us introduce a minor, optional, change, we will give a name to your Docker project and containers: edit the &lt;code&gt;docker-compose.yml&lt;/code&gt; file and add a line with &lt;code&gt;name: xxxx&lt;/code&gt; where &lt;code&gt;xxxx&lt;/code&gt; is the name of your choice. Do the same but using &lt;code&gt;container_name&lt;/code&gt; this time for the two services; for instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.9'&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kingsbridge&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;joomla&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kingsbridge-app&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;joomladb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kingsbridge-db&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We won't be restarting your Docker containers yet. For now, the &lt;code&gt;kingsbridge&lt;/code&gt; name won't be considered. For this to be the case, we would need to launch &lt;code&gt;docker compose down&lt;/code&gt; followed by &lt;code&gt;docker compose up --detach&lt;/code&gt;, but let us wait a little longer before doing so. &lt;/p&gt;

&lt;h2&gt;
  
  
  Docker images
&lt;/h2&gt;

&lt;p&gt;If you're curious, you can run the &lt;code&gt;docker image list&lt;/code&gt; command to get the list of Docker images already downloaded on your machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker image list
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
joomla       latest    882b2151d890   2 days ago    663MB
mysql        8.0.13    102816b1ee7d   4 years ago   486MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, so, Docker has downloaded Joomla (in its &lt;em&gt;latest&lt;/em&gt; version) and MySQL (version 8.0.13).&lt;/p&gt;

&lt;p&gt;What about Joomla 5.0 i.e. force a version?&lt;br&gt;
By default, when we don't specify any version number (&lt;em&gt;which isn't recommended&lt;/em&gt;), Docker will download the version known as the &lt;code&gt;latest&lt;/code&gt; one. &lt;code&gt;latest&lt;/code&gt;, here, is what Docker calls a &lt;em&gt;tag&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;joomla&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;joomla&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To retrieve the list of all tags, please navigate to &lt;a href="https://hub.docker.com/_/joomla/tags" rel="noopener noreferrer"&gt;https://hub.docker.com/_/joomla/tags&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;During writing this article, Joomla &lt;em&gt;latest&lt;/em&gt; correspond to Joomla version 4.4.0. So, what about to force to use Joomla 5.0. By surfing on the &lt;a href="https://hub.docker.com/_/joomla/tags" rel="noopener noreferrer"&gt;tags&lt;/a&gt; page, you can retrieve in the list of tags this one: &lt;em&gt;5.0.0-php8.2-apache&lt;/em&gt;. So just replace &lt;code&gt;image: joomla&lt;/code&gt; with &lt;code&gt;image: joomla:5.0.0-php8.2-apache&lt;/code&gt; in &lt;code&gt;docker-compose.yml&lt;/code&gt; and it's done. You're forcing a version.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;joomla&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;joomla:5.0.0-php8.2-apache&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker containers
&lt;/h2&gt;

&lt;p&gt;We're almost done. Please run &lt;code&gt;docker container list&lt;/code&gt; to get the list of containers created by Docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker container list
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                    NAMES
0798f8f25d2b   joomla         &lt;span class="s2"&gt;"/entrypoint.sh apac…"&lt;/span&gt;   8 minutes ago    Up 5 minutes    0.0.0.0:8080-&amp;gt;80/tcp     joomla-joomla-1
7b7fcd3809b0   mysql:8.0.13   &lt;span class="s2"&gt;"docker-entrypoint.s…"&lt;/span&gt;   8 minutes ago    Up 7 minutes    3306/tcp, 33060/tcp      joomla-joomladb-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have two running containers (your two services). Pay attention to the &lt;code&gt;PORTS&lt;/code&gt; column: your &lt;code&gt;joomla&lt;/code&gt; container is listening on the port &lt;code&gt;8080&lt;/code&gt; and your &lt;code&gt;mysql&lt;/code&gt; container is listening on port &lt;code&gt;3306&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hey, port &lt;code&gt;8080&lt;/code&gt;, does that mean anything to you? That is a port for a web page, isn't it?&lt;/p&gt;

&lt;p&gt;Let us try by starting your favorite browser and navigating to &lt;code&gt;http://localhost:8080&lt;/code&gt; (&lt;em&gt;or &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt;, it's strictly the same&lt;/em&gt;) and... Wow!&lt;/p&gt;

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

&lt;p&gt;Just incredible; no?&lt;br&gt;
Wow, doesn't that sound crazy? With a single command (&lt;code&gt;docker compose up --detach&lt;/code&gt;), you have downloaded everything you need to get Joomla running on your machine.&lt;/p&gt;

&lt;p&gt;Let us rewind for a few seconds: to run Joomla, we knew we needed three things + 1; a webserver, a database server, PHP and, of course, we need Joomla. &lt;strong&gt;And here, just by running one command, hop, all the magic happens.&lt;/strong&gt; And nothing to configure too!&lt;/p&gt;
&lt;h2&gt;
  
  
  Install Joomla
&lt;/h2&gt;

&lt;p&gt;Back to &lt;code&gt;http://localhost:8080&lt;/code&gt; and we will continue the installation.&lt;/p&gt;

&lt;p&gt;On the first screen, just select your preferred language then enter a name for your Joomla site:&lt;/p&gt;

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

&lt;p&gt;When Joomla will ask for your admin credentials, just fill in the value of your choice:&lt;/p&gt;

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

&lt;p&gt;But, for the database configuration, here you need to be strict:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The database type should be &lt;code&gt;MySQLi&lt;/code&gt; (since we're using MySQL),&lt;/li&gt;
&lt;li&gt;The name of the host should be &lt;code&gt;joomladb&lt;/code&gt; (the name we have chosen for the database service),&lt;/li&gt;
&lt;li&gt;The username should be &lt;code&gt;root&lt;/code&gt; (default value) and&lt;/li&gt;
&lt;li&gt;The password for that user should be &lt;code&gt;example&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why these values?&lt;br&gt;
These values can be retrieved inside the &lt;code&gt;docker-compose.yml&lt;/code&gt; file. If you have named your database service something other than &lt;code&gt;joomladb&lt;/code&gt;, then please use the name you have chosen.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;joomladb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_ROOT_PASSWORD=example&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;And, after a few seconds, tadaaa...&lt;/p&gt;

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

&lt;p&gt;The administrator page:&lt;/p&gt;

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

&lt;p&gt;And the administrator dashboard:&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Congratulations, you have successfully installed a fresh Joomla website using Docker!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Everything is done in RAM
&lt;/h2&gt;

&lt;p&gt;Let us leave a few minutes the browser and go back to your Linux console.&lt;/p&gt;

&lt;p&gt;In the previous chapter, we have installed Joomla so we should have Joomla on your computer, right?&lt;/p&gt;

&lt;p&gt;Let us verify by returning to our Linux console:&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;pwd&lt;/span&gt;
/tmp/joomla

❯ &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-alh&lt;/span&gt;
Permissions Size User       Group      Date Modified    Name
drwxr-xr-x     - christophe christophe 2023-11-04 09:32  &lt;span class="nb"&gt;.&lt;/span&gt;
drwxrwxrwt     - christophe christophe 2023-11-04 09:32 ..
.rw-r--r--   325 christophe christophe 2023-11-04 09:32 docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oh? Nothing... &lt;strong&gt;Nothing has been downloaded in your folder.&lt;/strong&gt; You don't have Joomla on your computer. How is this possible?&lt;/p&gt;

&lt;p&gt;We will discuss this later but yes, by default with Docker, everything happens in memory, nothing on the disk. If you can't wait, please read my "&lt;a href="https://www.avonture.be/blog/docker-volume" rel="noopener noreferrer"&gt;Share data between your running Docker container and your computer&lt;/a&gt;" article to better understand why and how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Play with containers
&lt;/h2&gt;

&lt;p&gt;Still on your console, type again &lt;code&gt;docker container list&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;❯ docker container list
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                    NAMES
0798f8f25d2b   joomla         &lt;span class="s2"&gt;"/entrypoint.sh apac…"&lt;/span&gt;   8 minutes ago    Up 5 minutes    0.0.0.0:8080-&amp;gt;80/tcp     joomla-joomla-1
7b7fcd3809b0   mysql:8.0.13   &lt;span class="s2"&gt;"docker-entrypoint.s…"&lt;/span&gt;   8 minutes ago    Up 7 minutes    3306/tcp, 33060/tcp      joomla-joomladb-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pay attention this time to the last column, called &lt;code&gt;NAMES&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We have thus two containers, one named &lt;code&gt;joomla-joomla-1&lt;/code&gt; and one name &lt;code&gt;joomla-joomladb-1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We will stop them by running &lt;code&gt;docker compose down&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;❯ docker compose down
&lt;span class="o"&gt;[&lt;/span&gt;+] Running 3/3
 ✔ Container joomla-joomla-1    Removed 2.6s
 ✔ Container joomla-joomladb-1  Removed 4.2s
 ✔ Network joomla       Removed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you go back to &lt;code&gt;http://localhost:8080&lt;/code&gt; with your browser and refresh the page; the site didn't exist anymore.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;docker compose up --detach&lt;/code&gt; again, surf to the site again, refresh the page and the site is, oh? not yet responding. Wait a few... a few more... and after a certain period, the site will be there. Why?&lt;/p&gt;

&lt;p&gt;Docker must (re)start two services, the Joomla one and the database server. Initialization of both services may take a few seconds, and the database service must be up so that Joomla can continue its initialization.&lt;/p&gt;

&lt;p&gt;You can see this by running &lt;code&gt;docker compose logs --follow&lt;/code&gt; (press CTRL+C to quit).&lt;/p&gt;

&lt;p&gt;Once Joomla will be ready, you will get the installation wizard of Joomla... just like the first time. So, by running &lt;code&gt;docker compose down&lt;/code&gt; you have lost your work.&lt;/p&gt;

&lt;p&gt;As mentioned earlier, everything is done in RAM. By stopping a Docker container, you will lose everything not saved on your computer. It's great for playing/learning but not what you expect when you're developing a real site.&lt;/p&gt;

&lt;p&gt;Remember the change we made earlier. We had added the name &lt;code&gt;kingsbridge&lt;/code&gt; as the project name in your &lt;code&gt;docker-compose.yml&lt;/code&gt; file and we've named the two containers. You can see that after relaunching &lt;code&gt;docker compose up&lt;/code&gt;, this time it's no longer &lt;code&gt;joomla-joomlaxxxx&lt;/code&gt; but &lt;code&gt;kingsbridge-app&lt;/code&gt; and &lt;code&gt;kingsbridge-db&lt;/code&gt;. This because changes made to the yaml file are processed only after a &lt;code&gt;down / up&lt;/code&gt; command. If you modify the yaml file, you should restart Docker containers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Synchronize with your computer
&lt;/h2&gt;

&lt;p&gt;We will now require that Docker store files/folders on your computer.&lt;/p&gt;

&lt;p&gt;We wish two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We want the entire website to be saved on your hard disk and&lt;/li&gt;
&lt;li&gt;we want the database to be saved on the hard disk as well.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To do this, please edit the &lt;code&gt;docker-compose.yml&lt;/code&gt; file and add the lines below:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kingsbridge&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;joomla&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1000:1000&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./site_joomla:/var/www/html&lt;/span&gt;

  &lt;span class="na"&gt;joomladb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1000:1000&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./db:/var/lib/mysql&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;/var/www/html&lt;/code&gt; folder of the Joomla service should be synchronized with the &lt;code&gt;site_joomla&lt;/code&gt; subfolder on your computer. This is for the Joomla website.&lt;/p&gt;

&lt;p&gt;And the &lt;code&gt;/var/lib/mysql&lt;/code&gt; folder of the MySQL service should be synchronized with your local &lt;code&gt;db&lt;/code&gt; subfolder.&lt;/p&gt;

&lt;p&gt;Please create folders first&lt;br&gt;
Make sure to, first, create these two directories on your computer so folder's permissions will be correct!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ &lt;span class="nb"&gt;mkdir &lt;/span&gt;site_joomla db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two lines &lt;code&gt;user: 1000:1000&lt;/code&gt; are really important and inform Docker to reuse your local credentials (the one used on your computer).&lt;/p&gt;

&lt;p&gt;Important&lt;br&gt;
If you don't do this, files and folders created by Docker will be owned by the &lt;code&gt;root&lt;/code&gt; user on your computer and not by us (in my case, by the user called &lt;code&gt;christophe&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Just check your folder's content:&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;pwd&lt;/span&gt;
/tmp/joomla

❯ &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-alh&lt;/span&gt;
Permissions Size User       Group      Date Modified    Name
drwxr-xr-x     - christophe christophe 2023-11-04 20:13  &lt;span class="nb"&gt;.&lt;/span&gt;
drwxrwxrwt     - christophe christophe 2023-11-04 20:13 ..
drwxr-xr-x     - christophe christophe 2023-11-04 20:13 db
drwxr-xr-x     - christophe christophe 2023-11-04 20:13 site_joomla
.rw-r--r--   478 christophe christophe 2023-11-04 20:13 docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run Docker again but first, make sure the previous containers are removed (not only stopped): &lt;code&gt;docker compose kill&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;❯ docker compose &lt;span class="nb"&gt;kill&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;+] Killing 2/2
 ✔ Container kingsbridge-db   Killed   2.1s
 ✔ Container kingsbridge-app  Killed   1.5s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;docker compose up --detach&lt;/code&gt; again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker compose up &lt;span class="nt"&gt;--detach&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;+] Running 3/3
 ✔ Network kingsbridge_default       Created    0.3s
 ✔ Container kingsbridge-db   Started    3.3s
 ✔ Container kingsbridge-app  Started
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you can, already, run &lt;code&gt;ls&lt;/code&gt; again to see that, yes, your local &lt;code&gt;site_joomla&lt;/code&gt; and &lt;code&gt;db&lt;/code&gt; folders are populated now. This is the result of the &lt;code&gt;volumes&lt;/code&gt; entry we have added in your &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ &lt;span class="nb"&gt;pwd&lt;/span&gt;
/tmp/joomla

❯ &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-alh&lt;/span&gt; site_joomla
Permissions Size User       Group      Date Modified    Name
drwxr-xr-x     - christophe christophe 2023-11-04 20:20 &lt;span class="nb"&gt;.&lt;/span&gt;
drwxr-xr-x     - christophe christophe 2023-11-04 20:16 ..
drwxr-xr-x     - christophe christophe 2023-10-14 14:42 administrator
drwxr-xr-x     - christophe christophe 2023-10-14 14:42 api
drwxr-xr-x     - christophe christophe 2023-10-14 14:42 cache
drwxr-xr-x     - christophe christophe 2023-10-14 14:42 cli
drwxr-xr-x     - christophe christophe 2023-10-14 14:42 components
drwxr-xr-x     - christophe christophe 2023-10-14 14:42 images
drwxr-xr-x     - christophe christophe 2023-10-14 14:42 includes
drwxr-xr-x     - christophe christophe 2023-10-14 14:42 installation
drwxr-xr-x     - christophe christophe 2023-10-14 14:42 language
drwxr-xr-x     - christophe christophe 2023-10-14 14:42 layouts
drwxr-xr-x     - christophe christophe 2023-10-14 14:43 libraries
drwxr-xr-x     - christophe christophe 2023-10-14 14:43 media
drwxr-xr-x     - christophe christophe 2023-10-14 14:42 modules
drwxr-xr-x     - christophe christophe 2023-10-14 14:42 plugins
drwxr-xr-x     - christophe christophe 2023-10-14 14:42 templates
drwxr-xr-x     - christophe christophe 2023-10-14 14:42 tmp
.rw-r--r--  6.9k christophe christophe 2023-11-04 20:20 .htaccess
.rw-r--r--  6.9k christophe christophe 2023-10-14 14:42 htaccess.txt
.rw-r--r--  1.1k christophe christophe 2023-10-14 14:42 index.php
.rw-r--r--   18k christophe christophe 2023-10-14 14:42 LICENSE.txt
.rw-r--r--  4.9k christophe christophe 2023-10-14 14:42 README.txt
.rw-r--r--   764 christophe christophe 2023-10-14 14:42 robots.txt.dist
.rw-r--r--  3.0k christophe christophe 2023-10-14 14:42 web.config.txt

❯ &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-alh&lt;/span&gt; db
Permissions Size User       Group      Date Modified    Name
drwxr-x---     - christophe christophe 2023-11-04 20:20 &lt;span class="c"&gt;#innodb_temp&lt;/span&gt;
drwxr-xr-x     - christophe christophe 2023-11-04 20:21 &lt;span class="nb"&gt;.&lt;/span&gt;
drwxr-xr-x     - christophe christophe 2023-11-04 20:16 ..
drwxr-x---     - christophe christophe 2023-11-04 20:21 mysql
drwxr-x---     - christophe christophe 2023-11-04 20:21 performance_schema
drwxr-x---     - christophe christophe 2023-11-04 20:21 sys
.rw-r-----    56 christophe christophe 2023-11-04 20:21 auto.cnf
.rw-------  1.7k christophe christophe 2023-11-04 20:21 ca-key.pem
.rw-r--r--  1.1k christophe christophe 2023-11-04 20:21 ca.pem
.rw-r--r--  1.1k christophe christophe 2023-11-04 20:21 client-cert.pem
.rw-------  1.7k christophe christophe 2023-11-04 20:21 client-key.pem
.rw-r-----   50M christophe christophe 2023-11-04 20:21 ib_logfile0
.rw-r-----   50M christophe christophe 2023-11-04 20:20 ib_logfile1
.rw-r-----   13M christophe christophe 2023-11-04 20:21 ibdata1
.rw-r-----   13M christophe christophe 2023-11-04 20:20 ibtmp1
.rw-r-----   24M christophe christophe 2023-11-04 20:21 mysql.ibd
.rw-------  1.7k christophe christophe 2023-11-04 20:21 private_key.pem
.rw-r--r--   452 christophe christophe 2023-11-04 20:21 public_key.pem
.rw-r--r--  1.1k christophe christophe 2023-11-04 20:21 server-cert.pem
.rw-------  1.7k christophe christophe 2023-11-04 20:21 server-key.pem
.rw-r-----   10M christophe christophe 2023-11-04 20:21 undo_001
.rw-r-----   10M christophe christophe 2023-11-04 20:21 undo_002
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Back to your browser and continue the installation of Joomla like we did in the previous chapter.&lt;/p&gt;

&lt;p&gt;When the installation wizard has finished successfully, return to your Linux console and check if you can see the &lt;code&gt;configuration.php&lt;/code&gt; file now.&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;pwd&lt;/span&gt;
/tmp/joomla

❯ &lt;span class="nb"&gt;ls &lt;/span&gt;site_joomla/configuration.php

Permissions Size User       Group      Date Modified    Name
.rw-r--r--  2.0k christophe christophe 2023-11-04 20:29 configuration.php

❯ &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 10 site_joomla/configuration.php
&amp;lt;?php
class JConfig &lt;span class="o"&gt;{&lt;/span&gt;
        public &lt;span class="nv"&gt;$offline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        public &lt;span class="nv"&gt;$offline_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'This site is down for maintenance.&amp;lt;br&amp;gt;Please check back again soon.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        public &lt;span class="nv"&gt;$display_offline_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 1&lt;span class="p"&gt;;&lt;/span&gt;
        public &lt;span class="nv"&gt;$offline_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        public &lt;span class="nv"&gt;$sitename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Kingsbridge'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        public &lt;span class="nv"&gt;$editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'tinymce'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        public &lt;span class="nv"&gt;$captcha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        public &lt;span class="nv"&gt;$list_limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 20&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes! This time we have stored your Joomla website on your computer.&lt;/p&gt;

&lt;p&gt;For the exercise, we can kill your containers by running &lt;code&gt;docker compose kill&lt;/code&gt; and run &lt;code&gt;docker compose up --detach&lt;/code&gt; again to start your containers again and, this time, we will retrieve your Joomla site as we just leave it. Nothing is lost now.&lt;/p&gt;

&lt;p&gt;And since files/folders are now on your computer, you can do everything you want with your website like committing it on a GitHub repository f.i.&lt;/p&gt;

&lt;p&gt;Synchronization has a cost&lt;br&gt;
When using one or more volumes, Docker must constantly check whether the files/folders on your computer are synchronized with the containers. This has a cost in terms of performance. Similarly, if Docker needs to write to a file (or to your Joomla database); if this is only in memory, it will be faster than if you also had to write the database to your disk. However, the difference in speed is not obvious under normal circumstances. If you're a developer writing hundreds or even thousands of records, you'll observe a noticeable difference.&lt;/p&gt;
&lt;h2&gt;
  
  
  Start a CLI command
&lt;/h2&gt;

&lt;p&gt;When working with a Joomla website, sometimes you need to run some PHP command like &lt;code&gt;php joomla.php&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To be able to do this, you will need to start a &lt;em&gt;interactive shell session&lt;/em&gt; in the Joomla container.&lt;/p&gt;

&lt;p&gt;Did you remember the name of your Joomla service? If no, just open the &lt;code&gt;docker-compose.yml&lt;/code&gt; file again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;joomla&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The name of your Joomla service is &lt;code&gt;joomla&lt;/code&gt; (and &lt;code&gt;joomladb&lt;/code&gt; is the name of your database service).&lt;/p&gt;

&lt;p&gt;Now we know everything we need: to run an interactive shell session in the Joomla container, just run &lt;code&gt;docker compose exec joomla /bin/sh&lt;/code&gt; to &lt;em&gt;jump&lt;/em&gt; into the Joomla container (&lt;em&gt;and &lt;code&gt;docker compose exec joomladb /bin/sh&lt;/code&gt; for the database container&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Let us rewind for a few seconds because it's complicated to understand.&lt;/p&gt;

&lt;p&gt;On your computer, in your Linux console, if you type &lt;code&gt;pwd&lt;/code&gt; to get the current folder, you will see &lt;code&gt;/tmp/joomla&lt;/code&gt; since it's the directory we have used in the tutorial.&lt;/p&gt;

&lt;p&gt;Then, we jump in the Joomla Docker container by running &lt;code&gt;docker compose exec joomla /bin/sh&lt;/code&gt; and, you can see it, we don't have any longer a prompt starting with &lt;code&gt;&amp;gt;&lt;/code&gt; but with &lt;code&gt;$&lt;/code&gt; but that isn't the only difference. If now, we run &lt;code&gt;pwd&lt;/code&gt; again, we're no more in your &lt;code&gt;/tmp/joomla&lt;/code&gt; folder but in &lt;code&gt;/var/www/html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It can drive you mad but ... when entering in the Docker container, you're &lt;em&gt;no more&lt;/em&gt; on your computer, you're virtually in another computer, the container. In that &lt;em&gt;computer&lt;/em&gt;, the current folder is thus &lt;code&gt;/var/www/html&lt;/code&gt;. By typing &lt;code&gt;exit&lt;/code&gt;, you will leave the container, go back to your computer and back in the &lt;code&gt;/tmp/joomla&lt;/code&gt; folder.&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;pwd&lt;/span&gt;
/tmp/joomla
❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;joomla /bin/sh
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;
/var/www/html
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;
❯ &lt;span class="nb"&gt;pwd&lt;/span&gt;
/tmp/joomla
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Something else to try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ php &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="nb"&gt;command &lt;/span&gt;not found: php
❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;joomla /bin/sh
&lt;span class="nv"&gt;$ &lt;/span&gt;php &lt;span class="nt"&gt;--version&lt;/span&gt;
PHP 8.1.25 &lt;span class="o"&gt;(&lt;/span&gt;cli&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;built: Nov  1 2023 06:20:35&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;NTS&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, on my computer (and probably on yours), by typing &lt;code&gt;php --version&lt;/code&gt;, I got an error. That is correct. I don't have PHP on my computer. &lt;em&gt;I work daily with PHP for years and I don't have it on my machine.&lt;/em&gt; 😄&lt;/p&gt;

&lt;p&gt;Then I jump in the Joomla container and type the same command again and, yes, inside the Docker container of Joomla, yes, PHP is installed and here, It's the version 8.1.25.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using alias
&lt;/h2&gt;

&lt;p&gt;Docker will always start your project on your localhost and on a port like &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Instead of using the IP address, it would be much nicer to use an alias like &lt;code&gt;http://kingsbridge:8080&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For this, on Windows, edit the file &lt;code&gt;C:\Windows\System32\Drivers\etc\hosts&lt;/code&gt; and add the &lt;code&gt;kingsbridge&lt;/code&gt; line as below illustrated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;127.0.0.1 localhost
127.0.0.1 kingsbridge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file. Now you can surf to &lt;code&gt;http://kingsbridge:8080&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;When creating an alias in the host file, some people prefer to use the &lt;code&gt;.local&lt;/code&gt; suffix like in &lt;code&gt;127.0.0.1 kingsbridge.local&lt;/code&gt; to make clear it's a localhost site. If you prefer this, so the URL will be &lt;code&gt;http://kingsbridge.local:8080&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using another port
&lt;/h2&gt;

&lt;p&gt;Imagine you have another project, no more the &lt;code&gt;Kingsbrige&lt;/code&gt; one. Can you have many Docker projects running at the same time? Yes! of course.&lt;/p&gt;

&lt;p&gt;You just need to make sure to use another, unused, port.&lt;/p&gt;

&lt;p&gt;Consider the &lt;code&gt;Shiring&lt;/code&gt; project &lt;code&gt;docker-compose.yml&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shiring&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;joomla&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;joomla&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8081:80&lt;/span&gt;

  &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will use the port &lt;code&gt;8081&lt;/code&gt; for that project and, in your host file, we will add &lt;code&gt;127.0.0.1 shiring&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, now and at the same time, we can access to &lt;code&gt;http://kingsbridge:8080&lt;/code&gt; and to &lt;code&gt;http://shiring:8081&lt;/code&gt; without conflicts since we have used a separate port number.&lt;/p&gt;

&lt;p&gt;Kingsbridge can be a Joomla 4.4 / PHP 7.4 website while Shiring is on Joomla 5.0 / PHP 8.2 without any conflict. &lt;strong&gt;And that's just astonishingly simple, if you think back to the way you worked before Docker.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using another port isn't mandatory. You can have several websites on the same port as &lt;code&gt;8080&lt;/code&gt;. But, in that case, we won't be able to use these websites at the same time. You can start the first one and when trying to start the second one, Docker will say &lt;em&gt;port already in use&lt;/em&gt;. This isn't a problem; you can just run &lt;code&gt;docker compose stop&lt;/code&gt; for the first one so free the port then start the second one.&lt;/p&gt;

&lt;p&gt;In this article, I'm using port &lt;code&gt;8080&lt;/code&gt; because Joomla has used it in his default &lt;code&gt;docker-compose.yml&lt;/code&gt; file. You're not forced to use that one, you can perfectly use &lt;code&gt;80&lt;/code&gt; and not &lt;code&gt;8080&lt;/code&gt;. In my daily work, I'm using ports &lt;code&gt;80&lt;/code&gt;, &lt;code&gt;81&lt;/code&gt;, &lt;code&gt;82&lt;/code&gt;, &lt;code&gt;83&lt;/code&gt;, ... varying the second figures for my projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using phpmyadmin
&lt;/h2&gt;

&lt;p&gt;Alongside Joomla and MySQL, it would be useful to have access to the database of your Joomla website. Can we use f.i. &lt;em&gt;phpmyadmin&lt;/em&gt;, &lt;em&gt;Adminer&lt;/em&gt;  or &lt;em&gt;pgadmin&lt;/em&gt; (for PostgreSQL) or ... ?&lt;/p&gt;

&lt;p&gt;The answer is, yes, of course.&lt;/p&gt;

&lt;p&gt;For the three mentioned above, there are official Docker images. For phpmyadmin, here it's: &lt;a href="https://hub.docker.com/_/phpmyadmin" rel="noopener noreferrer"&gt;https://hub.docker.com/_/phpmyadmin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To use it, just run this command: &lt;code&gt;docker run --name phpmyadmin -d --link joomladb:db --network kingsbridge_default -p 8089:80 phpmyadmin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We will run the phpmyadmin (aka PMA) Docker image and&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--name phpmyadmin&lt;/code&gt; allow us to give it a friendly name (optional)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-d&lt;/code&gt; is like &lt;code&gt;--detach&lt;/code&gt;: the container should stay in up&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--link joomladb:db&lt;/code&gt;: phpmyadmin should access to your Joomla database service. Remember the name in your &lt;code&gt;docker-compose.yml&lt;/code&gt; file,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--network kingsbridge_default&lt;/code&gt;: your database server is accessible on the &lt;code&gt;kingsbridge_default&lt;/code&gt; network and&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-p 8089:80&lt;/code&gt; tells Docker that we wish to access the web interface of PMA on port &lt;code&gt;8089&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have forgotten the name of the network used by your containers, run &lt;code&gt;docker compose up --detach&lt;/code&gt; again and you will see it. Otherwise run &lt;code&gt;docker network list&lt;/code&gt; to get the list of networks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker network list
NETWORK ID     NAME                  DRIVER    SCOPE
ddb1c1606b76   bridge                bridge    &lt;span class="nb"&gt;local
&lt;/span&gt;336cd6fec416   host                  host      &lt;span class="nb"&gt;local
&lt;/span&gt;16d351a0e393   kingsbridge_default   bridge    &lt;span class="nb"&gt;local
&lt;/span&gt;d8cdc43a7272   none                  null      &lt;span class="nb"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To open phpmyadmin, start your browser and navigate to &lt;code&gt;http://127.0.0.1:8089&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Did you remember your MySQL credentials? It was &lt;code&gt;root&lt;/code&gt; / &lt;code&gt;example&lt;/code&gt;.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Using Adminer
&lt;/h2&gt;

&lt;p&gt;If you prefer &lt;a href="https://hub.docker.com/_/adminer/" rel="noopener noreferrer"&gt;Adminer&lt;/a&gt;, here is the command to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; adminer &lt;span class="nt"&gt;--link&lt;/span&gt; joomladb:db &lt;span class="nt"&gt;--network&lt;/span&gt; kingsbridge_default &lt;span class="nt"&gt;-p&lt;/span&gt; 8088:8080 adminer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is the configured URL to use for Adminer: &lt;code&gt;http://127.0.0.1:8088?server=joomladb&amp;amp;username=root&amp;amp;db=joomla_db&lt;/code&gt;.  (&lt;code&gt;joomla_db&lt;/code&gt; is the name of the database we've created earlier in chapter Install Joomla)&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Did you prefer PostgreSQL or MariaDB ?
&lt;/h2&gt;

&lt;p&gt;So far, we've chosen to use MySQL as our database manager. Our &lt;code&gt;docker-compose.yml&lt;/code&gt; file is the one, slightly modified, that can be found on &lt;a href="https://hub.docker.com/_/joomla" rel="noopener noreferrer"&gt;https://hub.docker.com/_/joomla&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Could you opt for something other than MySQL? Of course, as long as Joomla supports this system (see &lt;a href="https://manual.joomla.org/docs/next/get-started/technical-requirements/" rel="noopener noreferrer"&gt;https://manual.joomla.org/docs/next/get-started/technical-requirements/&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;We just need to replace the &lt;code&gt;joomladb&lt;/code&gt; service, don't use anymore &lt;code&gt;mysql&lt;/code&gt; but the one we wish.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using PostgreSQL
&lt;/h3&gt;

&lt;p&gt;Let's try PostgreSQL... We'll replace &lt;code&gt;mysql&lt;/code&gt;. The official PostgreSQL Docker image can be retrieved on &lt;a href="https://hub.docker.com/_/postgres" rel="noopener noreferrer"&gt;https://hub.docker.com/_/postgres&lt;/a&gt;.  The documentation tell us which &lt;code&gt;image&lt;/code&gt; we should use and how to define variables like the default password (&lt;code&gt;POSTGRES_PASSWORD&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;We also need to change a few variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The default database user should be specified and it will be f.i. &lt;code&gt;postgres&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;We should define too the name of the database in both services; we'll name our db &lt;code&gt;joomla_db&lt;/code&gt; and&lt;/li&gt;
&lt;li&gt;We need to inform Joomla that we'll use PostgreSQL so we need to set &lt;code&gt;JOOMLA_DB_TYPE&lt;/code&gt; to &lt;code&gt;pgsql&lt;/code&gt; (can be either &lt;code&gt;mysql&lt;/code&gt; or &lt;code&gt;pgsql&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This information has been retrieved from this Pull requests: &lt;a href="https://github.com/joomla-docker/docker-joomla/pull/156" rel="noopener noreferrer"&gt;https://github.com/joomla-docker/docker-joomla/pull/156&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;docker-compose.yml&lt;/code&gt; will become:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kingsbridge&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;joomla&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;JOOMLA_DB_HOST=joomladb&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;JOOMLA_DB_USER=postgres&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;JOOMLA_DB_PASSWORD=example&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;JOOMLA_DB_NAME=joomla_db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;JOOMLA_DB_TYPE=pgsql&lt;/span&gt;

  &lt;span class="na"&gt;joomladb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16.0-alpine&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DB=joomla_db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER=postgres&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=example&lt;/span&gt;      
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, during the configuration of Joomla, make sure to choose &lt;code&gt;PostgreSQL (PDO)&lt;/code&gt; for the database type and fill in the database wizard with the correct values.&lt;/p&gt;

&lt;p&gt;Use alpine images wherever possible&lt;br&gt;
For the first time during this tutorial, we're using an &lt;code&gt;alpine&lt;/code&gt; image (&lt;code&gt;postgres:16.0-alpine&lt;/code&gt; here). These images are lighter than the &lt;em&gt;not&lt;/em&gt; alpine image. They contain the bare essentials for running the service, whereas a &lt;em&gt;traditional&lt;/em&gt; image contains additional tools, binaries, ... that you may need but are not certain to use.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using MariaDB
&lt;/h3&gt;

&lt;p&gt;If you plan to use MariaDB, here is the Docker Official Image: &lt;a href="https://hub.docker.com/_/mariadb" rel="noopener noreferrer"&gt;https://hub.docker.com/_/mariadb&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kingsbridge&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;joomla&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;joomladb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mariadb:11.1.2&lt;/span&gt;
    &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;...&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For MariaDB, please select &lt;code&gt;MySQLi&lt;/code&gt; during the installation wizard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extra information
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The container will be restarted by Windows
&lt;/h3&gt;

&lt;p&gt;If you shut down your computer, if one or more containers are still running, Docker will run them again on the next startup.&lt;/p&gt;

&lt;p&gt;This means that the next time you start your computer, your website will still be accessible, and you won't have to run a single command. It's so easy!&lt;/p&gt;

&lt;h3&gt;
  
  
  Working with Windows
&lt;/h3&gt;

&lt;p&gt;Imagine you're in your console (f.i. run &lt;code&gt;cd /tmp/joomla&lt;/code&gt; in the Linux console) and you wish to open the site with Visual Studio Code, already installed on your Windows machine.&lt;/p&gt;

&lt;p&gt;It's easy: just run &lt;code&gt;code .&lt;/code&gt; to open the current folder so your project within vscode.&lt;/p&gt;

&lt;p&gt;Another use case, you wish to start the Windows Explorer program and navigate in your project's structure. Here too, it's possible, just run &lt;code&gt;explorer.exe .&lt;/code&gt; to open it and load the current directory. See my "&lt;a href="https://www.avonture.be/blog/wsl-windows-explorer" rel="noopener noreferrer"&gt;Open your Linux folder in Windows Explorer&lt;/a&gt;" article to read more about this feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make it easy
&lt;/h3&gt;

&lt;p&gt;Only for Linux / WSL (not for DOS/PowerShell)&lt;br&gt;
This chapter only concern Linux since DOS/PowerShell didn't support the GNU make command.&lt;/p&gt;

&lt;p&gt;In this blog article, we have seen a lot of docker commands.&lt;/p&gt;

&lt;p&gt;By alphabetical order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;docker compose down&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker compose exec joomla /bin/sh&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker compose kill&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker compose logs --follow&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker compose up --detach&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker container list&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker image list&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker network list&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker run -d --rm --name adminer --link joomladb:db --network kingsbridge_default -p 8088:8080 adminer&lt;/code&gt; and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker run -d --rm --name phpmyadmin --link joomladb:db --network kingsbridge_default -p 8089:80 phpmyadmin&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's not easy to remember them all, so why not simplify things?&lt;/p&gt;

&lt;p&gt;We will use &lt;code&gt;GNU make&lt;/code&gt; for this.&lt;/p&gt;

&lt;p&gt;First run &lt;code&gt;which make&lt;/code&gt; in your Linux console to check if &lt;code&gt;make&lt;/code&gt; is installed. If so, you will get f.i. &lt;code&gt;/usr/bin/make&lt;/code&gt; as result. If you got &lt;code&gt;make not found&lt;/code&gt;, please run &lt;code&gt;sudo apt-get update &amp;amp;&amp;amp; sudo apt-get -y install make&lt;/code&gt; to install it.&lt;/p&gt;

&lt;p&gt;This done, we will create a new file called &lt;code&gt;makefile&lt;/code&gt; in your directory. We will use &lt;code&gt;code makefile&lt;/code&gt; to start Visual Studio code and create the &lt;code&gt;makefile&lt;/code&gt; in your directory.&lt;/p&gt;

&lt;p&gt;This file is specific to each project, not global.&lt;br&gt;
The &lt;code&gt;makefile&lt;/code&gt;, being created in your project folder, can contain instructions for that specific project. You could have one &lt;code&gt;makefile&lt;/code&gt; for each project.&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;pwd&lt;/span&gt;
/tmp/joomla

❯ code makefile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now copy/paste this content in your &lt;code&gt;makefile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;adminer&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="nl"&gt;@printf "\e[1;033m%s\e[0m\n\n" "User is root and password is example. Please open http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//127.0.0.1:8088?server=joomladb&amp;amp;username=root&amp;amp;db=joomla_db to open Adminer."&lt;/span&gt;
  &lt;span class="nl"&gt;@printf "\e[1;033m%s\e[0m\n\n" "Starting adminer. If the browser didn't open automatically, please surf to http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//127.0.0.1:8088?server=joomladb&amp;amp;username=root&amp;amp;db=joomla_db to open adminer."&lt;/span&gt;
  &lt;span class="nl"&gt;docker run -d --rm --name adminer --link joomladb&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;db --network kingsbridge_default -p 8088:8080 adminer&lt;/span&gt;
  &lt;span class="nl"&gt;-sensible-browser http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//localhost:8088 &amp;amp;&lt;/span&gt;

&lt;span class="nl"&gt;bash&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="err"&gt;@printf&lt;/span&gt; &lt;span class="s2"&gt;"\e[1;033m%s\e[0m\n\n"&lt;/span&gt; &lt;span class="s2"&gt;"Start an interactive shell in the Joomla Docker container; type exit to quit"&lt;/span&gt;
  &lt;span class="err"&gt;docker&lt;/span&gt; &lt;span class="err"&gt;compose&lt;/span&gt; &lt;span class="err"&gt;exec&lt;/span&gt; &lt;span class="err"&gt;joomla&lt;/span&gt; &lt;span class="err"&gt;/bin/sh&lt;/span&gt;

&lt;span class="nl"&gt;code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="err"&gt;code&lt;/span&gt; &lt;span class="err"&gt;.&lt;/span&gt;

&lt;span class="nl"&gt;down&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="err"&gt;docker&lt;/span&gt; &lt;span class="err"&gt;compose&lt;/span&gt; &lt;span class="err"&gt;down&lt;/span&gt;

&lt;span class="nl"&gt;explorer&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="err"&gt;explorer.exe&lt;/span&gt; &lt;span class="err"&gt;.&lt;/span&gt;

&lt;span class="nl"&gt;kill&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="err"&gt;docker&lt;/span&gt; &lt;span class="err"&gt;compose&lt;/span&gt; &lt;span class="err"&gt;kill&lt;/span&gt;

&lt;span class="nl"&gt;logs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="err"&gt;docker&lt;/span&gt; &lt;span class="err"&gt;compose&lt;/span&gt; &lt;span class="err"&gt;logs&lt;/span&gt; &lt;span class="err"&gt;--follow&lt;/span&gt;

&lt;span class="nl"&gt;start&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="nl"&gt;@printf "\e[1;033m%s\e[0m\n\n" "Starting your website. If the browser didn't open automatically, please surf to http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//127.0.0.1:8080 to open your site."&lt;/span&gt;
  &lt;span class="nl"&gt;-sensible-browser http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//localhost:8080 &amp;amp;&lt;/span&gt;

&lt;span class="nl"&gt;up&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="err"&gt;docker&lt;/span&gt; &lt;span class="err"&gt;compose&lt;/span&gt; &lt;span class="err"&gt;up&lt;/span&gt; &lt;span class="err"&gt;--detach&lt;/span&gt;

&lt;span class="nl"&gt;phpmyadmin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="nl"&gt;@printf "\e[1;033m%s\e[0m\n\n" "User is root and password is example. Please open http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//127.0.0.1:8089 to open phpmyadmin."&lt;/span&gt;
  &lt;span class="nl"&gt;@printf "\e[1;033m%s\e[0m\n\n" "Starting phpmyadmin. If the browser didn't open automatically, please surf to http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//127.0.0.1:8089 to open phpmyadmin."&lt;/span&gt;
  &lt;span class="nl"&gt;docker run --name phpmyadmin -d --link joomladb&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;db --network kingsbridge_default -p 8089:80 phpmyadmin&lt;/span&gt;
  &lt;span class="nl"&gt;-sensible-browser http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;//localhost:8089 &amp;amp;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure indentation is using tabs, not space.&lt;/p&gt;

&lt;p&gt;Save and close vscode.&lt;/p&gt;

&lt;p&gt;Make sure values are correct&lt;br&gt;
The &lt;code&gt;makefile&lt;/code&gt; here above contains hardcoded values like &lt;code&gt;joomla_db&lt;/code&gt; for the database name. Make sure these values are still correct when you'll reuse this file for other projects.&lt;/p&gt;

&lt;p&gt;The indentation in makefile &lt;strong&gt;SHOULD BE&lt;/strong&gt; made using tabs and not spaces, this is crucial. So please make sure, if your file didn't work, you know what to do.&lt;/p&gt;

&lt;p&gt;Now, instead of running f.i. &lt;code&gt;docker compose up --detach&lt;/code&gt; for running your Joomla site, just run &lt;code&gt;make up&lt;/code&gt;. Instead of running &lt;code&gt;docker run --name phpmyadmin -d --link joomladb:db --network kingsbridge_default -p 8089:80 phpmyadmin&lt;/code&gt; to start phpmyadmin, just run &lt;code&gt;make phpmyadmin&lt;/code&gt;. To launch the browser and surf on your site, it will be &lt;code&gt;make start&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Use printf to echo valuable information&lt;br&gt;
By typing &lt;code&gt;make phpmyadmin&lt;/code&gt;, it would be nice to see, on the console, the credentials to use and a small tip like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ make phpmyadmin
User is root and password is example. Please open http://127.0.0.1:8089 to open phpmyadmin.

docker run &lt;span class="nt"&gt;--name&lt;/span&gt; phpmyadmin &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--link&lt;/span&gt; joomladb:db &lt;span class="nt"&gt;--network&lt;/span&gt; kingsbridge_default &lt;span class="nt"&gt;-p&lt;/span&gt; 8089:80 phpmyadmin
a0c37edd9f8c139556f1f0a6b028ec5102362f16233efbc05f56d184edfb83c9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To do this, just use the &lt;code&gt;printf&lt;/code&gt; function like illustrated above.&lt;/p&gt;

&lt;p&gt;Please read my &lt;a href="https://github.com/cavo789/makefile_tips" rel="noopener noreferrer"&gt;Makefile - Tutorial and Tips &amp;amp; Tricks&lt;/a&gt; GitHub repository if you wish to learn more about Make.&lt;/p&gt;

&lt;p&gt;Feel free to add your own make instructions; can be multiline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final docker-compose.yml
&lt;/h3&gt;

&lt;p&gt;In the introduction of this article, I have said &lt;em&gt;we will learn how to use Docker to install Joomla and start a new website **in seconds&lt;/em&gt;**.&lt;/p&gt;

&lt;p&gt;This is how:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On your computer, create a folder for your new project (f.i. &lt;code&gt;mkdir ~/projects/my_new_project &amp;amp;&amp;amp; cd $_&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;In that folder, create a &lt;code&gt;docker-compose.yml&lt;/code&gt; file with this content:
&lt;/li&gt;
&lt;/ol&gt;

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

  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yourprojectname&lt;/span&gt;

  &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;joomla&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;joomla:5.0.0-php8.2-apache&lt;/span&gt;
      &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kingsbridge-app&lt;/span&gt;
      &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8080:80&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;JOOMLA_DB_HOST=joomladb&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;JOOMLA_DB_PASSWORD=example&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1000:1000&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./site_joomla:/var/www/html&lt;/span&gt;
      &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;joomladb&lt;/span&gt;

    &lt;span class="na"&gt;joomladb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:8.0.13&lt;/span&gt;
      &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kingsbridge-db&lt;/span&gt;
      &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_ROOT_PASSWORD=example&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1000:1000&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./db:/var/lib/mysql&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create your two sub-folders: &lt;code&gt;mkdir db site_joomla&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;docker compose up --detach&lt;/code&gt; to start Docker and create your containers&lt;/li&gt;
&lt;li&gt;Wait a few seconds and your new site is up.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Make sure, for each project, to update the &lt;code&gt;name:&lt;/code&gt; line and if you plan to be able to run your Joomla sites concurrently, make sure to update the port number for Joomla and chose a new one every time (can be &lt;code&gt;80&lt;/code&gt;, &lt;code&gt;81&lt;/code&gt;, &lt;code&gt;82&lt;/code&gt; and so one).&lt;/p&gt;

&lt;h2&gt;
  
  
  FrankenPHP instead of Apache
&lt;/h2&gt;

&lt;p&gt;A new player is entering the game: &lt;a href="https://frankenphp.dev/" rel="noopener noreferrer"&gt;FrankenPHP&lt;/a&gt;. This is a new application server which can be used instead of Apache or nginx. &lt;/p&gt;

&lt;p&gt;Based on their documentation, it is 3.5 faster than PHP FPM. If you want to learn how to run Joomla on FrankenPHP, please read this post article: &lt;a href="https://www.avonture.be/blog/frankenphp-docker-joomla" rel="noopener noreferrer"&gt;FrankenPHP, a modern application server for PHP&lt;/a&gt;. We'll discover the work of &lt;a href="https://github.com/alexandreelise/frankenphp-joomla" rel="noopener noreferrer"&gt;Alexandre Elisé&lt;/a&gt; on this.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>joomla</category>
      <category>php</category>
    </item>
    <item>
      <title>Using volumes with Docker, use cases</title>
      <dc:creator>Christophe Avonture</dc:creator>
      <pubDate>Fri, 24 Nov 2023 08:03:10 +0000</pubDate>
      <link>https://dev.to/cavo789/using-volumes-with-docker-use-cases-3k6c</link>
      <guid>https://dev.to/cavo789/using-volumes-with-docker-use-cases-3k6c</guid>
      <description>&lt;p&gt;When working with a Docker container, data can be persistent or not. Imagine you're creating a localhost website with Joomla, Wordpress or any other tool (Laravel, Symfony, etc.).&lt;/p&gt;

&lt;p&gt;You've perfectly created the various Docker files needed to run the local site, you've run the command &lt;code&gt;docker compose up --detach&lt;/code&gt; to start the containers and now you're busy installing the site.  After a few moments, your local site is up and you can start developing its functionalities.&lt;/p&gt;

&lt;p&gt;By default, if you haven't taken any precautions, the moment you stop the container (&lt;code&gt;docker compose down&lt;/code&gt;), you'll kill your site, i.e. by default, having not taken care to save your data (your site, your database), everything will be lost and reset the next time you run &lt;code&gt;docker compose up --detach&lt;/code&gt;. Well... Maybe that was your wish (something totally ephemeral); maybe not;&lt;/p&gt;

&lt;p&gt;To illustrate the notion of persistence, we're going to work with a Docker image that we'll create with our own little hands, and which will never be anything more than an execution counter. Each time the container is executed, you'll see "You have executed this script 1 time", and this number will increase with each execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creation of our Docker image
&lt;/h2&gt;

&lt;p&gt;For the illustration, please start a Linux shell and run &lt;code&gt;mkdir -p /tmp/counter &amp;amp;&amp;amp; cd $_&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now that you're in a temporary folder on your disk, please create a new file called &lt;code&gt;Dockerfile&lt;/code&gt; with this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine:3.14&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; counter.sh counter.sh&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x counter.sh

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["tail", "-f", "/dev/null"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please, too, create a file called &lt;code&gt;counter.sh&lt;/code&gt; with this content:&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="c"&gt;#!/usr/bin/env sh&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /data/counter.txt &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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /data
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Creating /data/counter.txt ..."&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"0"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /data/counter.txt
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /data/counter.txt&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"You have executed this script &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;counter&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; times."&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;counter&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /data/counter.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, just create the Docker image by running &lt;code&gt;docker build -t demo/counter .&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;❯ docker image list
REPOSITORY     TAG       IMAGE ID       CREATED          SIZE
demo/counter   latest    89505911ec33   21 minutes ago   5.61MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Can't be smaller&lt;br&gt;
As you can see, our image is really small. This is the advantage using the alpine Docker image.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using our image
&lt;/h2&gt;

&lt;p&gt;Now, it's time to create our &lt;code&gt;docker-compose.yml&lt;/code&gt; file with this content:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;counter&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo/counter&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll run our container by running &lt;code&gt;docker compose up --detach&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;❯ docker compose up &lt;span class="nt"&gt;--detach&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;+] Building 0.0s &lt;span class="o"&gt;(&lt;/span&gt;0/0&lt;span class="o"&gt;)&lt;/span&gt;                    docker:default
&lt;span class="o"&gt;[&lt;/span&gt;+] Running 3/3
 ✔ Network demo_default  Created           0.2s
 ✔ Volume &lt;span class="s2"&gt;"demo_data"&lt;/span&gt;    Created           0.1s
 ✔ Container counter     Started
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can verify our container is running using &lt;code&gt;docker container list&lt;/code&gt; (simplified output):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker container list
CONTAINER ID   IMAGE          STATUS          NAMES
6296459f7827   demo/counter   Up 30 seconds   counter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Calling our container for the first time
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;docker compose exec counter /counter.sh&lt;/code&gt; is the command to use to execute our script and we'll call it multiple times:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 1 times.

❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 2 times.

❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 3 times.

❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 4 times.

❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 5 times.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok so we have validated that our counter is working fine.&lt;/p&gt;

&lt;p&gt;What about if we stop the container and start it again by running &lt;code&gt;docker compose down ; docker compose up --detach&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Running our counter again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 1 times.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've lost our data&lt;br&gt;
As you can see, we've lost our counter. By stopping and starting the container, our data has been lost. And that's perfectly normal, because that's the intrinsic concept of a Docker container: it's ephemeral. &lt;strong&gt;A container should be disposable; by restarting it, the container is reset.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Introducing the notion of volume
&lt;/h2&gt;

&lt;p&gt;There are two types of volumes, the ones &lt;strong&gt;managed by Docker&lt;/strong&gt; and, on the other side, &lt;strong&gt;mounted volumes&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Volumes managed by Docker
&lt;/h3&gt;

&lt;p&gt;Update the &lt;code&gt;docker-compose.yml&lt;/code&gt; file like this:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;counter&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo/counter&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;counter_data:/data&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;As you can see, we're using a &lt;code&gt;volumes&lt;/code&gt; (always plural form) and we're saying that the &lt;code&gt;/data&lt;/code&gt; folder inside the container should be mapped to a volume called &lt;code&gt;counter_data&lt;/code&gt;. At the bottom of the &lt;code&gt;docker-compose.yml&lt;/code&gt; file, we are just declaring our volume.&lt;/p&gt;

&lt;p&gt;We'll start our container again: &lt;code&gt;docker compose down ; docker compose up --detach&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But now, we should have a Docker volume called &lt;code&gt;counter_data&lt;/code&gt;; let's check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker volume list
DRIVER    VOLUME NAME
&lt;span class="nb"&gt;local     &lt;/span&gt;demo_counter_data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, we've it.&lt;/p&gt;

&lt;p&gt;Let's try again some calls then stop/restart and a few calls then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
Creating /data/counter.txt ...
You have executed this script 1 times.
❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 2 times.
❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 3 times.
❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 4 times.
❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 5 times.
❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 6 times.

❯ docker compose down &lt;span class="p"&gt;;&lt;/span&gt; docker compose up &lt;span class="nt"&gt;--detach&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;+] Running 2/2
 ✔ Container counter     Removed    11.1s
 ✔ Network demo_default  Removed     0.5s
&lt;span class="o"&gt;[&lt;/span&gt;+] Building 0.0s &lt;span class="o"&gt;(&lt;/span&gt;0/0&lt;span class="o"&gt;)&lt;/span&gt;    docker:default
&lt;span class="o"&gt;[&lt;/span&gt;+] Running 2/2
 ✔ Network demo_default  Created     0.2s
 ✔ Container counter     Started     0.7s

❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 7 times.
❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 8 times.
❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 9 times.
❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 10 times.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, our counter was well persistent this time&lt;br&gt;
As you can see, by running &lt;code&gt;down&lt;/code&gt; followed by &lt;code&gt;up&lt;/code&gt;, we have kept the value of our counter. This value is saved in a file which is now stored in a Docker volume. As long as we don't delete the volume, our value will be preserved.&lt;/p&gt;

&lt;p&gt;You can remove the volume by running &lt;code&gt;docker volume rm demo_counter_data&lt;/code&gt; but:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker volume &lt;span class="nb"&gt;rm &lt;/span&gt;demo_counter_data
Error response from daemon: remove demo_counter_data: volume is &lt;span class="k"&gt;in &lt;/span&gt;use - &lt;span class="o"&gt;[&lt;/span&gt;b976c92eed6ed4e54f6ec75d652b8977bbbd86392e604216dd61d0c446e1fc0c]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Indeed, you can't remove a volume if there is still, at least, one container who use it so, you should run &lt;code&gt;docker compose down &amp;amp;&amp;amp; docker volume rm demo_counter_data&lt;/code&gt; or, simpler, &lt;code&gt;docker compose down --volumes&lt;/code&gt;. The &lt;code&gt;--volumes&lt;/code&gt; flag says to remove any volume declared in the &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;h4&gt;
  
  
  Location of the volumes
&lt;/h4&gt;

&lt;p&gt;Volumes are stored &lt;em&gt;somewhere&lt;/em&gt; on the disk by Docker, you don't need to take care about this.&lt;/p&gt;

&lt;p&gt;Just keep in mind that files are not saved in your folder; let's check this:&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;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; /tmp/counter

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-alh&lt;/span&gt;
total 28K
drwxr-xr-x  2 christophe christophe 4.0K Nov 22 09:40 &lt;span class="nb"&gt;.&lt;/span&gt;
drwxrwxrwt 28 root       root        12K Nov 22 09:35 ..
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;  1 christophe christophe  109 Nov 22 09:36 Dockerfile
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;  1 christophe christophe  287 Nov 22 10:00 counter.sh
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;  1 christophe christophe  190 Nov 22 10:09 docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Files are not stored in our project&lt;br&gt;
As you can see, we've only our files, not the counter. Files stored in a volume managed by Docker aren't stored in our project's directory.&lt;/p&gt;

&lt;p&gt;Location&lt;br&gt;
In fact, volumes are stored in &lt;code&gt;\\wsl$\docker-desktop-data\data\docker\volumes&lt;/code&gt; if you're running WSL but it's really a bad idea to access files directly from there. Let Docker do the job for you.&lt;/p&gt;
&lt;h4&gt;
  
  
  Accessing files in the volume
&lt;/h4&gt;
&lt;h4&gt;
  
  
  Using Docker Desktop
&lt;/h4&gt;

&lt;p&gt;One of the easiest ways to access the files contained in a volume is to use the Docker Desktop graphical interface.&lt;/p&gt;

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

&lt;p&gt;By clicking of the volume name (&lt;code&gt;demo_counter_data&lt;/code&gt; here)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3thyjshht9ktrpl8obev.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3thyjshht9ktrpl8obev.png" alt="Docker Desktop - Show the data folder" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By double-clicking on the filename, you'll start a basic text editor where you can, if you want, update the counter and save the change.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr194rxew9uhs9nwxemdd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr194rxew9uhs9nwxemdd.png" alt="Docker Desktop - Updating the counter" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A new call to our counter shows that we have hacked the number:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 51 times.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Using vscode
&lt;/h4&gt;

&lt;p&gt;But you can, too, use Visual Studio code to access files. &lt;/p&gt;

&lt;p&gt;First, if needed, install the Docker extension:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Press CTRL+SHIFT+X to display the &lt;code&gt;Extensions&lt;/code&gt; window of vscode,&lt;/li&gt;
&lt;li&gt;Search for the &lt;code&gt;Docker&lt;/code&gt; extension of Microsoft (make sure to search for &lt;code&gt;ms-azuretools.vscode-docker&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;and Install the extension&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, in the left pane, you'll see a new button for Docker. Click on it.&lt;/p&gt;

&lt;p&gt;In the new window, you'll get the list of containers, the list of images and other things.&lt;/p&gt;

&lt;p&gt;Deploy the list of containers, click on &lt;code&gt;demo/counter&lt;/code&gt; (our container) and display the list of files.&lt;/p&gt;

&lt;p&gt;Open the &lt;code&gt;data&lt;/code&gt; root folder and right-click on &lt;code&gt;counter.txt&lt;/code&gt;, our counter file and select &lt;code&gt;Open&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, you can edit that file from vscode, make changes and save them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv4k2ue7bsp9qv4ysfe8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv4k2ue7bsp9qv4ysfe8m.png" alt="VSCode - Accessing to files in the container" width="800" height="460"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
You have executed this script 101 times.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, accessing files using vscode works too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mounted volumes
&lt;/h3&gt;

&lt;p&gt;A mounted volume is synchronized with your hard disk. Instead of letting Docker manage everything for you, you'll decide where files should be stored.&lt;/p&gt;

&lt;p&gt;Let's make a few cleaning right now, please run &lt;code&gt;docker compose down --volumes&lt;/code&gt; to kill the volume used in the previous chapter and kill the docker container.&lt;/p&gt;

&lt;p&gt;Update the &lt;code&gt;docker-compose.yml&lt;/code&gt; file like this:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;counter&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo/counter&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./data:/data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The syntax now is, just a few, different: we don't have a &lt;code&gt;volumes&lt;/code&gt; entry at the bottom of the file but we've used a relative notation like &lt;code&gt;./data:/data&lt;/code&gt;.  So, the &lt;code&gt;./data&lt;/code&gt; local folder (on your hard disk) has to be synchronized with the &lt;code&gt;/data&lt;/code&gt; folder of the container.&lt;/p&gt;

&lt;p&gt;By running &lt;code&gt;docker compose up --detach &amp;amp;&amp;amp; docker compose exec counter /counter.sh&lt;/code&gt; we'll run our counter and expect to see &lt;code&gt;You have executed this script 1 times.&lt;/code&gt; but you'll probably get an error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
Creating /data/counter.txt ...
/counter.sh: line 6: can&lt;span class="s1"&gt;'t create /data/counter.txt: nonexistent directory
cat: can'&lt;/span&gt;t open &lt;span class="s1"&gt;'/data/counter.txt'&lt;/span&gt;: No such file or directory
You have executed this script 1 times.
/counter.sh: line 13: can&lt;span class="s1"&gt;'t create /data/counter.txt: nonexistent directory
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to create our local &lt;code&gt;data&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ &lt;span class="nb"&gt;mkdir &lt;/span&gt;data

❯ &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-alh&lt;/span&gt;
total 32K
drwxr-xr-x  3 christophe christophe 4.0K Nov 22 10:54 &lt;span class="nb"&gt;.&lt;/span&gt;
drwxrwxrwt 28 root       root        12K Nov 22 09:35 ..
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;  1 christophe christophe  109 Nov 22 09:36 Dockerfile
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;  1 christophe christophe  287 Nov 22 10:00 counter.sh
drwxr-xr-x  2 christophe christophe 4.0K Nov 22 10:54 data
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;  1 christophe christophe  149 Nov 22 10:48 docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we've our data folder, try again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ docker compose up &lt;span class="nt"&gt;--detach&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;counter /counter.sh
&lt;span class="o"&gt;[&lt;/span&gt;+] Building 0.0s &lt;span class="o"&gt;(&lt;/span&gt;0/0&lt;span class="o"&gt;)&lt;/span&gt;        docker:default
&lt;span class="o"&gt;[&lt;/span&gt;+] Running 2/2
 ✔ Network demo_default  Created         0.2s
 ✔ Container counter     Started         0.8s
Creating /data/counter.txt ...
You have executed this script 1 times.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time, the &lt;code&gt;counter.txt&lt;/code&gt; file is present in our directory:&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;ls&lt;/span&gt; &lt;span class="nt"&gt;-alh&lt;/span&gt; data
total 12K
drwxr-xr-x 2 christophe christophe 4.0K Nov 22 10:56 &lt;span class="nb"&gt;.&lt;/span&gt;
drwxr-xr-x 3 christophe christophe 4.0K Nov 22 10:54 ..
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 root       root          2 Nov 22 10:56 counter.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oups, the file is owned by &lt;code&gt;root&lt;/code&gt; not me&lt;br&gt;
Uh oh! The file is owned by the root user and not me (i.e. user &lt;code&gt;christophe&lt;/code&gt; in my case). That's annoying since I can't edit it or remove it without using &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The file is owned by &lt;code&gt;root&lt;/code&gt; because the current user; used inside the container, is the &lt;code&gt;root&lt;/code&gt; user. We need to inform Docker that he has to use ours.&lt;/p&gt;

&lt;p&gt;To do this, we'll update once more our &lt;code&gt;docker-compose.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;counter&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo/counter&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1000:1000&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./data:/data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why 1000:1000?&lt;br&gt;
We need to pass to Docker our current user id and group id so Docker will be able to create files/folders using our user. To get your current user id and group id, just run &lt;code&gt;echo "$(id -u):$(id -g)"&lt;/code&gt; in the console and, you'll see, the first created user (after the installation of Linux) is, always, user id 1000, group id 1000. Most probably you.&lt;/p&gt;

&lt;p&gt;Let's try again but, first remove the incorrect file: &lt;code&gt;sudo rm -f data/counter.txt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then run &lt;code&gt;docker compose down &amp;amp;&amp;amp; docker compose up --detach &amp;amp;&amp;amp; docker compose exec counter /counter.sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, the file will be yours:&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;ls&lt;/span&gt; &lt;span class="nt"&gt;-alh&lt;/span&gt; data
total 12K
drwxr-xr-x 2 christophe christophe 4.0K Nov 22 10:56 &lt;span class="nb"&gt;.&lt;/span&gt;
drwxr-xr-x 3 christophe christophe 4.0K Nov 22 10:54 ..
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 christophe christophe    2 Nov 22 10:56 counter.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;We've seen three ways of playing with data:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We don't care about data,&lt;/li&gt;
&lt;li&gt;We rely on Docker to manage the volume for us and&lt;/li&gt;
&lt;li&gt;We really value our data and want it to be part of our project.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Depending on your needs, you can opt for one of three solutions.&lt;/p&gt;

&lt;p&gt;You want to &lt;em&gt;play&lt;/em&gt; with a Docker container, test it, learn from it... You don't want to keep any traces on your hard disk. The first solution is perfect here i.e. don't matter about volumes.&lt;/p&gt;

&lt;p&gt;You want to test but also keep the data somewhere without &lt;em&gt;polluting&lt;/em&gt; your hard disk. You're working on something temporary, so you may want to keep the data, but you can't be sure. The second solution will suit you best i.e. self managed volumes.&lt;/p&gt;

&lt;p&gt;On the contrary, your work is important and you don't want to lose anything. Your data must be saved on your hard disk. The third solution will be the one you use i.e. mounted volumes.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Working with Laravel events</title>
      <dc:creator>Christophe Avonture</dc:creator>
      <pubDate>Sun, 19 Feb 2023 06:51:30 +0000</pubDate>
      <link>https://dev.to/cavo789/working-with-laravel-events-2i6m</link>
      <guid>https://dev.to/cavo789/working-with-laravel-events-2i6m</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;How to dispatch an event and process returned values&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You need to run an event having one or more listeners and, in your main code, you wish to retrieve some values once listeners have done their job.&lt;/p&gt;

&lt;p&gt;In our example below, we'll fire a &lt;code&gt;SampleEvent&lt;/code&gt; class and his &lt;code&gt;SampleListener&lt;/code&gt;. The idea is to initialize an &lt;code&gt;employee&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;File &lt;code&gt;app/Providers/EventServiceProvider.php&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$listen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;SampleEvent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nc"&gt;SampleListener&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For our sample, your &lt;code&gt;routes/web.php&lt;/code&gt; can looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Employee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Events\SampleEvent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$employee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nc"&gt;SampleEvent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$employee&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'FIRSTNAME is '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$employee&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getFirstName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'NAME      is '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$employee&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getLastName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'PSEUDO    is '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$employee&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPseudo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we do is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new &lt;code&gt;employee&lt;/code&gt; based on the &lt;code&gt;Employee&lt;/code&gt; class,&lt;/li&gt;
&lt;li&gt;Call our &lt;code&gt;SampleEvent&lt;/code&gt; event and give our new &lt;code&gt;employee&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;Let the magic happens,&lt;/li&gt;
&lt;li&gt;Display the employee's first and last name.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here, by default, our employee.&lt;/p&gt;

&lt;h2&gt;
  
  
  File app/Employee.php
&lt;/h2&gt;

&lt;p&gt;This class will initialize our employee and provide setters and getters.&lt;/p&gt;

&lt;p&gt;By default, our employee will be called &lt;code&gt;John Doe (cavo789)&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Employee&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$firstname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'John'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$lastname&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Doe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$pseudo&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'cavo789'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getFirstName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setFirstName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$firstname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$firstname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getLastName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setLastName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$lastname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lastname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$lastname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getPseudo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;pseudo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setPseudo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$pseudo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;pseudo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$pseudo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  File app/Events/SampleEvent.php
&lt;/h2&gt;

&lt;p&gt;Our event will receive an employee and make it private.&lt;/p&gt;

&lt;p&gt;Make three setters public to allow listeners to update the first and the last name. Also allow to initialize the pseudo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Events&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Employee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Events\Dispatchable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SampleEvent&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Dispatchable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;Employee&lt;/span&gt; &lt;span class="nv"&gt;$employee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setFirstName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$firstname&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;employee&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setFirstName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$firstname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setLastName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$lastname&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;employee&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setLastName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$lastname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setPseudo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$pseudo&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;employee&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setPseudo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pseudo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  File app/Listeners/SampleListener.php
&lt;/h2&gt;

&lt;p&gt;Our listener logic. &lt;code&gt;SampleListener&lt;/code&gt; will receive the &lt;code&gt;SampleEvent&lt;/code&gt; as parameter and, thus, has access to all his public methods. We'll here update the first and the lastname, we'll not update the pseudo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Listeners&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Events\SampleEvent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SampleListener&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;SampleEvent&lt;/span&gt; &lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$event&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setFirstName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Georges'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setLastName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Washington'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;If we run &lt;code&gt;curl localhost&lt;/code&gt; in the console, we'll get the output below showing us it has worked perfectly as expected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;FIRSTNAME is Georges
NAME      is Washington
PSEUDO    is cavo789
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we edit back the &lt;code&gt;app/Providers/EventServiceProvider.php&lt;/code&gt; file and comment the listener like below illustrated, our code will still works&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$listen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;SampleEvent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="c1"&gt;// SampleListener::class,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;FIRSTNAME is John
NAME      is Doe
PSEUDO    is cavo789
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Photo credit: &lt;a href="https://unsplash.com/@jasonrosewell?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Jason Rosewell&lt;/a&gt; on &lt;a href="https://unsplash.com/fr/photos/ASKeuOZqhYU?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Docker - Run/Refactor PHP code from a web interface</title>
      <dc:creator>Christophe Avonture</dc:creator>
      <pubDate>Sat, 01 Jan 2022 11:11:31 +0000</pubDate>
      <link>https://dev.to/cavo789/docker-runrefactor-php-code-from-a-web-interface-1ffn</link>
      <guid>https://dev.to/cavo789/docker-runrefactor-php-code-from-a-web-interface-1ffn</guid>
      <description>&lt;p&gt;As a loyal reader of several forums for years, I frequently find unreadable PHP code posted by beginners asking for help. Before we can try to help them, it is sometimes useful to reformat the code and rewrite it partially. This can take times...&lt;/p&gt;

&lt;p&gt;To execute the code to see where the problem is before fixing it, I have been using the &lt;a href="https://github.com/websiteduck/Run-PHP-Code" rel="noopener noreferrer"&gt;Run-PHP-Code&lt;/a&gt; tool for a few years but it does not meet the need for reformatting (&lt;a href="https://github.com/FriendsOfPHP/PHP-CS-Fixer" rel="noopener noreferrer"&gt;php-cs-fixer&lt;/a&gt; / &lt;a href="https://github.com/squizlabs/PHP_CodeSniffer/" rel="noopener noreferrer"&gt;php code-beautifier&lt;/a&gt;) or refactoring (&lt;a href="https://github.com/rectorphp/rector" rel="noopener noreferrer"&gt;rector&lt;/a&gt;). Second disadvantage here (since I don't trust the PHP code), &lt;em&gt;Run-PHP-Code&lt;/em&gt; is running on my localhost i.e. on my machine and that can represent a risk (creation/deletion of files, ...). The ideal is to execute the code in a sandbox.&lt;/p&gt;

&lt;p&gt;It had been a while since I wanted to do it: I took some hours to take the code of &lt;em&gt;Run-PHP-Code&lt;/em&gt; to make his own Docker image, based on PHP 7.4.26 (version 1.0) or 8.1 (version 1.1) and thus to allow to run it in a secure environment.&lt;/p&gt;

&lt;p&gt;I also took the time to add a "refactor" button which then calls php-cs-fixer, phpcbf and Rector.&lt;/p&gt;

&lt;p&gt;The result is this ready-to-use Docker image: &lt;a href="https://hub.docker.com/r/cavo789/runcode" rel="noopener noreferrer"&gt;https://hub.docker.com/r/cavo789/runcode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In only two CLI commands, you will have a web interface with an editor where, on the left side, you can copy/paste or type a PHP code and on the right side visualize the result of its execution (button &lt;code&gt;Run&lt;/code&gt;) or its refactoring (button &lt;code&gt;Refactor&lt;/code&gt;); the whole running in a Docker container and thus isolated from your machine. &lt;/p&gt;

&lt;p&gt;Pretty easy and helpful when trying to give support on forums.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F25uvrxisg07nwr7sygsz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F25uvrxisg07nwr7sygsz.png" alt="Run and refactor php from an isolated environment" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>php</category>
      <category>tooling</category>
      <category>refactorit</category>
    </item>
  </channel>
</rss>
