<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Jesus&#39;s Blog Posts</title>
  <subtitle>An archive of cool projects I have worked on.</subtitle>
  <link href="https://jesus.twk95.com/feed.xml" rel="self" />
  <link href="https://jesus.twk95.com/" />
  <updated>2025-09-21T00:00:00Z</updated>
  <id>https://jesus.twk95.com/</id>
  <author>
    <name>Jesus Otero Lagunes</name>
  </author>
  <entry>
    <title>Custom Docker containers in Cisco Modeling Labs!</title>
    <link href="https://jesus.twk95.com/blog/custom-docker-containers-in-cisco-modeling-labs/" />
    <updated>2025-09-21T00:00:00Z</updated>
    <id>https://jesus.twk95.com/blog/custom-docker-containers-in-cisco-modeling-labs/</id>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://jesus.twk95.com/assets/images/9.21.25/cml+docker.webp#center&quot; alt=&quot;Banner Image&quot;&gt;
&lt;br&gt;
It&#39;s no surprise I&#39;m very fascinated by Docker containers, just ask my wife! So when &lt;a href=&quot;https://www.cisco.com/site/us/en/learn/training-certifications/training/modeling-labs/index.html&quot;&gt;Cisco Modeling Labs&lt;/a&gt; (CML) added support for Docker, you can imagine I was excited for the possibilities that opened up. This new version 2.9 comes with some pretty cool baked-in images like TACPlus, FreeRadius, and even a Dnsmasq server! But what if you want to run your own docker image? Like maybe this same website??&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;What You Need&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;An instance of CML 2.9 or higher&lt;/li&gt;
&lt;li&gt;A Docker image you&#39;d like to use&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;Prepping The Image&lt;/h2&gt;
&lt;p&gt;I deploy this website in production using a &lt;a href=&quot;https://docs.docker.com/build/concepts/dockerfile/&quot;&gt;Dockerfile&lt;/a&gt; and my own container registry, but for brevity&#39;s sake, let&#39;s assume you have either built your own image already or pulled one from some registry. Either way, we will need to bundle it up to use it in CML.
&lt;br&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First let&#39;s see what images we have locally. Run &lt;code&gt;docker image ls&lt;/code&gt; to verify your image is available.&lt;/p&gt;&lt;pre class=&quot;command-line language-bash&quot; data-user=&quot;jesus&quot; data-host=&quot;desktop&quot; data-output=&quot;2-5&quot;&gt;
&lt;code class=&quot;language-bash&quot;&gt;docker image ls
REPOSITORY                      TAG               IMAGE ID       CREATED        SIZE
git.twk95.com/twk95/11ty-site   latest            11b0c9d9ec70   8 hours ago    131MB
linuxserver/wireguard           latest            6c92a81d85f6   2 days ago     118MB
moby/buildkit                   buildx-stable-1   44f5d48d5c6c   2 months ago   219MB&lt;/code&gt;
&lt;/pre&gt;&lt;br&gt;&lt;p&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use the &lt;code&gt;docker save&lt;/code&gt; command to archive the image for CML. We&#39;ll be using my &lt;code&gt;twk95/11ty-site&lt;/code&gt; image for this example.&lt;/p&gt;&lt;pre class=&quot;command-line language-bash&quot; data-user=&quot;jesus&quot; data-host=&quot;desktop&quot; data-output=&quot;3&quot;&gt;
&lt;code class=&quot;language-bash&quot;&gt;docker save -o jesus.twk95.com.tar git.twk95.com/twk95/11ty-site:latest
ls
jesus.twk95.com.tar&lt;/code&gt;
&lt;/pre&gt;&lt;br&gt;&lt;p&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Before we leave the terminal, we have to grab one more thing. Run &lt;code&gt;docker image inspect&lt;/code&gt; to output the image&#39;s checksum. Keep this handy, as we&#39;ll need it in CML.&lt;/p&gt;&lt;pre class=&quot;command-line language-bash&quot; data-user=&quot;jesus&quot; data-host=&quot;desktop&quot; data-output=&quot;2&quot;&gt;
&lt;code class=&quot;language-bash&quot;&gt;docker image inspect -f &#39;{{ index .Id }}&#39; git.twk95.com/twk95/11ty-site:latest
sha256:11b0c9d9ec70cb97832fa98029cf0e3548466760646d7431c19a4cc427bc83e0&lt;/code&gt;
&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;Upload to CML&lt;/h2&gt;
&lt;p&gt;Next, head to CML. Navigate to &lt;code&gt;Tools &amp;gt; Node and Image Definitions &amp;gt; Image Definitions&lt;/code&gt; and upload the .tar file we just created. I&#39;m running WSL2, so it is easy enough to open the Linux folder in Windows and upload it to CML.
&lt;img src=&quot;https://jesus.twk95.com/assets/images/9.21.25/cml-upload.webp#center&quot; alt=&quot;Upload prompt in CML&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Create a Node Definition&lt;/h2&gt;
&lt;p&gt;This next part is lengthy so feel free to download an existing node definition and tweak as needed. Any options not mentioned here are optional. Refer to the CML &lt;a href=&quot;https://developer.cisco.com/docs/modeling-labs/creating-a-new-node-definition/&quot;&gt;Node Definition docs&lt;/a&gt; for more information.&lt;/p&gt;
&lt;h3&gt;General&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ID&lt;/td&gt;
&lt;td&gt;jesus.twk95.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Description&lt;/td&gt;
&lt;td&gt;My website (Docker)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nature&lt;/td&gt;
&lt;td&gt;server&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;User Interface&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Prefix&lt;/td&gt;
&lt;td&gt;jesus-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Icon&lt;/td&gt;
&lt;td&gt;server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Label&lt;/td&gt;
&lt;td&gt;jesus.twk95.com&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Linux Native Simulation&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Domain Driver&lt;/td&gt;
&lt;td&gt;Docker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simulation Driver&lt;/td&gt;
&lt;td&gt;server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disk Driver&lt;/td&gt;
&lt;td&gt;VirtIO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAM&lt;/td&gt;
&lt;td&gt;1024&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPUs&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Interfaces&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Has a Loopback Interface&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Number of serial ports&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface 0&lt;/td&gt;
&lt;td&gt;eth0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Boot&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Timeout&lt;/td&gt;
&lt;td&gt;30 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Provisioning&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Enable Provisioning&lt;/td&gt;
&lt;td&gt;Enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Media Type&lt;/td&gt;
&lt;td&gt;RAW&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration Disk Volume Name&lt;/td&gt;
&lt;td&gt;cfg&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+ ADD FILE&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;td&gt;config.json&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Editable&lt;/td&gt;
&lt;td&gt;Enable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content&lt;/td&gt;
&lt;td&gt;&lt;em&gt;See below&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+ ADD FILE&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;td&gt;boot.sh&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Editable&lt;/td&gt;
&lt;td&gt;Enable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content&lt;/td&gt;
&lt;td&gt;&lt;em&gt;See below&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;config.json&lt;/h3&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;docker&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;image&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;git.twk95.com/twk95/11ty-site:latest&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;mounts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;type=bind,source=cfg/boot.sh,target=/boot.sh&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;shell&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/bin/bash&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;day0cmd&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/bin/bash&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/boot.sh&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;busybox&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;boot.sh&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# insert more commands here&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# ip address add dev eth0 10.0.0.1/24&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# ip link set dev eth0 up&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# keep the next line to indicate that the machine is ready&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;READY&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;/dev/console
&lt;span class=&quot;token builtin class-name&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;Create an Image Definition&lt;/h2&gt;
&lt;p&gt;Click on the &lt;code&gt;Create New Image Definition&lt;/code&gt; button then use the template below to fill out the form. Again, tweak as needed.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ID&lt;/td&gt;
&lt;td&gt;jesus.twk95.com-v1.4.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Label&lt;/td&gt;
&lt;td&gt;jesus.twk95.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Description&lt;/td&gt;
&lt;td&gt;My website in Docker!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node Definition&lt;/td&gt;
&lt;td&gt;jesus.twk95.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disk Image&lt;/td&gt;
&lt;td&gt;jesus.twk95.com.tar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disk Hash&lt;/td&gt;
&lt;td&gt;&lt;em&gt;checksum from earlier&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;Finally ready to test!&lt;/h2&gt;
&lt;p&gt;Here&#39;s the big moment! Create a new lab in CML and add a few things&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An external connector, I prefer to use a bridge with my actual network&lt;/li&gt;
&lt;li&gt;An unmanaged switch&lt;/li&gt;
&lt;li&gt;Your new docker node definition&lt;/li&gt;
&lt;li&gt;Optionally, a host to test the container! I&#39;m using the Chrome container&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Lab setup&lt;/h3&gt;
&lt;div class=&quot;mermaid&quot;&gt;
graph LR
subgraph &quot;Host Machine&quot;
direction TB
subgraph &quot;CML&quot;
Docker[Custom Docker Node]
Switch[Unmanaged Switch]
ExtConn[External Connector]
Chrome[Chrome Container]
Docker &lt;--&gt; Switch
Chrome &lt;--&gt; Switch
Switch &lt;--&gt; ExtConn
end
HomeNet[Home Network]
ExtConn &lt;--&gt; HomeNet
end
&lt;/div&gt;
&lt;h3&gt;Final test&lt;/h3&gt;
&lt;p&gt;Click the custom Docker container and check the IP address, then use that IP to test your new container!
Hopefully all went well, and you can connect to your container from the host machine like below!
&lt;img src=&quot;https://jesus.twk95.com/assets/images/9.21.25/final-test.webp#center&quot; alt=&quot;Website-ception&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;It was a lengthy setup, but it is very rewarding seeing my website hosted locally in CML, even if its only purpose is to verify connectivity for my labs. Also big shout out to &lt;code&gt;Jens Albrecht&lt;/code&gt; from the Cisco Community Knowledge Base. He made a very in-depth tutorial for Radius in CML 2.9, and this blog post relied heavily on that. Linked below, go mark his post as helpful! And as always, if you have any questions, feel free to &lt;a href=&quot;https://jesus.twk95.com/#contact&quot;&gt;reach out&lt;/a&gt;!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://community.cisco.com/t5/cisco-modeling-labs-knowledge-base/how-to-create-your-own-docker-container-for-cml-2-9/ta-p/5322346#toc-hId-628485567&quot;&gt;https://community.cisco.com/t5/cisco-modeling-labs-knowledge-base/how-to-create-your-own-docker-container-for-cml-2-9/ta-p/5322346#toc-hId-628485567&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.cisco.com/docs/modeling-labs/creating-a-new-node-definition/&quot;&gt;https://developer.cisco.com/docs/modeling-labs/creating-a-new-node-definition/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/build/concepts/dockerfile/&quot;&gt;https://docs.docker.com/build/concepts/dockerfile/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  <entry>
    <title>An Eleventy Showcase!</title>
    <link href="https://jesus.twk95.com/blog/an-eleventy-showcase/" />
    <updated>2025-08-30T00:00:00Z</updated>
    <id>https://jesus.twk95.com/blog/an-eleventy-showcase/</id>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://jesus.twk95.com/assets/images/8.30.25/11ty.webp#center&quot; alt=&quot;Banner Image&quot;&gt;
&lt;br&gt;
Welcome back to my blog! This one is a brief post. Just a showcase of what Eleventy can do with Markdown!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;What is Eleventy?&lt;/h2&gt;
&lt;p&gt;Eleventy (or 11ty) is a simpler static site generator. It&#39;s written in JavaScript and transforms a directory of templates of various types into a folder of plain HTML files. It&#39;s known for its flexibility, speed, and the fact that it doesn&#39;t ship any client-side JavaScript by default.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Markdown Features&lt;/h2&gt;
&lt;p&gt;Eleventy has excellent support for Markdown. Here are some examples of what you can do.&lt;/p&gt;
&lt;h3&gt;Basic Formatting&lt;/h3&gt;
&lt;p&gt;You can use &lt;strong&gt;bold text&lt;/strong&gt;, &lt;em&gt;italic text&lt;/em&gt;, and even &lt;em&gt;&lt;strong&gt;both&lt;/strong&gt;&lt;/em&gt;. You can also create links, like this one to the &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;official Eleventy website&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Lists&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Unordered list item 1&lt;/li&gt;
&lt;li&gt;Unordered list item 2
&lt;ul&gt;
&lt;li&gt;Nested item&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;Ordered list item 1&lt;/li&gt;
&lt;li&gt;Ordered list item 2&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Code Blocks&lt;/h3&gt;
&lt;p&gt;You can include inline code like &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; within a sentence. For larger code blocks, you can use fenced code blocks with syntax highlighting:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// This is a JavaScript code block&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;greet&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Hello, &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;greet&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;World&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Tables&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&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;Templating&lt;/td&gt;
&lt;td&gt;Supports over 10 different templating languages.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Cascade&lt;/td&gt;
&lt;td&gt;Merge data from different sources to use in your templates.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Blockquotes&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;The web should be a platform for creativity and expression. Eleventy helps make that a reality.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Markdown Plugins&lt;/h3&gt;
&lt;p&gt;You can extend Markdown&#39;s functionality with plugins. For example, with &lt;code&gt;markdown-it-emoji&lt;/code&gt;, you can write things like :tada: and get 🎉.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Templating and Data&lt;/h2&gt;
&lt;p&gt;Eleventy can use data from JSON or JavaScript files. Imagine you have a &lt;code&gt;_data/users.json&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Alice&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;role&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Developer&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bob&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;role&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Designer&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    ...
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You could then use a templating language like Nunjucks within your Markdown file to loop through this data:&lt;/p&gt;
&lt;h3&gt;Team Members:&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Alice&lt;/strong&gt; - Developer&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Bob&lt;/strong&gt; - Designer&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Charlie&lt;/strong&gt; - Project Manager&lt;/li&gt;&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;Shortcodes&lt;/h2&gt;
&lt;p&gt;Shortcodes are reusable snippets of content. You could create a shortcode for a callout box like this:&lt;/p&gt;
&lt;div class=&quot;panel panel-accent&quot; role=&quot;alert&quot; style=&quot;margin: 1.5rem 0;&quot;&gt;
              &lt;div style=&quot;font-family: var(--font-mono); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--accent); margin-bottom: 0.5rem;&quot;&gt;Heads up!&lt;/div&gt;
              &lt;div style=&quot;color: var(--text-primary);&quot;&gt;
This is a custom callout box created with a shortcode. It&#39;s a great way to create reusable components.
&lt;/div&gt;
            &lt;/div&gt;
&lt;hr&gt;
&lt;h2&gt;Layouts&lt;/h2&gt;
&lt;p&gt;Layouts allow you to wrap your content in a parent template. For example, this entire page could be a Markdown file that uses a main layout file to provide the header, footer, and overall page structure. This avoids repeating the same HTML in every file.&lt;/p&gt;
&lt;p&gt;In your Markdown file&#39;s front matter, you would specify the layout like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
layout: post.njk
title: My Awesome Page
---
Your Markdown content goes here...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;References:&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/languages/markdown/&quot;&gt;https://www.11ty.dev/docs/languages/markdown/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/layouts/&quot;&gt;https://www.11ty.dev/docs/layouts/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/plugins/&quot;&gt;https://www.11ty.dev/docs/plugins/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  <entry>
    <title>Junos ZTP with Dnsmasq DHCP in OPNsense</title>
    <link href="https://jesus.twk95.com/blog/junos-ztp-with-dnsmasq-dhcp-in-opnsense/" />
    <updated>2025-08-14T00:00:00Z</updated>
    <id>https://jesus.twk95.com/blog/junos-ztp-with-dnsmasq-dhcp-in-opnsense/</id>
    <content type="html">&lt;p&gt;&lt;img src=&quot;https://jesus.twk95.com/assets/images/8.14.25/junos+opnsense.webp#center&quot; alt=&quot;Banner Image&quot;&gt;
&lt;br&gt;
Most people know that DHCP (Dynamic Host Configuration Protocol) is a protocol used to dynamically allocate IP addresses. But did you know that it can be used to configure other host device settings? Network device vendors like Junip... &lt;em&gt;ermm&lt;/em&gt;, HPE Networking... take advantage of DHCP to implement &amp;quot;Zero Touch Provisioning&amp;quot; and even perform software upgrades for out-of-the-box devices. Here I will show you how to use OPNsense with Dnsmasq DHCP to &amp;quot;auto-provision&amp;quot; your Junos devices.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Requirements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;At least one zeroized Junos device.&lt;/li&gt;
&lt;li&gt;A Junos base configuration file saved on an (S)FTP server.&lt;/li&gt;
&lt;li&gt;An (S)FTP server in your network reachable by the Junos device(s).&lt;/li&gt;
&lt;li&gt;An OPNsense device with Dnsmasq DHCP enabled&lt;sup&gt;&lt;a href=&quot;https://jesus.twk95.com/blog/junos-ztp-with-dnsmasq-dhcp-in-opnsense/#bottom&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;li&gt;An understanding of OPNsense firewall rules&lt;sup&gt;&lt;a href=&quot;https://jesus.twk95.com/blog/junos-ztp-with-dnsmasq-dhcp-in-opnsense/#bottom&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;li&gt;A hex converter. &lt;a href=&quot;https://www.rapidtables.com/convert/number/ascii-to-hex.html&quot;&gt;Link to the one I used here&lt;/a&gt;.&lt;sup&gt;&lt;a href=&quot;https://jesus.twk95.com/blog/junos-ztp-with-dnsmasq-dhcp-in-opnsense/#bottom&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;Junos Base Configuration&lt;/h2&gt;
&lt;p&gt;Below is a very simple base config to allow SSH, but I highly recommend you set up your own. Try configuring a Junos device once with some basic configuration, then use that to create your own template. Remember, this will apply to &lt;em&gt;all&lt;/em&gt; out-of-the-box devices that pull a DHCP address.&lt;/p&gt;
&lt;pre class=&quot;language-conf&quot;&gt;&lt;code class=&quot;language-conf&quot;&gt;system {
    root-authentication {
        encrypted-password &quot;$6$9rdHQ5nJ$ilwzYPYghLkr9mXFVLrXRKnOaj.jhIDwYLT31w0//bunn1JSPUxVNEkGuoBoRinJrMiOKJKLCWsuLmyBcejzD0&quot;; ## SECRET-DATA
    }
    services {
        ssh {
            protocol-version v2;
        }
    }
}
interfaces {
    fxp0 {
        unit 0 {
            family inet {
                dhcp;
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
&lt;p&gt;The root password here is set to &lt;code&gt;Tut0ria1!&lt;/code&gt;. Feel free to customize your base config as needed! Add non-root users, ssh keys, a management routing instance, name-servers, default routes, the list goes on!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Configuring DHCP Option 43 Suboptions&lt;/h2&gt;
&lt;p&gt;This is the tricky part that really makes or breaks the setup. Before we start, we have to decide on a few things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The config filename.&lt;/li&gt;
&lt;li&gt;The file transfer method. (FTP, SFTP, etc.)&lt;/li&gt;
&lt;li&gt;The character length of #1 and #2.&lt;/li&gt;
&lt;li&gt;Any other suboptions you&#39;re configuring.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For this example we are using the filename &lt;code&gt;init.conf&lt;/code&gt; and the &lt;code&gt;FTP&lt;/code&gt; protocol. The filename is 9 characters long and the protocol is 3. Easy enough right?
&lt;br&gt;&lt;/p&gt;
&lt;h3&gt;Playing with hex&lt;/h3&gt;
&lt;p&gt;To encode all of this info for DHCP option 43, we will need a hex converter to put it all together. The order for combining them is as follows: &lt;code&gt;suboption&lt;/code&gt; + &lt;code&gt;length&lt;/code&gt; + &lt;code&gt;value&lt;/code&gt;. This can be repeated for all suboptions you&#39;re configuring.&lt;/p&gt;
&lt;div class=&quot;panel panel-accent&quot; role=&quot;alert&quot; style=&quot;margin: 1.5rem 0;&quot;&gt;
              &lt;div style=&quot;font-family: var(--font-mono); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--accent); margin-bottom: 0.5rem;&quot;&gt;Heads up!&lt;/div&gt;
              &lt;div style=&quot;color: var(--text-primary);&quot;&gt;
Be sure to convert integers like the suboption and value length from &lt;b&gt;decimal&lt;/b&gt; to hex. Using ASCII to hex can provide different results.
&lt;/div&gt;
            &lt;/div&gt;
&lt;h3&gt;Suboption 1&lt;/h3&gt;
&lt;p&gt;Junos uses this suboption to set the config filename. For this example, we will use suboption &lt;code&gt;1&lt;/code&gt; + &lt;code&gt;9&lt;/code&gt; + &lt;code&gt;init.conf&lt;/code&gt;. Converting these to hex individually (with colon separators) becomes &lt;code&gt;01&lt;/code&gt; + &lt;code&gt;09&lt;/code&gt; + &lt;code&gt;69:6E:69:74:2E:63:6F:6E:66&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Suboption 3&lt;/h3&gt;
&lt;p&gt;This suboption is used by Junos devices to specify the file transfer protocol. The same process applies here: convert and combine. Suboption &lt;code&gt;3&lt;/code&gt; + &lt;code&gt;3&lt;/code&gt; + &lt;code&gt;FTP&lt;/code&gt; becomes &lt;code&gt;03&lt;/code&gt; + &lt;code&gt;03&lt;/code&gt; + &lt;code&gt;66:74:70&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Putting it all together&lt;/h3&gt;
&lt;p&gt;Once you&#39;ve performed your conversions, combine them all like so: &lt;code&gt;01:09:69:6E:69:74:2E:63:6F:6E:66:03:03:66:74:70&lt;/code&gt;. You should be good to move on to the next step. Unless...&lt;/p&gt;
&lt;h3&gt;Go the extra mile&lt;/h3&gt;
&lt;p&gt;If you have physical Junos devices you can also perform a software upgrade using ZTP. Suboptions 0 or 4 can be used to specify a software image for upgrades. Use the same steps as above to convert the suboptions and combine them. More Junos ZTP &lt;a href=&quot;https://www.juniper.net/documentation/us/en/software/junos/junos-install-upgrade/topics/topic-map/zero-touch-provision.html&quot;&gt;info here&lt;/a&gt;&lt;sup&gt;&lt;a href=&quot;https://jesus.twk95.com/blog/junos-ztp-with-dnsmasq-dhcp-in-opnsense/#bottom&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;OPNsense Settings&lt;/h2&gt;
&lt;h3&gt;Dnsmasq DHCP&lt;/h3&gt;
&lt;p&gt;This guide assumes you have OPNsense in your network already handing out old boring DHCP leases using Dnsmasq on a predetermined VLAN. If you&#39;re already there thankfully OPNsense makes it easy to just add some DHCP options.&lt;/p&gt;
&lt;h3&gt;DHCP options tab&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the DHCP Options tab in OPNsense. In the &#39;Options&#39; section click the plus to add a your first DHCP option.&lt;/li&gt;
&lt;li&gt;Configure Option 150 like shown. Be sure to select the interface that your network devices are using and the IP of your FTP server.
&lt;img src=&quot;https://jesus.twk95.com/assets/images/8.14.25/option150.webp&quot; alt=&quot;Option 150 Settings&quot;&gt;&lt;/li&gt;
&lt;li&gt;Click add again and now we add Option 43 like so. Use the hex value you calculated earlier here.
&lt;img src=&quot;https://jesus.twk95.com/assets/images/8.14.25/option43.webp&quot; alt=&quot;Option 43 Settings&quot;&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Firewall rules&lt;/h3&gt;
&lt;p&gt;OPNsense will open up the port needed for DHCP but you will need to create your own firewall rule for the file transfer protocol you&#39;re using.
&lt;br&gt;
&lt;br&gt;
In this case I am using my NAS to host the FTP server so my config looks like so:
&lt;img src=&quot;https://jesus.twk95.com/assets/images/8.14.25/firewallrule.webp&quot; alt=&quot;FTP Firewall Rule&quot;&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Be sure to apply the changes as needed!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Finally, Zero Touch Provisioning!&lt;/h2&gt;
&lt;p&gt;Now that you have your configuration file, ftp server, and firewall rules in place you can finally provision your devices!
&lt;br&gt;
&lt;br&gt;
Connect your Junos devices to management and boot them up! Once up, assuming all goes well, then you should get something like this:&lt;/p&gt;
&lt;pre class=&quot;language-log&quot;&gt;&lt;code class=&quot;language-log&quot;&gt;root&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; 
&lt;span class=&quot;token property&quot;&gt;Auto Image Upgrade:&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;DHCP INET Options for client interface fxp0.0 ConfigFile:&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;init.conf Gateway:&lt;/span&gt; &lt;span class=&quot;token ip-address constant&quot;&gt;10.0.0.1&lt;/span&gt; DHCP Server&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token ip-address constant&quot;&gt;10.0.0.1&lt;/span&gt; File Server&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token ip-address constant&quot;&gt;10.0.0.254&lt;/span&gt;
 &lt;span class=&quot;token property&quot;&gt;Options state:&lt;/span&gt;
Partial Options&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;Config File set&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;Image File not set&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;File Server set
&lt;span class=&quot;token property&quot;&gt;Auto Image Upgrade:&lt;/span&gt; Active on INET client interface &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; fxp0&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;0
&lt;span class=&quot;token property&quot;&gt;Auto Image Upgrade:&lt;/span&gt; Interface&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;token string&quot;&gt;&quot;fxp0&quot;&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;Auto Image Upgrade:&lt;/span&gt; Server&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;      &lt;span class=&quot;token string&quot;&gt;&quot;10.0.0.254&quot;&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;Auto Image Upgrade:&lt;/span&gt; Image File&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;NOT SPECIFIED&quot;&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;Auto Image Upgrade:&lt;/span&gt; Config File&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;init.conf&quot;&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;Auto Image Upgrade:&lt;/span&gt; Gateway&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;     &lt;span class=&quot;token string&quot;&gt;&quot;10.0.0.1&quot;&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;Auto Image Upgrade:&lt;/span&gt; Protocol&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;ftp&quot;&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;Auto Image Upgrade:&lt;/span&gt; FTP timeout set to &lt;span class=&quot;token number&quot;&gt;7200&lt;/span&gt; seconds
&lt;span class=&quot;token property&quot;&gt;Auto Image Upgrade:&lt;/span&gt; Start fetching &lt;span class=&quot;token domain constant&quot;&gt;init.conf&lt;/span&gt; file from server &lt;span class=&quot;token ip-address constant&quot;&gt;10.0.0.254&lt;/span&gt; through fxp0 using ftp
&lt;span class=&quot;token property&quot;&gt;Auto Image Upgrade:&lt;/span&gt; File &lt;span class=&quot;token domain constant&quot;&gt;init.conf&lt;/span&gt; fetched from server &lt;span class=&quot;token ip-address constant&quot;&gt;10.0.0.254&lt;/span&gt; through fxp0
&lt;span class=&quot;token property&quot;&gt;Auto Image Upgrade:&lt;/span&gt; Applying &lt;span class=&quot;token domain constant&quot;&gt;init.conf&lt;/span&gt; file configuration fetched from server &lt;span class=&quot;token ip-address constant&quot;&gt;10.0.0.254&lt;/span&gt; through fxp0
Broadcast Message from root&lt;span class=&quot;token operator&quot;&gt;@&lt;/span&gt;VM689D3B3F6F
        &lt;span class=&quot;token operator&quot;&gt;(&lt;/span&gt;no tty&lt;span class=&quot;token operator&quot;&gt;)&lt;/span&gt; at &lt;span class=&quot;token number&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;29&lt;/span&gt; EDT&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token property&quot;&gt;Auto image Upgrade:&lt;/span&gt; Stopped
&lt;span class=&quot;token property&quot;&gt;Auto Image Upgrade:&lt;/span&gt; Committed Configuration &lt;span class=&quot;token domain constant&quot;&gt;init.conf&lt;/span&gt; received from &lt;span class=&quot;token ip-address constant&quot;&gt;10.0.0.254&lt;/span&gt; through fxp0

root&lt;span class=&quot;token operator&quot;&gt;@&lt;/span&gt;VM689D3B3F6F&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
&lt;p&gt;For those with a keen eye you may notice that the base config does not have host-name configured. But with the magic of DHCP the device was able to configure its own unique hostname! Now you can use that hostname or the DHCP IP to SSH to the devices using root and &lt;code&gt;Tut0ria1!&lt;/code&gt; as the password thanks to our config file!
&lt;br&gt;
&lt;br&gt;
If at this point you are not seeing successful ZTP logs check your Dnsmasq configuration and be sure the OPNsense firewall rule is working properly. If you have any questions or need help, feel free to &lt;a href=&quot;https://jesus.twk95.com/#contact&quot;&gt;reach out&lt;/a&gt;!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This setup really helped me create many virtual labs while pursuing my certifications. I hope this tutorial can be helpful to someone starting their own lab. I know I could have used this a long time ago for sure!
&lt;br&gt;
&lt;br&gt;
This is only the beginning of our automation journey though! In the future I may do a tutorial on how to further automate device-specific settings using other automation tools and inventory files. Stay tuned!&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;References:&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.opnsense.org/manual/dnsmasq.html&quot;&gt;https://docs.opnsense.org/manual/dnsmasq.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.opnsense.org/manual/firewall.html&quot;&gt;https://docs.opnsense.org/manual/firewall.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rapidtables.com/convert/number/ascii-to-hex.html&quot;&gt;https://www.rapidtables.com/convert/number/ascii-to-hex.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.juniper.net/documentation/us/en/software/junos/junos-install-upgrade/topics/topic-map/zero-touch-provision.html&quot;&gt;https://www.juniper.net/documentation/us/en/software/junos/junos-install-upgrade/topics/topic-map/zero-touch-provision.html&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
</feed>