<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Farros FR]]></title><description><![CDATA[Practical guides on cybersecurity and data engineering]]></description><link>https://www.farrosfr.com</link><image><url>https://substackcdn.com/image/fetch/$s_!cjva!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F488c8271-36ef-4d1b-846b-2e998b147193_1000x1000.png</url><title>Farros FR</title><link>https://www.farrosfr.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 29 Jul 2026 14:21:40 GMT</lastBuildDate><atom:link href="https://www.farrosfr.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Mochammad Farros Fatchur Roji]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[farrosfr@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[farrosfr@substack.com]]></itunes:email><itunes:name><![CDATA[Mochammad Farros Fatchur Roji]]></itunes:name></itunes:owner><itunes:author><![CDATA[Mochammad Farros Fatchur Roji]]></itunes:author><googleplay:owner><![CDATA[farrosfr@substack.com]]></googleplay:owner><googleplay:email><![CDATA[farrosfr@substack.com]]></googleplay:email><googleplay:author><![CDATA[Mochammad Farros Fatchur Roji]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Virtualization and Containers | TryHackMe Write-up]]></title><description><![CDATA[Walkthrough for Virtualization and Containers TryHackMe room. Learn bare-metal and hosted hypervisors, Docker containers, and Kubernetes orchestration.]]></description><link>https://www.farrosfr.com/p/virtualization-and-containers-tryhackme-write-up</link><guid isPermaLink="false">https://www.farrosfr.com/p/virtualization-and-containers-tryhackme-write-up</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Tue, 21 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/be956ff5-0de1-4edc-b525-8ee0670a6260_1376x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zSRv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe884d2ab-ba22-4f10-9f9d-8ad1494e86cb_1376x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zSRv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe884d2ab-ba22-4f10-9f9d-8ad1494e86cb_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!zSRv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe884d2ab-ba22-4f10-9f9d-8ad1494e86cb_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!zSRv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe884d2ab-ba22-4f10-9f9d-8ad1494e86cb_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!zSRv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe884d2ab-ba22-4f10-9f9d-8ad1494e86cb_1376x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zSRv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe884d2ab-ba22-4f10-9f9d-8ad1494e86cb_1376x768.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e884d2ab-ba22-4f10-9f9d-8ad1494e86cb_1376x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Virtualization and Containers | TryHackMe Write-up&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Virtualization and Containers | TryHackMe Write-up" title="Virtualization and Containers | TryHackMe Write-up" srcset="https://substackcdn.com/image/fetch/$s_!zSRv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe884d2ab-ba22-4f10-9f9d-8ad1494e86cb_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!zSRv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe884d2ab-ba22-4f10-9f9d-8ad1494e86cb_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!zSRv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe884d2ab-ba22-4f10-9f9d-8ad1494e86cb_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!zSRv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe884d2ab-ba22-4f10-9f9d-8ad1494e86cb_1376x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>This is my complete walkthrough and write-up for the <a href="https://tryhackme.com/room/virtualizationandcontainers">Virtualization and Containers</a> room on TryHackMe. In this room, we examine the fundamental concepts of virtualization, hypervisors, Docker containers, and Kubernetes cluster orchestration.</p>
      <p>
          <a href="https://www.farrosfr.com/p/virtualization-and-containers-tryhackme-write-up">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Network Security Protocols | TryHackMe Write-up]]></title><description><![CDATA[Complete walkthrough for Network Security Protocols TryHackMe room. Learn about secure network protocols at the different layers of the OSI model.]]></description><link>https://www.farrosfr.com/p/network-security-protocols-tryhackme-write-up</link><guid isPermaLink="false">https://www.farrosfr.com/p/network-security-protocols-tryhackme-write-up</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Tue, 21 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a5f901e9-9796-4151-9e86-d1e5e11532d2_1376x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vSwM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16cced6d-b3b1-42eb-960d-126a4dd75f58_1376x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vSwM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16cced6d-b3b1-42eb-960d-126a4dd75f58_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!vSwM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16cced6d-b3b1-42eb-960d-126a4dd75f58_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!vSwM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16cced6d-b3b1-42eb-960d-126a4dd75f58_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!vSwM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16cced6d-b3b1-42eb-960d-126a4dd75f58_1376x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vSwM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16cced6d-b3b1-42eb-960d-126a4dd75f58_1376x768.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/16cced6d-b3b1-42eb-960d-126a4dd75f58_1376x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Network Security Protocols | TryHackMe Write-up&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Network Security Protocols | TryHackMe Write-up" title="Network Security Protocols | TryHackMe Write-up" srcset="https://substackcdn.com/image/fetch/$s_!vSwM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16cced6d-b3b1-42eb-960d-126a4dd75f58_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!vSwM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16cced6d-b3b1-42eb-960d-126a4dd75f58_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!vSwM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16cced6d-b3b1-42eb-960d-126a4dd75f58_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!vSwM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16cced6d-b3b1-42eb-960d-126a4dd75f58_1376x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>This is my complete walkthrough and write-up for the <a href="https://tryhackme.com/room/networksecurityprotocols">Network Security Protocols</a> room on TryHackMe. In this room, we examine primary protocols essential for network security across each layer of the OSI model.</p>
      <p>
          <a href="https://www.farrosfr.com/p/network-security-protocols-tryhackme-write-up">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Network Device Hardening | TryHackMe Write-up]]></title><description><![CDATA[A complete write-up for the TryHackMe Network Device Hardening room, showing how to secure VPNs, routers, switches, firewalls, and logging.]]></description><link>https://www.farrosfr.com/p/network-device-hardening-tryhackme-write-up</link><guid isPermaLink="false">https://www.farrosfr.com/p/network-device-hardening-tryhackme-write-up</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Sun, 19 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/21f10cd2-a10e-42d2-b2a2-2c1651beaf63_1376x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Uwzm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa25ba631-b3b7-4f1b-8274-97de38e7b161_1376x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Uwzm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa25ba631-b3b7-4f1b-8274-97de38e7b161_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!Uwzm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa25ba631-b3b7-4f1b-8274-97de38e7b161_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!Uwzm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa25ba631-b3b7-4f1b-8274-97de38e7b161_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!Uwzm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa25ba631-b3b7-4f1b-8274-97de38e7b161_1376x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Uwzm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa25ba631-b3b7-4f1b-8274-97de38e7b161_1376x768.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a25ba631-b3b7-4f1b-8274-97de38e7b161_1376x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Network Device Hardening | TryHackMe Write-up&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Network Device Hardening | TryHackMe Write-up" title="Network Device Hardening | TryHackMe Write-up" srcset="https://substackcdn.com/image/fetch/$s_!Uwzm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa25ba631-b3b7-4f1b-8274-97de38e7b161_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!Uwzm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa25ba631-b3b7-4f1b-8274-97de38e7b161_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!Uwzm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa25ba631-b3b7-4f1b-8274-97de38e7b161_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!Uwzm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa25ba631-b3b7-4f1b-8274-97de38e7b161_1376x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>This write-up covers the <a href="https://tryhackme.com/room/networkdevicehardening">Network Device Hardening</a> room on TryHackMe. We will configure secure virtual private networks, build router firewall rules, implement secure administration protocols, and deploy network monitoring tools.</p>
      <p>
          <a href="https://www.farrosfr.com/p/network-device-hardening-tryhackme-write-up">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Active Directory Hardening | TryHackMe Write-up]]></title><description><![CDATA[A complete walkthrough and write-up for the Active Directory Hardening TryHackMe room, focusing on securing AD environments and domain controllers.]]></description><link>https://www.farrosfr.com/p/active-directory-hardening-tryhackme-write-up</link><guid isPermaLink="false">https://www.farrosfr.com/p/active-directory-hardening-tryhackme-write-up</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Sat, 18 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/fb688eeb-8ac4-4838-9ac3-42abf8cb8ec2_1376x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NoEa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aec2d05-9afe-4798-a02d-12f12ad4422d_1376x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NoEa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aec2d05-9afe-4798-a02d-12f12ad4422d_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!NoEa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aec2d05-9afe-4798-a02d-12f12ad4422d_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!NoEa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aec2d05-9afe-4798-a02d-12f12ad4422d_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!NoEa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aec2d05-9afe-4798-a02d-12f12ad4422d_1376x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NoEa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aec2d05-9afe-4798-a02d-12f12ad4422d_1376x768.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4aec2d05-9afe-4798-a02d-12f12ad4422d_1376x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Active Directory Hardening | TryHackMe Write-up&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Active Directory Hardening | TryHackMe Write-up" title="Active Directory Hardening | TryHackMe Write-up" srcset="https://substackcdn.com/image/fetch/$s_!NoEa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aec2d05-9afe-4798-a02d-12f12ad4422d_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!NoEa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aec2d05-9afe-4798-a02d-12f12ad4422d_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!NoEa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aec2d05-9afe-4798-a02d-12f12ad4422d_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!NoEa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aec2d05-9afe-4798-a02d-12f12ad4422d_1376x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>This is my complete walkthrough and write-up for the <a href="https://tryhackme.com/room/activedirectoryhardening">Active Directory Hardening</a> room on TryHackMe. In this lab, we will cover key techniques for hardening Active Directory (AD) environments, including secure authentication settings, the Tiered Access Model, Group Policy Objects, and mitigating common AD attacks.</p>
      <p>
          <a href="https://www.farrosfr.com/p/active-directory-hardening-tryhackme-write-up">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[How I Contributed to Astro Core: Fixing Cryptic Zod CSP Errors]]></title><description><![CDATA[How I improved Content Security Policy validation in Astro by refactoring Zod schemas and custom error mapping.]]></description><link>https://www.farrosfr.com/p/how-i-contributed-to-astro-core-fixing-cryptic-zod-csp-errors</link><guid isPermaLink="false">https://www.farrosfr.com/p/how-i-contributed-to-astro-core-fixing-cryptic-zod-csp-errors</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Fri, 17 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/11be6bfc-3b61-4af0-89c6-2fdf076e7e58_1376x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ymon!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4d784-f05e-4bd4-865a-8b350e20644e_1376x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ymon!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4d784-f05e-4bd4-865a-8b350e20644e_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!ymon!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4d784-f05e-4bd4-865a-8b350e20644e_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!ymon!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4d784-f05e-4bd4-865a-8b350e20644e_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!ymon!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4d784-f05e-4bd4-865a-8b350e20644e_1376x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ymon!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4d784-f05e-4bd4-865a-8b350e20644e_1376x768.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/13f4d784-f05e-4bd4-865a-8b350e20644e_1376x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;How I Contributed to Astro Core: Fixing Cryptic Zod CSP Errors&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="How I Contributed to Astro Core: Fixing Cryptic Zod CSP Errors" title="How I Contributed to Astro Core: Fixing Cryptic Zod CSP Errors" srcset="https://substackcdn.com/image/fetch/$s_!ymon!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4d784-f05e-4bd4-865a-8b350e20644e_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!ymon!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4d784-f05e-4bd4-865a-8b350e20644e_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!ymon!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4d784-f05e-4bd4-865a-8b350e20644e_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!ymon!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4d784-f05e-4bd4-865a-8b350e20644e_1376x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p></p><p>Earlier this year, while configuring Content Security Policy (CSP) options for my apps, I ran into a cryptic configuration error in the Astro framework. To help other developers, I submitted a pull request directly to the Astro core repository: <a href="https://github.com/withastro/astro/pull/16685">docs(csp): improve validation messages for directives (withastro/astro#16685)</a> which successfully closes <a href="https://github.com/withastro/astro/issues/16663">issue #16663</a>.</p><p>Here is a full technical walkthrough of the problem, the codebase implementation, and what I learned from contributing to a major open-source project.</p><div><hr></div><h2>The Problem: Cryptic Zod Union Errors</h2><p>Astro uses the <a href="https://zod.dev/">Zod library</a> to define and validate its configuration schema. Zod is excellent for validating structures, but it can struggle with user-friendly messages when checking union types.</p><p>In Astro's security configuration, users can define CSP directives in <code>security.csp.directives</code>. However, because of how browser parsers behave, the directives <code>script-src</code> and <code>style-src</code> must be handled separately using dedicated options like <code>security.csp.scriptDirective</code> and <code>security.csp.styleDirective</code>.</p><p>If a developer mistakenly placed <code>script-src</code> directly into the general <code>directives</code> array like this:</p><pre><code>// astro.config.mjs
export default defineConfig({
  security: {
    csp: {
      directives: ["script-src 'self'"]
    }
  }
});
</code></pre><p>Astro's validation engine would output a frustratingly vague error:</p><pre><code>[config] Astro found issue(s) with your configuration:
! security.csp: Did not match union.
</code></pre><p>This occurred because the configuration schema evaluated the input against a union of valid directives and fell back to the generic Zod union error, leaving the developer with no indication of what went wrong or how to fix it.</p><div><hr></div><h2>The Solution: Refactoring Zod Schema &amp; Custom Error Maps</h2><p>To resolve the issue and provide clear, actionable instructions, we had to apply a two-step surgical update to the Astro core package.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DSHx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F260ea8c5-5991-4abc-b94c-eb8069d69395_2560x1067.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DSHx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F260ea8c5-5991-4abc-b94c-eb8069d69395_2560x1067.png 424w, https://substackcdn.com/image/fetch/$s_!DSHx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F260ea8c5-5991-4abc-b94c-eb8069d69395_2560x1067.png 848w, https://substackcdn.com/image/fetch/$s_!DSHx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F260ea8c5-5991-4abc-b94c-eb8069d69395_2560x1067.png 1272w, https://substackcdn.com/image/fetch/$s_!DSHx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F260ea8c5-5991-4abc-b94c-eb8069d69395_2560x1067.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DSHx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F260ea8c5-5991-4abc-b94c-eb8069d69395_2560x1067.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/260ea8c5-5991-4abc-b94c-eb8069d69395_2560x1067.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Astro CSP Validation Flow&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Astro CSP Validation Flow" title="Astro CSP Validation Flow" srcset="https://substackcdn.com/image/fetch/$s_!DSHx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F260ea8c5-5991-4abc-b94c-eb8069d69395_2560x1067.png 424w, https://substackcdn.com/image/fetch/$s_!DSHx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F260ea8c5-5991-4abc-b94c-eb8069d69395_2560x1067.png 848w, https://substackcdn.com/image/fetch/$s_!DSHx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F260ea8c5-5991-4abc-b94c-eb8069d69395_2560x1067.png 1272w, https://substackcdn.com/image/fetch/$s_!DSHx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F260ea8c5-5991-4abc-b94c-eb8069d69395_2560x1067.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><em>Figure 1: The lifecycle flow of a custom configuration validation error traversing the schema and zod-error-map.</em></p><h3>1. Refactoring schema validation with <code>superRefine</code></h3><p>In <code>packages/astro/src/core/csp/config.ts</code>, the original schema for checking allowed directives was a simple <code>z.custom</code> returning a boolean check:</p><pre><code>export const allowedDirectivesSchema = z.custom&lt;CspDirective&gt;((value) =&gt; {
  if (typeof value !== 'string') {
    return false;
  }
  return ALLOWED_DIRECTIVES.some((allowedValue) =&gt; {
    return value.startsWith(allowedValue);
  });
});
</code></pre><p>I refactored this validator to use <code>.superRefine</code>. This allowed us to inspect the invalid inputs and attach distinct custom issues depending on the specific error context:</p><pre><code>export const allowedDirectivesSchema = z.custom&lt;CspDirective&gt;((v) =&gt; typeof v === 'string').superRefine(
  (value, ctx) =&gt; {
    const isAllowed = ALLOWED_DIRECTIVES.some((allowedValue) =&gt; {
      return value.startsWith(allowedValue);
    });
    if (!isAllowed) {
      if (value.startsWith('script-src') || value.startsWith('style-src')) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: `Directives \`script-src\` and \`style-src\` are not allowed in \`security.csp.directives\`. Please use \`security.csp.scriptDirective\` and \`security.csp.styleDirective\` instead.`,
          fatal: true,
        });
      } else {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: `Invalid directive: "${value}". Allowed directives are: ${ALLOWED_DIRECTIVES.join(', ')}`,
          fatal: true,
        });
      }
    }
  },
);
</code></pre><h3>2. Surfacing custom messages in <code>zod-error-map.ts</code></h3><p>Even with <code>superRefine</code> adding the custom issues, Zod's default union error formatter would still swallow the custom messages during validation formatting.</p><p>To fix this, we updated Astro's custom Zod error formatter in <code>packages/astro/src/core/errors/zod-error-map.ts</code>. We intercepted custom issue codes containing <code>security.csp</code> and directly pushed the custom messages to the expected error shape array:</p><pre><code>if (
  _issue.code === 'custom' &amp;&amp;
  _issue.message &amp;&amp;
  _issue.message.includes('security.csp')
) {
  expectedShape.push(_issue.message);
} else if ('expected' in _issue &amp;&amp; typeof _issue.expected === 'string') {
  expectedShape.push(
    relativePath ? `${relativePath}: ${_issue.expected}` : _issue.expected,
  );
}
</code></pre><p>This bypasses the union-flattening logic, successfully outputting our clean, helpful instructions to the developer's console.</p><div><hr></div><h2>Testing the Validation</h2><p>To ensure the new error mapping behaves correctly, I added a new unit test in <code>packages/astro/test/units/config/config-validate.test.ts</code>:</p><pre><code>it('should provide a helpful error message when script-src or style-src is used in directives', async () =&gt; {
  const configError = await validateConfig({
    security: {
      csp: {
        directives: ["script-src 'self'"],
      },
    },
  }).catch((err) =&gt; err);

  const formattedError = stripVTControlCharacters(formatConfigErrorMessage(configError));
  assert.equal(
    formattedError,
    `[config] Astro found issue(s) with your configuration:\n\n! security.csp: Did not match union.\n  &gt; Expected type boolean | Directives script-src and style-src are not allowed in security.csp.directives. Please use security.csp.scriptDirective and security.csp.styleDirective instead.\n  &gt; Received { "directives": [ "script-src 'self'" ] }`,
  );
});
</code></pre><p>The test runs a config validation, formats the message, strips terminal coloring control characters, and asserts that our specific help instruction is rendered perfectly alongside the union error representation.</p><div><hr></div><h2>Contribution Takeaways</h2><p>Contributing to Astro's core was a fantastic experience. The codebase is clean, well-tested, and uses changesets to automate package version patches. Because this validation error directly affects DX (Developer Experience), it was merged quickly and rolled out in a patch release, resolving configuration confusion for thousands of developers worldwide.</p><p>Thanks for reading. See you in the next lab.</p>]]></content:encoded></item><item><title><![CDATA[Stop Letting AI Guess Your Requirements: The Grill-Me Paradigm]]></title><description><![CDATA[Why Socratic interrogations through the Grill-Me skill are essential to align developer plans, prevent agent assumptions, and write better code.]]></description><link>https://www.farrosfr.com/p/stop-letting-ai-guess-your-requirements-the-grill-me-paradigm</link><guid isPermaLink="false">https://www.farrosfr.com/p/stop-letting-ai-guess-your-requirements-the-grill-me-paradigm</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Fri, 17 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/48055fd0-3c1f-4135-86ac-d26b3c763888_1376x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tFhh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0eb3b441-464b-4cf9-bce5-c7dd9e31889d_1376x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tFhh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0eb3b441-464b-4cf9-bce5-c7dd9e31889d_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!tFhh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0eb3b441-464b-4cf9-bce5-c7dd9e31889d_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!tFhh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0eb3b441-464b-4cf9-bce5-c7dd9e31889d_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!tFhh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0eb3b441-464b-4cf9-bce5-c7dd9e31889d_1376x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tFhh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0eb3b441-464b-4cf9-bce5-c7dd9e31889d_1376x768.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0eb3b441-464b-4cf9-bce5-c7dd9e31889d_1376x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Stop Letting AI Guess Your Requirements: The Grill-Me Paradigm&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Stop Letting AI Guess Your Requirements: The Grill-Me Paradigm" title="Stop Letting AI Guess Your Requirements: The Grill-Me Paradigm" srcset="https://substackcdn.com/image/fetch/$s_!tFhh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0eb3b441-464b-4cf9-bce5-c7dd9e31889d_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!tFhh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0eb3b441-464b-4cf9-bce5-c7dd9e31889d_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!tFhh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0eb3b441-464b-4cf9-bce5-c7dd9e31889d_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!tFhh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0eb3b441-464b-4cf9-bce5-c7dd9e31889d_1376x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p></p><p>We have all done it. We open our AI coding assistant, type a vague command like <em>"implement OAuth login"</em> or <em>"refactor this database handler"</em>, and hit enter.</p><p>Immediately, the autonomous agent starts spinning. It refactors three files, creates two new utility modules, updates the dependencies, and generates a massive diff. You compile, and the build fails. You realize the AI made a dozen unchecked assumptions about your architecture, secret keys, and routing structures.</p><p>Vague prompts are the absolute enemy of autonomous coding. To fix this, we need to change how we interact with our agents. Instead of letting them guess, we need to let them interrogate us.</p><p>Enter the <strong>Grill-Me</strong> paradigm.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NF7N!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d1aeec-f468-42bd-a291-a427d1bc03e0_2560x1067.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NF7N!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d1aeec-f468-42bd-a291-a427d1bc03e0_2560x1067.png 424w, https://substackcdn.com/image/fetch/$s_!NF7N!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d1aeec-f468-42bd-a291-a427d1bc03e0_2560x1067.png 848w, https://substackcdn.com/image/fetch/$s_!NF7N!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d1aeec-f468-42bd-a291-a427d1bc03e0_2560x1067.png 1272w, https://substackcdn.com/image/fetch/$s_!NF7N!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d1aeec-f468-42bd-a291-a427d1bc03e0_2560x1067.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NF7N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d1aeec-f468-42bd-a291-a427d1bc03e0_2560x1067.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c9d1aeec-f468-42bd-a291-a427d1bc03e0_2560x1067.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Grill-Me Alignment Flow&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Grill-Me Alignment Flow" title="Grill-Me Alignment Flow" srcset="https://substackcdn.com/image/fetch/$s_!NF7N!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d1aeec-f468-42bd-a291-a427d1bc03e0_2560x1067.png 424w, https://substackcdn.com/image/fetch/$s_!NF7N!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d1aeec-f468-42bd-a291-a427d1bc03e0_2560x1067.png 848w, https://substackcdn.com/image/fetch/$s_!NF7N!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d1aeec-f468-42bd-a291-a427d1bc03e0_2560x1067.png 1272w, https://substackcdn.com/image/fetch/$s_!NF7N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9d1aeec-f468-42bd-a291-a427d1bc03e0_2560x1067.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p><em>Figure 1: Comparison of execution cycles: Vague prompts lead to broken builds, whereas Socratic alignment loops produce clean, surgical code edits.</em></p><p>Originally developed as part of <a href="https://github.com/mattpocock/skills">Matt Pocock's skills repository</a>, the <code>grill-me</code> skill shifts the human-agent relationship from black-box execution to an interactive Socratic alignment loop.</p><div><hr></div><h2>The Socratic Flow: How the Grill Works</h2><p>The mechanics of the <code>grill-me</code> skill are intentionally restrictive and highly disciplined:</p><ol><li><p><strong>One Question at a Time</strong>: The agent is forbidden from dumping a list of questions. It must ask exactly one probing question at a time to keep your cognitive load low.</p></li><li><p><strong>Recommended Answers</strong>: For every question asked, the agent must propose a suggested answer (e.g., <em>"Recommended: Use the existing auth helper in utils.js"</em>). You can accept it with a simple yes or refine it with your own input.</p></li><li><p><strong>Codebase Awareness</strong>: The agent is instructed to explore your codebase first. It should never ask you questions that can be answered by looking at your files.</p></li></ol><p>This creates a systematic decision tree. You resolve dependencies one by one before a single line of code is edited.</p><div><hr></div><h2>The Developer's Lens: Resolving Plan Confusion</h2><p>As developers, we often start tasks feeling slightly confused or overwhelmed. We know the high-level goal, but we haven't mapped out the edge cases or implementation details.</p><p>When you prompt an agent with <code>/grill-me</code>, it forces you to pause.</p><p>By interviewing you, the AI acts as a sounding board. As you respond to its questions, you are forced to clarify your own requirements. You decide on routing parameters, database constraints, and error boundaries before writing code.</p><p>Instead of staring at a blank editor trying to plan, you simply answer a sequence of simple prompts. By the time the interview is complete, you and the agent share a perfect, validated blueprint of the task.</p><div><hr></div><h2>The Agent's Lens: Preventing Wasted Autonomy</h2><p>From the AI agent's perspective, vagueness is a recipe for context drift and token waste.</p><p>When an agent doesn't have clear requirements, it is forced to hallucinate constraints. It might over-engineer a simple solution or refactor unrelated files. Once it takes a wrong turn, it gets stuck in feedback loops, burning through your API limits.</p><p>Grilling the user beforehand acts as a guardrail. It locks down the implementation parameters (like library versions, error formats, and target paths). This keeps the agent's edits surgical, reduces token usage, and increases the success rate of the build on the first attempt.</p><div><hr></div><h2>Getting Started with Grill-Me</h2><p>You can add the <code>grill-me</code> skill to your agent's configuration using the following command:</p><pre><code>npx skills add https://github.com/mattpocock/skills --skill grill-me
</code></pre><p>Once installed, simply prefix your complex tasks with <code>/grill-me</code> (e.g., <code>/grill-me I want to add a caching layer to our API routes</code>) to initiate the interview.</p><p>By shifting the starting line from <em>writing code</em> to <em>answering questions</em>, you eliminate guesswork, save your API budget, and build a clearer understanding of your own projects.</p><p>Thanks for reading. See you in the next experience.</p>]]></content:encoded></item><item><title><![CDATA[Boredom by Design: Why Staring at a Wall Requires a Clean Mind]]></title><description><![CDATA[My experience with the 10-minute wall-staring method, and why mental visual clarity and self-control are essential to unlocking deep, productive focus.]]></description><link>https://www.farrosfr.com/p/boredom-by-design-why-staring-at-a-wall-requires-a-clean-mind</link><guid isPermaLink="false">https://www.farrosfr.com/p/boredom-by-design-why-staring-at-a-wall-requires-a-clean-mind</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Fri, 17 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/c6fcafbd-273b-4674-bf52-865a555b871f_1376x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gCWk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae619b45-c4e0-45e5-8067-170caaed7752_1376x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gCWk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae619b45-c4e0-45e5-8067-170caaed7752_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!gCWk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae619b45-c4e0-45e5-8067-170caaed7752_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!gCWk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae619b45-c4e0-45e5-8067-170caaed7752_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!gCWk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae619b45-c4e0-45e5-8067-170caaed7752_1376x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gCWk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae619b45-c4e0-45e5-8067-170caaed7752_1376x768.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ae619b45-c4e0-45e5-8067-170caaed7752_1376x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Boredom by Design: Why Staring at a Wall Requires a Clean Mind&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Boredom by Design: Why Staring at a Wall Requires a Clean Mind" title="Boredom by Design: Why Staring at a Wall Requires a Clean Mind" srcset="https://substackcdn.com/image/fetch/$s_!gCWk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae619b45-c4e0-45e5-8067-170caaed7752_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!gCWk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae619b45-c4e0-45e5-8067-170caaed7752_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!gCWk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae619b45-c4e0-45e5-8067-170caaed7752_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!gCWk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae619b45-c4e0-45e5-8067-170caaed7752_1376x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p></p><p>In a world engineered for hyper-stimulation, doing absolutely nothing has become a radical act. Between doom scrolling, notifications, and background music, our brains are constantly flooded with cheap dopamine.</p><p>Recently, I began practicing a simple ritual: the <strong>10-minute wall-staring method</strong>. Before starting a 3-hour session of deep study or deep work, I sit in a chair and stare at a completely blank wall for exactly ten minutes. No phone, no music, no food - just me and the wall.</p><p>This simple practice has transformed my productivity, but I quickly realized it has a strict prerequisite: mental visual clarity. Here is how the method works, why it is deeply connected to strict self-control, and how intentional boredom resets your focus.</p><div><hr></div><h2>The Mirror of the Wall: Connecting to Self-Control</h2><blockquote><p>"If you want to destroy any nation without war, make adultery or nudity common in the young generation."<br><strong>Saladin the Wise</strong></p></blockquote><p>This ancient observation points to a timeless truth: a society's focus and strength are directly tied to its self-control. On an individual level, the same principle applies. If you want to destroy your own focus without effort, flood your mind with hyper-stimulation.</p><p>When you stare at a blank wall, there are no external inputs to distract you. You are looking at a blank canvas. Factually, your eyes see nothing, which means the wall becomes a projector for your internal thoughts. It reflects whatever you have been feeding your mind.</p><p>If you do not exercise strict self-control (especially regarding highly stimulating content like sexual content, nudity, or doom scrolling), staring at a blank wall becomes significantly harder.</p><p>In that blank space, your brain attempts to replace the lack of external visual stimulation with internal imagery. If your mind is cluttered with hyper-sexualized thoughts or the residue of cheap stimulation, those unclean loops will flood your consciousness. You will struggle to sit still, get anxious, and find it extremely difficult to maintain peace. This discipline is found across many spiritual traditions, most strictly in Islamic teachings on guarding one's gaze and thoughts.</p><p>To reap the benefits of the wall-staring method, you must first keep your mental canvas clean. Cultivating self-control removes the high-stimulus clutter, allowing the blank space of the wall to remain calm rather than chaotic.</p><div><hr></div><h2>The Friction of Extreme Boredom</h2><p>Staring at a wall for ten minutes sounds easy until you try it.</p><p>Around the three-minute mark, an intense, crushing boredom sets in. Your brain, desperate for a dopamine hit, will start suggesting alternative, "productive" distractions. You will think:</p><ul><li><p><em>"This is a waste of time. Doing push-ups would be much better than doing nothing!"</em></p></li><li><p><em>"I should quickly tidy up my desk."</em></p></li><li><p><em>"Let me plan my study schedule instead."</em></p></li></ul><p>The core rule of the method is that <strong>you must hold</strong>. You must resist even productive urges until the 10-minute timer is completely finished. You have to sit through the friction of doing nothing.</p><div><hr></div><h2>Re-calibration: Deep Work as a Reward</h2><p>The magic of the wall-staring method lies in the phenomena of measurable, intentional boredom. By forcing your brain to experience absolute inactivity, you lower your dopamine threshold.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!phaJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24afe9de-83be-441f-ab77-5684dcaa2090_2560x1067.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!phaJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24afe9de-83be-441f-ab77-5684dcaa2090_2560x1067.png 424w, https://substackcdn.com/image/fetch/$s_!phaJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24afe9de-83be-441f-ab77-5684dcaa2090_2560x1067.png 848w, https://substackcdn.com/image/fetch/$s_!phaJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24afe9de-83be-441f-ab77-5684dcaa2090_2560x1067.png 1272w, https://substackcdn.com/image/fetch/$s_!phaJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24afe9de-83be-441f-ab77-5684dcaa2090_2560x1067.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!phaJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24afe9de-83be-441f-ab77-5684dcaa2090_2560x1067.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/24afe9de-83be-441f-ab77-5684dcaa2090_2560x1067.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Dopamine Threshold Comparison&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Dopamine Threshold Comparison" title="Dopamine Threshold Comparison" srcset="https://substackcdn.com/image/fetch/$s_!phaJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24afe9de-83be-441f-ab77-5684dcaa2090_2560x1067.png 424w, https://substackcdn.com/image/fetch/$s_!phaJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24afe9de-83be-441f-ab77-5684dcaa2090_2560x1067.png 848w, https://substackcdn.com/image/fetch/$s_!phaJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24afe9de-83be-441f-ab77-5684dcaa2090_2560x1067.png 1272w, https://substackcdn.com/image/fetch/$s_!phaJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24afe9de-83be-441f-ab77-5684dcaa2090_2560x1067.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><em>Figure 1: Comparison of dopamine thresholds: over-stimulation blocks cognitive tasks, while wall-staring recalibrates sensitivity.</em></p><p>If you spend ten minutes staring at a blank wall, your baseline adjusts. When the timer finally goes off, starting to read a technical book, writing code, or studying feels like a stimulating escape. Your brain welcomes the work because it is infinitely more engaging than the void of the wall.</p><p>By contrast, if you start your study session after doom scrolling or looking at sexual content, your dopamine threshold is raised so high that sitting down to study feels like pulling teeth.</p><p>Doing nothing with a clean mind is a powerful tool to reset your baseline, allowing you to transition easily into 3 hours of uninterrupted, deep focus.</p><p>Thanks for reading. See you in the next experience.</p>]]></content:encoded></item><item><title><![CDATA[Strava API Changes: The Death of the Free Developer Tier]]></title><description><![CDATA[My experience integrating the Strava API in my Threads Watermark app, and how Strava's 2026 subscription mandate broke free-tier API access.]]></description><link>https://www.farrosfr.com/p/strava-api-changes-the-death-of-the-free-developer-tier</link><guid isPermaLink="false">https://www.farrosfr.com/p/strava-api-changes-the-death-of-the-free-developer-tier</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Thu, 16 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/558d92c4-493b-4f8a-8969-89b746803297_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-iAc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa400bca0-83f8-4271-8c63-71d1ee973c7a_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-iAc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa400bca0-83f8-4271-8c63-71d1ee973c7a_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!-iAc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa400bca0-83f8-4271-8c63-71d1ee973c7a_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!-iAc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa400bca0-83f8-4271-8c63-71d1ee973c7a_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!-iAc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa400bca0-83f8-4271-8c63-71d1ee973c7a_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-iAc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa400bca0-83f8-4271-8c63-71d1ee973c7a_1200x630.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a400bca0-83f8-4271-8c63-71d1ee973c7a_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Strava API Changes: The Death of the Free Developer Tier&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Strava API Changes: The Death of the Free Developer Tier" title="Strava API Changes: The Death of the Free Developer Tier" srcset="https://substackcdn.com/image/fetch/$s_!-iAc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa400bca0-83f8-4271-8c63-71d1ee973c7a_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!-iAc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa400bca0-83f8-4271-8c63-71d1ee973c7a_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!-iAc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa400bca0-83f8-4271-8c63-71d1ee973c7a_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!-iAc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa400bca0-83f8-4271-8c63-71d1ee973c7a_1200x630.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p></p><p>Earlier this year, I started a side project called <a href="https://github.com/farrosfr/strava">Daily Threads Watermark</a>, which is a static web application designed to help runners and fitness enthusiasts generate watermarked workout summaries and text drafts for Threads.</p><p>One of the application's most popular features was its seamless Strava integration. However, due to recent policy shifts in the Strava Developer Program, this integration is now completely broken for free-tier users. Here is what happened, how the integration worked, and the workaround for developer-athletes.</p><div><hr></div><h2>The History: Asynchronous Static Sync</h2><p>Because the application is hosted as a serverless static site on GitHub Pages, we could not query the Strava API directly from the client side without leaking private credentials (<code>Client Secret</code>).</p><p>To solve this securely, the app was designed around an asynchronous build pipeline:</p><ol><li><p><strong>GitHub Actions Workflow</strong>: A cron job triggered every 30 minutes.</p></li><li><p><strong>Strava API Query</strong>: The workflow read repository secrets (<code>STRAVA_CLIENT_ID</code>, <code>STRAVA_CLIENT_SECRET</code>, and <code>STRAVA_REFRESH_TOKEN</code>), fetched my latest run and walk distances directly from Strava's endpoints, and compiled the data.</p></li><li><p><strong>Static Summary File</strong>: The workflow wrote the fetched metrics into a public JSON summary at <code>public/data/strava-summary.json</code>.</p></li><li><p><strong>Local Consumption</strong>: When the static frontend loaded in a browser, it requested the local JSON file to pre-fill the day's distance, avoiding direct API requests from client code.</p></li></ol><p>This architecture allowed for a lightweight, zero-cost, and completely secure sync cycle.</p><div><hr></div><h2>The Policy Shift: Pay-to-Play API Access</h2><p>In June 2026, Strava overhauled its Developer Program. The most significant change directly affects "single-player" developers who write scripts or small tools for their personal use:</p><ul><li><p><strong>Subscription Mandate</strong>: Access to the <strong>Standard Tier</strong> API (up to 10 athletes) now requires an active, paid Strava subscription.</p></li><li><p><strong>Effective Date</strong>: The policy went into effect immediately for new applications, with a grace period for existing active developer accounts ending on <strong>June 30, 2026</strong>.</p></li></ul><p>Without an active Strava subscription connected to the developer account, API requests are rejected, immediately halting the GitHub Actions automated sync workflow. You can check your application status and subscription eligibility directly on your <a href="https://www.strava.com/settings/api">Strava API Settings Dashboard</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VxD_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F653ec6bc-f68c-4919-b02b-9838e21cd9c1_1280x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VxD_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F653ec6bc-f68c-4919-b02b-9838e21cd9c1_1280x800.png 424w, https://substackcdn.com/image/fetch/$s_!VxD_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F653ec6bc-f68c-4919-b02b-9838e21cd9c1_1280x800.png 848w, https://substackcdn.com/image/fetch/$s_!VxD_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F653ec6bc-f68c-4919-b02b-9838e21cd9c1_1280x800.png 1272w, https://substackcdn.com/image/fetch/$s_!VxD_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F653ec6bc-f68c-4919-b02b-9838e21cd9c1_1280x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VxD_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F653ec6bc-f68c-4919-b02b-9838e21cd9c1_1280x800.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/653ec6bc-f68c-4919-b02b-9838e21cd9c1_1280x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Strava Subscription Requirement&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Strava Subscription Requirement" title="Strava Subscription Requirement" srcset="https://substackcdn.com/image/fetch/$s_!VxD_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F653ec6bc-f68c-4919-b02b-9838e21cd9c1_1280x800.png 424w, https://substackcdn.com/image/fetch/$s_!VxD_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F653ec6bc-f68c-4919-b02b-9838e21cd9c1_1280x800.png 848w, https://substackcdn.com/image/fetch/$s_!VxD_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F653ec6bc-f68c-4919-b02b-9838e21cd9c1_1280x800.png 1272w, https://substackcdn.com/image/fetch/$s_!VxD_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F653ec6bc-f68c-4919-b02b-9838e21cd9c1_1280x800.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><em>Figure 1: The Strava API Application dashboard displaying the banner warning that API access is updating to be subscriber-only.</em></p><div><hr></div><h2>The Fallback: Manual CSV Imports</h2><p>Fortunately, when designing the application, I built in a fallback mechanism in anticipation of potential API outages or sync errors.</p><p>Rather than relying on automated API hooks, users can manually export their activity history from their Strava account settings and upload the CSV file directly into the browser. The application processes the CSV locally in-memory, parses the activity distances by date, and updates the daily counter dashboard without sending any data to external servers.</p><p>While the automation era of Strava's free API tier is officially over, static tools can still survive by shifting data ownership back to local browser storage and manual exports.</p><div><hr></div><h2>Follow Me on Strava</h2><p>If you want to look or follow my daily workouts, feel free to check out my Strava account here:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://www.strava.com/athletes/farrosfr" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5dnv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe53b3c00-bb49-4f80-8587-3afd230aa98f_1280x800.png 424w, https://substackcdn.com/image/fetch/$s_!5dnv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe53b3c00-bb49-4f80-8587-3afd230aa98f_1280x800.png 848w, https://substackcdn.com/image/fetch/$s_!5dnv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe53b3c00-bb49-4f80-8587-3afd230aa98f_1280x800.png 1272w, https://substackcdn.com/image/fetch/$s_!5dnv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe53b3c00-bb49-4f80-8587-3afd230aa98f_1280x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5dnv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe53b3c00-bb49-4f80-8587-3afd230aa98f_1280x800.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e53b3c00-bb49-4f80-8587-3afd230aa98f_1280x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;My Strava Account&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:&quot;https://www.strava.com/athletes/farrosfr&quot;,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="My Strava Account" title="My Strava Account" srcset="https://substackcdn.com/image/fetch/$s_!5dnv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe53b3c00-bb49-4f80-8587-3afd230aa98f_1280x800.png 424w, https://substackcdn.com/image/fetch/$s_!5dnv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe53b3c00-bb49-4f80-8587-3afd230aa98f_1280x800.png 848w, https://substackcdn.com/image/fetch/$s_!5dnv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe53b3c00-bb49-4f80-8587-3afd230aa98f_1280x800.png 1272w, https://substackcdn.com/image/fetch/$s_!5dnv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe53b3c00-bb49-4f80-8587-3afd230aa98f_1280x800.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><em>Figure 2: Feel free to check out or follow my athlete profile at <a href="https://www.strava.com/athletes/farrosfr">strava.com/athletes/farrosfr</a>.</em></p><p>Thanks for reading. See you in the next lab.</p>]]></content:encoded></item><item><title><![CDATA[How I Added Affixed Capture Support to Axum's Typed Paths]]></title><description><![CDATA[How I contributed to tokio-rs/axum to support prefixed and suffixed typed path captures like /@{username} and /files/{name}.json.]]></description><link>https://www.farrosfr.com/p/how-i-added-affixed-capture-support-to-axum-s-typed-paths</link><guid isPermaLink="false">https://www.farrosfr.com/p/how-i-added-affixed-capture-support-to-axum-s-typed-paths</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Thu, 16 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/15656332-abda-435b-bf80-e9c7a5415138_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3vto!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13eeed6d-d2c0-4654-b538-0da4380b9876_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3vto!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13eeed6d-d2c0-4654-b538-0da4380b9876_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!3vto!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13eeed6d-d2c0-4654-b538-0da4380b9876_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!3vto!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13eeed6d-d2c0-4654-b538-0da4380b9876_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!3vto!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13eeed6d-d2c0-4654-b538-0da4380b9876_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3vto!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13eeed6d-d2c0-4654-b538-0da4380b9876_1200x630.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/13eeed6d-d2c0-4654-b538-0da4380b9876_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;How I Added Affixed Capture Support to Axum's Typed Paths&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="How I Added Affixed Capture Support to Axum's Typed Paths" title="How I Added Affixed Capture Support to Axum's Typed Paths" srcset="https://substackcdn.com/image/fetch/$s_!3vto!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13eeed6d-d2c0-4654-b538-0da4380b9876_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!3vto!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13eeed6d-d2c0-4654-b538-0da4380b9876_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!3vto!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13eeed6d-d2c0-4654-b538-0da4380b9876_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!3vto!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13eeed6d-d2c0-4654-b538-0da4380b9876_1200x630.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>A few weeks ago, my pull request <a href="https://github.com/tokio-rs/axum/pull/3782">tokio-rs/axum#3782</a> was merged into <code>axum</code>. This contribution resolves a long-standing limitation in Axum's typed routing system: the inability to support affixed (prefixed or suffixed) capture patterns in typed paths.</p><p>Here is the story behind the problem, how the macro parser was updated, and what this means for your Rust APIs.</p><h2>What is Axum?</h2><p><a href="https://github.com/tokio-rs/axum">Axum</a> is a modern web application framework built for <strong>Rust</strong>, the systems programming language known for memory safety, performance, and concurrency. Axum is developed as part of the <a href="https://tokio.rs/">Tokio</a> ecosystem (Rust's premier asynchronous runtime), making it highly efficient for handling concurrent network traffic at scale.</p><p>Axum stands out because of its ergonomic, declarative programming model:</p><ol><li><p><strong>Type-Safe Routing</strong>: Routes map requests directly to handler functions.</p></li><li><p><strong>Extractors</strong>: Handlers extract parameters (such as JSON payloads, headers, query parameters, or paths) directly from signature arguments using types.</p></li><li><p><strong>Middleware</strong>: Built on top of the <code>tower</code> ecosystem, allowing modular middleware stack reusability.</p></li></ol><p>Here is a simple example of a standard Axum server setup in Rust:</p><pre><code>use axum::{routing::get, Router};

#[tokio::main]
async fn main() {
    // Define routing and handlers
    let app = Router::new()
        .route("/", get(hello_world))
        .route("/users/{id}", get(get_user));

    // Run server on localhost:3000
    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

async fn hello_world() -&gt; &amp;'static str {
    "Hello, World!"
}

async fn get_user(axum::extract::Path(id): axum::extract::Path&lt;u32&gt;) -&gt; String {
    format!("User ID: {}", id)
}
</code></pre><p>By leveraging Rust's strong static typing and macro system, Axum compiles checks for route correctness, route parameters, and request payload safety at build time.</p><div><hr></div><h2>The Problem: Segment-Bound Captures</h2><p>Axum provides a powerful macro-based router extension called <code>TypedPath</code>. It allows developers to define type-safe routes by deriving the <code>TypedPath</code> trait on structs representing route parameters:</p><pre><code>use axum_extra::routing::TypedPath;
use serde::Deserialize;

#[derive(TypedPath, Deserialize)]
#[typed_path("/users/{id}")]
struct ShowUser {
    id: u32,
}
</code></pre><p>However, the previous typed path parser in <code>axum-macros</code> split route paths strictly by the <code>/</code> separator and assumed each path segment was either entirely static or entirely a capture (surrounded by <code>{</code> and <code>}</code>).</p><p>This design meant route patterns with prefixed or suffixed captures (such as <code>/@{username}</code> for user profiles or <code>/files/{name}.json</code> for format extensions) would fail to compile, even though they are perfectly valid route patterns in standard routers.</p><div><hr></div><h2>The Solution: Parsing Affixed Captures</h2><p>To solve this, we needed to update the macro parser in <code>axum-macros/src/typed_path.rs</code>. Instead of checking if a segment starts and ends with braces, we updated the parser to scan for capture brackets <em>inside</em> each path segment.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5QAo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3eb2b521-d6ec-4aa7-9908-67007a85b85b_2560x1333.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5QAo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3eb2b521-d6ec-4aa7-9908-67007a85b85b_2560x1333.png 424w, https://substackcdn.com/image/fetch/$s_!5QAo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3eb2b521-d6ec-4aa7-9908-67007a85b85b_2560x1333.png 848w, https://substackcdn.com/image/fetch/$s_!5QAo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3eb2b521-d6ec-4aa7-9908-67007a85b85b_2560x1333.png 1272w, https://substackcdn.com/image/fetch/$s_!5QAo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3eb2b521-d6ec-4aa7-9908-67007a85b85b_2560x1333.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5QAo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3eb2b521-d6ec-4aa7-9908-67007a85b85b_2560x1333.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3eb2b521-d6ec-4aa7-9908-67007a85b85b_2560x1333.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Typed Path Segment Parsing Flow&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Typed Path Segment Parsing Flow" title="Typed Path Segment Parsing Flow" srcset="https://substackcdn.com/image/fetch/$s_!5QAo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3eb2b521-d6ec-4aa7-9908-67007a85b85b_2560x1333.png 424w, https://substackcdn.com/image/fetch/$s_!5QAo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3eb2b521-d6ec-4aa7-9908-67007a85b85b_2560x1333.png 848w, https://substackcdn.com/image/fetch/$s_!5QAo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3eb2b521-d6ec-4aa7-9908-67007a85b85b_2560x1333.png 1272w, https://substackcdn.com/image/fetch/$s_!5QAo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3eb2b521-d6ec-4aa7-9908-67007a85b85b_2560x1333.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><em>Figure 1: Visual flowchart showing the parsing logic extracting static prefixes, capture keys, and static suffixes from a route segment.</em></p><p>Here is the core logic implemented in the PR to split segments by capture boundaries while handling double-brace escaping (e.g., <code>{{escaped}}</code>):</p><pre><code>fn parse_path(path: &amp;LitStr) -&gt; syn::Result&lt;Vec&lt;Segment&gt;&gt; {
    let value = path.value();
    let mut segments = Vec::new();
    let mut rest = value.as_str();

    while let Some(start) = find_first_not_double(b'{', rest.as_bytes()) {
        if start &gt; 0 {
            segments.push(Segment::Static(rest[..start].to_owned()));
        }

        rest = &amp;rest[start + 1..];

        if let Some(end) = rest.find('}') {
            let capture = &amp;rest[..end];
            if capture.is_empty() || capture.contains('{') {
                return Err(syn::Error::new_spanned(path, "invalid capture in path"));
            }

            segments.push(Segment::Capture(
                capture.strip_prefix('*').unwrap_or(capture).to_owned(),
                path.span(),
            ));

            rest = &amp;rest[end + 1..];
        } else {
            segments.push(Segment::Static(format!("{{{rest}")));
            rest = "";
        }
    }

    if !rest.is_empty() {
        segments.push(Segment::Static(rest.to_owned()));
    }

    Ok(segments)
}
</code></pre><p>We also introduced a helper function, <code>find_first_not_double</code>, to skip escaped braces so they are treated as static route components rather than dynamic captures:</p><pre><code>fn find_first_not_double(needle: u8, haystack: &amp;[u8]) -&gt; Option&lt;usize&gt; {
    let mut possible_capture = 0;
    while let Some(index) = haystack
        .get(possible_capture..)
        .and_then(|haystack| haystack.iter().position(|byte| byte == &amp;needle))
    {
        let index = index + possible_capture;

        if haystack.get(index + 1) == Some(&amp;needle) {
            possible_capture = index + 2;
            continue;
        }

        return Some(index);
    }

    None
}
</code></pre><div><hr></div><h2>Verifying with Formatting &amp; Tests</h2><p>A crucial part of <code>TypedPath</code> is implementing the <code>Display</code> trait so path instances can be formatted back into URLs:</p><pre><code>let path = PrefixedCapture { username: "alice".to_owned() };
assert_eq!(format!("{}", path), "/@alice");
</code></pre><p>Because the parser now isolates the static prefix and suffix parts of a segment, <code>TypedPath</code> preserves formatting, percent-encodes capture values correctly (e.g. spaces turn into <code>%20</code>), and supports all standard Rust primitive types and custom deserialize structures.</p><p>The test coverage added in the PR ensures that prefixed, suffixed, and escaped routes compile and execute correctly:</p><pre><code>#[derive(TypedPath, Deserialize)]
#[typed_path("/@{username}")]
struct PrefixedCapture {
    username: String,
}

#[derive(TypedPath, Deserialize)]
#[typed_path("/files/{name}.json")]
struct SuffixedCapture {
    name: String,
}
</code></pre><p>This PR makes Axum's typed routing much more flexible and brings full path matching parity with standard dynamic route definitions.</p><p>Thanks for reading. See you in the next lab.</p>]]></content:encoded></item><item><title><![CDATA[Microsoft Windows Hardening | TryHackMe Write-up]]></title><description><![CDATA[Complete walkthrough for the Microsoft Windows Hardening TryHackMe room. Learn how to secure and harden Windows 10 OS configurations.]]></description><link>https://www.farrosfr.com/p/microsoft-windows-hardening-tryhackme-write-up</link><guid isPermaLink="false">https://www.farrosfr.com/p/microsoft-windows-hardening-tryhackme-write-up</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Thu, 09 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4dc25df2-a006-4e28-9938-a41286896d53_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1pdZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa90ec010-ad4e-4d3f-b96a-593a970f93f3_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1pdZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa90ec010-ad4e-4d3f-b96a-593a970f93f3_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!1pdZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa90ec010-ad4e-4d3f-b96a-593a970f93f3_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!1pdZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa90ec010-ad4e-4d3f-b96a-593a970f93f3_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!1pdZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa90ec010-ad4e-4d3f-b96a-593a970f93f3_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1pdZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa90ec010-ad4e-4d3f-b96a-593a970f93f3_1200x630.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a90ec010-ad4e-4d3f-b96a-593a970f93f3_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Microsoft Windows Hardening | TryHackMe Write-up&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Microsoft Windows Hardening | TryHackMe Write-up" title="Microsoft Windows Hardening | TryHackMe Write-up" srcset="https://substackcdn.com/image/fetch/$s_!1pdZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa90ec010-ad4e-4d3f-b96a-593a970f93f3_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!1pdZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa90ec010-ad4e-4d3f-b96a-593a970f93f3_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!1pdZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa90ec010-ad4e-4d3f-b96a-593a970f93f3_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!1pdZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa90ec010-ad4e-4d3f-b96a-593a970f93f3_1200x630.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>This is my write-up for the TryHackMe room on <a href="https://tryhackme.com/room/microsoftwindowshardening">Microsoft Windows Hardening</a>. Written in 2026, I hope this write-up helps others learn and practice cybersecurity.</p><h2>Task 1: Introduction</h2><p>System hardening improves a workstation's security posture by reducing vulnerabilities in its services, identity permissions, network connectivity, storage configurations, and &#8230;</p>
      <p>
          <a href="https://www.farrosfr.com/p/microsoft-windows-hardening-tryhackme-write-up">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Building a Full-Stack App on Cloudflare's Free Tier with Astro SSR]]></title><description><![CDATA[A practical guide to building and deploying a full-stack web app using Cloudflare Workers, D1 database, KV storage, and Astro SSR. Completely free.]]></description><link>https://www.farrosfr.com/p/building-a-full-stack-app-on-cloudflare-s-free-tier-with-astro-ssr</link><guid isPermaLink="false">https://www.farrosfr.com/p/building-a-full-stack-app-on-cloudflare-s-free-tier-with-astro-ssr</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Mon, 06 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/9d94dedf-792f-4725-96ca-5bc7962d5cf8_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Jyqx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec363f67-276c-4da0-808e-ebeaedd1b3b1_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Jyqx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec363f67-276c-4da0-808e-ebeaedd1b3b1_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!Jyqx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec363f67-276c-4da0-808e-ebeaedd1b3b1_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!Jyqx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec363f67-276c-4da0-808e-ebeaedd1b3b1_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!Jyqx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec363f67-276c-4da0-808e-ebeaedd1b3b1_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Jyqx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec363f67-276c-4da0-808e-ebeaedd1b3b1_1200x630.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ec363f67-276c-4da0-808e-ebeaedd1b3b1_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Building a Full-Stack App on Cloudflare's Free Tier with Astro SSR&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Building a Full-Stack App on Cloudflare's Free Tier with Astro SSR" title="Building a Full-Stack App on Cloudflare's Free Tier with Astro SSR" srcset="https://substackcdn.com/image/fetch/$s_!Jyqx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec363f67-276c-4da0-808e-ebeaedd1b3b1_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!Jyqx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec363f67-276c-4da0-808e-ebeaedd1b3b1_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!Jyqx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec363f67-276c-4da0-808e-ebeaedd1b3b1_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!Jyqx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec363f67-276c-4da0-808e-ebeaedd1b3b1_1200x630.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>I recently shared a <a href="https://www.threads.com/@farrosfr/post/DaZUbtqEsYT">post on Threads</a> about how generous Cloudflare's free tier is for side projects.</p><p>This isn't theoretical. I run a production app on this exact stack, handling <strong>27,000+ requests per day</strong> with <strong>zero errors</strong> and an average CPU time of <strong>5.24ms per request</strong>, all without paying a single cent.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pGU7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c74fc66-bf5c-4233-848c-aa2668c2c44f_1280x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pGU7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c74fc66-bf5c-4233-848c-aa2668c2c44f_1280x800.png 424w, https://substackcdn.com/image/fetch/$s_!pGU7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c74fc66-bf5c-4233-848c-aa2668c2c44f_1280x800.png 848w, https://substackcdn.com/image/fetch/$s_!pGU7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c74fc66-bf5c-4233-848c-aa2668c2c44f_1280x800.png 1272w, https://substackcdn.com/image/fetch/$s_!pGU7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c74fc66-bf5c-4233-848c-aa2668c2c44f_1280x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pGU7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c74fc66-bf5c-4233-848c-aa2668c2c44f_1280x800.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1c74fc66-bf5c-4233-848c-aa2668c2c44f_1280x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Cloudflare D1 Pricing Page&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Cloudflare D1 Pricing Page" title="Cloudflare D1 Pricing Page" srcset="https://substackcdn.com/image/fetch/$s_!pGU7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c74fc66-bf5c-4233-848c-aa2668c2c44f_1280x800.png 424w, https://substackcdn.com/image/fetch/$s_!pGU7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c74fc66-bf5c-4233-848c-aa2668c2c44f_1280x800.png 848w, https://substackcdn.com/image/fetch/$s_!pGU7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c74fc66-bf5c-4233-848c-aa2668c2c44f_1280x800.png 1272w, https://substackcdn.com/image/fetch/$s_!pGU7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c74fc66-bf5c-4233-848c-aa2668c2c44f_1280x800.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p><em>Figure 1: Cloudflare D1's free tier includes 5 GB storage, 5 million reads/day, and 100,000 writes/day.</em></p><h2>Why Cloudflare's Free Tier?</h2><p>Most cloud providers give you a "free trial" that expires after 30 days. Cloudflare's free tier is <strong>permanent</strong>. No credit card required, no surprise bills. For indie developers and side projects, this is a game changer.</p><p>Here's what you get for free:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wMRC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcadb7f20-3a47-4e81-96cf-9a0a3e8873cb_900x340.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wMRC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcadb7f20-3a47-4e81-96cf-9a0a3e8873cb_900x340.png 424w, https://substackcdn.com/image/fetch/$s_!wMRC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcadb7f20-3a47-4e81-96cf-9a0a3e8873cb_900x340.png 848w, https://substackcdn.com/image/fetch/$s_!wMRC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcadb7f20-3a47-4e81-96cf-9a0a3e8873cb_900x340.png 1272w, https://substackcdn.com/image/fetch/$s_!wMRC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcadb7f20-3a47-4e81-96cf-9a0a3e8873cb_900x340.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wMRC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcadb7f20-3a47-4e81-96cf-9a0a3e8873cb_900x340.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cadb7f20-3a47-4e81-96cf-9a0a3e8873cb_900x340.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Cloudflare Free Tier Limits&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Cloudflare Free Tier Limits" title="Cloudflare Free Tier Limits" srcset="https://substackcdn.com/image/fetch/$s_!wMRC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcadb7f20-3a47-4e81-96cf-9a0a3e8873cb_900x340.png 424w, https://substackcdn.com/image/fetch/$s_!wMRC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcadb7f20-3a47-4e81-96cf-9a0a3e8873cb_900x340.png 848w, https://substackcdn.com/image/fetch/$s_!wMRC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcadb7f20-3a47-4e81-96cf-9a0a3e8873cb_900x340.png 1272w, https://substackcdn.com/image/fetch/$s_!wMRC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcadb7f20-3a47-4e81-96cf-9a0a3e8873cb_900x340.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p><em>Figure 2: Summary of Cloudflare's permanent free tier limits for Workers, D1 database, KV store, and Pages.</em></p><p>Combined, this gives you a full-stack platform: compute, database, caching, and static hosting, all at the edge, globally distributed.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bAFX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ae9a20c-dd92-43b7-b17e-c4f1e1d46b7c_1280x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bAFX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ae9a20c-dd92-43b7-b17e-c4f1e1d46b7c_1280x800.png 424w, https://substackcdn.com/image/fetch/$s_!bAFX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ae9a20c-dd92-43b7-b17e-c4f1e1d46b7c_1280x800.png 848w, https://substackcdn.com/image/fetch/$s_!bAFX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ae9a20c-dd92-43b7-b17e-c4f1e1d46b7c_1280x800.png 1272w, https://substackcdn.com/image/fetch/$s_!bAFX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ae9a20c-dd92-43b7-b17e-c4f1e1d46b7c_1280x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bAFX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ae9a20c-dd92-43b7-b17e-c4f1e1d46b7c_1280x800.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ae9a20c-dd92-43b7-b17e-c4f1e1d46b7c_1280x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Cloudflare Workers Dashboard&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Cloudflare Workers Dashboard" title="Cloudflare Workers Dashboard" srcset="https://substackcdn.com/image/fetch/$s_!bAFX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ae9a20c-dd92-43b7-b17e-c4f1e1d46b7c_1280x800.png 424w, https://substackcdn.com/image/fetch/$s_!bAFX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ae9a20c-dd92-43b7-b17e-c4f1e1d46b7c_1280x800.png 848w, https://substackcdn.com/image/fetch/$s_!bAFX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ae9a20c-dd92-43b7-b17e-c4f1e1d46b7c_1280x800.png 1272w, https://substackcdn.com/image/fetch/$s_!bAFX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ae9a20c-dd92-43b7-b17e-c4f1e1d46b7c_1280x800.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><em>Figure 3: A real production dashboard. 27K requests in 24 hours, 0 errors, bindings for D1, KV, Assets, and Images.</em></p><h2>The Architecture</h2><p>The key insight from my experience: <strong>not everything needs to be server-rendered</strong>. By using Astro's hybrid rendering mode, you can prerender static pages at build time and only use SSR for pages that genuinely need real-time data. This dramatically reduces your D1 reads and keeps you well within free tier limits.</p><pre><code>&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474;                  Cloudflare Edge                &#9474;
&#9474;                                                 &#9474;
&#9474;  &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;  &#9474;
&#9474;  &#9474;  Assets  &#9474;   &#9474;  Worker  &#9474;   &#9474;     KV      &#9474;  &#9474;
&#9474;  &#9474; (Static) &#9474;   &#9474;  (SSR)   &#9474;&#9668;&#9472;&#9472;&#9474;  (Sessions) &#9474;  &#9474;
&#9474;  &#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;   &#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;   &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;  &#9474;
&#9474;       &#9474;              &#9474;                          &#9474;
&#9474;       &#9474;              &#9660;                          &#9474;
&#9474;       &#9474;         &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;                    &#9474;
&#9474;       &#9474;         &#9474;    D1    &#9474;                    &#9474;
&#9474;       &#9474;         &#9474;   (SQL)  &#9474;                    &#9474;
&#9474;       &#9474;         &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;                    &#9474;
&#9474;       &#9660;                                         &#9474;
&#9474;   Static Pages    Dynamic Pages                 &#9474;
&#9474;   (prerendered)   (server-rendered)             &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
</code></pre><p><strong>Static pages</strong> (homepage, about, blog posts) are prerendered at build time and served directly from the Assets binding. No Worker invocation, no D1 reads.</p><p><strong>Dynamic pages</strong> (dashboard, user settings, API routes) are server-rendered by the Worker, which queries D1 for data and KV for session management.</p><h3>Edge Routing with <code>_routes.json</code></h3><p>When you build an Astro hybrid application, the <code>@astrojs/cloudflare</code> adapter automatically generates a <code>_routes.json</code> file in the build output (<code>dist/</code>). This file is a configuration manifest for Cloudflare's edge router, defining:</p><ul><li><p><strong>Include rules</strong>: Wildcard patterns for routes that must invoke the Worker (e.g., <code>/bookmarks</code>, <code>/api/*</code>).</p></li><li><p><strong>Exclude rules</strong>: Patterns for routes that should bypass the Worker completely and serve static assets directly from Cloudflare's CDN storage (e.g., <code>/about</code>, <code>/_astro/*</code>, <code>/favicon.svg</code>).</p></li></ul><p>A typical automatically generated <code>_routes.json</code> looks like this:</p><pre><code>{
  "version": 1,
  "include": [
    "/bookmarks",
    "/api/*"
  ],
  "exclude": [
    "/about",
    "/_astro/*",
    "/favicon.svg"
  ]
}
</code></pre><p>Because this routing happens at Cloudflare's CDN layer <em>before</em> reaching the Worker:</p><ol><li><p><strong>0ms Worker CPU Time</strong>: Static pages cost zero Worker compute, leaving the full 10ms CPU limit for dynamic endpoints.</p></li><li><p><strong>0 Worker requests count</strong>: Excluded routes do not count toward your daily 100,000 Workers request quota.</p></li></ol><h3>Serverless SQL Without Connection Pooling</h3><p>In a traditional cloud setup (such as AWS Lambda or traditional VMs), scaling serverless functions requires connecting to a relational database like PostgreSQL or MySQL. This introduces two major performance bottlenecks:</p><ol><li><p><strong>TCP Handshake Latency</strong>: Creating new database connections is slow and expensive.</p></li><li><p><strong>Connection Exhaustion</strong>: High concurrent traffic can crash the database by exhausting available connections, requiring complex external poolers (like PgBouncer).</p></li></ol><p>Cloudflare D1 is different. It is a serverless SQL database built on SQLite that runs directly inside Cloudflare's V8 isolate environment. Because the database bindings are native, there is <strong>zero TCP connection overhead</strong> and <strong>zero pool limit constraints</strong>. When your Worker runs a query, it accesses D1 instantly without a database cold start.</p><h2>Step 1: Initialize the Project</h2><p>Start by creating a new Astro project with the Cloudflare adapter:</p><pre><code>npm create astro@latest ./my-app -- --template minimal --yes
cd my-app
npx astro add cloudflare --yes
</code></pre><p>This sets up Astro with the <code>@astrojs/cloudflare</code> adapter, which compiles your app into a Cloudflare Worker.</p><h2>Step 2: Create the D1 Database</h2><p>Use Wrangler (Cloudflare's CLI) to create a D1 database:</p><pre><code>npx wrangler d1 create my-app-db
</code></pre><p>This outputs a database ID. Add it to your <code>wrangler.toml</code> (create this file in your project root):</p><pre><code>name = "my-app"
compatibility_date = "2026-07-01"

[assets]
directory = "./dist"

[[d1_databases]]
binding = "DB"
database_name = "my-app-db"
database_id = "your-database-id-here"
</code></pre><p>Now create your schema. Create a file called <code>schema.sql</code>:</p><pre><code>CREATE TABLE IF NOT EXISTS bookmarks (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  url TEXT NOT NULL,
  title TEXT NOT NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
</code></pre><p>Apply it:</p><pre><code>npx wrangler d1 execute my-app-db --file=./schema.sql
</code></pre><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!a982!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ed55a43-3925-4949-b3a5-b3c6ae956500_1280x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!a982!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ed55a43-3925-4949-b3a5-b3c6ae956500_1280x800.png 424w, https://substackcdn.com/image/fetch/$s_!a982!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ed55a43-3925-4949-b3a5-b3c6ae956500_1280x800.png 848w, https://substackcdn.com/image/fetch/$s_!a982!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ed55a43-3925-4949-b3a5-b3c6ae956500_1280x800.png 1272w, https://substackcdn.com/image/fetch/$s_!a982!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ed55a43-3925-4949-b3a5-b3c6ae956500_1280x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!a982!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ed55a43-3925-4949-b3a5-b3c6ae956500_1280x800.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3ed55a43-3925-4949-b3a5-b3c6ae956500_1280x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Cloudflare D1 Database Dashboard Metrics&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Cloudflare D1 Database Dashboard Metrics" title="Cloudflare D1 Database Dashboard Metrics" srcset="https://substackcdn.com/image/fetch/$s_!a982!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ed55a43-3925-4949-b3a5-b3c6ae956500_1280x800.png 424w, https://substackcdn.com/image/fetch/$s_!a982!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ed55a43-3925-4949-b3a5-b3c6ae956500_1280x800.png 848w, https://substackcdn.com/image/fetch/$s_!a982!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ed55a43-3925-4949-b3a5-b3c6ae956500_1280x800.png 1272w, https://substackcdn.com/image/fetch/$s_!a982!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ed55a43-3925-4949-b3a5-b3c6ae956500_1280x800.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><em>Figure 4: Cloudflare D1 dashboard displaying total queries, row metrics (reads and writes), and current storage usage.</em></p><h3>Managing D1 with a GUI</h3><p>If you are used to desktop database managers like PGAdmin (for Postgres), Laragon/phpMyAdmin (for MySQL), or DBGate, you don't have to manage D1 solely via the command line. You can explore and edit your database using graphical interfaces:</p><h4>1. Remote Database: Cloudflare Dashboard Console</h4><p>For your deployed production database, Cloudflare provides a built-in web console and data explorer:</p><ul><li><p>Log in to your Cloudflare Dashboard.</p></li><li><p>Navigate to <strong>Workers &amp; Pages &gt; D1</strong> and select your database (<code>my-app-db</code>).</p></li><li><p>Click the <strong>Console</strong> tab to run SQL queries directly in your browser.</p></li><li><p>Click the <strong>Tables</strong> tab to browse schemas, view rows, and edit table values visually without writing SQL.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Z39j!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c10e14-160d-469d-ac5a-99a972c3ee22_1280x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Z39j!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c10e14-160d-469d-ac5a-99a972c3ee22_1280x800.png 424w, https://substackcdn.com/image/fetch/$s_!Z39j!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c10e14-160d-469d-ac5a-99a972c3ee22_1280x800.png 848w, https://substackcdn.com/image/fetch/$s_!Z39j!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c10e14-160d-469d-ac5a-99a972c3ee22_1280x800.png 1272w, https://substackcdn.com/image/fetch/$s_!Z39j!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c10e14-160d-469d-ac5a-99a972c3ee22_1280x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Z39j!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c10e14-160d-469d-ac5a-99a972c3ee22_1280x800.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/80c10e14-160d-469d-ac5a-99a972c3ee22_1280x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Cloudflare D1 Studio Data Explorer&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Cloudflare D1 Studio Data Explorer" title="Cloudflare D1 Studio Data Explorer" srcset="https://substackcdn.com/image/fetch/$s_!Z39j!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c10e14-160d-469d-ac5a-99a972c3ee22_1280x800.png 424w, https://substackcdn.com/image/fetch/$s_!Z39j!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c10e14-160d-469d-ac5a-99a972c3ee22_1280x800.png 848w, https://substackcdn.com/image/fetch/$s_!Z39j!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c10e14-160d-469d-ac5a-99a972c3ee22_1280x800.png 1272w, https://substackcdn.com/image/fetch/$s_!Z39j!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80c10e14-160d-469d-ac5a-99a972c3ee22_1280x800.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><em>Figure 5: Cloudflare D1 Studio interface displaying visual table columns, rows, and datatypes.</em></p><h4>2. Local Database: Standard SQLite Clients (TablePlus, DBeaver, DB Browser)</h4><p>When developing locally using Wrangler's local dev server, your database state is stored as a standard SQLite file inside your project directory at: <code>.wrangler/state/v3/d1/miniflare-D1DatabaseObject/</code></p><p>You can open this <code>.sqlite</code> file directly in any desktop SQLite client (such as TablePlus, DBeaver, DB Browser for SQLite, or the VS Code SQLite Viewer extension) to manage tables, run queries, and edit mock data locally.</p><h2>Step 3: Set Up KV for Sessions</h2><p>Create a KV namespace for session storage:</p><pre><code>npx wrangler kv namespace create SESSION
</code></pre><p>Add the output to your <code>wrangler.toml</code>:</p><pre><code>[[kv_namespaces]]
binding = "SESSION"
id = "your-kv-namespace-id-here"
</code></pre><p>KV is ideal for sessions because reads are extremely fast (edge-cached globally) and sessions are typically small key-value pairs. With 100K free reads/day, you can handle thousands of authenticated users.</p><h2>Step 4: Configure Astro for Hybrid Rendering</h2><p>Update your <code>astro.config.mjs</code> to enable hybrid rendering:</p><pre><code>import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';

export default defineConfig({
  output: 'hybrid',
  adapter: cloudflare({
    platformProxy: { enabled: true },
  }),
});
</code></pre><p>With <code>output: 'hybrid'</code>, pages are <strong>prerendered by default</strong>. Only pages that explicitly opt in to SSR will run on the Worker. This is how you keep your D1 reads low.</p><h2>Step 5: Build a Dynamic Page</h2><p>Create a server-rendered page that queries D1. Create <code>src/pages/bookmarks.astro</code>:</p><pre><code>---
export const prerender = false;

const runtime = Astro.locals.runtime;
const db = runtime.env.DB;

const { results } = await db
  .prepare('SELECT * FROM bookmarks ORDER BY created_at DESC')
  .all();
---

&lt;html&gt;
  &lt;body&gt;
    &lt;h1&gt;My Bookmarks&lt;/h1&gt;
    &lt;ul&gt;
      {results.map((b) =&gt; (
        &lt;li&gt;
          &lt;a href={b.url}&gt;{b.title}&lt;/a&gt;
          &lt;small&gt;{b.created_at}&lt;/small&gt;
        &lt;/li&gt;
      ))}
    &lt;/ul&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre><p>The key line is <code>export const prerender = false</code>. This tells Astro to server-render this page instead of prerendering it.</p><h2>Step 6: Add an API Route</h2><p>Create <code>src/pages/api/bookmarks.ts</code> to handle form submissions:</p><pre><code>export const prerender = false;

import type { APIRoute } from 'astro';

export const POST: APIRoute = async ({ request, locals }) =&gt; {
  const db = locals.runtime.env.DB;
  const form = await request.formData();
  const url = form.get('url')?.toString();
  const title = form.get('title')?.toString();

  if (!url || !title) {
    return new Response('Missing fields', { status: 400 });
  }

  await db
    .prepare('INSERT INTO bookmarks (url, title) VALUES (?, ?)')
    .bind(url, title)
    .run();

  return Response.redirect(new URL('/bookmarks', request.url), 303);
};
</code></pre><h2>Step 7: Deploy</h2><p>Deploy your app to Cloudflare:</p><pre><code>npx astro build
npx wrangler deploy
</code></pre><p>That's it. Your full-stack app is live on Cloudflare's global edge network.</p><h2>Optimization: Staying Within Free Tier Limits</h2><p>Here's the strategy I use to keep my app comfortably within the free tier:</p><h3>1. Prerender Everything You Can</h3><p>Any page that doesn't need real-time data should be prerendered. Homepage, about page, blog posts, documentation, all static. This means zero D1 reads for the majority of your traffic.</p><h3>2. Use Indexes on D1</h3><p>D1 counts <strong>every row scanned</strong>, not just rows returned. A full table scan on a 5,000-row table counts as 5,000 reads even if you only return 1 row. Always add indexes on columns you filter or sort by:</p><pre><code>CREATE INDEX idx_bookmarks_created
  ON bookmarks(created_at DESC);
</code></pre><h3>3. Use KV as a Cache Layer</h3><p>For frequently-read but rarely-changed data, cache D1 results in KV:</p><pre><code>const cacheKey = 'bookmarks:latest';
let cached = await env.SESSION.get(cacheKey, 'json');

if (!cached) {
  const { results } = await env.DB
    .prepare('SELECT * FROM bookmarks ORDER BY created_at DESC LIMIT 20')
    .all();
  await env.SESSION.put(cacheKey, JSON.stringify(results), {
    expirationTtl: 300,
  });
  cached = results;
}
</code></pre><p>This pattern converts D1 reads into KV reads, which have a much higher free tier limit (100K vs 5M, but KV reads are faster and reduce database load).</p><h3>4. Use Astro's Built-in Static Pages</h3><p>For your landing page and marketing content, keep <code>prerender = true</code> (the default in hybrid mode). These pages are served directly from the Assets binding with zero Worker invocations.</p><h2>Final Thoughts</h2><p>Cloudflare's free tier is genuinely one of the best offerings for indie developers right now. The combination of D1 (SQL database), KV (fast caching), Workers (edge compute), and Assets (static hosting) gives you a complete full-stack platform without spending a cent.</p><p>The trick is architecture: use Astro's hybrid rendering to keep static pages static, index your D1 tables properly, and cache aggressively with KV. Do this right, and you can serve tens of thousands of requests per day, completely free.</p><p>Thanks for reading. See you in the next lab.</p>]]></content:encoded></item><item><title><![CDATA[Linux System Hardening | TryHackMe Write-up]]></title><description><![CDATA[Complete walkthrough for Linux System Hardening TryHackme room. Learn how to improve the security posture of your Linux systems.]]></description><link>https://www.farrosfr.com/p/linux-system-hardening-tryhackme-write-up</link><guid isPermaLink="false">https://www.farrosfr.com/p/linux-system-hardening-tryhackme-write-up</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Sun, 05 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/7686860c-f777-40cd-9aac-33d450d5a442_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xIBg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3847b4de-fb3f-481a-b7b4-b0e55d3be475_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xIBg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3847b4de-fb3f-481a-b7b4-b0e55d3be475_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!xIBg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3847b4de-fb3f-481a-b7b4-b0e55d3be475_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!xIBg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3847b4de-fb3f-481a-b7b4-b0e55d3be475_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!xIBg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3847b4de-fb3f-481a-b7b4-b0e55d3be475_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xIBg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3847b4de-fb3f-481a-b7b4-b0e55d3be475_1200x630.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3847b4de-fb3f-481a-b7b4-b0e55d3be475_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Linux System Hardening | TryHackMe Write-up&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Linux System Hardening | TryHackMe Write-up" title="Linux System Hardening | TryHackMe Write-up" srcset="https://substackcdn.com/image/fetch/$s_!xIBg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3847b4de-fb3f-481a-b7b4-b0e55d3be475_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!xIBg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3847b4de-fb3f-481a-b7b4-b0e55d3be475_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!xIBg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3847b4de-fb3f-481a-b7b4-b0e55d3be475_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!xIBg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3847b4de-fb3f-481a-b7b4-b0e55d3be475_1200x630.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p></p><p>This is my write-up for the TryHackMe room on <a href="https://tryhackme.com/room/linuxsystemhardening">Linux System Hardening</a>. Written in 2026, I hope this write-up helps others learn and practice cybersecurity.</p><h2>Task 1: Introduction</h2><p>Linux is a robust and cost-effective alternative to closed-source operating systems for hosting critical services. However, deploying Linux securely requires system hardening. This &#8230;</p>
      <p>
          <a href="https://www.farrosfr.com/p/linux-system-hardening-tryhackme-write-up">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Solar PV Monitoring Networks: Troubleshooting Routing and Subnets]]></title><description><![CDATA[A comprehensive guide on network architecture, troubleshooting subnets, routing gateways, and DNS settings for industrial solar PV loggers.]]></description><link>https://www.farrosfr.com/p/solar-pv-monitoring-networks-troubleshooting-routing-and-subnets</link><guid isPermaLink="false">https://www.farrosfr.com/p/solar-pv-monitoring-networks-troubleshooting-routing-and-subnets</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Thu, 02 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/442d99c1-899b-413f-bf27-41e5645a6958_1376x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_0rk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d4292af-5ece-485e-b7f0-82761010abcb_1376x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_0rk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d4292af-5ece-485e-b7f0-82761010abcb_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!_0rk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d4292af-5ece-485e-b7f0-82761010abcb_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!_0rk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d4292af-5ece-485e-b7f0-82761010abcb_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!_0rk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d4292af-5ece-485e-b7f0-82761010abcb_1376x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_0rk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d4292af-5ece-485e-b7f0-82761010abcb_1376x768.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9d4292af-5ece-485e-b7f0-82761010abcb_1376x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Solar PV Monitoring Networks: Troubleshooting Routing and Subnets&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Solar PV Monitoring Networks: Troubleshooting Routing and Subnets" title="Solar PV Monitoring Networks: Troubleshooting Routing and Subnets" srcset="https://substackcdn.com/image/fetch/$s_!_0rk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d4292af-5ece-485e-b7f0-82761010abcb_1376x768.png 424w, https://substackcdn.com/image/fetch/$s_!_0rk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d4292af-5ece-485e-b7f0-82761010abcb_1376x768.png 848w, https://substackcdn.com/image/fetch/$s_!_0rk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d4292af-5ece-485e-b7f0-82761010abcb_1376x768.png 1272w, https://substackcdn.com/image/fetch/$s_!_0rk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d4292af-5ece-485e-b7f0-82761010abcb_1376x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>Connecting a <strong>Huawei SmartLogger 3000</strong> to the cloud via a cellular 4G router, such as the <strong>TP-Link TL-MR6400</strong>, often presents routing and subnet mismatch challenges for solar PV installers.</p><p>This post provides a quick troubleshooting guide and step-by-step instructions to resolve gateway mismatches and connect your SmartLogger to the <strong>Huawei FusionSolar management system (NMS)</strong>.</p><div><hr></div><h2>1. Network Theory: Subnets, Gateways, and DNS</h2><p>To understand why connection issues occur, we must look at how data travels across the network. A foundational framework for this is the <strong>OSI (Open Systems Interconnection) Model</strong>, which divides network communication into seven logical layers:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!i9CA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F496db55f-c67d-4893-aad3-6c6286a688d5_3200x1493.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!i9CA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F496db55f-c67d-4893-aad3-6c6286a688d5_3200x1493.png 424w, https://substackcdn.com/image/fetch/$s_!i9CA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F496db55f-c67d-4893-aad3-6c6286a688d5_3200x1493.png 848w, https://substackcdn.com/image/fetch/$s_!i9CA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F496db55f-c67d-4893-aad3-6c6286a688d5_3200x1493.png 1272w, https://substackcdn.com/image/fetch/$s_!i9CA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F496db55f-c67d-4893-aad3-6c6286a688d5_3200x1493.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!i9CA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F496db55f-c67d-4893-aad3-6c6286a688d5_3200x1493.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/496db55f-c67d-4893-aad3-6c6286a688d5_3200x1493.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;OSI Model Layers and Setup Applications&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="OSI Model Layers and Setup Applications" title="OSI Model Layers and Setup Applications" srcset="https://substackcdn.com/image/fetch/$s_!i9CA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F496db55f-c67d-4893-aad3-6c6286a688d5_3200x1493.png 424w, https://substackcdn.com/image/fetch/$s_!i9CA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F496db55f-c67d-4893-aad3-6c6286a688d5_3200x1493.png 848w, https://substackcdn.com/image/fetch/$s_!i9CA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F496db55f-c67d-4893-aad3-6c6286a688d5_3200x1493.png 1272w, https://substackcdn.com/image/fetch/$s_!i9CA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F496db55f-c67d-4893-aad3-6c6286a688d5_3200x1493.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p><em>Figure 1: Visual representation of the 7 OSI layers mapping to our SmartLogger setup.</em></p><p>While a complete connection relies on all seven layers, troubleshooting connectivity issues almost always starts at the bottom three layers: <strong>Physical (Layer 1)</strong>, <strong>Data Link (Layer 2)</strong>, and <strong>Network (Layer 3)</strong>. Let's examine these core concepts in detail:</p><h3>Subnetting and Subnet Masks</h3><p>An IP address consists of two parts: the network address and the host address. The <strong>Subnet Mask</strong> determines where the division lies. For example, with a standard subnet mask of <code>255.255.255.0</code> (or a <code>/24</code> prefix):</p><ul><li><p>Devices on the <code>192.168.8.x</code> network can only communicate directly with other devices on <code>192.168.8.x</code>.</p></li><li><p>Devices on the <code>192.168.7.x</code> network are isolated and cannot see the <code>192.168.8.x</code> network, even if they are plugged into the same switch.</p></li></ul><h3>The Role of the Default Gateway</h3><p>When a device (like a SmartLogger) wants to send a packet to an IP address outside its local subnet (for example, to a cloud server on the internet), it cannot send it directly. Instead, it must forward the packet to a local coordinator called the <strong>Default Gateway</strong> (typically your router). For routing to work:</p><ol><li><p>The Default Gateway's IP address <strong>must be on the same subnet</strong> as the device's local interface.</p></li><li><p>If your device has an IP of <code>192.168.8.20</code>, its gateway must be something like <code>192.168.8.1</code> or <code>192.168.8.2</code>. It cannot be on another subnet like <code>192.168.0.1</code>.</p></li></ol><h3>Domain Name Resolution (DNS)</h3><p>When connecting to a server like <code>intl.fusionsolar.huawei.com</code>, the logger must translate that domain name into a numeric IP address. The <strong>DNS Server</strong> is responsible for this lookup. If your DNS setting is incorrect or pointing to a dead gateway, the logger will fail to resolve the domain, resulting in connection timeouts.</p><h3>Solar PV Telemetry Architecture: Local Modbus to Cloud WAN</h3><p>To contextualize this network theory, consider the physical and logical flow of telemetry in a typical commercial solar installation:</p><ol><li><p><strong>Data Acquisition (Field Level):</strong> Solar inverters, grid meters, and weather sensors (measuring solar irradiance and module temperature) generate raw telemetry. These devices communicate locally via <strong>RS-485 serial daisy-chains</strong> using the <strong>Modbus RTU</strong> protocol, or via local switches using <strong>Modbus TCP</strong>.</p></li><li><p><strong>Data Aggregation (Edge Level):</strong> The SmartLogger acts as the network coordinator (Modbus Master), polling the slaved inverters and sensors at regular intervals (e.g., every 5 minutes) to gather active power outputs, voltage readings, and environmental diagnostics.</p></li><li><p><strong>Data Transmission (WAN Level):</strong> The SmartLogger packetizes this data, encrypts it via SSL/TLS, and routes it out of its WAN interface into a local router (like the 4G TP-Link). The router forwards these outbound TCP packets across cellular or fiber WANs to the <strong>FusionSolar Cloud Network Management System (NMS)</strong>.</p></li></ol><h4>The "Local vs. Cloud" Diagnostic Trap</h4><p>When the default gateway is misconfigured, a classic diagnostic mismatch occurs:</p><ul><li><p><strong>Locally:</strong> The SmartLogger successfully polls the inverters via local Modbus. The inverter status LEDs blink green, showing active generation.</p></li><li><p><strong>Remotely:</strong> The central NMS cloud portal registers the entire solar plant as <strong>offline</strong> and triggers alarms because the SmartLogger's outbound TCP packets cannot route past the misconfigured local gateway.</p></li><li><p><strong>The Trap:</strong> Field technicians often troubleshoot the physical cabling or serial Modbus parameters first, failing to realize the fault is a simple Layer 3 IP routing mismatch between the logger WAN port and the cellular router.</p></li></ul><div><hr></div><h2>2. Case Study: Troubleshooting a Connection Mismatch</h2><p>Let's look at a common scenario where a technician is onsite attempting to configure a SmartLogger using a laptop.</p><h3>The Diagnostic State</h3><p>To configure the SmartLogger without losing internet connectivity, the laptop is connected to <strong>two network ports simultaneously</strong>:</p><ul><li><p><strong>Port 1 (Physical LAN Port):</strong> Connected via Ethernet cable directly to the SmartLogger.</p><ul><li><p><strong>Laptop IP:</strong> <code>192.168.7.100</code> (Static)</p></li><li><p><strong>Destination Local WebUI:</strong> <code>192.168.7.10</code></p></li></ul></li><li><p><strong>Port 2 (Wireless Wi-Fi Card):</strong> Connected wirelessly to the TP-Link Router.</p><ul><li><p><strong>Laptop IP:</strong> <code>192.168.8.100</code> (DHCP)</p></li><li><p><strong>Default Gateway (Internet):</strong> <code>192.168.8.2</code></p></li></ul></li></ul><h3>Laptop Dual-Routing Behavior</h3><p>In this state, the laptop's operating system maintains two distinct routing paths:</p><ol><li><p><strong>Local Subnet Traffic:</strong> Packets bound for <code>192.168.7.x</code> are routed directly out of the physical Ethernet interface to access the SmartLogger's local WebUI (Enspire).</p></li><li><p><strong>Internet-Bound Traffic:</strong> All external traffic (requests to NMS portals, search engines, etc.) is routed out of the wireless interface to the TP-Link router (<code>192.168.8.2</code>), which serves as the default gateway. The SmartLogger is not a gateway router and does not provide internet access to the laptop over the LAN cable.</p></li></ol><p>Running <code>ipconfig</code> on the PC displays the active configuration:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!buct!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a19cef3-024b-430e-b6cb-ffa0b1a0dceb_720x1280.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!buct!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a19cef3-024b-430e-b6cb-ffa0b1a0dceb_720x1280.png 424w, https://substackcdn.com/image/fetch/$s_!buct!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a19cef3-024b-430e-b6cb-ffa0b1a0dceb_720x1280.png 848w, https://substackcdn.com/image/fetch/$s_!buct!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a19cef3-024b-430e-b6cb-ffa0b1a0dceb_720x1280.png 1272w, https://substackcdn.com/image/fetch/$s_!buct!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a19cef3-024b-430e-b6cb-ffa0b1a0dceb_720x1280.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!buct!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a19cef3-024b-430e-b6cb-ffa0b1a0dceb_720x1280.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0a19cef3-024b-430e-b6cb-ffa0b1a0dceb_720x1280.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Laptop Network Configuration showing active Wi-Fi and Ethernet adapters&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Laptop Network Configuration showing active Wi-Fi and Ethernet adapters" title="Laptop Network Configuration showing active Wi-Fi and Ethernet adapters" srcset="https://substackcdn.com/image/fetch/$s_!buct!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a19cef3-024b-430e-b6cb-ffa0b1a0dceb_720x1280.png 424w, https://substackcdn.com/image/fetch/$s_!buct!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a19cef3-024b-430e-b6cb-ffa0b1a0dceb_720x1280.png 848w, https://substackcdn.com/image/fetch/$s_!buct!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a19cef3-024b-430e-b6cb-ffa0b1a0dceb_720x1280.png 1272w, https://substackcdn.com/image/fetch/$s_!buct!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a19cef3-024b-430e-b6cb-ffa0b1a0dceb_720x1280.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><em>Figure 2: ipconfig output proving the TP-Link router resides on 192.168.8.2.</em></p><h3>The Root Cause of Connection Failure</h3><p>The SmartLogger's WAN port was configured with a static IP of <code>192.168.8.11</code>, which matches the router's subnet (<code>192.168.8.x</code>). However, two critical parameters were misconfigured:</p><ol><li><p><strong>Default Gateway:</strong> Set to <code>192.168.8.1</code>. Since the router is actually at <code>192.168.8.2</code> (as confirmed by the PC's Wi-Fi network gateway), all internet-bound packets from the logger were being sent to a non-existent IP address.</p></li><li><p><strong>Primary DNS:</strong> Set to <code>192.168.8.1</code>, which also failed to resolve.</p></li></ol><h3>Subnet Conflict &amp; Ambiguity (LAN vs. WAN)</h3><p>By default, the Huawei SmartLogger's LAN interface is pre-configured with the IP address <code>192.168.8.10</code> (subnet <code>192.168.8.x</code>). However, the TP-Link cellular router also routes traffic on the <code>192.168.8.x</code> subnet.</p><p>If the SmartLogger's LAN port is left at its default IP, connecting its WAN port to the TP-Link router results in a <strong>subnet routing conflict</strong>&#8212;where both physical interfaces belong to the same IP subnet. Since a device cannot distinguish routing paths when two active interfaces share a subnet, the routing table becomes ambiguous. To resolve this, the installer must change the SmartLogger's LAN port IP to a different subnet, such as <code>192.168.7.10</code> (subnet <code>192.168.7.x</code>). This isolates local configuration traffic from WAN internet traffic.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fqrE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5f3786d-156e-47e6-aab2-5b9959afd1e8_2667x1467.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fqrE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5f3786d-156e-47e6-aab2-5b9959afd1e8_2667x1467.png 424w, https://substackcdn.com/image/fetch/$s_!fqrE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5f3786d-156e-47e6-aab2-5b9959afd1e8_2667x1467.png 848w, https://substackcdn.com/image/fetch/$s_!fqrE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5f3786d-156e-47e6-aab2-5b9959afd1e8_2667x1467.png 1272w, https://substackcdn.com/image/fetch/$s_!fqrE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5f3786d-156e-47e6-aab2-5b9959afd1e8_2667x1467.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fqrE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5f3786d-156e-47e6-aab2-5b9959afd1e8_2667x1467.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d5f3786d-156e-47e6-aab2-5b9959afd1e8_2667x1467.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Huawei SmartLogger 3000 Routing Topology&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Huawei SmartLogger 3000 Routing Topology" title="Huawei SmartLogger 3000 Routing Topology" srcset="https://substackcdn.com/image/fetch/$s_!fqrE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5f3786d-156e-47e6-aab2-5b9959afd1e8_2667x1467.png 424w, https://substackcdn.com/image/fetch/$s_!fqrE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5f3786d-156e-47e6-aab2-5b9959afd1e8_2667x1467.png 848w, https://substackcdn.com/image/fetch/$s_!fqrE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5f3786d-156e-47e6-aab2-5b9959afd1e8_2667x1467.png 1272w, https://substackcdn.com/image/fetch/$s_!fqrE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5f3786d-156e-47e6-aab2-5b9959afd1e8_2667x1467.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><em>Figure 3: Visual mapping of the routing mismatch (left) and the corrected working topology (right).</em></p><div><hr></div><h2>3. Practical Steps: Establishing the Connection</h2><p>To connect the SmartLogger 3000 to the internet through the TP-Link router, perform the following steps:</p><h3>Step 1: Physical Cabling</h3><p>Connect a standard RJ45 Ethernet cable from the <strong>WAN port</strong> of the SmartLogger to one of the yellow <strong>LAN ports</strong> of the TP-Link router. Keep your laptop plugged into the SmartLogger's <strong>LAN port</strong> to access the settings.</p><h3>Step 2: Configure Wired Network Parameters</h3><p>Log in to the Enspire WebUI (default LAN IP <code>https://192.168.8.10</code> or your custom IP, e.g., <code>https://192.168.7.10</code>). Navigate to <strong>Settings</strong> &gt; <strong>Comm. Param.</strong> &gt; <strong>Wired Network</strong> and configure the WAN parameters:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lrTN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcfd0aaf-95e7-4754-97b0-b0689d6f7569_720x1280.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lrTN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcfd0aaf-95e7-4754-97b0-b0689d6f7569_720x1280.png 424w, https://substackcdn.com/image/fetch/$s_!lrTN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcfd0aaf-95e7-4754-97b0-b0689d6f7569_720x1280.png 848w, https://substackcdn.com/image/fetch/$s_!lrTN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcfd0aaf-95e7-4754-97b0-b0689d6f7569_720x1280.png 1272w, https://substackcdn.com/image/fetch/$s_!lrTN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcfd0aaf-95e7-4754-97b0-b0689d6f7569_720x1280.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lrTN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcfd0aaf-95e7-4754-97b0-b0689d6f7569_720x1280.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bcfd0aaf-95e7-4754-97b0-b0689d6f7569_720x1280.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Corrected Wired Network Parameters in the Enspire interface&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Corrected Wired Network Parameters in the Enspire interface" title="Corrected Wired Network Parameters in the Enspire interface" srcset="https://substackcdn.com/image/fetch/$s_!lrTN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcfd0aaf-95e7-4754-97b0-b0689d6f7569_720x1280.png 424w, https://substackcdn.com/image/fetch/$s_!lrTN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcfd0aaf-95e7-4754-97b0-b0689d6f7569_720x1280.png 848w, https://substackcdn.com/image/fetch/$s_!lrTN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcfd0aaf-95e7-4754-97b0-b0689d6f7569_720x1280.png 1272w, https://substackcdn.com/image/fetch/$s_!lrTN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcfd0aaf-95e7-4754-97b0-b0689d6f7569_720x1280.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><em>Figure 4: Wired Network configuration settings in Enspire.</em></p><ul><li><p><strong>WAN/LAN port working mode:</strong> Set to <code>WAN+LAN</code> (default).</p></li><li><p><strong>IP Address:</strong> Set to <code>192.168.8.20</code> (use a static IP outside the router's DHCP pool&#8212;typically <code>.100</code> to <code>.199</code>&#8212;to avoid IP conflicts).</p></li><li><p><strong>Subnet Mask:</strong> <code>255.255.255.0</code></p></li><li><p><strong>Default Gateway:</strong> <code>192.168.8.2</code> (Matching the router's LAN IP).</p></li><li><p><strong>Primary DNS Server:</strong> <code>8.8.8.8</code> (Google Public DNS).</p></li><li><p><strong>Secondary DNS Server:</strong> <code>8.8.4.4</code> (Backup DNS).</p></li></ul><p>Click <strong>Submit</strong> to save and apply the settings.</p><h3>Step 3: Configure the Management System (NMS)</h3><p>Navigate to <strong>Settings</strong> &gt; <strong>Comm. Param.</strong> &gt; <strong>Management System</strong> to connect the logger to the Huawei FusionSolar cloud portal:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8cMl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e944b1a-c33a-4603-9f34-89e261b111bb_720x1280.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8cMl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e944b1a-c33a-4603-9f34-89e261b111bb_720x1280.png 424w, https://substackcdn.com/image/fetch/$s_!8cMl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e944b1a-c33a-4603-9f34-89e261b111bb_720x1280.png 848w, https://substackcdn.com/image/fetch/$s_!8cMl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e944b1a-c33a-4603-9f34-89e261b111bb_720x1280.png 1272w, https://substackcdn.com/image/fetch/$s_!8cMl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e944b1a-c33a-4603-9f34-89e261b111bb_720x1280.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8cMl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e944b1a-c33a-4603-9f34-89e261b111bb_720x1280.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4e944b1a-c33a-4603-9f34-89e261b111bb_720x1280.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;FusionSolar Management System parameters showing Connected status&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="FusionSolar Management System parameters showing Connected status" title="FusionSolar Management System parameters showing Connected status" srcset="https://substackcdn.com/image/fetch/$s_!8cMl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e944b1a-c33a-4603-9f34-89e261b111bb_720x1280.png 424w, https://substackcdn.com/image/fetch/$s_!8cMl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e944b1a-c33a-4603-9f34-89e261b111bb_720x1280.png 848w, https://substackcdn.com/image/fetch/$s_!8cMl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e944b1a-c33a-4603-9f34-89e261b111bb_720x1280.png 1272w, https://substackcdn.com/image/fetch/$s_!8cMl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e944b1a-c33a-4603-9f34-89e261b111bb_720x1280.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><em>Figure 5: NMS settings showing successful connection status.</em></p><ul><li><p><strong>Server:</strong> <code>intl.fusionsolar.huawei.com</code> (or regional servers like <code>sg5.fusionsolar.huawei.com</code> for Southeast Asia).</p></li><li><p><strong>Port:</strong> <code>27250</code> (or <code>25000</code> depending on the portal's SSL requirements).</p></li><li><p><strong>Address Mode:</strong> <code>Logical address</code>.</p></li><li><p><strong>SSL Encryption:</strong> <code>Enable</code>.</p></li></ul><p>Click <strong>Submit</strong>. After a few moments, the <strong>NMS connection status</strong> should change from <em>Connecting</em> to <strong>Connected</strong>, verifying the logger is online and reporting telemetry successfully.</p><div><hr></div><h2>4. Troubleshooting Summary Checklist</h2><p>When setting up solar monitoring network devices, always verify:</p><ul><li><p><strong>Router IP Address:</strong> Double-check your router's actual LAN IP rather than assuming it is <code>.1</code> or <code>.254</code>.</p></li><li><p><strong>Static IP Safety:</strong> Choose static IPs that sit outside your router's active DHCP range to prevent random connection dropouts due to IP conflicts.</p></li><li><p><strong>Gateway Congruence:</strong> Ensure your device's static gateway matches the router IP on the same subnet.</p></li><li><p><strong>DNS Verification:</strong> Configure a public DNS (e.g. <code>8.8.8.8</code>) if your router does not support local DNS forwarding.</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Become a Defender | TryHackMe Write-up]]></title><description><![CDATA[Complete walkthrough for Become a Defender TryHackme room. Explore defensive security, cyber infrastructure, and how to protect systems from attacks.]]></description><link>https://www.farrosfr.com/p/become-a-defender-tryhackme-write-up</link><guid isPermaLink="false">https://www.farrosfr.com/p/become-a-defender-tryhackme-write-up</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Wed, 01 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/70d65d00-75b6-45ab-aa7d-0fe50e8a4710_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Yis0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ecb539-c430-43cc-9923-48842190547a_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Yis0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ecb539-c430-43cc-9923-48842190547a_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!Yis0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ecb539-c430-43cc-9923-48842190547a_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!Yis0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ecb539-c430-43cc-9923-48842190547a_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!Yis0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ecb539-c430-43cc-9923-48842190547a_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Yis0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ecb539-c430-43cc-9923-48842190547a_1200x630.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/71ecb539-c430-43cc-9923-48842190547a_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Become a Defender | TryHackMe Write-up&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Become a Defender | TryHackMe Write-up" title="Become a Defender | TryHackMe Write-up" srcset="https://substackcdn.com/image/fetch/$s_!Yis0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ecb539-c430-43cc-9923-48842190547a_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!Yis0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ecb539-c430-43cc-9923-48842190547a_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!Yis0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ecb539-c430-43cc-9923-48842190547a_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!Yis0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71ecb539-c430-43cc-9923-48842190547a_1200x630.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>This is my write-up for the TryHackMe room on <a href="https://tryhackme.com/room/becomeadefender">Become a Defender</a>. Written in 2026, I hope this write-up helps others learn and practice cybersecurity.</p><h2>Task 1: What Is Defensive Security?</h2><p>Defensive security focuses on preventing, detecting, and mitigating cyberattacks. Defenders, collectively known as the Blue Team, must adopt a defense mindset&#8212;understandin&#8230;</p>
      <p>
          <a href="https://www.farrosfr.com/p/become-a-defender-tryhackme-write-up">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Cryptography Concepts | TryHackMe Write-up]]></title><description><![CDATA[Complete walkthrough for Cryptography Concepts TryHackme room. This room provides an understanding of cryptography in our everyday digital encounters.]]></description><link>https://www.farrosfr.com/p/cryptography-concepts-tryhackme-write-up</link><guid isPermaLink="false">https://www.farrosfr.com/p/cryptography-concepts-tryhackme-write-up</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Wed, 01 Jul 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/04bf1aa5-2502-43b7-b7b0-27b6cd1fc10c_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LAoO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb53057fb-89db-468f-bfb9-a31c9366a26d_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LAoO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb53057fb-89db-468f-bfb9-a31c9366a26d_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!LAoO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb53057fb-89db-468f-bfb9-a31c9366a26d_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!LAoO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb53057fb-89db-468f-bfb9-a31c9366a26d_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!LAoO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb53057fb-89db-468f-bfb9-a31c9366a26d_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LAoO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb53057fb-89db-468f-bfb9-a31c9366a26d_1200x630.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b53057fb-89db-468f-bfb9-a31c9366a26d_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Cryptography Concepts | TryHackMe Write-up&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Cryptography Concepts | TryHackMe Write-up" title="Cryptography Concepts | TryHackMe Write-up" srcset="https://substackcdn.com/image/fetch/$s_!LAoO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb53057fb-89db-468f-bfb9-a31c9366a26d_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!LAoO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb53057fb-89db-468f-bfb9-a31c9366a26d_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!LAoO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb53057fb-89db-468f-bfb9-a31c9366a26d_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!LAoO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb53057fb-89db-468f-bfb9-a31c9366a26d_1200x630.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>This is my write-up for the TryHackMe room on <a href="https://tryhackme.com/room/cryptographyconcepts">Cryptography Concepts</a>. Written in 2026, I hope this write-up helps others learn and practice cybersecurity.</p><h2>Task 1: Introduction</h2><p>Cryptography is the practice of securing communications by mathematical scrambling, ensuring the confidentiality and integrity of data in transit. In a digital world where informatio&#8230;</p>
      <p>
          <a href="https://www.farrosfr.com/p/cryptography-concepts-tryhackme-write-up">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[JavaScript: Simple Demo | TryHackMe Write-up]]></title><description><![CDATA[Complete walkthrough for JavaScript: Simple Demo TryHackme room. Explore what a basic JavaScript program looks like.]]></description><link>https://www.farrosfr.com/p/javascript-simple-demo-tryhackme-write-up</link><guid isPermaLink="false">https://www.farrosfr.com/p/javascript-simple-demo-tryhackme-write-up</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Tue, 30 Jun 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/36f906b5-ba8d-43f1-83e9-3163249ea100_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4tzG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6158ccf6-84bb-44fb-a7e7-79f814f6caf6_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4tzG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6158ccf6-84bb-44fb-a7e7-79f814f6caf6_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!4tzG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6158ccf6-84bb-44fb-a7e7-79f814f6caf6_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!4tzG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6158ccf6-84bb-44fb-a7e7-79f814f6caf6_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!4tzG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6158ccf6-84bb-44fb-a7e7-79f814f6caf6_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4tzG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6158ccf6-84bb-44fb-a7e7-79f814f6caf6_1200x630.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6158ccf6-84bb-44fb-a7e7-79f814f6caf6_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;JavaScript: Simple Demo | TryHackMe Write-up&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="JavaScript: Simple Demo | TryHackMe Write-up" title="JavaScript: Simple Demo | TryHackMe Write-up" srcset="https://substackcdn.com/image/fetch/$s_!4tzG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6158ccf6-84bb-44fb-a7e7-79f814f6caf6_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!4tzG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6158ccf6-84bb-44fb-a7e7-79f814f6caf6_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!4tzG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6158ccf6-84bb-44fb-a7e7-79f814f6caf6_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!4tzG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6158ccf6-84bb-44fb-a7e7-79f814f6caf6_1200x630.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>This is my write-up for the TryHackMe room on <a href="https://tryhackme.com/room/javascriptsimpledemo">JavaScript: Simple Demo</a>. Written in 2026, I hope this write-up helps others learn and practice cybersecurity.</p><h2>Task 1: Introduction</h2><p>JavaScript is a versatile programming language used widely for client-side interactions in web browsers and server-side applications through Node.js. In this room, we will build a &#8230;</p>
      <p>
          <a href="https://www.farrosfr.com/p/javascript-simple-demo-tryhackme-write-up">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[The CIA Triad | TryHackMe Write-up]]></title><description><![CDATA[Complete walkthrough for The CIA Triad TryHackme room. Understand the CIA Triad and how it shapes cyber security mindset.]]></description><link>https://www.farrosfr.com/p/the-cia-triad-tryhackme-write-up</link><guid isPermaLink="false">https://www.farrosfr.com/p/the-cia-triad-tryhackme-write-up</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Tue, 30 Jun 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/033d73ac-ee0c-49c9-8325-8e6488e039bd_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_OBP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dce8f69-c2db-49df-80ca-c69e48f9af47_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_OBP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dce8f69-c2db-49df-80ca-c69e48f9af47_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!_OBP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dce8f69-c2db-49df-80ca-c69e48f9af47_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!_OBP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dce8f69-c2db-49df-80ca-c69e48f9af47_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!_OBP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dce8f69-c2db-49df-80ca-c69e48f9af47_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_OBP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dce8f69-c2db-49df-80ca-c69e48f9af47_1200x630.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4dce8f69-c2db-49df-80ca-c69e48f9af47_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;The CIA Triad | TryHackMe Write-up&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The CIA Triad | TryHackMe Write-up" title="The CIA Triad | TryHackMe Write-up" srcset="https://substackcdn.com/image/fetch/$s_!_OBP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dce8f69-c2db-49df-80ca-c69e48f9af47_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!_OBP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dce8f69-c2db-49df-80ca-c69e48f9af47_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!_OBP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dce8f69-c2db-49df-80ca-c69e48f9af47_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!_OBP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4dce8f69-c2db-49df-80ca-c69e48f9af47_1200x630.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>This is my write-up for the TryHackMe room on <a href="https://tryhackme.com/room/theciatriad">The CIA Triad</a>. Written in 2026, I hope this write-up helps others learn and practice cybersecurity.</p><h2>Task 1: Introduction</h2><p>Cybersecurity focuses on protecting the digital world&#8212;systems, networks, and applications. Specifically, security measures guard three core aspects of data: confidentiality, integrity, and a&#8230;</p>
      <p>
          <a href="https://www.farrosfr.com/p/the-cia-triad-tryhackme-write-up">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Python: Simple Demo | TryHackMe Write-up]]></title><description><![CDATA[Complete walkthrough for Python: Simple Demo TryHackme room. Explore what a basic Python program looks like.]]></description><link>https://www.farrosfr.com/p/python-simple-demo-tryhackme-write-up</link><guid isPermaLink="false">https://www.farrosfr.com/p/python-simple-demo-tryhackme-write-up</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Mon, 29 Jun 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/10dd749c-a5e5-47fd-b3fe-4c1178fc185e_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SniY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794513e8-3fba-4a3a-8ad3-ee01615c12d2_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SniY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794513e8-3fba-4a3a-8ad3-ee01615c12d2_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!SniY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794513e8-3fba-4a3a-8ad3-ee01615c12d2_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!SniY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794513e8-3fba-4a3a-8ad3-ee01615c12d2_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!SniY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794513e8-3fba-4a3a-8ad3-ee01615c12d2_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SniY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794513e8-3fba-4a3a-8ad3-ee01615c12d2_1200x630.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/794513e8-3fba-4a3a-8ad3-ee01615c12d2_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Python: Simple Demo | TryHackMe Write-up&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Python: Simple Demo | TryHackMe Write-up" title="Python: Simple Demo | TryHackMe Write-up" srcset="https://substackcdn.com/image/fetch/$s_!SniY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794513e8-3fba-4a3a-8ad3-ee01615c12d2_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!SniY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794513e8-3fba-4a3a-8ad3-ee01615c12d2_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!SniY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794513e8-3fba-4a3a-8ad3-ee01615c12d2_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!SniY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794513e8-3fba-4a3a-8ad3-ee01615c12d2_1200x630.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>This is my write-up for the TryHackMe room on <a href="https://tryhackme.com/room/pythonsimpledemo">Python: Simple Demo</a>. Written in 2026, I hope this write-up helps others learn and practice cybersecurity.</p><h2>Task 1: Introduction</h2><p>Python is a popular, high-level, general-purpose language widely used in automation, script writing, web applications, and data science. In this room, we will build a basic "Guess the &#8230;</p>
      <p>
          <a href="https://www.farrosfr.com/p/python-simple-demo-tryhackme-write-up">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Windows CLI Basics | TryHackMe Write-up]]></title><description><![CDATA[Complete walkthrough for Windows CLI Basics TryHackme room. Explore what Windows CLI is, how to navigate, and interact with the system using Windows CLI.]]></description><link>https://www.farrosfr.com/p/windows-cli-basics-tryhackme-write-up</link><guid isPermaLink="false">https://www.farrosfr.com/p/windows-cli-basics-tryhackme-write-up</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Sat, 27 Jun 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d5d405f7-255b-4263-b81b-d0a804089b55_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yq-T!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcec6fd74-8a46-4e87-9311-b46012763c0e_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yq-T!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcec6fd74-8a46-4e87-9311-b46012763c0e_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!yq-T!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcec6fd74-8a46-4e87-9311-b46012763c0e_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!yq-T!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcec6fd74-8a46-4e87-9311-b46012763c0e_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!yq-T!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcec6fd74-8a46-4e87-9311-b46012763c0e_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yq-T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcec6fd74-8a46-4e87-9311-b46012763c0e_1200x630.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cec6fd74-8a46-4e87-9311-b46012763c0e_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Windows CLI Basics | TryHackMe Write-up&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Windows CLI Basics | TryHackMe Write-up" title="Windows CLI Basics | TryHackMe Write-up" srcset="https://substackcdn.com/image/fetch/$s_!yq-T!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcec6fd74-8a46-4e87-9311-b46012763c0e_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!yq-T!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcec6fd74-8a46-4e87-9311-b46012763c0e_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!yq-T!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcec6fd74-8a46-4e87-9311-b46012763c0e_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!yq-T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcec6fd74-8a46-4e87-9311-b46012763c0e_1200x630.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>This is my write-up for the TryHackMe room on <a href="https://tryhackme.com/room/windowsclibasics">Windows CLI Basics</a>. Written in 2026, I hope this write-up helps others learn and practice cybersecurity.</p><h2>Task 1: Introduction</h2><p>This section introduces the Windows Command Prompt (CMD), a text-based interface where users type commands instead of clicking menus to interact with the system. Cybersecurity professio&#8230;</p>
      <p>
          <a href="https://www.farrosfr.com/p/windows-cli-basics-tryhackme-write-up">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Data Encoding | TryHackMe Write-up]]></title><description><![CDATA[Complete walkthrough for Data Encoding TryHackme room. Learn how computer encodes characters, from ASCII to Unicode's UTF.]]></description><link>https://www.farrosfr.com/p/data-encoding-tryhackme-write-up</link><guid isPermaLink="false">https://www.farrosfr.com/p/data-encoding-tryhackme-write-up</guid><dc:creator><![CDATA[Mochammad Farros Fatchur Roji]]></dc:creator><pubDate>Sat, 27 Jun 2026 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/87614fd5-64f4-4edb-b435-ed0dbb82c8bc_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!C3ES!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F849d7fe7-4024-49f3-95e3-7a21cf488b9c_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!C3ES!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F849d7fe7-4024-49f3-95e3-7a21cf488b9c_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!C3ES!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F849d7fe7-4024-49f3-95e3-7a21cf488b9c_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!C3ES!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F849d7fe7-4024-49f3-95e3-7a21cf488b9c_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!C3ES!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F849d7fe7-4024-49f3-95e3-7a21cf488b9c_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!C3ES!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F849d7fe7-4024-49f3-95e3-7a21cf488b9c_1200x630.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/849d7fe7-4024-49f3-95e3-7a21cf488b9c_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Data Encoding | TryHackMe Write-up&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Data Encoding | TryHackMe Write-up" title="Data Encoding | TryHackMe Write-up" srcset="https://substackcdn.com/image/fetch/$s_!C3ES!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F849d7fe7-4024-49f3-95e3-7a21cf488b9c_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!C3ES!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F849d7fe7-4024-49f3-95e3-7a21cf488b9c_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!C3ES!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F849d7fe7-4024-49f3-95e3-7a21cf488b9c_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!C3ES!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F849d7fe7-4024-49f3-95e3-7a21cf488b9c_1200x630.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>This is my write-up for the TryHackMe room on <a href="https://tryhackme.com/room/dataencoding">Data Encoding</a>. Written in 2026, I hope this write-up helps others learn and practice cybersecurity.</p><h2>Task 1: Introduction</h2><p>Computers store all data as numbers, relying on an agreed-upon mapping known as encoding to convert these numbers into characters like letters, punctuation, and emojis. Because each characte&#8230;</p>
      <p>
          <a href="https://www.farrosfr.com/p/data-encoding-tryhackme-write-up">
              Read more
          </a>
      </p>
   ]]></content:encoded></item></channel></rss>