<?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[Rebuilt]]></title><description><![CDATA[Complex systems, rebuilt from first principles. Software, networks, infrastructure, devices, and the physical world.]]></description><link>https://www.dmytrohuz.com</link><image><url>https://substackcdn.com/image/fetch/$s_!JM5w!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png</url><title>Rebuilt</title><link>https://www.dmytrohuz.com</link></image><generator>Substack</generator><lastBuildDate>Fri, 04 Sep 2026 14:47:46 GMT</lastBuildDate><atom:link href="https://www.dmytrohuz.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Dmytro Huz]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[dmytrohuz@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[dmytrohuz@substack.com]]></itunes:email><itunes:name><![CDATA[Dmytro Huz]]></itunes:name></itunes:owner><itunes:author><![CDATA[Dmytro Huz]]></itunes:author><googleplay:owner><![CDATA[dmytrohuz@substack.com]]></googleplay:owner><googleplay:email><![CDATA[dmytrohuz@substack.com]]></googleplay:email><googleplay:author><![CDATA[Dmytro Huz]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Networking Machinery for Software Engineers Part 2: Extending The Empire and Rebuilding a Global Network]]></title><description><![CDATA[We pushed our kingdom beyond the horizon. To keep it connected, we had to extend our Signal Tower system with Layer 3: IP addresses, subnets, gateways, routing tables, and DHCP.]]></description><link>https://www.dmytrohuz.com/p/networking-machinery-for-software-f6b</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/networking-machinery-for-software-f6b</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Wed, 02 Sep 2026 16:02:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!JAas!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d96a595-7108-43f7-92b7-4c57c97c5f2a_1672x941.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JAas!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d96a595-7108-43f7-92b7-4c57c97c5f2a_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JAas!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d96a595-7108-43f7-92b7-4c57c97c5f2a_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!JAas!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d96a595-7108-43f7-92b7-4c57c97c5f2a_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!JAas!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d96a595-7108-43f7-92b7-4c57c97c5f2a_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!JAas!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d96a595-7108-43f7-92b7-4c57c97c5f2a_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JAas!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d96a595-7108-43f7-92b7-4c57c97c5f2a_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0d96a595-7108-43f7-92b7-4c57c97c5f2a_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3508483,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213862386?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d96a595-7108-43f7-92b7-4c57c97c5f2a_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JAas!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d96a595-7108-43f7-92b7-4c57c97c5f2a_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!JAas!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d96a595-7108-43f7-92b7-4c57c97c5f2a_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!JAas!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d96a595-7108-43f7-92b7-4c57c97c5f2a_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!JAas!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d96a595-7108-43f7-92b7-4c57c97c5f2a_1672x941.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Previous Article:</h2><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;7a220686-cfcb-48e3-b64a-8cfb6a19a369&quot;,&quot;caption&quot;:&quot;Recently I started working on a networking series for software developers who enter the electrical-grid world and suddenly discover that the grid speaks in packets, interfaces, switches, routes, protocols and a suspicious number of acronyms.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Networking Machinery for Software Engineers\nPart 1: Rebuilding a Local Network with Medieval Signal Towers&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer exploring how complex systems are built. I take them apart, rebuild them from first principles, and trace the layers connecting software, networks, infrastructure, devices, and the physical world.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-08-28T09:48:20.438Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!Xg26!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81428888-7e1b-4174-8ad1-092e46214718_1672x941.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/networking-machinery-for-software&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:213120887,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><p><a href="https://www.dmytrohuz.com/p/networking-machinery-for-software">We have just built our small kingdom</a>. One valley, a few villages, a few signal towers, and a local network that works surprisingly well for something invented by people who still believe that medicine is mostly a matter of balancing four bodily fluids.</p><p>Unfortunately, sooner or later power becomes the main goal of the most ambitious people in the kingdom, and sooner or later one kingdom becomes too small for them. Scouts discover settlements behind the mountains, armies march along roads that were previously used for sheep, and within a few years our neat little kingdom becomes an empire with several valleys somewhere beyond the horizon.</p><p>The moral dilemma is outside the scope of this article, and we, as network engineers in medieval Europe, are definitely not in a position to judge the military policy of our lords. What we do need to judge is whether the communication system from <a href="https://www.dmytrohuz.com/p/networking-machinery-for-software">Part 1</a> can survive this expansion.</p><p>It cannot.</p><p>Our old system knows how to move a frame inside one valley, but it has no idea what a valley is, where its border lies, or what to do when a destination is hidden behind three mountain passes and somebody else&#8217;s tax system.</p><p>So we will build the larger system in the same way we built the local one. We will remain with our towers until messages can cross the whole empire, and only after the machinery works will we return to a real computer and the Internet. This order matters because IP addresses, gateways and routing tables are much easier to remember when they arrive as answers to problems we have already felt.</p><p>In this post we will discuss how IP addresses, network prefixes, gateways, routing tables and ARP turn local networks into a network of networks. We will then see how the same model appears on Linux, how DHCP gives a host the information it needs, and what changes while one packet crosses several routers.</p><p>The real-world part focuses on IPv4 carried over Ethernet. Other link technologies can carry IP without Ethernet, and IPv6 uses Neighbor Discovery instead of ARP, but one carefully bounded world is enough for now. Our empire is already difficult to govern without opening several additional continents.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><h2>Two orders of names</h2><p>In our existing system every tower already has a local name such as <code>0A</code>, <code>0B</code> or <code>0C</code>, and that worked perfectly while the entire known world fitted inside one valley.</p><p>Then we acquired another valley.</p><p>It has its own towers, which may be called <code>1A</code>, <code>1B</code> and <code>1C</code>. They may also be called <code>0A</code>, <code>0B</code> and <code>0C</code>, because coordination between medieval kingdoms is apparently not much better than coordination between modern IT departments.</p><p>Now an order addressed to <code>0A</code> is ambiguous. There is an <code>0A</code> in Valley 1 and another <code>0A</code> in Valley 2, and the old name tells us who should receive a message only after we already know which local network we are talking about.</p><p>This is not a flaw in the old system. A local name was invented for local delivery, and inside one valley it still does that job perfectly. The empire has simply created a second question that the local name was never meant to answer:</p><blockquote><p>In which valley does the destination live?</p></blockquote><p>So we introduce another order of names. Tower <code>0A</code> keeps its local address and independently receives the wider address <code>V1.7</code>. A tower in Valley 2 may reuse the same local address <code>0A</code> while independently receiving <code>V2.12</code>. The local and wider addresses are not constructed from one another. They are separate identifiers assigned for different scopes.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LCQo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83cce10d-858c-4273-98ec-989757ccfc1d_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LCQo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83cce10d-858c-4273-98ec-989757ccfc1d_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!LCQo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83cce10d-858c-4273-98ec-989757ccfc1d_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!LCQo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83cce10d-858c-4273-98ec-989757ccfc1d_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!LCQo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83cce10d-858c-4273-98ec-989757ccfc1d_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LCQo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83cce10d-858c-4273-98ec-989757ccfc1d_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/83cce10d-858c-4273-98ec-989757ccfc1d_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2249090,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213862386?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83cce10d-858c-4273-98ec-989757ccfc1d_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LCQo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83cce10d-858c-4273-98ec-989757ccfc1d_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!LCQo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83cce10d-858c-4273-98ec-989757ccfc1d_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!LCQo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83cce10d-858c-4273-98ec-989757ccfc1d_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!LCQo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83cce10d-858c-4273-98ec-989757ccfc1d_1672x941.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 1. The local address </em><code>0A</code><em> can be reused in both valleys. The independent wider addresses </em><code>V1.7</code><em> and </em><code>V2.12</code><em> identify the towers across the empire, and neither is derived from </em><code>0A</code><em>.</em></p><p>We have just reconstructed the reason a machine can need both a MAC address and an IP address.</p><p>The MAC address is the local name. It identifies the immediate sender or receiver on one Ethernet network. The IP address is the wider name. It identifies the source and destination across many connected networks.</p><p>The two addresses do not compete, and one is not a more modern replacement for the other. They describe the same machine at different scopes, rather like a person&#8217;s room number and full postal address. A room number can be perfectly useful inside one building even though a letter crossing the country needs more information.</p><h3>Is the destination still inside our valley?</h3><p>Imagine that tower <code>0A</code> in Valley 1 receives an order:</p><blockquote><p>Deliver this message to <code>V1.12</code>.</p></blockquote><p>The destination begins with <code>V1</code>, and our tower also belongs to <code>V1</code>, so the destination is local. It can use exactly the machinery we built in Part 1. It discovers which local tower owns <code>V1.12</code>, learns that tower&#8217;s local address if necessary, and sends a frame through the valley.</p><p>Then another order arrives:</p><blockquote><p>Deliver this message to <code>V2.12</code>.</p></blockquote><p>This time the wider address tells us something important before a single signal is sent. The destination belongs to Valley 2, while our tower belongs to Valley 1. None of the local towers can deliver a frame directly through the mountain.</p><p>Our medieval rule can still be very simple:</p><pre><code><code>V1.*  local
everything else  beyond the valley
</code></code></pre><p>Modern networking calls the precise version of this boundary a network prefix, but we do not need the binary notation yet. For the moment, the important discovery is that an address must contain enough structure to tell us not only who the destination is, but also whether it belongs to our local world.</p><p>Once <code>0A</code> knows that <code>V2.12</code> is remote, it needs somewhere local to send the message.</p><h2>A gateway at the edge of the valley</h2><p>We build a special tower at the border of Valley 1. It can receive local frames from our valley, but it also has a road leading into another network. Let us call it <code>G1</code>.</p><p>Tower <code>0A</code> now learns one additional rule:</p><blockquote><p>If the final destination is outside Valley 1, give the packet to <code>G1</code>.</p></blockquote><p>This creates a situation that looks strange only until the two scopes become visible. Suppose <code>0A</code> wants to reach <code>V2.12</code>. The final destination is still <code>V2.12</code>, but the next tower that can physically receive a local frame is <code>G1</code>.</p><p>The message therefore carries two destinations:</p><pre><code><code>Final IP destination: V2.12
Local MAC destination: G1
</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!S9s_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc704fc62-2439-4d16-b27f-78f0054e6665_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!S9s_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc704fc62-2439-4d16-b27f-78f0054e6665_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!S9s_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc704fc62-2439-4d16-b27f-78f0054e6665_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!S9s_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc704fc62-2439-4d16-b27f-78f0054e6665_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!S9s_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc704fc62-2439-4d16-b27f-78f0054e6665_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!S9s_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc704fc62-2439-4d16-b27f-78f0054e6665_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c704fc62-2439-4d16-b27f-78f0054e6665_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2934167,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213862386?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc704fc62-2439-4d16-b27f-78f0054e6665_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!S9s_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc704fc62-2439-4d16-b27f-78f0054e6665_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!S9s_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc704fc62-2439-4d16-b27f-78f0054e6665_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!S9s_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc704fc62-2439-4d16-b27f-78f0054e6665_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!S9s_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc704fc62-2439-4d16-b27f-78f0054e6665_1672x941.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 2. The local frame is an outer delivery envelope addressed to the next hop, </em><code>G1</code><em>. The packet inside keeps the final destination, </em><code>V2.12</code><em>.</em></p><p>The outer address gets the message across the current local network. The inner address survives beyond that network and tells every gateway where the journey should eventually end.</p><p>Gateway <code>G1</code> receives the frame because its own local address is written on the outside. It removes that local envelope and reads the wider address inside:</p><pre><code><code>Destination IP: V2.12
</code></code></pre><p>Now <code>G1</code> faces the same question that tower <code>0A</code> faced, only on a larger map. Where should this packet go next?</p><h2>A small map inside every gateway</h2><p>We hang a parchment inside <code>G1</code>:</p><pre><code><code>Valley 1          directly connected
Valley 2          eastern relay R1
Valley 3          northern relay R2
Everything else  royal highway G0
</code></code></pre><p>This parchment is our routing table.</p><p>It does not describe the complete road from Valley 1 to every tower in the empire. <code>G1</code> does not need to know every bridge, every mountain pass or every official who will lose the paperwork. It only needs to know the next useful step.</p><p>For <code>V2.12</code>, the table selects relay <code>R1</code>. If the link between <code>G1</code> and <code>R1</code> is another local Ethernet-like network, the wider address of the next hop is still not enough to send a frame. <code>G1</code> needs the local address of <code>R1</code> on that link.</p><p>This brings us back to the machinery from Part 1. If the mapping is not already known, <code>G1</code> asks the local network which MAC address belongs to the next-hop IP address. In IPv4 over Ethernet, this is ARP.</p><p>The forwarding process is therefore not one mysterious act called routing. It is a sequence of smaller questions:</p><pre><code><code>Where is the packet ultimately going?
        &#8595;
Which route best matches that destination?
        &#8595;
What is the next hop on that route?
        &#8595;
Which local address belongs to that next hop?
        &#8595;
Send one local frame
</code></code></pre><p>Routing chooses the direction. ARP, when the current link is IPv4 over Ethernet, supplies the local delivery address needed to take the next step.</p><h3>The same packet, a new local frame</h3><p>The route across our empire might look like this:</p><pre><code><code>Tower 0A in Valley 1
        &#8595;
Gateway G1
        &#8595;
Eastern relay R1
        &#8595;
Gateway G2
        &#8595;
Tower 0B in Valley 2
</code></code></pre><p>On the first hop, the local frame is addressed to <code>G1</code>. After <code>G1</code> opens that frame and chooses the next route, it creates a new local frame addressed to <code>R1</code>. Relay <code>R1</code> repeats the process and creates another frame addressed to <code>G2</code>. Inside Valley 2, <code>G2</code> finally creates a frame addressed to tower <code>0B</code>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qmAC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25b49c1d-311e-4d69-8e7c-f762a0c33139_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qmAC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25b49c1d-311e-4d69-8e7c-f762a0c33139_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!qmAC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25b49c1d-311e-4d69-8e7c-f762a0c33139_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!qmAC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25b49c1d-311e-4d69-8e7c-f762a0c33139_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!qmAC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25b49c1d-311e-4d69-8e7c-f762a0c33139_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qmAC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25b49c1d-311e-4d69-8e7c-f762a0c33139_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/25b49c1d-311e-4d69-8e7c-f762a0c33139_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2958392,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213862386?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25b49c1d-311e-4d69-8e7c-f762a0c33139_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qmAC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25b49c1d-311e-4d69-8e7c-f762a0c33139_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!qmAC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25b49c1d-311e-4d69-8e7c-f762a0c33139_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!qmAC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25b49c1d-311e-4d69-8e7c-f762a0c33139_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!qmAC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25b49c1d-311e-4d69-8e7c-f762a0c33139_1672x941.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 3. The blue end-to-end destination remains </em><code>V2.12</code><em>. Each gold local delivery ends at one next hop, after which a new local frame is created for the following link.</em></p><p>The IP destination does not become <code>G1</code>, then <code>R1</code>, then <code>G2</code>. It remains <code>V2.12</code>, because that is the end of the journey. What changes is the local delivery information wrapped around it.</p><p>This distinction gives us the mental model for the whole article:</p><blockquote><p>The IP packet describes the end-to-end conversation. The local frame describes only the next delivery.</p></blockquote><p>Every gateway repeats the same small procedure. It removes the local frame, reads the destination IP, consults its routing table, chooses a next hop, and creates whatever local frame the next link requires.</p><p>The routes also describe valleys rather than every individual tower. <code>G1</code> does not need separate rules for <code>V2.1</code>, <code>V2.2</code>, <code>V2.3</code> and every other address in Valley 2. One rule for <code>V2.*</code> is enough, because the next useful step is the same for all of them.</p><p>Our empire may eventually grow too large for routes to be written by hand. Routers can then exchange information and learn routes from one another, but that changes how the parchment is produced, not how a packet uses it. Forwarding still means reading the destination, selecting the best route and taking one local step.</p><p>We have now rebuilt the complete mechanism with towers. Local names move frames inside a valley. Wider addresses identify destinations across valleys. A boundary tells a tower whether the destination is local. A gateway accepts everything beyond that boundary. A routing table chooses the next hop, and each local network carries the packet one step farther.</p><p>Our little kingdom is no longer one network.</p><p>It is becoming a network of networks.</p><p>In other words, we have started building Layer 3.</p><p>Only now are we ready to leave the towers.</p><h2>Back to the real world</h2><p>Imagine one Linux machine connected to a home or office network:</p><pre><code><code>IP address:      192.168.1.23/24
Interface:       eth0
Default gateway: 192.168.1.1
MAC address:     3c:52:82:xx:xx:xx
</code></code></pre><p>This is almost exactly what our tower knew. The machine has a local Ethernet identity, a wider IPv4 identity, a description of its local boundary, and the address of a gateway that can accept packets leaving that boundary.</p><p>Suppose an application wants to reach <code>192.168.1.50</code>. Linux has a directly connected route for the local network, so the selected next hop is the destination itself. If the neighbor cache does not already contain the answer, ARP asks:</p><blockquote><p>Who has <code>192.168.1.50</code>?</p></blockquote><p>Once the machine learns a mapping such as <code>192.168.1.50 &#8594; aa:bb:cc:dd:ee:ff</code>, it can place the IP packet inside an Ethernet frame addressed directly to that MAC address.</p><p>Nothing particularly dramatic happened. We stayed inside one valley.</p><h3>Leaving the valley</h3><p>Now the same application wants to reach <code>8.8.8.8</code>.</p><p>Linux exposes the relevant routes with <code>ip route</code>:</p><pre><code><code>default via 192.168.1.1 dev eth0
192.168.1.0/24 dev eth0 scope link
</code></code></pre><p>At first this looks like the usual Linux habit of turning a simple idea into compressed hieroglyphics, but the table contains only two important rules. Destinations in <code>192.168.1.0/24</code> are directly reachable through <code>eth0</code>. Everything for which no more specific route exists goes through <code>192.168.1.1</code>.</p><p>For <code>8.8.8.8</code>, the local route does not match, so the default route selects <code>192.168.1.1</code> as the next hop. The packet remains addressed to <code>8.8.8.8</code>, while the first Ethernet frame is addressed to the MAC address of <code>192.168.1.1</code>.</p><p>If that MAC address is unknown, ARP asks:</p><blockquote><p>Who has <code>192.168.1.1</code>?</p></blockquote><p>There is one technical correction worth making explicit here. It is common to explain the host as if it first performs a separate subnet test and then, only for a remote destination, remembers that routing tables exist. The operating system actually performs a route lookup. Configuring <code>192.168.1.23/24</code> on <code>eth0</code> creates the directly connected route, while configuring the gateway creates the default route. Local and remote delivery are two outcomes of the same lookup.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dRRQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04a65802-2ecb-4e05-8d50-c450eea4361f_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dRRQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04a65802-2ecb-4e05-8d50-c450eea4361f_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!dRRQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04a65802-2ecb-4e05-8d50-c450eea4361f_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!dRRQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04a65802-2ecb-4e05-8d50-c450eea4361f_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!dRRQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04a65802-2ecb-4e05-8d50-c450eea4361f_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dRRQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04a65802-2ecb-4e05-8d50-c450eea4361f_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/04a65802-2ecb-4e05-8d50-c450eea4361f_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2955647,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213862386?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04a65802-2ecb-4e05-8d50-c450eea4361f_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dRRQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04a65802-2ecb-4e05-8d50-c450eea4361f_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!dRRQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04a65802-2ecb-4e05-8d50-c450eea4361f_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!dRRQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04a65802-2ecb-4e05-8d50-c450eea4361f_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!dRRQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04a65802-2ecb-4e05-8d50-c450eea4361f_1672x941.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 4. The route lookup happens first. It selects either the destination itself or the gateway as the next hop, and only then does ARP resolve that selected next hop on Ethernet.</em></p><p>This ordering prevents two common confusions. ARP does not decide whether a destination is local, and it does not choose a route. It answers a local address-resolution question after routing has already chosen the next hop.</p><h2>Where does the valley end?</h2><p>Our tower used a rule such as <code>V1.*</code> to recognize its valley. IPv4 represents the same idea with a network prefix.</p><p>An IPv4 address contains 32 bits, which we usually write as four decimal octets. In <code>192.168.1.23/24</code>, the <code>/24</code> says that the first 24 bits belong to the network portion and the remaining 8 belong to the host portion.</p><p>For this address, the network is <code>192.168.1.0/24</code>. Addresses such as <code>192.168.1.5</code>, <code>192.168.1.50</code> and <code>192.168.1.200</code> belong to that network, while <code>192.168.2.5</code> does not.</p><p>The traditional subnet mask <code>255.255.255.0</code> expresses the same boundary. In binary it contains 24 ones followed by 8 zeroes. The ones mark the network portion, while the zeroes leave room for host addresses.</p><p>The boundary does not have to respect the dots in the decimal notation, because the dots exist for us and the bits exist for the machine. Consider <code>192.168.1.10/26</code>. The first 24 bits and the first 2 bits of the final octet belong to the network, leaving 6 host bits.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Dgl9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c80a44-3b68-464e-8f4b-5b8901f96055_1600x900.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Dgl9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c80a44-3b68-464e-8f4b-5b8901f96055_1600x900.png 424w, https://substackcdn.com/image/fetch/$s_!Dgl9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c80a44-3b68-464e-8f4b-5b8901f96055_1600x900.png 848w, https://substackcdn.com/image/fetch/$s_!Dgl9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c80a44-3b68-464e-8f4b-5b8901f96055_1600x900.png 1272w, https://substackcdn.com/image/fetch/$s_!Dgl9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c80a44-3b68-464e-8f4b-5b8901f96055_1600x900.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Dgl9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c80a44-3b68-464e-8f4b-5b8901f96055_1600x900.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f7c80a44-3b68-464e-8f4b-5b8901f96055_1600x900.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1119051,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213862386?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c80a44-3b68-464e-8f4b-5b8901f96055_1600x900.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Dgl9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c80a44-3b68-464e-8f4b-5b8901f96055_1600x900.png 424w, https://substackcdn.com/image/fetch/$s_!Dgl9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c80a44-3b68-464e-8f4b-5b8901f96055_1600x900.png 848w, https://substackcdn.com/image/fetch/$s_!Dgl9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c80a44-3b68-464e-8f4b-5b8901f96055_1600x900.png 1272w, https://substackcdn.com/image/fetch/$s_!Dgl9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7c80a44-3b68-464e-8f4b-5b8901f96055_1600x900.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 5. Each final octet contains exactly eight bit positions. A </em><code>/24</code><em> leaves positions 1 through 8 for hosts, while a </em><code>/26</code><em> uses positions 1 and 2 for the network and leaves positions 3 through 8, exactly six bits, for hosts.</em></p><p>Those four <code>/26</code> networks begin at:</p><pre><code><code>192.168.1.0/26
192.168.1.64/26
192.168.1.128/26
192.168.1.192/26
</code></code></pre><p>This is why <code>192.168.1.10</code> and <code>192.168.1.50</code> belong to the first <code>/26</code>, while <code>192.168.1.70</code> belongs to the second. The decimal addresses look almost like neighbors, but the prefix has placed a real border between them.</p><p>The prefix is not an intermediate technique unrelated to our story. It is the exact mathematical form of the question our first tower had to answer:</p><blockquote><p>Does the destination belong to my local network, or must the selected route lead through a gateway?</p></blockquote><h2>Who gave the host its map?</h2><p>So far our computer somehow knew its IP address, its prefix, its default gateway and usually a DNS server. On a normal home or office network, nobody sits down every morning and manually configures every laptop, phone, printer and coffee machine that has somehow acquired WiFi.</p><p>Most of the time, DHCP does the paperwork.</p><p>A new host already has its local Ethernet identity, but it does not yet know its IPv4 address, its network boundary or its default gateway. It cannot send a normal IP request to a server whose address it does not know from an address it does not have, so it begins with a local broadcast:</p><blockquote><p>I am here. Can somebody tell me who I am supposed to be?</p></blockquote><p>The basic exchange is usually remembered as DORA: Discover, Offer, Request and Acknowledgement. The server may eventually give the client:</p><pre><code><code>IP address:      192.168.1.23
Prefix:          /24
Default gateway: 192.168.1.1
DNS server:      192.168.1.1
Lease:           24 hours
</code></code></pre><p>DHCP did not route anything. It simply handed the host the small piece of the map it needs before routing can begin.</p><p>The lease means that the address is borrowed rather than carved into stone. Before the lease expires, the client normally tries to renew it, and the server may allow the same address to remain or assign another one.</p><p>The first DHCP discovery is a local broadcast, and routers normally do not forward local broadcasts. When the DHCP server lives in another network, a DHCP relay listens locally and carries the request toward the remote server. This lets one server configure many networks without joining their broadcast domains together.</p><p>If DHCP is absent, nothing fundamental breaks. We can configure the IP address, prefix, gateway and DNS server manually, provided that the values are correct and the chosen address does not conflict with another host.</p><p>Small networks often place DHCP, routing, NAT, firewalling, DNS forwarding and WiFi inside the same plastic box near the wall. Calling that entire creature a router is convenient but slightly misleading. Router is one role performed by the device, just as a castle can be a home, a fortress, a court, a prison and a very expensive heating problem at the same time.</p><h2>Following one real packet</h2><p>Host A lives at <code>192.168.1.23/24</code>, and somewhere beyond several networks Host Z lives at <code>10.20.0.42/16</code>. Host A&#8217;s route lookup selects <code>192.168.1.1</code> as the gateway, and ARP gives it the gateway interface&#8217;s MAC address.</p><p>The word <em>interface</em> matters here. A router connects at least two networks, so it does not have one universal IP address or one universal MAC address. Each Ethernet interface belongs to a particular local network and has its own MAC address, while it will usually have an IP address in that network as well.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Jmd8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdafd6728-b9ce-45d8-ad98-507cb7da588d_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Jmd8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdafd6728-b9ce-45d8-ad98-507cb7da588d_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!Jmd8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdafd6728-b9ce-45d8-ad98-507cb7da588d_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!Jmd8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdafd6728-b9ce-45d8-ad98-507cb7da588d_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!Jmd8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdafd6728-b9ce-45d8-ad98-507cb7da588d_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Jmd8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdafd6728-b9ce-45d8-ad98-507cb7da588d_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dafd6728-b9ce-45d8-ad98-507cb7da588d_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2852013,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213862386?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdafd6728-b9ce-45d8-ad98-507cb7da588d_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Jmd8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdafd6728-b9ce-45d8-ad98-507cb7da588d_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!Jmd8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdafd6728-b9ce-45d8-ad98-507cb7da588d_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!Jmd8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdafd6728-b9ce-45d8-ad98-507cb7da588d_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!Jmd8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdafd6728-b9ce-45d8-ad98-507cb7da588d_1672x941.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 6. A router&#8217;s interfaces belong to different local networks. The incoming frame ends at Interface A, while a new local frame leaves through Interface B with that interface&#8217;s identity.</em></p><p>Hosts on <code>192.168.1.0/24</code> use <code>192.168.1.1</code> as their gateway because that address belongs to the router interface standing inside their own network. The interface on the other side belongs to another network and has different local neighbors.</p><p>Host A creates the first frame:</p><pre><code><code>Ethernet destination: MAC of 192.168.1.1
IPv4 destination:     10.20.0.42
</code></code></pre><p>The router removes the Ethernet frame, reads the IPv4 destination, performs its own route lookup and chooses the next hop. If the outgoing link is also Ethernet, the router resolves that next hop&#8217;s MAC address and creates a completely new frame. The next router repeats the same process.</p><p>Eventually a router finds that <code>10.20.0.0/16</code> is directly connected. On the final Ethernet network, it uses ARP to learn Host Z&#8217;s MAC address and creates the last local frame.</p><p>The IPv4 source and destination normally remain the same in this simple routed topology. NAT can deliberately rewrite addresses, but NAT is another official with another stamp and is not required to explain routing.</p><p>The packet is not completely untouched, however. Every router decreases the IPv4 Time to Live, usually called TTL, by at least one. Because TTL is part of the IPv4 header, the router also updates the IPv4 header checksum.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!L_ZY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd2733a9-260c-4b6b-9048-d7473451cb12_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!L_ZY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd2733a9-260c-4b6b-9048-d7473451cb12_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!L_ZY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd2733a9-260c-4b6b-9048-d7473451cb12_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!L_ZY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd2733a9-260c-4b6b-9048-d7473451cb12_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!L_ZY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd2733a9-260c-4b6b-9048-d7473451cb12_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!L_ZY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd2733a9-260c-4b6b-9048-d7473451cb12_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bd2733a9-260c-4b6b-9048-d7473451cb12_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2211619,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213862386?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd2733a9-260c-4b6b-9048-d7473451cb12_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!L_ZY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd2733a9-260c-4b6b-9048-d7473451cb12_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!L_ZY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd2733a9-260c-4b6b-9048-d7473451cb12_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!L_ZY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd2733a9-260c-4b6b-9048-d7473451cb12_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!L_ZY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd2733a9-260c-4b6b-9048-d7473451cb12_1672x941.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 7. The IPv4 source and destination stay end to end, each local frame is rebuilt for one link, and TTL decreases as routers forward the packet.</em></p><p>TTL exists because routing information can be wrong. If two routers keep sending a packet back and forth, the packet must not wander between them until the end of history. When TTL reaches zero, the router discards it and normally sends an ICMP Time Exceeded message back toward the source.</p><p>Ethernet is not mandatory on every link. Another link technology may use different framing and may have no MAC addresses or ARP at all. What survives is the larger mechanism: the router removes the old link-layer envelope, keeps the IP destination, chooses the next route and creates whatever local delivery the outgoing link requires.</p><p>Layer 3 does not bypass Layer 2. It uses one local link, then another one, then another one. A global network is made from local networks that repeatedly agree to pass the packet on.</p><h2>Routers do not know the whole journey</h2><p>A router does not normally calculate the complete road from Host A to Host Z. It needs to answer only one question:</p><blockquote><p>Where should I send this packet next?</p></blockquote><p>This is why routing tables usually describe networks rather than every individual host. One rule can say that the whole <code>10.20.0.0/16</code> network is reachable through Router B.</p><p>Sometimes several routes match the same destination:</p><pre><code><code>10.0.0.0/8       via Router A
10.20.0.0/16     via Router B
10.20.5.0/24     via Router C
default          via Router D
</code></code></pre><p>The address <code>10.20.5.17</code> matches every line, including the default, but the <code>/24</code> route wins because it has the longest matching prefix. A longer prefix describes a smaller and more specific group of addresses. The default route has a prefix length of zero, so it is the vaguest possible instruction: if nobody knows better, send the packet this way.</p><p>For a small network, somebody can configure these routes by hand. In a much larger system, routers can exchange routes through protocols such as OSPF, IS-IS and BGP. Those protocols deserve their own story, but forwarding remains the same after the table has been built: read the destination IP, choose the most specific matching route, select the next hop, and perform one local delivery.</p><h2>What actually happens when we type <code>ping</code></h2><p>When we run:</p><pre><code><code>ping 8.8.8.8
</code></code></pre><p>the operating system performs the route lookup, selects the next hop, resolves the necessary local address if the outgoing link requires it, and sends an IPv4 packet containing an ICMP Echo Request.</p><p>If the remote host chooses to answer, it sends an ICMP Echo Reply back toward us. A successful reply means that the forward route worked, the return route worked, the necessary local deliveries succeeded, and the policies along the way allowed ICMP.</p><p>A failed <code>ping</code> therefore does not prove that the destination is dead. It proves only that the complete conversation did not return, which is a much less satisfying answer and a much more honest one.</p><h2>The mental model to keep</h2><p>We began with a local network that knew only local tower names. The second valley made those names ambiguous, so we added a wider address that named both the valley and the tower. Once a destination could be remote, we needed a boundary that distinguished our local world from everything beyond it. A remote packet needed a gateway, and the gateway needed a routing table that selected the next useful step.</p><p>Every new idea appeared because the growing system made the previous model insufficient.</p><p>The result can be carried in one sentence:</p><blockquote><p>Routing keeps an end-to-end IP destination inside the packet while rebuilding the local delivery around it for every link.</p></blockquote><p>A MAC address answers who should receive this frame here. An IP address answers where the packet is ultimately going. A prefix describes which addresses belong to a network. A route chooses the next hop, and ARP maps that next-hop IP address to a local Ethernet address when the current link needs one.</p><p>None of this replaced the network from Part 1. We built above it and then reused it at every hop.</p><p>Put those answers together and our valleys become a network of networks, which is rather inconveniently the same direction in which our rulers were taking their empire anyway.</p><h2>One machine is still a black box</h2><p>There is one character in this story that we have treated with suspicious casualness: the computer itself.</p><p>Throughout both parts I have written that the computer checks a route, stores a neighbor, owns a MAC address and sends a frame, but what inside the machine actually does those things? Where does a network interface begin and the operating system end? What changes when one computer has several interfaces, and what happens when some of those interfaces are not physical at all?</p><p>Linux can create virtual interfaces, connect them with virtual Ethernet pairs, place them in bridges, and split the network into namespaces that behave like separate hosts. One physical machine can contain several isolated valleys and the roads between them.</p><p>Which means that, instead of invading another kingdom for the next experiment, we can build almost the entire empire inside one Linux machine.</p><p>That is where we go next.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Rebuilt is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Series Hub:</strong></h2><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;cf3dcbc9-766c-4093-b324-5597c004acb2&quot;,&quot;caption&quot;:&quot;I have worked with networked software for years, but for most of that time the network was something I used rather than something I really understood. I could open a socket, call an API, connect to an IP address, and continue with the part of the system I was responsible for.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Networking in the Power Grid for Software Developers&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer exploring how complex systems are built. I take them apart, rebuild them from first principles, and trace the layers connecting software, networks, infrastructure, devices, and the physical world.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-08-27T21:18:02.367Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!sXgD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/networking-in-the-power-grid-for&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:213058272,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div>]]></content:encoded></item><item><title><![CDATA[Networking Machinery for Software Engineers
Part 1: Rebuilding a Local Network with Medieval Signal Towers]]></title><description><![CDATA[How a ridiculous thought experiment leads to Ethernet frames, MAC addresses, switches, broadcast, and ARP.]]></description><link>https://www.dmytrohuz.com/p/networking-machinery-for-software</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/networking-machinery-for-software</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Fri, 28 Aug 2026 09:48:20 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Xg26!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81428888-7e1b-4174-8ad1-092e46214718_1672x941.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Xg26!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81428888-7e1b-4174-8ad1-092e46214718_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Xg26!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81428888-7e1b-4174-8ad1-092e46214718_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!Xg26!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81428888-7e1b-4174-8ad1-092e46214718_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!Xg26!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81428888-7e1b-4174-8ad1-092e46214718_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!Xg26!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81428888-7e1b-4174-8ad1-092e46214718_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Xg26!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81428888-7e1b-4174-8ad1-092e46214718_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/81428888-7e1b-4174-8ad1-092e46214718_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1901889,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213120887?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81428888-7e1b-4174-8ad1-092e46214718_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Xg26!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81428888-7e1b-4174-8ad1-092e46214718_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!Xg26!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81428888-7e1b-4174-8ad1-092e46214718_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!Xg26!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81428888-7e1b-4174-8ad1-092e46214718_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!Xg26!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81428888-7e1b-4174-8ad1-092e46214718_1672x941.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Recently I started working on a networking series for software developers who enter the electrical-grid world and suddenly discover that the grid speaks in packets, interfaces, switches, routes, protocols and a suspicious number of acronyms.</p><p>Before going anywhere near IEC 61850, utility WANs or substation networks, I wanted to understand the ordinary networking machinery itself. Not only what a switch or ARP does, but why these things had to appear in the first place.</p><p>I could start with the OSI model. I have seen that diagram enough times in my life. The problem is that a finished diagram is very good at telling us where something belongs and surprisingly bad at showing why it exists.</p><p>So I had a more ridiculous idea.</p><p>Imagine that I am somewhere in medieval Europe. No copper cable, no fiber, no radio and definitely no Ethernet. I have stone towers on hills, and the only useful property I can rely on is visibility. If one tower can see another, I can make light visible or hide it.</p><p>Could I start from that and slowly rebuild a network?</p><p>This is not a historical reconstruction. I am not claiming that medieval Europe was one good standards committee away from IEEE 802.3. The towers are only a constraint. I want to begin with the smallest possible communication system, push it until it becomes uncomfortable, fix the new problem, and then compare the thing we invented with the machinery inside a real network.</p><p>That approach is much closer to how I like to understand systems. The finished technology often hides the reasons for its own shape. Broken and incomplete versions expose them.</p><p>In this post we will discuss the local part of the network. We will begin with physical signalling between two towers, then add more participants and see why frames, MAC addresses, switching, flooding, broadcast and ARP appear. Near the end we will come back to Linux and look at the same machinery on a real machine.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><h2>Two towers and one bit</h2><p>I want to begin before packets, addresses and protocols exist at all.</p><p>Two towers stand on neighboring hills. Tower A can see Tower B directly.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9xb0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04b2efcb-70e6-4c61-a47b-863cdd855705_1280x720.svg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9xb0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04b2efcb-70e6-4c61-a47b-863cdd855705_1280x720.svg 424w, https://substackcdn.com/image/fetch/$s_!9xb0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04b2efcb-70e6-4c61-a47b-863cdd855705_1280x720.svg 848w, https://substackcdn.com/image/fetch/$s_!9xb0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04b2efcb-70e6-4c61-a47b-863cdd855705_1280x720.svg 1272w, https://substackcdn.com/image/fetch/$s_!9xb0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04b2efcb-70e6-4c61-a47b-863cdd855705_1280x720.svg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9xb0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04b2efcb-70e6-4c61-a47b-863cdd855705_1280x720.svg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/04b2efcb-70e6-4c61-a47b-863cdd855705_1280x720.svg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:87732,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/svg+xml&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213120887?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04b2efcb-70e6-4c61-a47b-863cdd855705_1280x720.svg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9xb0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04b2efcb-70e6-4c61-a47b-863cdd855705_1280x720.svg 424w, https://substackcdn.com/image/fetch/$s_!9xb0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04b2efcb-70e6-4c61-a47b-863cdd855705_1280x720.svg 848w, https://substackcdn.com/image/fetch/$s_!9xb0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04b2efcb-70e6-4c61-a47b-863cdd855705_1280x720.svg 1272w, https://substackcdn.com/image/fetch/$s_!9xb0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04b2efcb-70e6-4c61-a47b-863cdd855705_1280x720.svg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Diagram 1. Our entire network consists of two towers with direct visibility.</em></p><p>Tower A wants to send one piece of information to Tower B. The bridge is closed, for example.</p><p>But even that sentence is already too advanced for our network. We do not yet have a way to move a single bit between the towers.</p><p>The simplest thing I can invent is a lantern with a shutter. During a fixed interval the light is either visible or hidden.</p><pre><code><code>light visible = 1
light hidden  = 0
</code></code></pre><p>So a guard can produce something like:</p><pre><code><code>1 0 1 1 0 0 1 0
</code></code></pre><p>And the other tower can observe it.</p><p>This looks almost stupidly primitive, but it already contains the first real networking problem. An abstract <code>1</code> inside one system has to become something physical, travel through a medium, and be recovered by the other system.</p><p>In our case the medium is light through air. In Ethernet it may be an electrical or optical signal. Wireless uses radio. Real physical layers do not literally push abstract bits through a cable one after another. They deal with symbols, encoding, timing, synchronization, noise, attenuation, clock recovery and many other details that become a rabbit hole very quickly.</p><p>Even the lantern version immediately asks awkward questions. How long does one interval last? How does Tower B know where the sequence begins? What happens in fog? If the light stays visible for three intervals, how does the receiver know that it saw <code>111</code> rather than one long <code>1</code>?</p><p>I am going to stop before our medieval guards have to invent signal processing.</p><p>The useful part for this article is that we have reconstructed the job of Layer 1: make information physical enough that it can cross one link and be recovered at the other side.</p><p>That works beautifully while our entire civilization consists of two towers.</p><p>Unfortunately, I want a network.</p><h2>Adding the rest of the valley</h2><p>So I add more towers.</p><p>Some can see each other directly. Some need a relay point between them. For the moment, imagine one local communication region where a relay tower has direct light paths toward several participants.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QjZS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc4c9fa-29c7-4359-a71d-1b16f5ec5ab8_1280x720.svg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QjZS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc4c9fa-29c7-4359-a71d-1b16f5ec5ab8_1280x720.svg 424w, https://substackcdn.com/image/fetch/$s_!QjZS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc4c9fa-29c7-4359-a71d-1b16f5ec5ab8_1280x720.svg 848w, https://substackcdn.com/image/fetch/$s_!QjZS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc4c9fa-29c7-4359-a71d-1b16f5ec5ab8_1280x720.svg 1272w, https://substackcdn.com/image/fetch/$s_!QjZS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc4c9fa-29c7-4359-a71d-1b16f5ec5ab8_1280x720.svg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QjZS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc4c9fa-29c7-4359-a71d-1b16f5ec5ab8_1280x720.svg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ebc4c9fa-29c7-4359-a71d-1b16f5ec5ab8_1280x720.svg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:133776,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/svg+xml&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213120887?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc4c9fa-29c7-4359-a71d-1b16f5ec5ab8_1280x720.svg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QjZS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc4c9fa-29c7-4359-a71d-1b16f5ec5ab8_1280x720.svg 424w, https://substackcdn.com/image/fetch/$s_!QjZS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc4c9fa-29c7-4359-a71d-1b16f5ec5ab8_1280x720.svg 848w, https://substackcdn.com/image/fetch/$s_!QjZS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc4c9fa-29c7-4359-a71d-1b16f5ec5ab8_1280x720.svg 1272w, https://substackcdn.com/image/fetch/$s_!QjZS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Febc4c9fa-29c7-4359-a71d-1b16f5ec5ab8_1280x720.svg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Diagram 2. Several towers now share one local communication system through a relay point.</em></p><p>The light can move bits across each individual path, but the moment several towers share the system, a stream like this becomes annoyingly ambiguous:</p><pre><code><code>10110010...
</code></code></pre><p>Who is it for? Where does one message end and the next one begin? If the relay receives it, which path should it use? And if I later want to carry different kinds of data, how does the receiver know what is inside?</p><p>This is where the simple Layer 1 picture starts to break. The physical signal still matters, but I need structure above it.</p><h2>Give the towers local addresses</h2><p>I will start with the most obvious missing piece and give every tower a local identifier.</p><pre><code><code>Tower A = 0A
Tower B = 0B
Tower C = 0C
Tower D = 0D
</code></code></pre><p>There is nothing magical about these values. My tiny kingdom does not need a 48-bit address space yet.</p><p>Now instead of sending naked bits, Tower A can send a structure:</p><pre><code><code>TO:   0C
FROM: 0A
TYPE: MESSAGE
DATA: THE BRIDGE IS CLOSED
</code></code></pre><p>The relay no longer has to guess what the bits mean. There is a destination, a source, a description of what the payload contains, and the payload itself.</p><p>That structure is already suspiciously close to an Ethernet frame.</p><p>Our tower frame Ethernet equivalent What it is doing <code>TO</code> Destination MAC address Identifies the local recipient of the frame <code>FROM</code> Source MAC address Identifies the local sender of the frame <code>TYPE</code> EtherType Tells the receiver what kind of payload is carried <code>DATA</code> Payload Carries the higher-level data</p><p><em>Table 1. The fields I needed for the tower network have direct relatives in an Ethernet frame.</em></p><p>A real Ethernet frame has more machinery around this, and the signal on the wire has additional synchronization and encoding details. Our invented text header is obviously not its real wire format. Those details solve different problems, so I will leave them outside this model for now.</p><p>The important thing is that <code>0A</code>, <code>0B</code> and the rest are local link-layer identities. They play the role of MAC addresses. They do not tell us how to reach a tower somewhere on the other side of Europe. They let this local network move a frame toward the right participant.</p><p>This is roughly where Layer 2 enters the picture. We have stopped dealing only with signals and started dealing with frames and local delivery.</p><h2>The relay starts remembering</h2><p>The first version of my relay can be extremely lazy. Every time it receives a transmission, it can repeat the signal toward every other light path. At the frame level, the result is that every frame becomes visible everywhere.</p><p>This is roughly the world of an old Ethernet hub. A real hub operates at Layer 1 and repeats signals rather than parsing Ethernet frames, which is one place where the tower analogy should not be pushed too literally.</p><p>But the relay is sitting in a very useful position. When a frame arrives from the western path and says:</p><pre><code><code>FROM: 0A
</code></code></pre><p>it has learned something for free: whatever <code>0A</code> is, the western path is how I just heard from it.</p><p>So the relay can remember that fact.</p><p>After some traffic its memory may look like this:</p><pre><code><code>0A &#8594; western path
0B &#8594; northern path
0C &#8594; eastern path
0D &#8594; southern path
</code></code></pre><p>Now a frame addressed to <code>0C</code> does not have to be repeated everywhere. The relay can send it only toward the eastern path.</p><p>This is the part where our relay has quietly become an Ethernet switch.</p><p>A switch builds a forwarding table by looking at the source MAC address of frames arriving on its ports. The source address is evidence. If a frame from <code>0C</code> arrived through port 3, then <code>0C</code> is currently reachable through port 3. Real switches also age these entries because networks change, cables move and machines disappear.</p><p>The destination MAC is used for the next decision. If the switch already knows where that destination lives, it forwards the frame through the corresponding port.</p><h3>The destination that has never spoken</h3><p>This was the first place where I caught myself giving the relay knowledge it had never earned.</p><p>Suppose its table contains only:</p><pre><code><code>0A &#8594; western path
0B &#8594; northern path
</code></code></pre><p>Then a frame arrives from the west:</p><pre><code><code>FROM: 0A
TO:   0C
</code></code></pre><p>The relay can refresh <code>0A &#8594; western path</code>, because it has just observed that fact. But the destination field tells it absolutely nothing about where <code>0C</code> is located. <code>TO: 0C</code> only describes what the sender wants.</p><p>So the relay has one honest option: try all the other paths.</p><p>It retransmits the frame everywhere except back through the path it arrived on. Every participant may see it, but only <code>0C</code> should accept a unicast frame addressed to <code>0C</code>.</p><p>Ethernet calls this unknown unicast flooding.</p><p>If Tower C later sends anything:</p><pre><code><code>FROM: 0C
TO:   0A
</code></code></pre><p>then the relay finally gets real evidence. The frame came from the east, so it can learn:</p><pre><code><code>0C &#8594; eastern path
</code></code></pre><p>Future frames for <code>0C</code> can go directly there.</p><p>There is a subtle point here that I want to keep separate from ARP. Unknown unicast flooding means the sender already put a destination MAC address into the Ethernet frame, but the switch does not know which port leads to that MAC. ARP solves a different problem: the sending host may not know the destination MAC address at all.</p><p>In a normal fresh IPv4 conversation, ARP often causes the destination host to reply before the first IP unicast frame is sent. That reply also gives the switch a chance to learn the destination MAC. So you may not actually observe unknown unicast flooding every time you contact a new local IP address.</p><p>The behavior still matters. Imagine that Tower A already knows <code>0C</code>, perhaps from an existing neighbour-cache entry, while the switch&#8217;s own forwarding entry for <code>0C</code> has expired. Then A can send a perfectly valid unicast frame to <code>0C</code>, and the switch may still have to flood it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EWRA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3ce0b6e-5f30-4336-a153-4105ec54446d_1280x720.svg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EWRA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3ce0b6e-5f30-4336-a153-4105ec54446d_1280x720.svg 424w, https://substackcdn.com/image/fetch/$s_!EWRA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3ce0b6e-5f30-4336-a153-4105ec54446d_1280x720.svg 848w, https://substackcdn.com/image/fetch/$s_!EWRA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3ce0b6e-5f30-4336-a153-4105ec54446d_1280x720.svg 1272w, https://substackcdn.com/image/fetch/$s_!EWRA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3ce0b6e-5f30-4336-a153-4105ec54446d_1280x720.svg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EWRA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3ce0b6e-5f30-4336-a153-4105ec54446d_1280x720.svg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e3ce0b6e-5f30-4336-a153-4105ec54446d_1280x720.svg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:97248,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/svg+xml&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213120887?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3ce0b6e-5f30-4336-a153-4105ec54446d_1280x720.svg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EWRA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3ce0b6e-5f30-4336-a153-4105ec54446d_1280x720.svg 424w, https://substackcdn.com/image/fetch/$s_!EWRA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3ce0b6e-5f30-4336-a153-4105ec54446d_1280x720.svg 848w, https://substackcdn.com/image/fetch/$s_!EWRA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3ce0b6e-5f30-4336-a153-4105ec54446d_1280x720.svg 1272w, https://substackcdn.com/image/fetch/$s_!EWRA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3ce0b6e-5f30-4336-a153-4105ec54446d_1280x720.svg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Diagram 3. The relay tower has become a Layer 2 switch by learning where local addresses are reachable.</em></p><p>The switch now has a useful memory, but Tower A can still be stuck for a completely different reason.</p><h2>I know the IP address. I still cannot send the frame</h2><p>Suppose an application on Tower A wants to send data to:</p><pre><code><code>192.168.1.20
</code></code></pre><p>Let us say that this address belongs to Tower C.</p><p>For the moment I will also grant Tower A one piece of knowledge: it knows that <code>192.168.1.20</code> is on the same local network. How the host makes that decision belongs to IP addressing, subnet masks and routing tables, which is exactly the problem I want to pick up in the next part.</p><p>Tower A can create an IP packet for <code>192.168.1.20</code>, but our local medium still does not forward an ordinary Ethernet frame by looking at that IP address. The Ethernet frame needs a destination MAC address.</p><p>And Tower A does not know it.</p><p>This is different from the problem we just had inside the switch.</p><p>Missing knowledge Who is missing it? Mechanism <code>MAC &#8594; switch port</code> The switch Source-MAC learning, with unknown unicast flooding when the destination is unknown <code>IPv4 address &#8594; MAC</code> The sending host ARP</p><p>I like this distinction because both failures can sound like &#8220;I do not know where C is,&#8221; while they live in different machines and are solved by different mechanisms.</p><p>ARP, the Address Resolution Protocol, exists to solve the second one for IPv4.</p><h2>A local shout</h2><p>There is a bootstrapping problem, though. If Tower A does not know Tower C&#8217;s MAC address, it cannot send Tower C a normal unicast Ethernet frame asking for it.</p><p>So I need one more local address in the tower world:</p><pre><code><code>EVERYONE
</code></code></pre><p>A frame sent to <code>EVERYONE</code> is copied toward every participant in this local communication region.</p><p>Ethernet already has exactly such a destination:</p><pre><code><code>ff:ff:ff:ff:ff:ff
</code></code></pre><p>That is the Ethernet broadcast MAC address.</p><p>Tower A can now send something equivalent to:</p><pre><code><code>Who has 192.168.1.20?
Tell 192.168.1.10.
</code></code></pre><p>The Ethernet destination is the broadcast address, so the switch floods the frame through the local broadcast domain. The switch does not need to understand the IP address in the question. In the ordinary forwarding model it is still doing a Layer 2 job: it sees a broadcast destination MAC and forwards accordingly.</p><p>Inside that Ethernet frame is an ARP message. ARP is not an IP packet, and the switch does not use ARP to decide where ordinary unicast Ethernet frames should go. ARP is a separate protocol carried directly inside Ethernet, identified by EtherType <code>0x0806</code>.</p><p>Every IPv4 host in the local broadcast domain may receive the request. Most of them inspect it, notice that <code>192.168.1.20</code> is not theirs, and move on with their lives.</p><p>Tower C recognizes its own IP address and replies with its MAC address:</p><pre><code><code>192.168.1.20 is at 02:00:00:00:00:0c
</code></code></pre><p>The reply can be sent as a unicast Ethernet frame back to Tower A because the ARP request already contained A&#8217;s addresses.</p><p>That reply does two useful things in two different places. Tower A can store:</p><pre><code><code>192.168.1.20 &#8594; 02:00:00:00:00:0c
</code></code></pre><p>in its neighbour cache, while the switch sees a frame arriving from Tower C and can learn <code>02:00:00:00:00:0c &#8594; eastern port</code> from the source MAC address.</p><p>Nobody had to teach the switch about <code>192.168.1.20</code>. It still does not need that information for normal Layer 2 forwarding.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Vn4O!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F383b81cb-d78c-4b76-8529-cbd937041a79_1280x720.svg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Vn4O!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F383b81cb-d78c-4b76-8529-cbd937041a79_1280x720.svg 424w, https://substackcdn.com/image/fetch/$s_!Vn4O!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F383b81cb-d78c-4b76-8529-cbd937041a79_1280x720.svg 848w, https://substackcdn.com/image/fetch/$s_!Vn4O!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F383b81cb-d78c-4b76-8529-cbd937041a79_1280x720.svg 1272w, https://substackcdn.com/image/fetch/$s_!Vn4O!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F383b81cb-d78c-4b76-8529-cbd937041a79_1280x720.svg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Vn4O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F383b81cb-d78c-4b76-8529-cbd937041a79_1280x720.svg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/383b81cb-d78c-4b76-8529-cbd937041a79_1280x720.svg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:182380,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/svg+xml&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213120887?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F383b81cb-d78c-4b76-8529-cbd937041a79_1280x720.svg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Vn4O!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F383b81cb-d78c-4b76-8529-cbd937041a79_1280x720.svg 424w, https://substackcdn.com/image/fetch/$s_!Vn4O!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F383b81cb-d78c-4b76-8529-cbd937041a79_1280x720.svg 848w, https://substackcdn.com/image/fetch/$s_!Vn4O!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F383b81cb-d78c-4b76-8529-cbd937041a79_1280x720.svg 1272w, https://substackcdn.com/image/fetch/$s_!Vn4O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F383b81cb-d78c-4b76-8529-cbd937041a79_1280x720.svg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Diagram 4. Broadcast lets ARP discover the local MAC address associated with an IPv4 address.</em></p><p>This is the part of the experiment I find especially satisfying because we now have two small pieces of memory that look similar on paper but belong to completely different parts of the system.</p><h2>Two different maps of the same local network</h2><p>Tower A may remember:</p><pre><code><code>192.168.1.20 &#8594; 02:00:00:00:00:0c
</code></code></pre><p>That is host knowledge. On Linux it lives in the neighbour table. For IPv4, ARP is the mechanism that normally creates and refreshes this mapping.</p><p>The switch may remember:</p><pre><code><code>02:00:00:00:00:0c &#8594; eastern port
</code></code></pre><p>That is switch knowledge. It was learned from the source MAC address of a frame that arrived through the eastern port.</p><p>The two tables answer different questions:</p><p>Machine What it knows Why it needs it Host <code>IPv4 address &#8594; MAC address</code> To build an Ethernet frame for a local IPv4 destination Switch <code>MAC address &#8594; port</code> To decide where to forward that Ethernet frame</p><p>This also makes the MAC and IP distinction less mystical.</p><p>A MAC address is useful for delivery on the current Layer 2 network. An IP address is the logical address of the packet&#8217;s destination in the larger Layer 3 system.</p><p>When A and C are sitting in the same valley, both addresses appear to identify the same machine, so having two of them can feel redundant. The redundancy is mostly an illusion created by the small example. Once the packet has to cross a router, the reason for both becomes much clearer.</p><p>For a local destination, A may build something conceptually like this:</p><pre><code><code>Ethernet:
  dst MAC = 02:00:00:00:00:0c
  src MAC = 02:00:00:00:00:0a
  type    = IPv4

IPv4 packet inside:
  dst IP  = 192.168.1.20
  src IP  = 192.168.1.10
</code></code></pre><p>The switch cares about the Ethernet destination MAC when forwarding the frame. Tower C eventually receives the frame, sees that the payload is IPv4, and passes the enclosed IP packet upward.</p><p>The complete first exchange is therefore not one magic lookup. It is several small mechanisms cooperating:</p><pre><code><code>Application wants to send to 192.168.1.20
            &#8595;
Host decides 192.168.1.20 is local
            &#8595;
Neighbour cache has no MAC for 192.168.1.20
            &#8595;
Host sends an ARP request in an Ethernet broadcast frame
            &#8595;
Switch learns A's source MAC and floods the broadcast
            &#8595;
C recognizes its IP address and sends an ARP reply
            &#8595;
Switch learns C's source MAC from the reply
            &#8595;
A stores 192.168.1.20 &#8594; C's MAC in its neighbour cache
            &#8595;
A puts the IP packet into a unicast Ethernet frame for C's MAC
            &#8595;
Switch uses C's MAC to select the correct port
            &#8595;
C receives the frame and extracts the IP packet
</code></code></pre><p>This is a simplified path, but it is finally a simplification I can reason with. Each table has an owner. Each address has a purpose. The switch never needs to resolve <code>192.168.1.20</code>, and ARP never tells the switch which destination port to use.</p><h2>Back on a real Linux machine</h2><p>After spending enough time with imaginary towers, I wanted to see whether the same structure is visible without the analogy.</p><p>Linux exposes the host-side neighbour table with:</p><pre><code><code>ip neigh
</code></code></pre><p>For an IPv4 neighbour, an entry can look like this:</p><pre><code><code>192.168.1.20 dev eth0 lladdr 02:00:00:00:00:0c REACHABLE
</code></code></pre><p>There it is: the same <code>IPv4 address &#8594; MAC address</code> mapping that Tower A had to learn. The Linux neighbour table is more general than ARP and also contains IPv6 neighbour information, but for IPv4 on Ethernet, ARP is the mechanism we care about here.</p><p>The exchange itself is even nicer because we can watch it happen:</p><pre><code><code>sudo tcpdump -i eth0 -n -e arp
</code></code></pre><p>If <code>eth0</code> is not your actual interface name, which is very likely on a modern Linux machine because apparently <code>eth0</code> was too easy, replace it with the real interface.</p><p>With no cached neighbour entry, contacting <code>192.168.1.20</code> should first produce an ARP request sent to the Ethernet broadcast address. Then the owner of that IP replies with its MAC address. After the mapping exists, the host can send normal unicast Ethernet frames.</p><p>If the neighbour entry already exists, the absence of ARP traffic is not evidence that the mechanism disappeared. Linux is simply using what it already knows.</p><blockquote><p>&#128270; <strong>Try it yourself:</strong> run <code>ip neigh</code>, start <code>sudo tcpdump -i &lt;interface&gt; -n -e arp</code>, and then ping another machine on the same local network. If a cached entry prevents the ARP exchange from appearing, remove only that entry with <code>sudo ip neigh del &lt;IP&gt; dev &lt;interface&gt;</code> and repeat the experiment. Use a machine and network you control.</p></blockquote><p></p><p>I will stop the Linux part here. Later in Act I I want to open one host properly and look at interfaces, bridges, network namespaces, virtual Ethernet devices and the rest of the machinery Linux piles underneath an innocent socket. Here I only wanted to verify that our medieval invention leaves fingerprints on a real machine.</p><h2>Then I add another valley</h2><p>So far everybody belongs to one local communication region. Broadcast can reach the whole group, and one Layer 2 system is enough.</p><p>Then I put another valley behind the mountains.</p><p>It has its own towers, its own local relay, its own broadcasts and its own local MAC addresses. Tower A cannot simply shout an ARP request across the mountains and expect all of Europe to participate.</p><p>Still, Tower A needs to send a message there.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MGcI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb9c3341-23c6-4b73-8265-d1666a070d38_1280x720.svg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MGcI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb9c3341-23c6-4b73-8265-d1666a070d38_1280x720.svg 424w, https://substackcdn.com/image/fetch/$s_!MGcI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb9c3341-23c6-4b73-8265-d1666a070d38_1280x720.svg 848w, https://substackcdn.com/image/fetch/$s_!MGcI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb9c3341-23c6-4b73-8265-d1666a070d38_1280x720.svg 1272w, https://substackcdn.com/image/fetch/$s_!MGcI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb9c3341-23c6-4b73-8265-d1666a070d38_1280x720.svg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MGcI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb9c3341-23c6-4b73-8265-d1666a070d38_1280x720.svg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/eb9c3341-23c6-4b73-8265-d1666a070d38_1280x720.svg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:115640,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/svg+xml&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213120887?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb9c3341-23c6-4b73-8265-d1666a070d38_1280x720.svg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MGcI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb9c3341-23c6-4b73-8265-d1666a070d38_1280x720.svg 424w, https://substackcdn.com/image/fetch/$s_!MGcI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb9c3341-23c6-4b73-8265-d1666a070d38_1280x720.svg 848w, https://substackcdn.com/image/fetch/$s_!MGcI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb9c3341-23c6-4b73-8265-d1666a070d38_1280x720.svg 1272w, https://substackcdn.com/image/fetch/$s_!MGcI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feb9c3341-23c6-4b73-8265-d1666a070d38_1280x720.svg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Diagram 5. The local-network model stops being sufficient when the destination belongs to another network.</em></p><p>This is where my local-network model finally runs out of road.</p><p>I could try to connect both valleys into one gigantic Layer 2 domain and let broadcasts spread farther and farther. Then I could keep adding valleys until one ARP request lights half the continent. Apart from being a rather beautiful medieval spectacle, it would also turn every local broadcast into everybody else&#8217;s problem.</p><p>The cleaner solution is to let each valley remain a local network and introduce a machine that knows how to move packets between networks.</p><p>That machine is a router.</p><p>And here the two-address idea starts paying rent.</p><p>If Tower A wants to send an IP packet to a host in the remote valley, the packet can keep the remote host as its IP destination. But the Ethernet frame used in A&#8217;s local valley is not addressed to that distant machine. It is addressed to the local router, the next machine that can move the packet closer to where it belongs.</p><p>Conceptually:</p><pre><code><code>IP destination:       remote host in another valley
Ethernet destination: local router
</code></code></pre><p>The router receives the local frame, removes that Layer 2 envelope, examines the IP packet, chooses the next route, and places the packet into a new Layer 2 frame appropriate for the next link.</p><p>This is the point where the medieval analogy also needs a new piece. A relay inside one valley was enough while everybody shared one local addressing and broadcast system. Communication between valleys requires a gateway that understands something larger than local tower addresses.</p><p>That larger system is what I want to rebuild in Part 2: IP addresses, subnet masks, the decision that a destination is local or remote, default gateways, routing tables and routers.</p><p>The towers got us surprisingly far, but the mountains finally forced us into Layer 3.</p><p>Which we cover in the next part!</p><p>Stay tuned!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Rebuilt is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2><strong>Series Hub</strong></h2><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;645e6aea-757c-46bb-b4f6-4c9de1db16c1&quot;,&quot;caption&quot;:&quot;I have worked with networked software for years, but for most of that time the network was something I used rather than something I really understood. I could open a socket, call an API, connect to an IP address, and continue with the part of the system I was responsible for.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Networking in the Power Grid for Software Developers&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer exploring how complex systems are built. I take them apart, rebuild them from first principles, and trace the layers connecting software, networks, infrastructure, devices, and the physical world.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-08-27T21:18:02.367Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!sXgD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/networking-in-the-power-grid-for&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:213058272,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><h2>References and further reading</h2><ul><li><p><a href="https://datatracker.ietf.org/doc/html/rfc826">RFC 826: An Ethernet Address Resolution Protocol</a></p></li><li><p><a href="https://www.ieee802.org/3/">IEEE 802.3 Ethernet Working Group</a></p></li><li><p><a href="https://man7.org/linux/man-pages/man8/ip-neighbour.8.html">Linux ip-neighbour manual</a></p></li><li><p><a href="https://docs.kernel.org/networking/tuntap.html">Linux kernel TUN/TAP documentation</a>, useful later when we rebuild networking machinery inside one Linux host</p></li><li><p><a href="https://www.dmytrohuz.com/p/a-developers-map-of-the-european">A Developer&#8217;s Map of the European Power Grid</a>, the wider series context for software developers entering the energy domain</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Networking in the Power Grid for Software Developers]]></title><description><![CDATA[A living map of my attempt to understand the networking machinery behind power-grid software, from physical links and Ethernet to substation communication, utility networks, and secure remote access.]]></description><link>https://www.dmytrohuz.com/p/networking-in-the-power-grid-for</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/networking-in-the-power-grid-for</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Thu, 27 Aug 2026 21:18:02 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!sXgD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sXgD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sXgD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!sXgD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!sXgD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!sXgD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sXgD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2435372,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213058272?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sXgD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!sXgD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!sXgD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!sXgD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea2f83a8-82b3-42d5-817b-5266707341bb_1672x941.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I have worked with networked software for years, but for most of that time the network was something I used rather than something I really understood. I could open a socket, call an API, connect to an IP address, and continue with the part of the system I was responsible for.</p><p>When I started working closer to the power grid, this became uncomfortable. Network details were no longer hidden somewhere below the application. Ethernet frames, multicast, VLANs, gateways, industrial protocols, and utility networks appeared directly in requirements and discussions.</p><p>The difficult part was not learning what each term meant. I could read a definition of ARP or a description of a routing table. The problem was seeing how all these mechanisms formed one system, and then seeing how that system was used by substations, protection devices, control centres, and remote engineering tools.</p><p>This series is my attempt to build that connected picture. I want to begin with ordinary network machinery, reconstruct enough of it in Linux to make it tangible, and then follow it into the power grid.</p><p>In this post I will explain the plan and keep links to every part as it is published. The plan may change while I work through it, and this page will change with it.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><h2>Why networking in the power grid needs its own map</h2><p>While writing <a href="https://www.dmytrohuz.com/p/a-developers-map-of-the-european">A Developer&#8217;s Map of the European Power Grid</a>, I kept running into communication at every level of the system. The last article, <a href="https://www.dmytrohuz.com/p/where-software-lives-in-the-power">Where Software Lives in the Power Grid</a>, made the gap even more obvious. A relay, an HMI, a gateway, and a control-centre service are all pieces of software, but the networks around them are shaped by very different physical jobs.</p><p>The vocabulary is dense, although the vocabulary itself is not the hardest part. The real difficulty is connecting ordinary mechanisms such as switching, routing, multicast, and redundancy to the events they carry. A frame in a substation might represent a protection decision. A remote connection might give an engineer access to equipment that controls real power.</p><p>When the networking foundation is fuzzy, grid protocols can look like a collection of arbitrary rules. When the grid context is missing, a generic networking explanation can feel detached from the work. I want this series to bring those two views together for software developers who are entering the energy domain.</p><h2>How I want to approach the subject</h2><p>I learn technical systems best when I can take a small version apart and rebuild it. That is the approach I want to use here.</p><p>Instead of beginning with a chapter called &#8220;ARP,&#8221; I would rather begin with two machines on one network and ask how one finds the other. Instead of introducing routing as a table of definitions, I want to place the destination somewhere else and watch the sending host decide that the packet has to leave through a gateway. The mechanism arrives because the problem makes it necessary.</p><p>Linux is a useful laboratory for this. Network namespaces can behave like separate hosts, <code>veth</code> pairs can connect them, a bridge can act as a switch, and another namespace can forward packets as a router. These experiments are small enough to run on one computer, but they expose the same decisions that appear in larger networks.</p><blockquote><p>&#10067;The question I want to keep asking is simple: what problem made this mechanism necessary?</p></blockquote><p>The examples will be simplified on purpose. They are models for understanding packet paths and engineering choices, not reference designs for operational substations or utility networks.</p><h2>The three acts</h2><p>I currently see the series in three acts. Each one widens the system under investigation: first one host and its nearby network, then a substation, and finally the connections between substations, control centres, and remote users.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!V8rr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a1c95-eb66-46af-ba49-3044181d68fa_3200x1360.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!V8rr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a1c95-eb66-46af-ba49-3044181d68fa_3200x1360.png 424w, https://substackcdn.com/image/fetch/$s_!V8rr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a1c95-eb66-46af-ba49-3044181d68fa_3200x1360.png 848w, https://substackcdn.com/image/fetch/$s_!V8rr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a1c95-eb66-46af-ba49-3044181d68fa_3200x1360.png 1272w, https://substackcdn.com/image/fetch/$s_!V8rr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a1c95-eb66-46af-ba49-3044181d68fa_3200x1360.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!V8rr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a1c95-eb66-46af-ba49-3044181d68fa_3200x1360.png" width="1456" height="619" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e64a1c95-eb66-46af-ba49-3044181d68fa_3200x1360.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:619,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:214728,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/213058272?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a1c95-eb66-46af-ba49-3044181d68fa_3200x1360.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!V8rr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a1c95-eb66-46af-ba49-3044181d68fa_3200x1360.png 424w, https://substackcdn.com/image/fetch/$s_!V8rr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a1c95-eb66-46af-ba49-3044181d68fa_3200x1360.png 848w, https://substackcdn.com/image/fetch/$s_!V8rr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a1c95-eb66-46af-ba49-3044181d68fa_3200x1360.png 1272w, https://substackcdn.com/image/fetch/$s_!V8rr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe64a1c95-eb66-46af-ba49-3044181d68fa_3200x1360.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Diagram 1. Each act reuses the mechanisms established in the previous one and applies them to a wider part of the grid.</em></p><p>The division is useful for planning, although I do not consider it fixed. If an experiment shows that an article belongs somewhere else or deserves its own part, I will change the map.</p><h2>Act I: Networking machinery for software engineers</h2><p>Act I is where I fill the gaps in my own networking foundation. We start with the smallest useful network: two machines, a physical link, and a switch. From there we can see how Ethernet frames move, how hosts learn MAC addresses, and why ARP exists.</p><p>The first part begins at Layer 1, or L1. Copper and fibre carry electrical or optical signals, while Ethernet gives those signals a frame structure and an addressing model at Layer 2. I do not plan to turn this into an electronics course, but the physical layer matters because every packet eventually depends on a real medium, a negotiated link, and hardware that can fail.</p><p>Next, we break the local-network assumption by placing the destination somewhere else. This introduces gateways and routing for a concrete reason. Only after those ideas are visible from the outside do we open a Linux host and find the interfaces, neighbour table, routes, bridges, namespaces, and virtual links that implement them.</p><p>Linux comes last for a reason. Once the external network is clear, a single computer can reproduce it. Namespaces become hosts, <code>veth</code> pairs become links, a bridge becomes a switch, and a forwarding namespace becomes a router. That gives us a laboratory for the rest of the series.</p><h3>Part 1: How Local Networks Work</h3><p><strong>Layer 1, Ethernet, MAC addresses, switches, and ARP</strong></p><p>We will connect two hosts on one local network and follow a message from the physical link upward. The main question is deceptively simple: what has to happen before one machine can send an Ethernet frame to another?</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;e5582bd3-9ba6-4441-b507-6bc4abf19cee&quot;,&quot;caption&quot;:&quot;Recently I started working on a networking series for software developers who enter the electrical-grid world and suddenly discover that the grid speaks in packets, interfaces, switches, routes, protocols and a suspicious number of acronyms.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Networking Machinery for Software Engineers\nPart 1: Rebuilding a Local Network with Medieval Signal Towers&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer exploring how complex systems are built. I take them apart, rebuild them from first principles, and trace the layers connecting software, networks, infrastructure, devices, and the physical world.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-08-28T09:48:20.438Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!Xg26!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81428888-7e1b-4174-8ad1-092e46214718_1672x941.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/networking-machinery-for-software&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:213120887,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><h3>Part 2: How Packets Travel Between Networks</h3><p><strong>IP addresses, subnet masks, gateways, routing tables, and routers</strong></p><p>The destination now moves outside the local network. We will follow the packet through the host&#8217;s routing decision, the default gateway, and the router that connects the two sides.</p><p><em>Planned.</em></p><h3>Part 3: How Linux Builds a Network</h3><p><strong>Interfaces, neighbour tables, routes, namespaces, veth pairs, bridges, forwarding, and TUN/TAP</strong></p><p>We will rebuild the first two parts inside one Linux machine and inspect the objects that the kernel uses to represent the network.</p><p><em>Planned.</em></p><h2>Act II: Networking inside the power grid</h2><p>Once the ordinary machinery is clear, I want to bring it into a substation. This is where familiar networking ideas begin carrying unfamiliar consequences. Ethernet and multicast are still Ethernet and multicast, but now the traffic can describe measurements, status changes, or protection events.</p><p>A small substation model should make this easier to reason about. We can place an IED, an HMI, a gateway, and a station bus on one diagram, then ask why the network is segmented, which traffic is multicast, where time matters, and what happens when a link or switch fails.</p><h3>Articles I currently plan</h3><p><strong>Building a Tiny Substation Network</strong></p><p>A compact network with representative devices, traffic paths, VLAN boundaries, and the practical reasons behind them.</p><p><strong>Why IEC 61850 Is Not One Protocol</strong></p><p>A map of the different jobs hidden behind one standard, including configuration, client-server communication, fast events, and sampled measurements.</p><p><strong>Rebuilding GOOSE From First Principles</strong></p><p>An attempt to understand GOOSE by starting with the protection problem, then examining multicast delivery, repeated messages, timing, and failure behaviour.</p><p><em>Act II is planned. I will add links here as the articles are released.</em></p><h2>Act III: Connecting the grid</h2><p>A substation is only one island. The next step is to follow communication beyond it: toward a control centre, another site, or an engineer connecting from somewhere outside the operational network.</p><p>This is where routing, firewalls, wide-area links, tunnels, and trust boundaries meet. A diagram that says &#8220;remote access&#8221; can hide a surprising amount of machinery, so I want to open that path and inspect each boundary.</p><h3>Articles I currently plan</h3><p><strong>From a Substation to a Control Centre</strong></p><p>We will follow telemetry and commands across a simplified utility topology and identify the role of each network segment.</p><p><strong>How Telecontrol Crosses Networks</strong></p><p>This part will connect application protocols to TCP/IP, routing, firewalls, and operational constraints without treating the network as an invisible pipe.</p><p><strong>Building a Secure Tunnel Into a Substation</strong></p><p>A small WireGuard experiment will show what a tunnel actually creates, which routes change, and where encrypted traffic enters and leaves the system.</p><p><em>Act III is planned. I will add links here as the articles are released.</em></p><h2>What this series should make possible</h2><p>My target is fairly modest: I want the network below an application to become something I can inspect and reason about.</p><p>When I see an unfamiliar architecture, I want to identify the local-network boundaries, understand why a packet follows a particular gateway, recognise where multicast is being used, and know which Linux tools can confirm my assumptions. In a grid diagram, I also want to connect those mechanisms to the physical role of a relay, gateway, substation, or control centre.</p><p>That level of understanding will not make me a protection engineer or a utility network architect. It should, however, make the conversations with those specialists much more useful and make network-related failures less mysterious.</p><h2>Follow the series</h2><p>I will use this page as the index for the whole project. As each article is published, I will replace its status with a direct link and update the plan if the investigation takes a different direction.</p><p>I am learning this subject in public. If you work with industrial networks, IEC 61850, utility communications, or Linux networking and notice that I have missed something, I would be glad to hear from you.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">You can subscribe to <strong>Rebuilt</strong> to receive the next part.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Where Software Lives in the Power Grid]]></title><description><![CDATA[This article maps the software ecosystem of the power grid and gives software engineers a mental model for understanding where different systems fit and how they work together.]]></description><link>https://www.dmytrohuz.com/p/where-software-lives-in-the-power</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/where-software-lives-in-the-power</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Tue, 04 Aug 2026 12:00:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!VcpN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d167517-6038-47fa-9548-a22e9beba2c7_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VcpN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d167517-6038-47fa-9548-a22e9beba2c7_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VcpN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d167517-6038-47fa-9548-a22e9beba2c7_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!VcpN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d167517-6038-47fa-9548-a22e9beba2c7_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!VcpN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d167517-6038-47fa-9548-a22e9beba2c7_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!VcpN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d167517-6038-47fa-9548-a22e9beba2c7_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VcpN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d167517-6038-47fa-9548-a22e9beba2c7_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6d167517-6038-47fa-9548-a22e9beba2c7_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2677087,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/209770599?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d167517-6038-47fa-9548-a22e9beba2c7_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VcpN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d167517-6038-47fa-9548-a22e9beba2c7_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!VcpN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d167517-6038-47fa-9548-a22e9beba2c7_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!VcpN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d167517-6038-47fa-9548-a22e9beba2c7_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!VcpN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d167517-6038-47fa-9548-a22e9beba2c7_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Previous part:</em></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;e04fa1d2-87b1-411f-b724-93c4a4708fcb&quot;,&quot;caption&quot;:&quot;Previous part:&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;How Europe&#8217;s Power System Is Organised&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer who takes foundational technologies apart and rebuilds them. Follow to understand how complex systems work, why they are designed this way, and how to reason about them from first principles.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-08-01T19:35:39.907Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!EXqg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/how-europes-power-system-is-organised&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:209412144,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:2,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><blockquote><p><em><span>&#8220;The metasphere remains. But it is more wilderness than ever now. Black forests of unknown time and space. Sounds in the night. Lions. And tigers. And bears.&#8221;</span></em> &#8213; Dan Simmons, <em><span>Hyperion</span></em></p></blockquote><p></p><p>Where does software live in the grid?</p><p>It lives between, within and above.</p><p>For most of <a href="https://www.dmytrohuz.com/p/a-developers-map-of-the-european">this series</a>, I was looking at the physical world. Generators produce electricity, transformers change voltage, transmission lines connect regions, and substations switch and protect all of it. These things have weight, occupy space and can be found on a map.</p><p>But during my research I slowly realised that there is another world hiding inside this one.</p><p>Software lives inside protection relays and control-room servers. It lives between devices, companies and countries. It stretches above cables and transformers as measurements, alarms, schedules, forecasts, bids and models. Almost every hollow space that is not fulfilled by the physical world hides another piece of software.</p><p>And it does not only observe the industry. It moves it. Software opens breakers, reconstructs the state of the grid, predicts tomorrow&#8217;s demand, accepts bids, calculates prices, activates reserves and later calculates who owes money to whom because reality did not follow the plan.</p><p>For me, it looks like a huge augmented reality built on top of the grid. At some point it becomes difficult to decide which reality is primary. Electricity still follows physics, but more and more of what happens around it is decided, coordinated and recorded in software.</p><p>It felt like discovering another continent.</p><p>I do not want to pretend that I can produce its Google Map. What I can draw is closer to the maps of Herodotus, collected from documents, conversations, tools I met at work and stories from people who travelled further than I did. It will contain blank places and probably a few sea monsters, but it should still be enough to understand where we are.</p><p>And AI, for better or worse, has been my Virgil during this journey.</p><p>In this post we will discuss three large software worlds: the software that operates the physical grid, the software that operates the electricity market, and the software that connects financial plans with physical reality.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dJzO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12e519c4-bc8b-4e35-8c29-a8e22620fe9e_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dJzO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12e519c4-bc8b-4e35-8c29-a8e22620fe9e_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!dJzO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12e519c4-bc8b-4e35-8c29-a8e22620fe9e_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!dJzO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12e519c4-bc8b-4e35-8c29-a8e22620fe9e_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!dJzO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12e519c4-bc8b-4e35-8c29-a8e22620fe9e_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dJzO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12e519c4-bc8b-4e35-8c29-a8e22620fe9e_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/12e519c4-bc8b-4e35-8c29-a8e22620fe9e_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2532589,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/209770599?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12e519c4-bc8b-4e35-8c29-a8e22620fe9e_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dJzO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12e519c4-bc8b-4e35-8c29-a8e22620fe9e_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!dJzO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12e519c4-bc8b-4e35-8c29-a8e22620fe9e_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!dJzO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12e519c4-bc8b-4e35-8c29-a8e22620fe9e_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!dJzO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12e519c4-bc8b-4e35-8c29-a8e22620fe9e_1536x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 1. Three software worlds of the grid. Their borders are not clean, but their main purposes are different.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><h2>Software that operates the physical grid</h2><p>This is the software closest to copper, steel and electromagnetic fields.</p><p>A breaker does not know that it is called <code>Q0</code>. A current transformer does not produce a neat object with a timestamp and a quality flag. The physical world gives us voltage, current, heat, motion and consequences. Software turns them into information that people and other systems can use.</p><p>The first computers we meet are <strong>Intelligent Electronic Devices</strong>, usually shortened to IEDs. This family includes protection relays, bay controllers, merging units and meters.</p><p>A <strong>protection relay</strong> watches electrical quantities and reacts when they indicate a fault. It may detect overcurrent, an abnormal frequency or a fault inside a transformer and send a trip command before a remote operator could even understand what happened.</p><p>A <strong>bay controller</strong> supervises breakers, disconnectors and earthing switches around one part of a substation. A <strong>merging unit</strong> digitises current and voltage measurements. A <strong>meter</strong> measures energy or power for operational and commercial use.</p><p>Above these devices sits the <strong>substation automation system</strong>. Its visible part is often a local HMI with a single-line diagram, measurements, alarms and controls. Behind it are gateways, Remote Terminal Units (RTU), event recorders, engineering tools and configuration files. The substation is already a distributed software system, only with unusually expensive outputs.</p><p>Communication inside a modern substation is often organised around <strong><a href="https://webstore.iec.ch/en/publication/105222">IEC 61850</a></strong>.</p><p>At first, it is tempting to think of IEC 61850 as just another network protocol, similar to HTTP or Modbus. But it is much broader than that. It is a common language for describing the devices, measurements, commands and protection functions inside a power-system automation system.</p><p>For example, different vendors may build protection relays in very different ways, but IEC 61850 gives them a shared model for concepts such as circuit breakers, voltage measurements, alarms and trip signals. This makes it easier for devices and engineering tools from different manufacturers to understand each other.</p><p>IEC 61850 also defines several ways in which these devices communicate. <strong>MMS</strong> is commonly used when one system needs to read data from another device, receive reports or send a control command. <strong>GOOSE</strong> is used for very fast messages between devices, for example when one protection relay must immediately tell another device to trip a breaker. <strong>Sampled Values</strong> are used to send digitised current and voltage measurements over the station network.</p><p>The standard also includes <strong>SCL</strong>, or Substation Configuration Language. SCL files describe which devices exist in the substation, what data they provide, how they are connected and how they communicate. In other words, IEC 61850 defines not only how messages travel, but also what those messages mean and how the whole system is engineered.</p><p>Communication between a substation and a remote control centre often uses another standard called <strong><a href="https://webstore.iec.ch/en/publication/25035">IEC 60870-5-104</a></strong>, usually shortened to <strong>IEC 104</strong>.</p><p>Its role is easier to imagine. A gateway or Remote Terminal Unit inside the substation gathers selected information from local devices and sends it to the control centre. This can include voltage and power measurements, breaker positions, alarms and events. The control centre can then send commands back, for example to open or close a breaker.</p><p>A simple mental model is this: IEC 61850 is often used to organise communication inside the substation, while IEC 104 is often used to connect the substation with the control centre.</p><p>There are many other protocols, including DNP3, Modbus and OPC UA. There are also decades of legacy equipment and vendor-specific behaviour, because standards can reduce chaos but apparently cannot eliminate human creativity.</p><p>At the control centre, <strong>SCADA</strong> collects telemetry, displays the current state, processes alarms and lets authorised operators issue commands. It is the operational window into the grid.</p><p>For transmission operators, SCADA is often surrounded by an <strong>Energy Management System</strong>, or EMS. The EMS runs applications such as state estimation, power-flow calculation and contingency analysis. State estimation combines measurements with a network model and calculates the most plausible state of the system. Contingency analysis asks what would happen if a line, transformer or generator disappeared.</p><p>Distribution operators use similar families of software, often called <strong>DMS</strong> or <strong>ADMS</strong>, to supervise distribution networks, manage outages, estimate states and increasingly coordinate distributed generation, batteries and flexible loads.</p><p>Around all of this sit historians, alarm systems, disturbance recorders, outage tools, switching-management systems and dispatcher training simulators. Each solves a different problem, but together they perform one purpose: they let humans observe, understand and control a physical system that is far too large and fast to operate directly.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JnSa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4862113-5ca8-4215-8b39-22f2567e4781_1774x887.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JnSa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4862113-5ca8-4215-8b39-22f2567e4781_1774x887.png 424w, https://substackcdn.com/image/fetch/$s_!JnSa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4862113-5ca8-4215-8b39-22f2567e4781_1774x887.png 848w, https://substackcdn.com/image/fetch/$s_!JnSa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4862113-5ca8-4215-8b39-22f2567e4781_1774x887.png 1272w, https://substackcdn.com/image/fetch/$s_!JnSa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4862113-5ca8-4215-8b39-22f2567e4781_1774x887.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JnSa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4862113-5ca8-4215-8b39-22f2567e4781_1774x887.png" width="1456" height="728" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e4862113-5ca8-4215-8b39-22f2567e4781_1774x887.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2069100,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/209770599?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4862113-5ca8-4215-8b39-22f2567e4781_1774x887.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JnSa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4862113-5ca8-4215-8b39-22f2567e4781_1774x887.png 424w, https://substackcdn.com/image/fetch/$s_!JnSa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4862113-5ca8-4215-8b39-22f2567e4781_1774x887.png 848w, https://substackcdn.com/image/fetch/$s_!JnSa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4862113-5ca8-4215-8b39-22f2567e4781_1774x887.png 1272w, https://substackcdn.com/image/fetch/$s_!JnSa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4862113-5ca8-4215-8b39-22f2567e4781_1774x887.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 2. A simplified path from physical equipment to the operator. Measurements travel to the right, while decisions and commands travel back.</em></p><h2>Software that operates the electricity market</h2><p>The market lives in a different world.</p><p>It does not normally open breakers or read raw current samples. It works with products, bids, schedules, contracts, positions and money. Still, it cannot completely escape physics, because the product it trades must be generated, transported and consumed at a specific time.</p><p>The process usually starts with <strong>forecasting and analytics</strong>. Generators forecast their available production. Suppliers and balance responsible parties forecast consumption. Traders forecast prices, weather and the behaviour of everybody else who is also forecasting prices, weather and the behaviour of traders. There is a pleasing circularity to the whole exercise.</p><p>These forecasts enter <strong>trading and bidding systems</strong>. Market participants prepare orders for forward, day-ahead, intraday and balancing markets. The software checks limits, builds bidding strategies, submits orders and records the results.</p><p>At the exchange side, market systems collect bids and offers. In the European day-ahead and intraday markets, market coupling allocates cross-zonal capacity together with energy orders. The <a href="https://www.acer.europa.eu/electricity/market-rules/capacity-allocation-and-congestion-management">Capacity Allocation and Congestion Management rules</a> define the framework for this process. The algorithm does not simply find a buyer for every seller. It tries to maximise economic surplus while respecting the capacity available between bidding zones.</p><p>Once the market clears, the result becomes a schedule. Generators know how much they should produce, suppliers know what they bought, and balance responsible parties have a position that they must later defend against reality.</p><p>Large participants commonly use <strong>Energy Trading and Risk Management systems</strong>, or ETRM. These systems keep track of trades, contracts, portfolios, exposure, nominations, collateral and settlement. They are the commercial memory of the company.</p><p>After delivery, <strong>metering and settlement systems</strong> compare contracted quantities, schedules and measured energy. They calculate invoices, fees and later the cost of imbalances. The market therefore does not end when the price is published. It ends much later, when the final numbers agree enough that money can move.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!M-bP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c1b5e5b-4bfd-4fa7-bb90-5f925ff12627_1774x887.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!M-bP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c1b5e5b-4bfd-4fa7-bb90-5f925ff12627_1774x887.png 424w, https://substackcdn.com/image/fetch/$s_!M-bP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c1b5e5b-4bfd-4fa7-bb90-5f925ff12627_1774x887.png 848w, https://substackcdn.com/image/fetch/$s_!M-bP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c1b5e5b-4bfd-4fa7-bb90-5f925ff12627_1774x887.png 1272w, https://substackcdn.com/image/fetch/$s_!M-bP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c1b5e5b-4bfd-4fa7-bb90-5f925ff12627_1774x887.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!M-bP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c1b5e5b-4bfd-4fa7-bb90-5f925ff12627_1774x887.png" width="1456" height="728" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3c1b5e5b-4bfd-4fa7-bb90-5f925ff12627_1774x887.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1996274,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/209770599?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c1b5e5b-4bfd-4fa7-bb90-5f925ff12627_1774x887.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!M-bP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c1b5e5b-4bfd-4fa7-bb90-5f925ff12627_1774x887.png 424w, https://substackcdn.com/image/fetch/$s_!M-bP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c1b5e5b-4bfd-4fa7-bb90-5f925ff12627_1774x887.png 848w, https://substackcdn.com/image/fetch/$s_!M-bP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c1b5e5b-4bfd-4fa7-bb90-5f925ff12627_1774x887.png 1272w, https://substackcdn.com/image/fetch/$s_!M-bP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c1b5e5b-4bfd-4fa7-bb90-5f925ff12627_1774x887.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 3. The commercial loop. A forecast becomes a bid, the bid becomes a schedule, and physical delivery eventually returns as money and new data.</em></p><h2>Software that connects both worlds</h2><p>The third area is where the article becomes especially interesting for me.</p><p>A market participant can create a good schedule. A control centre can observe the real grid. Neither is enough alone. Somebody must continuously compare the planned world with the physical one and decide what to do when they differ.</p><p>This is one of the main software responsibilities of a Transmission System Operator.</p><p>A TSO receives schedules, forecasts and availability information from market participants. At the same time, SCADA and EMS show what the system is actually doing. The TSO compares the two realities and checks whether the grid can safely carry the planned flows.</p><p>This area contains <strong>load and generation forecasting</strong>, <strong>scheduling systems</strong>, <strong>network models</strong>, <strong>capacity-calculation tools</strong>, <strong>congestion-management tools</strong> and <strong>operational-security analysis</strong>. European TSOs also exchange their individual grid models and combine them into a Common Grid Model through shared infrastructure such as the Operational Planning Data Environment. It is software used not merely by one company, but to construct a common view of an interconnected continent.</p><p>When expected flows violate limits, TSOs may use remedial actions such as changing generation, modifying topology, redispatching power or countertrading. When production and consumption diverge in real time, balancing software procures and activates reserves.</p><p>Some control happens almost automatically. Frequency Containment Reserves respond quickly to frequency deviations. Automatic and manual Frequency Restoration Reserves bring the system back toward its target. European platforms such as <a href="https://www.entsoe.eu/network_codes/eb/picasso/">PICASSO</a> for aFRR and <a href="https://www.entsoe.eu/network_codes/eb/mari/">MARI</a> for mFRR coordinate the exchange of balancing energy between TSOs.</p><p>Afterwards, imbalance-calculation and settlement systems compare the final measured position of each balance responsible party with its schedule. The physical deviation becomes a financial result.</p><p>This is the point where the two worlds finally meet. A forecast becomes a bid, a bid becomes a schedule, a schedule becomes a power flow, a power flow becomes a frequency deviation, and the deviation eventually becomes an invoice.</p><p>The grid and the market are not separate systems. They are two models of the same reality, connected by a large amount of software and by the stubborn requirement that, in every moment, production and consumption still have to match.</p><h2>Regulation is part of the architecture</h2><p>In most software projects, requirements begin with a customer, a product manager or somebody who has discovered a new button they urgently need.</p><p>In the grid, a requirement may have started years earlier in an EU regulation.</p><p>The chain roughly looks like this:</p><p><code>EU legislation &#8594; Network Codes and Guidelines &#8594; ACER and national regulators &#8594; national laws, tariffs and approved methodologies &#8594; company processes and technical requirements &#8594; software behaviour, interfaces and audit trails</code></p><p>For system operation, the <a href="https://eur-lex.europa.eu/eli/reg/2017/1485/oj/eng">System Operation Guideline, Regulation (EU) 2017/1485</a>, defines rules around operational security, coordination, data exchange and planning between TSOs, DSOs and significant grid users.</p><p>For balancing, the <a href="https://eur-lex.europa.eu/eli/reg/2017/2195">Electricity Balancing Guideline, Regulation (EU) 2017/2195</a>, establishes common principles for procuring, activating and settling reserves.</p><p>For day-ahead and intraday markets, the CACM framework defines how capacity calculation and market coupling should work across Europe.</p><p>Technical standards sit beside these legal layers. IEC 61850 shapes data models and communication inside utility automation. IEC 104 defines a common telecontrol path. Other standards define cybersecurity, grid-model exchange, metering, testing and many other details that developers eventually meet as requirements.</p><p>There is still room for architecture, design and creativity, but not every behaviour is free to invent. A configuration field may exist because a standard requires it. An audit trail may exist because an operator must later prove who issued a command. A market interface may have a strange deadline because an approved methodology defines a gate-closure time.</p><p>This was one of the most important discoveries for me. Regulation does not sit somewhere outside the software. It slowly flows down through organisations until it becomes a database field, a validation rule, a protocol message or a test case.</p><h2>A map, not an encyclopedia</h2><p>My goal was not to create the full catalogue of all software, protocols and standards used in the grid. That catalogue would be enormous and, more importantly, almost unreadable.</p><p>I wanted to draw a mental map that gives you an impression and a raw feeling of what exists, why it exists and where your own software takes its place.</p><p>The map has three large regions.</p><p>Operation and control software turns physical processes into measurements, alarms, models and commands.</p><p>Market software turns forecasts and electricity into bids, schedules, contracts and prices.</p><p>Coordination software stands between them and compares the planned world with the real one until they agree, or at least disagree within limits that the grid can survive.</p><p>Regulation and standards cover all three. They define many of the roads, borders and languages through which these systems communicate.</p><p>This is still not Google Maps. It is closer to Herodotus, with incomplete coastlines and unknown territory beyond the edge. But now, when I meet a new protocol, algorithm or application at work, I at least understand on which part of the continent I have landed.</p><p>In the future I want to visit some of these places properly. I would like to rebuild substation communication, follow a signal from a relay to a control centre, reconstruct a market-clearing algorithm, and understand how one planned megawatt becomes an imbalance and finally money.</p><p>The next topics will probably be defined by the problems I face in my current position and by questions from people who read this series. That feels like the most honest way to continue the journey.</p><p>Stay tuned.</p><p>And may the Force be with you.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Rebuilt is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p><em>All parts of the series:</em></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;f29ac184-97d3-4dfa-9bca-7a8dacfb1a89&quot;,&quot;caption&quot;:&quot;I have spent a lot of time learning technical systems by rebuilding them from first principles.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;A Developer&#8217;s Map of the European Power Grid&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer who takes foundational technologies apart and rebuilds them. Follow to understand how complex systems work, why they are designed this way, and how to reason about them from first principles.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-05-12T15:14:05.930Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!r2v5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/a-developers-map-of-the-european&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:197363882,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div>]]></content:encoded></item><item><title><![CDATA[How Europe’s Power System Is Organised]]></title><description><![CDATA[The EU electricity sector is not one company moving electricity from power plants to consumers. It is a regulated system of different actors whose responsibilities overlap without becoming identical.]]></description><link>https://www.dmytrohuz.com/p/how-europes-power-system-is-organised</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/how-europes-power-system-is-organised</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Sat, 01 Aug 2026 19:35:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!EXqg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EXqg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EXqg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!EXqg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!EXqg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!EXqg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EXqg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2534044,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/209412144?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EXqg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!EXqg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!EXqg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!EXqg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Previous part:</em></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;b3cbd340-af74-4e9c-b5fa-ee76798a9c44&quot;,&quot;caption&quot;:&quot;Suppose you operate a web-service across three data centres. One region handles a large share of the traffic, and then it disappears.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;How the European Grid Stays Stable&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer who takes foundational technologies apart and rebuilds them. Follow to understand how complex systems work, why they are designed this way, and how to reason about them from first principles.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-07-20T07:02:23.698Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!z1Qz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/how-the-european-grid-stays-stable&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:207691626,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>I was new to the electricity sector as a software engineer. I came into the industry from web development.</p><p>The web was a pretty straightforward world. I usually knew for whom and why we developed a solution. Even when the software was highly technical, it was still clear who used it and who paid for it.</p><p>When I came into energy, everything was different.</p><p>Customers, users, regulators, and all possible three-letter abbreviations that meant companies, agencies, markets, services, and roles. It was hard to understand who actually bought the software. Who used it. Who paid for it. Who paid if something went wrong. Who defined how it should work. Who checked that it worked as it should.</p><p>And many... no. <strong>A LOT</strong> of other &#8220;who&#8221; and &#8220;why&#8221; questions.</p><p>Not knowing these answers might be acceptable in another industry. In energy, the structure of the sector shapes the architecture of the software. It defines requirements and explains why those requirements exist. A feature that looks strange from a purely technical perspective may be necessary because the customer must fulfil a legal, operational, market, security, or reporting obligation.</p><p>The person using the software may not be the person buying it. The company buying it may not be the organisation that defined the requirement. The asset owner may not be the system operator. The party that loses money when something fails may not be the party that approved the budget.</p><p>I am writing this article for colleagues who entered energy from other fields and are still trying to understand how the whole system fits together. By the end, you should have a clear mental model showing who owns the assets, who operates the power system, who buys and sells electricity, where the money comes from, and who defines the rules.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><h2>Regulation created the structure</h2><p>Laws, regulations, network codes, national rules, licences, and agreements define the main actors of the electricity sector and the way they interact. Therefore, regulation is not a separate layer added on top of an already existing market. It is one of the main forces that created the current structure.</p><p>The common EU framework is primarily established by the <a href="https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32019L0944">Electricity Directive, Directive (EU) 2019/944</a>, and the <a href="https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32019R0943">Electricity Regulation, Regulation (EU) 2019/943</a>. Together, they define common principles for generation, transmission, distribution, storage, supply, consumer participation, system operation, and electricity markets.</p><p>These documents are not implementation manuals for software engineers. They define something more fundamental: the environment in which energy companies, grid operators, markets, and eventually our software must work.</p><h3>Why electricity is regulated so heavily</h3><p>Electricity is a commercial product, but the power system is also critical infrastructure.</p><p>Electricity cannot be handled like a normal product that is manufactured, placed in a warehouse, and delivered later. Production and consumption must remain balanced continuously, while thousands of producers and millions of consumers use the same interconnected physical system.</p><p>The network itself also behaves differently from an ordinary competitive business. Building several competing transmission grids between the same regions would be enormously expensive and technically unnecessary. The same is generally true for local distribution networks. It would make little sense for several companies to dig up the same street and install parallel cables so that every household could choose its preferred physical grid.</p><p>Transmission and distribution networks are therefore treated as regulated monopolies. Competition is introduced where it is practical, particularly in generation, trading, and supply, while access to the physical networks is regulated.</p><p>This gives us the first part of the mental model:</p><blockquote><p><strong>Generation, trading, and supply can be competitive. Transmission and distribution are regulated network activities.</strong></p></blockquote><p>Because users cannot realistically choose another physical network, system operators cannot freely set any price or access condition they want. Their tariffs, investments, service obligations, and treatment of network users are supervised by regulators.</p><h3>Why one company does not simply do everything</h3><p>Historically, electricity systems were often organised around vertically integrated utilities. One company could generate electricity, own and operate the network, and sell electricity to consumers.</p><p>From a technical perspective, that structure looks convenient. One organisation owns the chain and coordinates it internally.</p><p>From a market perspective, it creates a conflict of interest.</p><p>Imagine a company that owns the transmission network and also owns power plants. Competing generators need access to the same network. The network owner could favour its own generation business by delaying connections, restricting access, using commercially sensitive information, or applying different conditions to competitors.</p><p>The EU response was <strong>unbundling</strong>, which separates network operation from potentially conflicting interests in generation and supply. The European Commission describes unbundling as one of the main pillars of the internal energy market because network operators must act independently and provide non-discriminatory access to infrastructure. The <a href="https://energy.ec.europa.eu/topics/markets-and-consumers/governance-internal-energy-market_en">Commission&#8217;s overview of internal energy market governance</a> explains the three main transmission unbundling models:</p><ul><li><p><strong>Ownership unbundling</strong>, where network ownership and operation are separated from generation and supply interests.</p></li><li><p><strong>Independent system operator</strong>, or ISO, where the integrated company may retain formal ownership of the network, but an independent organisation operates, maintains, and develops it.</p></li><li><p><strong>Independent transmission operator</strong>, or ITO, where the network remains inside an integrated group but is operated through an independent subsidiary under detailed rules.</p></li></ul><p>Distribution unbundling is less absolute. A distribution system operator that belongs to a vertically integrated group must generally be independent in its legal form, organisation, and decision-making, but EU law does not automatically require separate ownership of its assets. The directive also allows Member States to exempt some smaller integrated undertakings from parts of these requirements. The details are set out in <a href="https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32019L0944">Article 35 of the Electricity Directive</a>.</p><p>The accurate conclusion is therefore not that a company can never participate in more than one part of the sector. The conclusion is that network operation must be sufficiently independent from competitive interests so that access remains fair.</p><p>Once this principle is introduced, the sector separates into several roles:</p><ul><li><p>generators produce electricity;</p></li><li><p>transmission system operators operate high-voltage transmission systems;</p></li><li><p>distribution system operators operate regional and local networks;</p></li><li><p>suppliers sell electricity contracts to consumers;</p></li><li><p>traders buy and sell electricity and related products;</p></li><li><p>market operators organise trading;</p></li><li><p>regulators supervise network and market activities.</p></li></ul><p>These roles are not merely names invented by companies. They are part of the regulated design of the sector.</p><h3>Who creates and enforces the rules</h3><p>The regulatory chain begins at EU level, but not every rule comes from the same organisation.</p><p>The European Commission proposes legislation and develops energy policy. The European Parliament and the Council adopt EU legislation. Regulations apply directly, while directives define results that Member States must implement through national law.</p><p>The main legislation is supported by more detailed network codes and guidelines. These rules cover grid connection, system operation, emergency procedures, capacity allocation, congestion management, forward markets, day-ahead and intraday trading, and electricity balancing. ACER provides a useful <a href="https://www.acer.europa.eu/electricity/market-rules">overview of the binding European electricity market rules</a>.</p><p>At national level, independent regulatory authorities supervise the market and regulated network businesses. Their responsibilities vary between countries, but they commonly include approving or reviewing network tariff methodologies, certifying system operators, supervising unbundling, monitoring competition, protecting consumers, and enforcing national and EU rules. In Austria, this role is performed by <a href="https://www.e-control.at/">E-Control</a>.</p><p>At European level, the <a href="https://www.acer.europa.eu/the-agency/about-acer">European Union Agency for the Cooperation of Energy Regulators, or ACER</a>, coordinates national regulators and acts where cooperation across borders is required. ACER contributes to common methodologies, monitors markets, and takes certain decisions when national regulators cannot reach agreement.</p><p>ENTSO-E and the DSO Entity have different roles. <a href="https://www.entsoe.eu/">ENTSO-E</a> coordinates transmission system operators and contributes technical expertise, common methodologies, planning, data publication, and operational cooperation. The <a href="https://eudsoentity.eu/">DSO Entity</a> performs a corresponding European coordination role for distribution system operators. Neither organisation is an independent public regulator.</p><p>Technical standards add another layer. Standards from organisations such as IEC, CENELEC, ETSI, and ISO may define communication protocols, security controls, equipment behaviour, interoperability, testing, and lifecycle requirements. A standard is not automatically a law, but it may become mandatory through regulation, a grid code, a licence, a contract, or a procurement specification.</p><p>The simplified chain looks like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hpa5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd61e5ab4-fd4d-445d-bb17-3a71985eb0c1_1024x1536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hpa5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd61e5ab4-fd4d-445d-bb17-3a71985eb0c1_1024x1536.png 424w, https://substackcdn.com/image/fetch/$s_!hpa5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd61e5ab4-fd4d-445d-bb17-3a71985eb0c1_1024x1536.png 848w, https://substackcdn.com/image/fetch/$s_!hpa5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd61e5ab4-fd4d-445d-bb17-3a71985eb0c1_1024x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!hpa5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd61e5ab4-fd4d-445d-bb17-3a71985eb0c1_1024x1536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hpa5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd61e5ab4-fd4d-445d-bb17-3a71985eb0c1_1024x1536.png" width="1024" height="1536" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d61e5ab4-fd4d-445d-bb17-3a71985eb0c1_1024x1536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1536,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1767034,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/209412144?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd61e5ab4-fd4d-445d-bb17-3a71985eb0c1_1024x1536.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hpa5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd61e5ab4-fd4d-445d-bb17-3a71985eb0c1_1024x1536.png 424w, https://substackcdn.com/image/fetch/$s_!hpa5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd61e5ab4-fd4d-445d-bb17-3a71985eb0c1_1024x1536.png 848w, https://substackcdn.com/image/fetch/$s_!hpa5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd61e5ab4-fd4d-445d-bb17-3a71985eb0c1_1024x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!hpa5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd61e5ab4-fd4d-445d-bb17-3a71985eb0c1_1024x1536.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 1: A software requirement can travel a long way before it reaches a development team.</em></p><p>This explains why a small validation rule in Jira may originate from an EU regulation, be interpreted by a national regulator, translated into a process by a system operator, and finally become a requirement for a software vendor.</p><h2>Who owns the assets of the power system?</h2><p>There is no single European company that owns everything between a power plant and a wall socket. The power system consists of assets owned by generators, transmission companies, distribution companies, governments, municipalities, investment funds, industrial companies, cooperatives, and private households.</p><p>It helps to separate the physical system into four groups.</p><h3>Generation assets</h3><p>Generation assets convert another form of energy into electrical energy. They include nuclear, gas, coal, hydro, wind, solar, biomass, and other power plants.</p><p>Their ownership can be private, public, municipal, cooperative, or mixed. A large utility may own dozens of plants. An industrial company may own generation for its factory. A household may own rooftop solar panels.</p><p>Generation is generally a competitive activity. A generator earns revenue by selling energy and, depending on the technology and market, may also sell balancing capacity, balancing energy, ancillary services, certificates, or other products.</p><h3>Transmission assets</h3><p>The transmission grid transports large amounts of power over long distances at high voltage. It connects large generators, large consumers, distribution networks, and neighbouring transmission systems.</p><p>Transmission assets include lines, cables, substations, transformers, switchgear, protection systems, communication networks, and control centres. They are normally owned or controlled by certified transmission system operators (TSO), although the ownership structure differs by country and by unbundling model.</p><p>A TSO can be publicly owned, privately owned, publicly listed, or held through a mixed structure. The ownership model does not change the fundamental point: the company performs a regulated system function and must satisfy independence, access, operational, and certification requirements.</p><p>The <a href="https://www.entsoe.eu/data/map/">ENTSO-E transmission system map</a> gives a useful view of the major transmission infrastructure operated by European TSOs.</p><h3>Distribution assets</h3><p>Distribution networks connect most consumers and smaller generators to the power system. They contain regional substations, medium and low-voltage lines and cables, local transformers, switching equipment, meters, communication systems, and an increasing number of distributed resources.</p><p>Distribution system operators can be large national or regional companies, municipal utilities, private companies, public companies, or members of larger utility groups. Because distribution is a regulated monopoly, consumers usually cannot choose their DSO. Their physical location determines which network connects them.</p><p>They can, however, normally choose a supplier.</p><p>This distinction is fundamental:</p><blockquote><p><strong>The supplier manages the customer&#8217;s commercial electricity contract. The DSO operates the local network to which the customer is physically connected.</strong></p></blockquote><p>Changing supplier does not cause another company to install a second cable to the building. The commercial relationship changes, while the physical connection normally remains with the same DSO.</p><h3>Customer and industrial assets</h3><p>Not every electrical asset belongs to a generator or grid operator.</p><p>Factories, railway systems, data centres, mines, hospitals, airports, and large commercial sites may own substations, transformers, internal networks, generators, batteries, protection systems, and communication infrastructure. Households may own solar panels, batteries, heat pumps, and electric vehicle chargers.</p><p>This creates an important boundary between the public network and the customer installation. The grid operator defines connection conditions, but the customer owns and operates equipment on its side of the boundary. Protection, metering, remote control, data exchange, maintenance, and fault responsibilities must be clearly assigned.</p><p>Knowing who owns an asset is therefore only the beginning. We still need to ask who operates it, who controls it in real time, who defines its requirements, and who carries the consequences when it fails.</p><h2>Who operates the power system?</h2><p>Ownership answers who possesses the assets. Operation answers who is responsible for making the system work.</p><p>The word <em>operator</em> appears everywhere in the sector. A power plant has operators. A substation may be remotely operated from a control centre. A distribution network has a system operator. A transmission network has another system operator. A market also has an operator.</p><p>We therefore need to ask what exactly is being operated.</p><h3>Transmission system operators</h3><p>A transmission system operator, or TSO, is responsible for operating the transmission system and maintaining system security within its area of responsibility.</p><p>A TSO monitors the high-voltage network, coordinates outages, manages congestion, procures balancing services, plans network development, exchanges operational data with neighbouring TSOs, and prepares for emergencies and restoration. It is also responsible for maintaining the balance of the power system within the operational framework defined by European and national rules.</p><p>The unusual part is that a TSO is responsible for the behaviour of a system made mostly from assets owned by other organisations. It does not own every generator, industrial load, battery, wind farm, or distribution network connected to the system.</p><p>It operates through measurements, forecasts, schedules, market mechanisms, reserve procurement, control signals, grid topology, operating agreements, and emergency procedures.</p><h3>Distribution system operators</h3><p>A distribution system operator, or DSO, operates, maintains, and develops a regional or local distribution network.</p><p>A DSO connects consumers and distributed generators, manages planned and unplanned outages, restores supply after local faults, maintains voltage within permitted limits, provides connection information, and exchanges data with suppliers, generators, aggregators, consumers, and TSOs.</p><p>Historically, distribution systems were often treated as passive networks through which electricity flowed from the transmission grid toward consumers. That model is becoming less accurate as distribution networks contain more solar generation, batteries, electric vehicles, heat pumps, flexible industrial demand, and local energy communities.</p><p>A DSO therefore needs increasingly good observability, forecasting, automation, and coordination with the TSO.</p><h3>Synchronous areas and operational responsibility</h3><p>The European power system is physically interconnected, but operational responsibility still needs clear boundaries.</p><p>A <strong>synchronous area</strong> is a group of AC systems operating at the same nominal frequency and connected strongly enough that a significant imbalance affects frequency across the whole area. Europe contains several synchronous areas, with Continental Europe being the largest.</p><p>Inside a synchronous area, balancing and frequency-control responsibilities are divided into defined operational structures. The formal terminology includes load-frequency control blocks, load-frequency control areas, monitoring areas, and scheduling areas. These concepts are defined in the <a href="https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32017R1485">System Operation Guideline, Regulation (EU) 2017/1485</a>.</p><p>For an introductory mental model, the important point is simpler:</p><blockquote><p><strong>The interconnected system is divided into defined operational areas so that schedules, measurements, deviations, reserves, and responsibility can be assigned to specific TSOs or coordinated groups of TSOs.</strong></p></blockquote><p>This is why we should not treat a country, TSO territory, synchronous area, control area, and bidding zone as synonyms. Sometimes their borders align. Often they solve different problems and therefore do not.</p><h3>ENTSO-E and regional coordination</h3><p>National transmission systems cannot be operated in isolation because power flows, outages, market schedules, and security problems cross borders.</p><p><a href="https://www.entsoe.eu/about/inside-entsoe/members/">ENTSO-E brings together 40 member TSOs from 36 countries</a> to support coordinated operation, market integration, planning, common methodologies, data publication, and technical cooperation.</p><p>ENTSO-E is not a European super-TSO. It does not replace national TSOs and does not directly operate every substation. A TSO operates its transmission system. ENTSO-E coordinates the TSOs and fulfils tasks assigned to it by European legislation.</p><p>Regional coordination centres provide another layer of cooperation. They support TSOs with regional security analysis, capacity calculation, outage coordination, adequacy forecasting, and common grid models. The individual TSO remains responsible for its own system, while the regional centre provides calculations and a wider view that no national operator can produce alone. ENTSO-E describes these tasks in its <a href="https://www.entsoe.eu/regions/">overview of European power regions and regional coordination</a>.</p><h2><strong>Who buys, sells, and pays?</strong></h2><p>When I started researching how the electricity market works, I expected it to be the most straightforward topic in this whole series.</p><p>The result was the opposite, and it was much more exciting than I expected.</p><p>The market opened another dimension of the power system for me. Its structure is almost as complex as the physical layer. The physical and commercial layers intersect and depend on each other, but they mostly exist as two parallel worlds with their own actors, rules, states, and processes.</p><p>In the physical world, we have generators, consumers, transmission lines, voltage, frequency, and power flows.</p><p>In the commercial world, we have contracts, bids, schedules, market positions, prices, and financial settlement.</p><p>Understanding the difference between these worlds is the foundation for understanding the electricity market.</p><h3><strong>The market is not the physical grid</strong></h3><p>My first question was simple: how does an electricity producer sell electricity and deliver it to a buyer?</p><p>The confusing answer is that it does not deliver its own electricity directly to that buyer.</p><p>Electrons in the network do not carry labels. We cannot take a particular group of electrons produced by Power Plant A and route it through selected transmission lines to Factory B. The physical power flow is determined by the grid topology, electrical impedances, voltages, and phase angles, not by the commercial contract.</p><p>A generator injects power into the interconnected system. A consumer withdraws power from the same system. Commercially, they may have bought and sold electricity between them, but physically there is no dedicated connection carrying only the electricity from that seller to that buyer.</p><p>This creates two parallel views of the same delivery period.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!V-p-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e54f3fa-0f93-4dd2-9456-3cd99ca25f1d_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!V-p-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e54f3fa-0f93-4dd2-9456-3cd99ca25f1d_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!V-p-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e54f3fa-0f93-4dd2-9456-3cd99ca25f1d_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!V-p-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e54f3fa-0f93-4dd2-9456-3cd99ca25f1d_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!V-p-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e54f3fa-0f93-4dd2-9456-3cd99ca25f1d_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!V-p-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e54f3fa-0f93-4dd2-9456-3cd99ca25f1d_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5e54f3fa-0f93-4dd2-9456-3cd99ca25f1d_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1601919,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/209412144?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e54f3fa-0f93-4dd2-9456-3cd99ca25f1d_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!V-p-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e54f3fa-0f93-4dd2-9456-3cd99ca25f1d_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!V-p-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e54f3fa-0f93-4dd2-9456-3cd99ca25f1d_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!V-p-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e54f3fa-0f93-4dd2-9456-3cd99ca25f1d_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!V-p-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e54f3fa-0f93-4dd2-9456-3cd99ca25f1d_1536x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The market does not route electricity. It coordinates what participants promise to inject or withdraw and assigns financial responsibility when their actual behaviour differs from those promises.</p><h3><strong>Contracts create the commercial plan</strong></h3><p>A seller and a buyer agree on an amount of electrical energy for a particular delivery period and usually for a particular market area.</p><p>One participant promises to provide a commercial quantity. Another participant takes the corresponding commercial position.</p><p>Across the market, thousands of such trades create the expected commercial balance between production and consumption. Depending on the market and national rules, these positions are translated into schedules, nominations, and other information used by market participants and system operators.</p><p>However, the sum of all commercial positions does not guarantee that the physical grid will operate securely.</p><p>A market result may be commercially balanced while still creating too much power flow through a particular transmission corridor. A generator may fail after selling its expected production. Consumers may use more or less electricity than forecast. Wind and solar production may differ from predictions.</p><p>The TSO therefore uses market schedules together with forecasts, measurements, network models, equipment availability, and security analysis. Commercial planning tells the TSO what participants expect to do. Physical operation determines whether the system can actually support it.</p><h3><strong>Electricity is traded across different timeframes</strong></h3><p>Electricity is not traded through one single market.</p><p>Participants make decisions at different times because their information and risks change as delivery approaches. A supplier can estimate next year&#8217;s consumption, but tomorrow&#8217;s forecast will be more accurate. A wind producer knows more about expected generation a few hours before delivery than several months earlier.</p><p>The European wholesale market is therefore divided into several timeframes. ACER describes forward, day-ahead, intraday, and balancing as the main connected market stages. [^https://www.acer.europa.eu/electricity/market-rules/market-rules-different-electricity-market-timeframes]</p><h4><strong>Long-term and forward trading</strong></h4><p>Long-term contracts are made months or years before delivery.</p><p>They include bilateral contracts, power purchase agreements, forwards, futures, and other hedging instruments. Their main purpose is often not to predict every future megawatt-hour precisely, but to reduce exposure to future price changes.</p><p>A supplier may want predictable purchasing costs. A generator may need stable revenues to support an investment. A factory may want to protect itself from extreme electricity prices.</p><h4><strong>Day-ahead market</strong></h4><p>In the day-ahead market, participants buy and sell electricity for delivery during the following day.</p><p>They submit bids and offers for defined delivery periods. Market coupling combines these orders across bidding zones while accounting for the available cross-zonal transmission capacity.</p><p>The day-ahead result becomes an important commercial baseline, but it is still based on forecasts.</p><h4><strong>Intraday market</strong></h4><p>After the day-ahead market closes, reality continues to develop.</p><p>Weather forecasts change. A generator becomes unavailable. Consumption expectations move. A battery operator changes its planned position.</p><p>The intraday market allows participants to adjust their positions closer to physical delivery. This helps them reduce the difference between what they previously traded and what they now expect to produce or consume. European intraday trading continues close to real time, subject to the applicable gate-closure rules. [^https://www.acer.europa.eu/news/acer-greenlights-30-minute-intraday-electricity-gate-closure-time-across-eu-borders]</p><h4><strong>Balancing market</strong></h4><p>Even after intraday trading, actual production and consumption will not exactly match the commercial positions.</p><p>The TSO must correct the remaining physical imbalance in real time. It does this by activating balancing resources that can increase or decrease their generation or consumption.</p><p>The balancing market is therefore different from the earlier markets. Forward, day-ahead, and intraday trading allow participants to build and correct their own commercial positions. Balancing allows TSOs to procure and activate the physical flexibility needed to maintain system frequency and avoid a wider failure when the final result still does not match. [<a href="https://www.acer.europa.eu/electricity/market-rules/market-rules-different-electricity-market-timeframes">https://www.acer.europa.eu/electricity/market-rules/market-rules-different-electricity-market-timeframes</a>]</p><h3><strong>Not every producer and consumer trades directly</strong></h3><p>It would be extremely difficult for every household, small generator, factory, and battery to buy and sell every delivery period independently.</p><p>The electricity market therefore contains actors that may not produce or consume electricity themselves but organise the commercial side of the system.</p><p>They aggregate customers, forecast consumption, access wholesale markets, manage schedules, trade changing positions, issue invoices, and carry financial responsibility.</p><h3><strong>Supplier</strong></h3><p>A supplier is the company that manages the commercial electricity relationship with the end customer.</p><p>For most households, this is the company that offers the tariff, signs the electricity contract, purchases energy for its customer portfolio, and sends the bill.</p><p>The supplier estimates how much electricity its customers will use and purchases corresponding quantities through contracts and markets. It also manages market access, forecasting, billing, customer service, and the financial consequences of differences between expected and actual consumption.</p><p>The supplier should not be confused with the DSO.</p><p><strong>The supplier manages the customer&#8217;s commercial electricity contract. The DSO operates the local network to which the customer is physically connected.</strong></p><p>Changing supplier normally changes who sells electricity to the customer. It does not change the physical cable or the local network operator.</p><h3><strong>What happens when the plan is wrong?</strong></h3><p>The grid must remain physically balanced, but no forecast is perfect.</p><p>A generator may produce less than planned because of a technical failure. A wind farm may produce more than forecast. Consumers may use more electricity than expected during a cold evening or less than expected during a holiday.</p><p>Suppose a supplier expects its customers to consume 50 MWh during one settlement period and purchases 50 MWh.</p><p>The customers actually consume 52 MWh.</p><p>Physically, the grid does not stop supplying them after the contracted 50 MWh has been consumed. The power system continues operating, and the TSO maintains the overall balance using the available physical response and balancing actions.</p><p>Commercially, however, somebody must be responsible for the missing 2 MWh and for the costs created by the deviation.</p><p>This is where the balance responsible party enters the picture.</p><h3><strong>Balance responsible party</strong></h3><p>A <strong>balance responsible party</strong>, or BRP, is a market role that accepts financial responsibility for the imbalance of a portfolio.</p><p>A BRP may manage a portfolio containing generators, suppliers, consumers, traders, storage systems, or aggregators. A company can become a BRP itself, or it can contract another BRP to carry its balance responsibility.</p><p>EU electricity-market rules require market participants either to be BRPs or to contractually delegate their balance responsibility to one, apart from limited exceptions. Each BRP is financially responsible for its imbalance and must strive to remain balanced or help the system remain balanced. [<a href="https://eur-lex.europa.eu/eli/reg/2019/943/oj/eng">https://eur-lex.europa.eu/eli/reg/2019/943/oj/eng</a>]</p><p>The BRP can be understood as the commercial boundary around a portfolio.</p><p>Inside that boundary, there may be many injections and withdrawals:</p><ul><li><p>power plants producing electricity;</p></li><li><p>suppliers serving consumers;</p></li><li><p>factories consuming electricity;</p></li><li><p>batteries charging and discharging;</p></li><li><p>traders buying and selling market positions.</p></li></ul><p>The BRP tries to make the portfolio&#8217;s total commercial position match its expected physical behaviour.</p><h3><strong>What does a BRP actually do?</strong></h3><p>A BRP does not simply wait until an imbalance happens and then pay the bill.</p><p>It actively manages the portfolio before delivery.</p><p>Its work can include:</p><ul><li><p>forecasting production and consumption;</p></li><li><p>collecting plans and availability information from portfolio members;</p></li><li><p>purchasing or selling electricity in long-term and day-ahead markets;</p></li><li><p>updating positions through intraday trading as forecasts change;</p></li><li><p>submitting schedules and position information required by market rules;</p></li><li><p>monitoring expected production and consumption;</p></li><li><p>reacting to plant failures or forecast changes;</p></li><li><p>receiving allocated metering data after delivery;</p></li><li><p>calculating or checking the portfolio&#8217;s imbalance;</p></li><li><p>settling the remaining imbalance with the connecting TSO.</p></li></ul><p>Before the applicable intraday gate closure, a BRP can change schedules and use the intraday market to reduce an expected shortage or surplus. After delivery, the TSO calculates the difference between the BRP&#8217;s final position and its allocated physical volume for each imbalance settlement period. That difference is settled using the applicable imbalance price. The precise procedures vary between countries and balancing arrangements. [<a href="https://eur-lex.europa.eu/eli/reg/2017/2195/oj/eng">https://eur-lex.europa.eu/eli/reg/2017/2195/oj/eng</a>]</p><p>Returning to our example, the supplier&#8217;s customers consumed 52 MWh while only 50 MWh had been purchased.</p><p>If the supplier belongs to a BRP portfolio, the shortage becomes part of the BRP&#8217;s total position. Other generators or consumers inside the same portfolio may partly offset it. If the portfolio still has a net shortage of 2 MWh, the remaining imbalance is settled between the BRP and the TSO.</p><p>The BRP therefore resembles an insurance provider only in a limited sense: it accepts responsibility for a risk that individual participants may not want to manage alone.</p><p>However, unlike normal insurance, it does not simply absorb the cost. It forecasts, trades, aggregates opposite deviations, charges its portfolio members, and manages the remaining financial exposure. Calling it a portfolio manager with balance responsibility is more accurate than calling it insurance.</p><p>For another practical explanation, the <a href="https://www.next-kraftwerke.be/knowledge-hub/balancing-responsible-party-brp">Next Kraftwerke overview of the BRP role</a> provides a useful industry perspective.</p><h3><strong>BRP and BSP are not the same thing</strong></h3><p>The abbreviations are similar, but the roles solve different problems.</p><p>A <strong>BRP</strong> carries financial responsibility for the difference between the commercial position and the allocated physical behaviour of its portfolio.</p><p>A <strong>balancing service provider</strong>, or BSP, provides physical flexibility that the TSO can activate. A BSP may operate a power plant, battery, industrial load, aggregated portfolio, or another controllable resource capable of changing its injection or withdrawal.</p><p>One company may perform both roles, but they remain separate responsibilities.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ihFi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F338c33b8-8c9e-4905-8d0b-2860aa4eeeff_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ihFi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F338c33b8-8c9e-4905-8d0b-2860aa4eeeff_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!ihFi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F338c33b8-8c9e-4905-8d0b-2860aa4eeeff_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!ihFi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F338c33b8-8c9e-4905-8d0b-2860aa4eeeff_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!ihFi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F338c33b8-8c9e-4905-8d0b-2860aa4eeeff_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ihFi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F338c33b8-8c9e-4905-8d0b-2860aa4eeeff_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/338c33b8-8c9e-4905-8d0b-2860aa4eeeff_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1390401,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/209412144?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F338c33b8-8c9e-4905-8d0b-2860aa4eeeff_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ihFi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F338c33b8-8c9e-4905-8d0b-2860aa4eeeff_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!ihFi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F338c33b8-8c9e-4905-8d0b-2860aa4eeeff_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!ihFi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F338c33b8-8c9e-4905-8d0b-2860aa4eeeff_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!ihFi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F338c33b8-8c9e-4905-8d0b-2860aa4eeeff_1536x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 2: The BRP manages the commercial deviation, while the BSP provides the physical response activated by the TSO.</em></p><p>Suppose a power plant unexpectedly disconnects.</p><p>Its BRP becomes exposed to the resulting commercial shortage. The BRP may have reduced that exposure through intraday trading before gate closure, or other assets in its portfolio may offset part of it.</p><p>At the same time, the TSO sees the physical power-system imbalance and activates balancing resources from BSPs.</p><p>The TSO solves the immediate physical problem.</p><p>The imbalance-settlement process assigns the commercial consequences.</p><p>This is where the two parallel worlds intersect.</p><p>The physical system cannot wait for contracts to be corrected. The TSO must keep it stable immediately. The commercial system then determines whose position differed from reality and who pays or receives money as a result.</p><p>That is the central purpose of the electricity market: not to route individual electrons from seller to buyer, but to coordinate planned injections and withdrawals, create prices, support efficient use of the network, and assign financial responsibility around one shared physical machine.</p><h2>Putting the layers together</h2><p>Consider a wind farm connected to a regional network and a factory consuming electricity elsewhere.</p><p>The <strong>physical flow</strong> begins with the wind farm injecting power into the interconnected system. The factory withdraws power through its local distribution network. The electricity reaching the factory is not a private stream routed from that particular wind farm.</p><p>The <strong>commercial flow</strong> is represented by contracts and market positions. The wind farm may sell through a trader or aggregator. A supplier buys electricity and sells a contract to the factory. A NEMO may operate the day-ahead or intraday market where part of the position is traded.</p><p>The <strong>operational flow</strong> is managed by system operators. The DSO operates the networks to which the wind farm and factory are connected. The TSO monitors the wider system, manages congestion, and procures balancing services. If wind production differs from the schedule, the physical system still has to remain balanced.</p><p>The <strong>financial-responsibility flow</strong> is assigned through balance responsibility. The relevant BRP carries the imbalance caused by the difference between scheduled and actual production or consumption. A BSP may provide balancing energy when activated by the TSO.</p><p>The <strong>regulatory flow</strong> begins with EU and national rules, continues through ACER and the national regulator, and becomes licences, tariffs, methodologies, grid codes, company processes, and technical requirements.</p><p>No single company owns or controls the complete process. The European electricity sector works through coordinated responsibility distributed among specialised actors.</p><h2>What this means for software engineers</h2><p>Once we understand the structure, many technical requirements stop looking arbitrary.</p><p>Suppose a team receives a requirement to record every control action with the user identity, timestamp, previous value, new value, source system, and reason for the change. From a narrow product perspective, this can look excessive.</p><p>However, the requirement may exist because several organisations share responsibility, an incident must be reconstructed, a regulator may require evidence, a control action can have safety consequences, or incorrect data can create financial liability.</p><p>The feature is not merely audit logging. It is the software representation of responsibility.</p><p>The same pattern appears in requirements for redundancy, strict time synchronisation, role-based access, configuration approval, long retention periods, traceable calculations, formal testing, standardised protocols, controlled updates, and operation during partial failures.</p><p>Some of these requirements come from physics. Some come from regulation. Most come from the interaction between technical reality and institutional responsibility.</p><p>When you begin work on an energy software system, ask eight questions:</p><ol><li><p><strong>Who owns the relevant asset?</strong></p></li><li><p><strong>Who operates the asset or process?</strong></p></li><li><p><strong>Who buys the software?</strong></p></li><li><p><strong>Who uses the software every day?</strong></p></li><li><p><strong>Who defined the requirement?</strong></p></li><li><p><strong>Who receives or relies on the data?</strong></p></li><li><p><strong>Who carries the operational and financial risk?</strong></p></li><li><p><strong>Who checks that the system complies with the rules?</strong></p></li></ol><p>The answers reveal the architecture around the architecture.</p><p>They explain why the system needs particular interfaces, security boundaries, access models, audit records, approval flows, availability targets, deployment procedures, and lifecycle guarantees.</p><h2>Conclusion</h2><p>When I entered the electricity sector, I tried to understand it as a simple chain. Someone produced electricity. Someone transported it. Someone sold it. Someone consumed it.</p><p>That picture was not completely wrong, but it was too small to be useful.</p><p>The sector is deliberately divided into specialised roles. Ownership, operation, commercial responsibility, and regulation are separate layers. A company may own an asset without operating the wider system. It may operate critical infrastructure while being privately owned. It may buy software whose requirements were defined by a regulator, a network code, or another operator.</p><p>Once these layers are separated, the collection of strange abbreviations starts to form a system.</p><p>More importantly, we can answer the questions that matter when building software:</p><p>Who is our customer? Who is our user? Who defined the requirement? Who pays for the system? Who carries the risk? And who will be responsible when something goes wrong?</p><p>These questions do not replace technical analysis. They tell us which technical problems actually matter.</p><p><em>All articles of the series:</em></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;925c57df-8cfc-48c0-9b3c-3b913aee0b78&quot;,&quot;caption&quot;:&quot;I have spent a lot of time learning technical systems by rebuilding them from first principles.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;A Developer&#8217;s Map of the European Power Grid&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer who takes foundational technologies apart and rebuilds them. Follow to understand how complex systems work, why they are designed this way, and how to reason about them from first principles.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-05-12T15:14:05.930Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!r2v5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/a-developers-map-of-the-european&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:197363882,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><h2>Primary sources</h2><ul><li><p><a href="https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32019L0944">Directive (EU) 2019/944 on common rules for the internal market for electricity</a></p></li><li><p><a href="https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32019R0943">Regulation (EU) 2019/943 on the internal market for electricity</a></p></li><li><p><a href="https://energy.ec.europa.eu/topics/markets-and-consumers/governance-internal-energy-market_en">European Commission: Governance of the internal energy market</a></p></li><li><p><a href="https://www.acer.europa.eu/electricity/market-rules">ACER: European electricity market rules</a></p></li><li><p><a href="https://www.acer.europa.eu/electricity/market-rules/market-rules-different-electricity-market-timeframes">ACER: Market rules for different electricity market timeframes</a></p></li><li><p><a href="https://www.acer.europa.eu/electricity/market-rules/electricity-balancing">ACER: Electricity balancing</a></p></li><li><p><a href="https://www.entsoe.eu/about/inside-entsoe/members/">ENTSO-E member companies</a></p></li><li><p><a href="https://www.entsoe.eu/regions/">ENTSO-E regional coordination</a></p></li><li><p><a href="https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32017R1485">Commission Regulation (EU) 2017/1485 establishing a guideline on electricity transmission system operation</a></p></li><li><p><a href="https://energy.ec.europa.eu/topics/markets-and-consumers/electricity-prices_en">European Commission: Electricity prices</a></p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Rebuilt is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[How the European Grid Stays Stable]]></title><description><![CDATA[Operations, monitoring, control and protection, Part 3 of A Developer&#8217;s Map of the European Power Grid]]></description><link>https://www.dmytrohuz.com/p/how-the-european-grid-stays-stable</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/how-the-european-grid-stays-stable</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Mon, 20 Jul 2026 07:02:23 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!z1Qz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!z1Qz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!z1Qz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!z1Qz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!z1Qz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!z1Qz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!z1Qz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2775367,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/207691626?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!z1Qz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!z1Qz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!z1Qz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!z1Qz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Previous part:</em></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;f198837e-1dec-4fd4-a233-8dd236313328&quot;,&quot;caption&quot;:&quot;Figure 1: The old picture says power flows through a pipe. The real grid is a synchronized graph that must stay balanced in real time.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;The Grid Is Not a Pipeline&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer who takes foundational technologies apart and rebuilds them. Follow to understand how complex systems work, why they are designed this way, and how to reason about them from first principles.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-05-29T15:42:22.475Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!h0bv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/the-grid-is-not-a-pipeline&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:199757049,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>Suppose you operate a web-service across three data centres. One region handles a large share of the traffic, and then it disappears.</p><p>Your monitoring detects failed health checks. The load balancer stops sending new requests to the failed region. Queues hold work that cannot be processed immediately. Clients retry some requests. Spare capacity in the remaining regions absorbs part of the load, autoscaling adds more instances, and operators receive alerts while the system settles into a degraded but usable state.</p><p>Software engineers know this story. We design distributed systems with observability, redundancy, failure detection, isolation, automated recovery and human escalation because components eventually fail.</p><p>Now replace the data centre with a 1,000 MW generator connected to the European power grid.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><p>The comparison still helps, but the failure is harder. Electricity cannot wait inside a queue until another generator is ready. Consumers continue withdrawing power at the same moment that generation disappears. The electrical state begins changing before a monitoring system has delivered the first alarm, and power redistributes through transmission lines according to physical laws rather than routes selected by an application.</p><p>The grid also has shared physical state. Frequency reflects the balance between active power generation and consumption. Voltage differs across the network and depends strongly on local reactive power and power flows. Current, equipment temperatures, rotor angles and line loading continue changing while software is still collecting measurements.</p><p>In <a href="https://www.dmytrohuz.com/p/electricity-is-not-water-a-better">Part 1, Electricity Is Not Water</a>, we built the physical model behind generators, transformers, AC and frequency. In <a href="https://www.dmytrohuz.com/p/the-grid-is-not-a-pipeline">Part 2, The Grid Is Not a Pipeline</a>, we assembled the network as a graph of substations, lines, generators, storage and loads. Now the machine is running, and we can ask how it stays alive when its state never stops changing.</p><p>In this post you will learn how protection, monitoring, operation and control work together, what SCADA contributes to that chain, which physical variables operators care about, and what happens from the first instant after a large generator disconnects until the grid reaches a new secure state.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XFzL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66015bd2-ff02-4a94-85e2-0383303110d4_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XFzL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66015bd2-ff02-4a94-85e2-0383303110d4_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!XFzL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66015bd2-ff02-4a94-85e2-0383303110d4_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!XFzL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66015bd2-ff02-4a94-85e2-0383303110d4_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!XFzL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66015bd2-ff02-4a94-85e2-0383303110d4_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XFzL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66015bd2-ff02-4a94-85e2-0383303110d4_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/66015bd2-ff02-4a94-85e2-0383303110d4_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1268227,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/207691626?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66015bd2-ff02-4a94-85e2-0383303110d4_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XFzL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66015bd2-ff02-4a94-85e2-0383303110d4_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!XFzL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66015bd2-ff02-4a94-85e2-0383303110d4_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!XFzL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66015bd2-ff02-4a94-85e2-0383303110d4_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!XFzL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66015bd2-ff02-4a94-85e2-0383303110d4_1672x941.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p><em>Figure 1: A software platform can queue and redirect work. A power-system disturbance begins changing the shared physical state immediately.</em></p><h2>A Distributed Physical System</h2><p>The grid behaves like a distributed system in the broad sense. It spans many locations, has no single machine that contains its complete state, depends on communication and coordination, and must continue operating when individual components become unavailable.</p><p>The difference is that its nodes are coupled by physics.</p><p>A web service can often tolerate short disagreement between replicas. Messages can arrive late, requests can wait, and a control plane can calculate a new routing decision before the data plane changes. The electrical grid has far less freedom. A breaker opening in one substation immediately changes the topology seen by the electrical system. Voltages and currents respond at electromagnetic speed, rotating machines accelerate or decelerate, and power flows settle into new paths throughout the connected network.</p><p>This makes grid stability a broader idea than keeping the lights on. The system must remain within several limits at the same time.</p><h3>Generation and load balance</h3><p>A <strong>load</strong> is anything withdrawing electrical power from the grid. It may be one motor, a railway, a steel plant, a house or the combined demand of an entire distribution network.</p><p>Generators&#8212;and storage systems when discharging&#8212;inject <strong>active power</strong>, measured in watts. Active power is the average rate at which electrical energy is transferred into net work or heat: it turns motors, warms heaters, moves pumps and powers computers.</p><p>Across a synchronous AC system, generation and other active-power injections must continuously match consumption and network losses. When consumption and losses require more active power than generators and other resources provide, energy is initially drawn from the rotating masses of connected machines and frequency falls. When injections exceed consumption and losses, those machines accelerate and frequency rises.</p><p>In Continental Europe the target is 50 Hz. Frequency is therefore both a controlled quantity and a system-wide symptom. It tells operators that the active-power balance has changed, although it does not by itself reveal where the cause is located.</p><h3>Voltage and reactive power</h3><p>Every connection point in the grid also has a <strong>voltage</strong>. Voltage can be thought of as the electrical potential that drives current and allows power to move, but operationally the key point is simpler: voltage must stay within an acceptable range at every important bus and connection point.</p><p>Frequency is broadly shared across a synchronous area. Voltage is local. A bus in western Austria, a substation near Vienna and an interconnector in Germany can all have different voltage magnitudes at the same moment.</p><p>AC equipment needs changing electric and magnetic fields. Part of the current repeatedly stores energy in those fields and returns it later in the AC cycle. The associated quantity is <strong>reactive power</strong>, measured in var. It does not produce net work over a complete cycle, but it still creates current, occupies network capacity and affects voltage.</p><p>When an area lacks reactive-power support, voltage tends to fall. When it has too much, voltage can rise. The relationship is not perfectly isolated, because active power, reactive power, current, voltage and network impedance affect each other. Still, the following first model is useful:</p><blockquote><p>Active power is closely connected to frequency, while reactive power is closely connected to voltage.</p></blockquote><h3>Power flow and transmission capacity</h3><p><strong>Power flow</strong> describes how active and reactive power move through the connected network. In software terms, the grid has a graph, but it has no router assigning each megawatt to a chosen path. Flows emerge from topology, line impedances, voltage magnitudes and phase angles.</p><p>If one transmission line opens, the power it carried does not wait for a new route. The electrical state changes and the flow redistributes over the lines that remain. A line far from the original event may receive much of the additional loading.</p><p>Each element has operational limits. A conductor can carry only so much current before heating becomes unacceptable. Transformers have thermal and equipment limits. Voltages must stay inside permitted ranges. The system also has stability limits that can become restrictive before a wire reaches its thermal rating.</p><p>This is what <strong>transmission capacity</strong> means operationally. It is not only a fixed number printed on a line specification. The usable capacity depends on the wider network state, including which elements are available, how power is injected and withdrawn, the weather, voltage conditions and what would happen if another component failed.</p><p>A grid can have enough total generation and still be unable to transport it safely to the loads that need it. This is why balancing generation and managing network congestion are related tasks, but they are not the same task.</p><h2>Protection, Operation and Control</h2><p>When I first tried to understand grid operations, these words blurred together. A relay trips a breaker, an operator opens another breaker, an automatic controller changes generator output, and SCADA displays all three events. It is easy to treat everything as one large control system.</p><p>The distinction becomes clearer when we ask what each area is trying to achieve.</p><h3>Protection detects and isolates danger</h3><p>A <strong>fault</strong> is an unintended electrical condition such as a short circuit, an insulation failure or an accidental connection between conductors and ground. Faults can create currents and voltages far outside normal operating values, damage expensive equipment and destabilise the surrounding network.</p><p>Protection systems exist to detect these conditions and isolate the affected equipment quickly.</p><p>A <strong>protection relay</strong> receives electrical measurements from instrument transformers or sensors. It applies configured logic to determine whether the measured condition indicates a fault or another dangerous state. Depending on the protected asset, the relay may compare currents entering and leaving a transformer, estimate the apparent distance to a fault on a line, watch for excessive current, or use measurements exchanged with a relay at the other end of the line.</p><p>When the relay decides that the equipment must be disconnected, it sends a trip signal to a <strong>circuit breaker</strong>. The breaker is the heavy electrical switch capable of interrupting normal load current and, within its rating, the much larger current produced by a fault.</p><p>The protected network is divided into <strong>protection zones</strong> around lines, transformers, busbars and generators. These zones usually overlap around breakers so that there is no unprotected gap. The design aims to remove the smallest practical part of the grid while still clearing the fault reliably. Backup protection covers cases where the primary relay, communication path or circuit breaker fails.</p><p>Protection is mainly local, automatic and fast. A line fault may need to be cleared within tens of milliseconds. The relay cannot wait for SCADA to send measurements to a control centre, for an operator to interpret an alarm and for a remote command to return. The trip path is designed to work without that sequence.</p><p>SCADA will report what happened. Operators will investigate and decide how to restore the network. Those steps matter, but they come after the immediate protection action.</p><h3>Operation builds and maintains a secure state</h3><p><strong>Operation</strong> is the continuous work of understanding the current grid, preparing it for expected conditions and responding when reality differs from the plan.</p><p>Dispatchers in control rooms track the network topology, planned outages, unavailable equipment, generator schedules, weather, load forecasts, active and reactive reserves, voltages and line loading. They coordinate switching, release equipment for maintenance, return it to service, communicate with generators and distribution operators, and exchange information with neighbouring transmission system operators.</p><p>Routine work occupies much of this domain. Taking a transformer out of service for maintenance changes the grid before any failure occurs. A dispatcher needs to know whether the remaining network can carry the expected power and whether it can still survive another credible outage.</p><p>This leads to <strong>contingency analysis</strong>, which repeatedly asks questions such as:</p><ul><li><p>What happens if this line trips?</p></li><li><p>What happens if the largest generator disconnects?</p></li><li><p>Will another transformer overload?</p></li><li><p>Will a bus voltage leave its permitted range?</p></li><li><p>Which remedial actions would still be available?</p></li></ul><p>The common <strong>N-1</strong> idea means that the system should normally tolerate the loss of one relevant component without leaving acceptable operating limits after the allowed corrective actions. The exact application is more detailed than that sentence, but the mental model is valuable: operators manage the present while continuously testing possible next states.</p><p>EU system-operation rules require TSOs to monitor active and reactive flows, voltages, frequency, reserves, generation and load in real time, and to perform recurring contingency analysis against operational security limits. They also require close-to-real-time analysis to use state estimation. The complete rules are in the <a href="https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A32017R1485">EU System Operation Guideline</a>.</p><h3>Control changes the state</h3><p><strong>Control</strong> is the set of actions that move the grid toward a desired operating state.</p><p>Some controls are built into equipment. A generator governor responds to frequency. An automatic voltage regulator changes excitation. A transformer tap changer adjusts its ratio. A capacitor controller switches a bank when voltage crosses a threshold.</p><p>Other controls are centralised. Automatic generation control sends changing active-power setpoints to participating resources. A control-room application can request a breaker operation. A dispatcher can instruct a power plant to change active or reactive output, order redispatch, or coordinate a topology change with another operator.</p><p>Operation and control therefore describe different parts of the same process. Operation provides the context, objectives and decisions. Control applies physical actions, either automatically or through commands initiated by operators. A protection relay also causes a physical action, but its purpose and logic are different: it removes danger immediately rather than optimising the wider operating state.</p><p>A useful software comparison is this:</p><ul><li><p>Protection resembles local safety logic with authority to shut down a dangerous component.</p></li><li><p>Monitoring provides observability.</p></li><li><p>Operation resembles the work of site reliability engineers who assess the complete service and choose a recovery strategy.</p></li><li><p>Control contains the automated loops and commands that change the running system.</p></li></ul><p>The comparison helps organise the responsibilities, although the grid remains coupled by physical laws throughout the whole process.</p><h2>How the Grid Becomes Visible</h2><p>A control room may have wall-sized diagrams and dozens of screens, but the operator still does not see the electrical system directly. The displayed grid is constructed from measurements, communication, equipment statuses and models.</p><p>The chain begins in the field.</p><h3>Measurements begin at the equipment</h3><p>Sensors and instrument transformers measure current and voltage. From these signals, devices calculate active power, reactive power, frequency and other electrical quantities. Breakers and disconnectors provide position indications. Transformers report tap positions, protection devices report trips, and equipment monitoring systems may provide temperatures, pressures and internal alarms.</p><p>A measurement always has context. A value needs a timestamp, a source, a unit and a quality indication. A current value from the wrong bay, a breaker state received late, or a voltage measurement marked good when its input circuit has failed can create a convincing but incorrect picture.</p><h3>Substation devices collect and process data</h3><p>Inside a substation, intelligent electronic devices, bay controllers, remote terminal units and substation automation systems collect measurements and statuses. Some values are processed locally. Some are stored as events. Some are forwarded to a remote control centre.</p><p>These devices may also receive commands. A control centre can request a breaker operation, change a setpoint or switch voltage-control equipment, subject to interlocks and operational procedures.</p><p>Protection lives close to this layer, but it should not be confused with telemetry. A protection relay can share measurements and event reports with the automation system while keeping its trip logic local and independent from the normal SCADA path.</p><h3>Communication networks transport telemetry and commands</h3><p>Substations and power plants are connected to control centres through operational communication networks. Depending on the system and its age, these links may use fibre, microwave, radio, leased communication services or other channels, often with redundant paths.</p><p>Protocols such as IEC 60870-5-104, IEC 61850, DNP3 and vendor-specific interfaces carry measurements, events, statuses and commands across different parts of the chain. The protocol tells us how information is represented and transported. It does not guarantee that the physical measurement is correct or that the model on the receiving side matches the real substation.</p><h3>SCADA provides the supervisory interface</h3><p><strong>SCADA</strong> stands for Supervisory Control and Data Acquisition. In a grid control centre, it collects telemetry from many remote sites, presents measurements and equipment states, manages alarms and events, stores trends, and provides authorised operators with remote-control functions.</p><p>The word <em>supervisory</em> matters. SCADA gives a central view and allows high-level control of dispersed assets. It does not replace local protection, and it does not independently understand every physical consequence of an action.</p><p>A SCADA screen may show a one-line diagram in which a breaker appears open, a line is coloured according to its loading and an alarm list reports a generator trip. Behind that screen sits a long chain of measurement circuits, field devices, communication links, protocol gateways, databases, application logic and configuration.</p><p>NIST&#8217;s <a href="https://csrc.nist.gov/pubs/sp/800/82/r3/final">Guide to Operational Technology Security</a> describes the same broad SCADA structure: field devices and RTUs or PLCs communicate through wide-area networks with control servers, operator interfaces, engineering workstations and historians in a control centre.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fqzI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c01cec7-ba2a-41a6-a3ad-e346edec2f4a_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fqzI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c01cec7-ba2a-41a6-a3ad-e346edec2f4a_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!fqzI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c01cec7-ba2a-41a6-a3ad-e346edec2f4a_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!fqzI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c01cec7-ba2a-41a6-a3ad-e346edec2f4a_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!fqzI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c01cec7-ba2a-41a6-a3ad-e346edec2f4a_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fqzI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c01cec7-ba2a-41a6-a3ad-e346edec2f4a_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6c01cec7-ba2a-41a6-a3ad-e346edec2f4a_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1216351,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/207691626?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c01cec7-ba2a-41a6-a3ad-e346edec2f4a_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fqzI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c01cec7-ba2a-41a6-a3ad-e346edec2f4a_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!fqzI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c01cec7-ba2a-41a6-a3ad-e346edec2f4a_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!fqzI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c01cec7-ba2a-41a6-a3ad-e346edec2f4a_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!fqzI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c01cec7-ba2a-41a6-a3ad-e346edec2f4a_1672x941.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p><em>Figure 2: Monitoring information travels toward the control centre, while protection can trip equipment locally without waiting for a remote decision.</em></p><h3>Why the screen can be wrong</h3><p>SCADA is often described as real time, but that does not mean every point reflects physical reality at the same instant.</p><p>Measurements are sampled and transmitted at different rates. Communication links can fail. A value can become stale. A breaker indication can disagree with the actual contact position. A substation may be in a temporary configuration that the central model does not yet represent. Sensors have errors, and some values are calculated rather than directly measured.</p><p>This creates an <strong>observability</strong> problem. Operators need enough trustworthy information to determine the state of the network, even when individual measurements are missing or inconsistent.</p><h3>State estimation reconstructs a coherent picture</h3><p><strong>State estimation</strong> combines telemetry with the electrical network model and the current topology. It checks whether measurements agree with each other, identifies likely bad data and estimates the bus voltages and phase angles that best explain the available information.</p><p>The resulting state is still an estimate. Its value comes from making the overall picture more coherent than a raw collection of telemetry points.</p><p>This estimated state becomes an input to other Energy Management System applications. Power-flow analysis calculates how power is moving through the network. Contingency analysis simulates possible outages. Security assessment identifies violations of operational limits. Forecasting tools compare the present with expected demand and generation.</p><p><strong>Automatic generation control</strong>, usually implemented within the European load-frequency control process, uses frequency and control-area interchange information to calculate the area imbalance and adjust participating resources. It does not replace the dispatcher. It performs a continuous control loop inside objectives and limits established by grid operation.</p><p>SCADA is therefore a central part of the picture, but it is only one layer. The control room needs telemetry, models, specialised applications, automatic controllers, procedures and experienced operators. Treating the SCADA screen as the grid itself would be like treating a monitoring dashboard as the production system.</p><h2>What the Grid Must Control</h2><p>Once the operator has a usable picture of the network, the next question is what can be changed.</p><p>There is no single control knob for stability. Different mechanisms influence different parts of the operating state, and changing one variable often affects several others.</p><h3>Frequency control and reserves</h3><p>When active-power generation and consumption stop matching, frequency begins to move. The response is organised in layers because no resource is simultaneously instantaneous, unlimited, cheap and available everywhere.</p><p>The first physical response comes from stored energy in rotating machines and, increasingly, fast controls in batteries and inverter-based resources. This slows the frequency movement but does not remove the underlying imbalance.</p><p>The first organised reserve layer in Continental Europe is <strong>Frequency Containment Reserve</strong>, or <strong>FCR</strong>. Participating generators, storage systems and loads monitor frequency locally and change active power automatically. A falling frequency causes upward response, which means more generation or less consumption. A rising frequency causes downward response.</p><p>FCR is shared across the synchronous area. Resources respond to the common frequency deviation regardless of which control area caused it. Its immediate purpose is containment: stop the deviation from growing and stabilise frequency.</p><p>A <strong>reserve</strong> is available upward or downward power held by a prequalified resource. The resource might be a hydro plant with headroom, a thermal unit operating below maximum output, a battery with charge available, a pumped-storage plant that can stop pumping, or an industrial load able to reduce consumption. Reserving capacity means keeping part of that flexibility unused during normal operation so it is available when needed.</p><p>Once the common response has contained the disturbance, the responsible control area must restore its own balance. <strong>Automatic Frequency Restoration Reserve</strong>, or <strong>aFRR</strong>, is activated by the load-frequency controller, often described more generally as automatic generation control. It adjusts selected resources so frequency and scheduled cross-border exchanges move back toward their targets.</p><p>If the imbalance is too large or lasts too long, <strong>manual Frequency Restoration Reserve</strong>, or <strong>mFRR</strong>, provides another layer. It replaces part of the automatic response and prevents aFRR from remaining occupied indefinitely.</p><p>As a concrete Austrian example, <a href="https://markt.apg.at/en/power-grid/balancing/">Austrian Power Grid&#8217;s balancing overview</a> describes FCR as an automatic response that must reach full activation within 30 seconds when the frequency deviation reaches 0.2 Hz. APG states that aFRR must activate within five minutes in the Austrian control area, while automatic and manual restoration reserves together must cover foreseeable balancing errors within 15 minutes. The exact products and rules belong to the European balancing framework and national implementation, but the sequence is the important part:</p><ol><li><p>Slow the frequency change.</p></li><li><p>Contain the deviation.</p></li><li><p>Restore the responsible control area.</p></li><li><p>Replace the used reserves and prepare for another event.</p></li></ol><h3>Voltage control and reactive power</h3><p>Frequency control works across the synchronous system. Voltage control is more local because voltage differs between buses and because transporting reactive power over long distances consumes current and network capacity.</p><p>Synchronous generators regulate voltage through their excitation systems. Increasing excitation allows a generator to supply more reactive power within its capability limits, while reducing excitation can make it absorb reactive power. Power-electronic converters can also provide controlled reactive current, although their capability depends on their design, current limits and active-power operating point.</p><p>Transformer <strong>tap changers</strong> adjust the turns ratio and therefore the voltage relationship between network levels. They are useful for maintaining a downstream voltage, but they do not create missing power. Under stressed conditions, repeatedly raising a distribution-side voltage can increase the demand seen by an already weak transmission system, which is why tap control may need to be coordinated or blocked during a voltage emergency.</p><p><strong>Capacitor banks</strong> supply reactive power and tend to support local voltage. <strong>Reactors</strong> absorb reactive power and help reduce excessive voltage, especially on lightly loaded high-voltage lines and cables. Devices such as STATCOMs and synchronous condensers provide dynamic reactive-power support when voltage needs to change quickly.</p><p>The EU System Operation Guideline treats voltage and reactive-power management as a direct operational responsibility. It lists </p><p>transformer tap changes, capacitor and reactor switching, power-electronic devices, generator reactive-power setpoints and coordinated actions with distribution operators among the available remedial actions.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!n_xL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F537a204d-6aca-4340-9ab5-aa035f8736da_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!n_xL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F537a204d-6aca-4340-9ab5-aa035f8736da_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!n_xL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F537a204d-6aca-4340-9ab5-aa035f8736da_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!n_xL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F537a204d-6aca-4340-9ab5-aa035f8736da_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!n_xL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F537a204d-6aca-4340-9ab5-aa035f8736da_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!n_xL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F537a204d-6aca-4340-9ab5-aa035f8736da_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/537a204d-6aca-4340-9ab5-aa035f8736da_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1269634,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/207691626?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F537a204d-6aca-4340-9ab5-aa035f8736da_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!n_xL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F537a204d-6aca-4340-9ab5-aa035f8736da_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!n_xL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F537a204d-6aca-4340-9ab5-aa035f8736da_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!n_xL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F537a204d-6aca-4340-9ab5-aa035f8736da_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!n_xL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F537a204d-6aca-4340-9ab5-aa035f8736da_1672x941.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p><em>Figure 3: Operators manage several coupled problems at once. Active power strongly affects frequency, reactive power strongly affects voltage, and topology determines how both move through the network.</em></p><h3>Power-flow control and redispatch</h3><p>Operators cannot assign a route to each unit of power, but they can change the conditions that determine the flows.</p><p>Opening or closing selected breakers changes the topology. Transformer taps and phase-shifting transformers influence voltage and the distribution of active power. HVDC links can use controlled setpoints. Generation and consumption can be changed at specific locations.</p><p>One of the main tools is <strong>redispatch</strong>. A generator in one location increases output while another decreases output, keeping the total generation approximately balanced but changing where power enters the network.</p><p>Suppose a northern generator is increasing the loading of a constrained north-to-south corridor, while another plant closer to the southern load has spare capacity. Reducing the northern plant and increasing the southern plant can relieve the corridor without changing the total amount of generation.</p><p>Redispatch shows why a megawatt is not operationally identical in every location. The energy amount may be the same, but the effect on line loading, losses, voltage and contingency margins depends on where it is injected.</p><h2>Normal Operation Is Already Active Work</h2><p>A control room is not a fire brigade waiting for the next alarm. Normal operation requires continuous preparation because the safe state for the next hour may differ from the safe state now.</p><p>Demand follows daily and seasonal patterns but never matches a forecast exactly. Wind and solar output change with the weather. Generators start, stop and change output. International exchanges follow schedules while actual physical flows respond to the complete interconnected network. Equipment enters and leaves service for inspection, repair and construction.</p><p>Operators prepare switching programs before planned work. They confirm which breakers and disconnectors must change position, how the equipment will be isolated, what interlocks and safety procedures apply, and what the resulting topology means for the rest of the network.</p><p>An outage that is harmless during low demand may be unacceptable during a winter evening. Two individually reasonable maintenance plans may conflict because taking both assets out at once would remove the system&#8217;s ability to survive a further failure. This is why outage coordination extends across substations, companies and national borders.</p><p>The operator also watches <strong>operational limits</strong>. These include line and transformer loading, bus voltages, generator active and reactive capability, reserve availability, short-circuit levels and stability constraints. Some limits are immediate. Others permit a short overload while corrective action is prepared.</p><p>When analysis shows that one additional failure would violate a limit, the grid may enter an alert state even though all customers are still supplied and frequency is close to 50 Hz. The system is operating, but the safety margin has become too small.</p><p>The response might be preventive redispatch, returning an out-of-service line, changing topology, adjusting reactive-power resources, restricting a planned transfer or postponing maintenance. Good operation often looks uneventful because the risky state was corrected before a second event exposed it.</p><p>Coordination matters because the electrical system ignores organisational borders. A remedial action in one country can change flows in another. A distribution operator may control generators and reactive-power resources that affect the transmission grid. A power plant may own the machine, while the transmission operator is responsible for the wider system state. The <a href="https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A32017R1485">EU System Operation Guideline</a> formalises much of this data exchange and operational coordination between TSOs, DSOs and significant grid users.</p><h2>A Large Generator Disconnects</h2><p>We now have enough vocabulary to follow the failure from the opening example.</p><p>Assume a large synchronous generator is supplying 1,000 MW of active power and a meaningful amount of reactive power. A problem inside the plant causes its protection system to trip the unit and open the generator circuit breaker.</p><p>The exact numbers in the following sequence depend on the system state, but the order of responsibilities is stable.</p><h3>The protection system disconnects the generator</h3><p>The first action belongs to plant or generator protection. A relay detects a condition that makes continued connection unsafe, then commands the relevant circuit breaker to open.</p><p>This action protects the generator and the nearby electrical system. It may happen before the transmission control room knows that anything is wrong.</p><p>The breaker changes the topology. Active-power injection falls by 1,000 MW. The generator&#8217;s reactive-power contribution disappears as well. From that instant, the network has a new physical state.</p><h3>Generation becomes lower than demand</h3><p>Consumers have not coordinated with the failed plant. Their motors, heaters, trains and computers continue drawing power.</p><p>Total active-power generation is now lower than total active-power demand. The missing 1,000 MW is not supplied by one designated replacement generator during the first instant. The difference is initially supplied mainly by kinetic energy stored in the rotating masses of connected machines, while fast converter-based resources may also begin responding.</p><p>The electrical torque on the remaining synchronous generators becomes slightly greater than the mechanical torque supplied by their turbines. Their rotors slow down together, and the system frequency begins to fall.</p><p>This response is physical. No operator has selected it, and no SCADA command has caused it.</p><h3>Local controls and FCR respond</h3><p>Generator governors and other frequency-sensitive controllers detect the frequency change locally. Resources providing FCR begin increasing active-power injection or reducing consumption.</p><p>A hydro unit may open its guide vanes. A thermal unit may increase turbine input within its available headroom. A battery may inject power quickly. A pumped-storage plant may reduce pumping load. A flexible industrial consumer may lower demand.</p><p>These resources are distributed across the synchronous area. They do not need to know which generator failed. Frequency provides the common signal.</p><p>The reserve response grows while frequency is still falling. Eventually the additional power matches the deficit closely enough to stop the decline. The lowest point reached is called the <strong>frequency nadir</strong>.</p><p>If the response is sufficient, frequency stabilises. It may remain below 50 Hz because containment has stopped the movement without yet restoring the original balance.</p><h3>Voltage and power flows change at the same time</h3><p>The failed generator may have supported the voltage near its connection point. Losing its reactive-power capability can cause local voltage to fall, even while the frequency event is visible across the whole synchronous area.</p><p>Nearby automatic voltage regulators respond within their limits. Capacitors, reactors, converter controls or transformer taps may also act, depending on the network and configured control modes.</p><p>At the same time, active power begins entering the affected region from other generators through the transmission network. Flows redistribute across many lines. A corridor that previously carried moderate power may become heavily loaded because the local generator is no longer serving nearby demand.</p><p>This is where the graph from Part 2 becomes operational. The missing injection changes conditions across the network, and the most stressed line may be far from the failed plant.</p><h3>Measurements and alarms reach the control centre</h3><p>The generator breaker status changes. Active and reactive output measurements drop. Frequency values move. Nearby line flows and bus voltages change. Plant systems and substations create time-stamped events and alarms.</p><p>IEDs and RTUs forward this information through the operational communication network. SCADA updates the one-line diagram and alarm list. The operator may see a generator trip alarm, changed line colours, a frequency deviation and several secondary alarms caused by the same event.</p><p>These messages arrive after the physical system has already responded. They are evidence of the new state, not the trigger for the initial system-wide reaction.</p><p>Alarm handling is also harder than reading one clear error message. One event can produce hundreds of signals, some arriving out of order because different devices and communication paths have different delays. Operators and software need to distinguish the initiating event from its consequences.</p><h3>State estimation and security analysis assess the new grid</h3><p>The control centre now needs to answer several questions:</p><ul><li><p>Was the generator the only element lost?</p></li><li><p>Are the received breaker states and measurements consistent?</p></li><li><p>Which lines and transformers are now more heavily loaded?</p></li><li><p>Has local voltage remained within its limits?</p></li><li><p>How much FCR and reactive-power capability is still available?</p></li><li><p>Can the grid survive the loss of another important component?</p></li></ul><p>State estimation combines the new telemetry and topology with the network model. Power-flow and contingency-analysis applications calculate the current loading and simulate further outages.</p><p>The result may show that the frequency event is contained while the network is still unsafe. Perhaps one transmission corridor is close to its thermal limit. Perhaps local voltage is low. Perhaps the largest remaining generator has become the next critical contingency.</p><p>This is why returning frequency toward 50 Hz is necessary but insufficient. The full operating state must be secure.</p><h3>aFRR and automatic generation control restore the area</h3><p>FCR support came from across the synchronous area. The control area where the imbalance occurred must now restore its own balance and release that shared support.</p><p>The load-frequency controller calculates the control error from frequency and scheduled interchange. Through automatic generation control, it sends changing setpoints to resources providing aFRR.</p><p>These resources gradually add active power until the control-area imbalance is corrected. As aFRR takes over, FCR returns toward its neutral position and becomes available for the next disturbance.</p><p>If the outage lasts or the required correction is too large, mFRR and other slower actions replace part of the automatic response.</p><h3>Operators create a new secure state</h3><p>The failed generator may remain unavailable for hours. Operators cannot treat the restored frequency as the end of the incident.</p><p>They may redispatch generation so replacement power comes from locations that do not overload the network. They may start another plant, change pumped-storage operation, adjust cross-border schedules, switch reactive-power equipment, request new voltage setpoints or change the network topology.</p><p>They also need to restore reserve margins. A battery that delivered immediate power may need to recharge. Hydro and thermal units providing aFRR need room to respond in both directions again. The system should be able to survive another credible failure rather than remain balanced only while nothing else goes wrong.</p><p>The final state may look different from the state before the trip. A different set of generators is running, power flows use different corridors, reserve allocations have changed and some equipment may remain disconnected.</p><p>Recovery therefore means reaching a secure operating state, not recreating the exact previous state.</p><h3>The same event on one timeline</h3><ul><li><p><strong>Milliseconds:</strong> Protection detects the plant condition and trips the breaker. <em>Local and automatic protection.</em></p></li><li><p><strong>First electrical instant:</strong> Power flows change and rotating machines release stored energy. <em>Physical response.</em></p></li><li><p><strong>First seconds:</strong> Frequency-sensitive controls and FCR increase power or reduce load. <em>Distributed automatic control.</em></p></li><li><p><strong>Seconds to minutes:</strong> Telemetry, events and alarms reach SCADA; state estimation reconstructs the network. <em>Monitoring and operational software.</em></p></li><li><p><strong>Minutes:</strong> aFRR and automatic generation control restore the control area. <em>Central automatic control.</em></p></li><li><p><strong>Minutes to tens of minutes:</strong> mFRR, redispatch, voltage actions and topology changes establish a secure state. <em>Automatic and operator-initiated control.</em></p></li><li><p><strong>Hours and beyond:</strong> Rescheduling, reserve replenishment, investigation and repair continue. <em>Operation and asset management.</em></p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uwE_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f7465b-effe-45c5-8f83-41552963940e_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uwE_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f7465b-effe-45c5-8f83-41552963940e_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!uwE_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f7465b-effe-45c5-8f83-41552963940e_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!uwE_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f7465b-effe-45c5-8f83-41552963940e_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!uwE_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f7465b-effe-45c5-8f83-41552963940e_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uwE_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f7465b-effe-45c5-8f83-41552963940e_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f0f7465b-effe-45c5-8f83-41552963940e_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1356976,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/207691626?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f7465b-effe-45c5-8f83-41552963940e_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uwE_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f7465b-effe-45c5-8f83-41552963940e_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!uwE_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f7465b-effe-45c5-8f83-41552963940e_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!uwE_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f7465b-effe-45c5-8f83-41552963940e_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!uwE_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f7465b-effe-45c5-8f83-41552963940e_1672x941.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p><em>Figure 4: A generator loss is handled by several overlapping layers. Physics and local automation contain the first moments, while central controls and operators rebuild a secure system.</em></p><h2>If the Normal Response Is Not Enough</h2><p>The scenario above ends well because the protection system isolates the plant cleanly, reserves are sufficient and the network has enough remaining capacity.</p><p>A larger event, several simultaneous outages or a weak initial state can exhaust those layers.</p><p>If frequency continues falling, automatic under-frequency schemes can disconnect blocks of load. Removing consumers is damaging, but it can rebalance an island or synchronous area before generators also disconnect and the entire system collapses.</p><p>If voltage keeps falling, operators and automatic schemes may use all available reactive-power support, block transformer tap changers, reduce voltage targets or disconnect demand. If power flows remain outside safe limits, equipment may be switched, generation may be redispatched, transfers may be reduced and, in an emergency, selected loads may be disconnected.</p><p>These measures are defined in system defence plans. The European framework for emergency and restoration operation is set out in <a href="https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A32017R2196">Regulation (EU) 2017/2196</a>.</p><p>Protection still has a difficult role. If an overloaded line trips, its flow redistributes over the remaining network. Another line may then exceed its limit and trip as well. Each relay may be correctly protecting its own asset while the sequence weakens the wider system.</p><p>This is the basic mechanism behind a cascading outage:</p><ol><li><p>One element disconnects.</p></li><li><p>Flows and voltages redistribute.</p></li><li><p>Another element exceeds its limits.</p></li><li><p>Protection disconnects it.</p></li><li><p>The remaining network receives even more stress.</p></li></ol><p>The grid may eventually split into electrical islands. Each island must immediately balance its own generation and load. An island with too little generation experiences falling frequency, while an island with too much generation experiences rising frequency.</p><p>Emergency controls attempt to stop the cascade, preserve stable islands and keep as much of the system supplied as possible.</p><h2>Different Disturbances Stress Different Layers</h2><p>The generator loss gives us a useful complete story, but it should not become a template for every event.</p><p>A <strong>transmission line fault</strong> begins with a short circuit or another abnormal electrical condition. Line protection detects the fault and opens breakers at one or both ends, often within a fraction of a second. Generation and demand may remain nearly balanced, so the initial frequency change can be small, while the main operational problem is redistributed power flow and reduced transmission margin.</p><p>A <strong>transformer outage</strong> can remove the connection between voltage levels or parts of a substation. The result may be a local supply problem, overloaded parallel transformers, changed short-circuit levels or a voltage issue rather than a large system-wide frequency event.</p><p>A sudden rise in <strong>reactive-power demand</strong>, perhaps from large motors or a heavily loaded region, can depress local voltage while total active-power generation still matches consumption. Frequency can remain close to 50 Hz while part of the network approaches voltage instability.</p><p>A <strong>regional separation</strong> creates the clearest example of the system&#8217;s coupled nature. Once tie lines open, the two sides no longer share one active-power balance. Each island follows its own imbalance and frequency trajectory.</p><p>Protection, monitoring, operation and control appear in every case, but their order and relative importance change with the physical disturbance.</p><h2>Where the Distributed-Systems Analogy Helps</h2><p>We can now return to the failed data centre.</p><p>Both systems need observability. Operators need trustworthy measurements, event histories, health information and models that explain what is connected and available.</p><p>Both need spare capacity. A service without compute headroom cannot absorb traffic from a failed region. A grid without active-power reserves, reactive capability or transmission margin cannot absorb an electrical outage safely.</p><p>Both use layered response. Local components handle some failures automatically, central systems coordinate wider recovery, and human operators intervene when the event crosses the assumptions built into automation.</p><p>Both can operate in a degraded state. A service may remain available with higher latency and reduced redundancy. A grid may restore frequency while running with tighter transmission margins and less reserve.</p><p>Both need to prepare for the next failure. Recovering the current workload is not enough if the platform has lost all remaining redundancy. Restoring generation-load balance is not enough if the grid can no longer survive another contingency.</p><p>These similarities make distributed systems a useful starting point for developers entering the energy industry.</p><h2>Where the Analogy Stops</h2><p>The limitations matter just as much.</p><p>Software work can often be queued. Electrical load continues interacting with the network at every instant.</p><p>Software traffic can be assigned to a region or route. AC power divides across the connected network according to impedance, voltage and phase angle.</p><p>Many software failures remain local until another component calls the failed service. An electrical disconnection changes the physical state of the wider network immediately.</p><p>A monitoring system in software may detect a problem before users notice it. In the grid, frequency, voltage and current may already be moving before the control centre receives the first event.</p><p>Software replicas can disagree temporarily while eventual consistency resolves the difference. The synchronous grid has shared physical variables that must remain inside narrow limits continuously.</p><p>Finally, grid control actions feed back into the same physical system being measured. Opening a breaker to remove an overload changes flows elsewhere. Raising a downstream voltage can increase demand on an upstream network. Increasing one generator can relieve frequency while worsening congestion.</p><p>This is why grid software cannot be designed only as ordinary enterprise software with stricter availability requirements. It participates in a control loop around a large physical machine.</p><h2>The Mental Model to Keep</h2><p>A developer does not need to become a protection engineer or a control-room dispatcher to understand where grid software fits. The following model is enough to organise the vocabulary:</p><ol><li><p><strong>Physics moves first.</strong> Changes in generation, load or topology immediately affect frequency, voltage, current and power flow.</p></li><li><p><strong>Protection removes immediate danger.</strong> Relays and circuit breakers isolate faults locally and quickly.</p></li><li><p><strong>Monitoring constructs visibility.</strong> Field measurements, substation devices, communications, SCADA and state estimation create an operational picture.</p></li><li><p><strong>Control changes the system.</strong> Governors, voltage regulators, reserves, automatic generation control, tap changers, reactive-power devices, redispatch and switching move the grid toward acceptable conditions.</p></li><li><p><strong>Operation chooses and coordinates the secure state.</strong> Dispatchers assess limits, contingencies, outages and available actions across organisational and national boundaries.</p></li></ol><p>None of these layers works alone. Protection can clear a fault but cannot replace lost generation. SCADA can show an overload but cannot decide which market and operational constraints matter. Reserves can restore active-power balance but cannot help if the replacement power has no safe transmission path. Operators cannot act effectively when measurements or models are wrong.</p><p>The European grid stays stable because these layers overlap across different timescales. Local physics and automation handle the first instant. Wide-area controls restore balance. Software helps operators understand the changing state. Human decisions rebuild enough margin for the next event.</p><p>In Part 1, we assembled the electromagnetic machine. In Part 2, we assembled the graph. Here, the graph became operational.</p><p>It is always changing, always measured and always being corrected. Stability is the result of that continuous work.</p><p><em>Next part:</em></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;40a8ff83-e551-4ea7-ae99-7eddcc23466c&quot;,&quot;caption&quot;:&quot;Previous part:&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;How Europe&#8217;s Power System Is Organised&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer who takes foundational technologies apart and rebuilds them. Follow to understand how complex systems work, why they are designed this way, and how to reason about them from first principles.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-08-01T19:35:39.907Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!EXqg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/how-europes-power-system-is-organised&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:209412144,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p><em>All parts of the series:</em></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;6807f644-f4a4-43df-9fbe-997dc5e355f7&quot;,&quot;caption&quot;:&quot;I have spent a lot of time learning technical systems by rebuilding them from first principles.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;A Developer&#8217;s Map of the European Power Grid&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer who takes foundational technologies apart and rebuilds them. Follow to understand how complex systems work, why they are designed this way, and how to reason about them from first principles.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-05-12T15:14:05.930Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!r2v5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/a-developers-map-of-the-european&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:197363882,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><h2>References</h2><ul><li><p><a href="https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A32017R1485">European Commission, Regulation (EU) 2017/1485 establishing a guideline on electricity transmission system operation</a></p></li><li><p><a href="https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A32017R2196">European Commission, Regulation (EU) 2017/2196 establishing a network code on electricity emergency and restoration</a></p></li><li><p><a href="https://markt.apg.at/en/power-grid/balancing/">Austrian Power Grid, Balancing and frequency reserves</a></p></li><li><p><a href="https://csrc.nist.gov/pubs/sp/800/82/r3/final">NIST SP 800-82 Rev. 3, Guide to Operational Technology Security</a></p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Rebuilt is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Adding Homemade TLS to a Homemade Web Server]]></title><description><![CDATA[I combined my self-written web server and my self-written TLS project. The surprising part was how little the HTTP layer needed to know.]]></description><link>https://www.dmytrohuz.com/p/adding-homemade-tls-to-a-homemade</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/adding-homemade-tls-to-a-homemade</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Sat, 04 Jul 2026 20:32:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!s2Hi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F272dd5c3-9c01-49fc-a311-175eec483b14_1672x941.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset=" 424w,  848w,  1272w,  1456w" sizes="100vw"><img src="" data-attrs="{&quot;src&quot;:&quot;&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;:null,&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="" srcset=" 424w,  848w,  1272w,  1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><figcaption class="image-caption"></figcaption><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!s2Hi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F272dd5c3-9c01-49fc-a311-175eec483b14_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!s2Hi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F272dd5c3-9c01-49fc-a311-175eec483b14_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!s2Hi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F272dd5c3-9c01-49fc-a311-175eec483b14_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!s2Hi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F272dd5c3-9c01-49fc-a311-175eec483b14_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!s2Hi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F272dd5c3-9c01-49fc-a311-175eec483b14_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!s2Hi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F272dd5c3-9c01-49fc-a311-175eec483b14_1672x941.png" width="1672" height="941" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/272dd5c3-9c01-49fc-a311-175eec483b14_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:941,&quot;width&quot;:1672,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:0,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;&quot;,&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="" srcset="https://substackcdn.com/image/fetch/$s_!s2Hi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F272dd5c3-9c01-49fc-a311-175eec483b14_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!s2Hi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F272dd5c3-9c01-49fc-a311-175eec483b14_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!s2Hi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F272dd5c3-9c01-49fc-a311-175eec483b14_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!s2Hi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F272dd5c3-9c01-49fc-a311-175eec483b14_1672x941.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><figcaption class="image-caption"></figcaption><figcaption class="image-caption"><strong>Original series:</strong> <a href="https://dev.to/dmytro_huz/building-your-own-web-server-part-1-theory-and-foundations-3kgo">Building Your Own Web Server</a> + <a href="https://www.dmytrohuz.com/p/rebuilding-tls-from-scratch-my-complete">Rebuilding TLS from Scratch</a></figcaption><p>This article connects two earlier series. In the web-server series, I rebuilt the HTTP side from raw sockets up to routing and file serving. In the TLS series, I rebuilt the secure-channel side: key exchange, certificates, key derivation, and encrypted records.</p><p>This piece is where the two meet: what has to change when a web server stops receiving plaintext HTTP bytes and starts receiving encrypted TCP bytes?</p><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?utm_source=email&r=&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?utm_source=email&r="><span>Subscribe</span></a></p><div><hr></div><figcaption class="image-caption">I expected adding TLS to my web server to change almost everything.</figcaption><p>It did not.</p><p>The HTTP parser stayed boring. The router stayed boring. The file-serving code stayed boring.</p><p>The real change happened one layer below HTTP.</p><p>I had two separate learning projects before this:</p><ul><li><p>a small web server built from scratch: sockets, HTTP parsing, <code>location</code> matching, file serving, and eventually a single-threaded event-loop server;</p></li><li><p>a small TLS-like secure channel built from scratch: ephemeral key exchange, certificate chains, server authentication, HKDF, AES-GCM records, and the difference between identity keys and session keys.</p></li></ul><p>Putting them together led to one question:</p><blockquote><p>What changes in the web server when the bytes coming from TCP are encrypted?</p></blockquote><p>The useful answer is smaller than I expected:</p><pre><code>TCP socket
   &#8595;
TLS handshake / record layer
   &#8595; decrypted plaintext bytes
HTTP parser / router / file serving
   &#8595; plaintext HTTP response
TLS record protection
   &#8595; encrypted bytes
TCP socket
</code></pre><p>That is the whole architecture of the companion project.</p><p>This is not production HTTPS. It does not implement the real TLS 1.3 wire format, and browsers will not connect to it with <code>https://localhost:8443</code>.</p><p>It is a learning project. The goal is to make the integration boundary visible.</p><p>Once that boundary becomes clear, HTTPS feels much less magical.</p><div><hr></div><h2>The plain web server had one assumption</h2><p>Before TLS, the web server had a simple mental model.</p><p>A client connects over TCP. The server reads bytes from the socket. Those bytes are HTTP bytes. The server appends them to a per-connection buffer, tries to parse an HTTP request, matches the path, reads a file, and writes an HTTP response.</p><p>The flow looked like this:</p><pre><code>accept TCP connection
   &#8595;
read bytes from socket
   &#8595;
append bytes to HTTP input buffer
   &#8595;
parse HTTP request
   &#8595;
match URL against location config
   &#8595;
read file from root
   &#8595;
write HTTP response
</code></pre><p>The buffer is important because TCP is a stream.</p><p>One <code>recv()</code> call can give you half a request. Or exactly one request. Or multiple requests joined together. The parser cannot assume that one socket read equals one HTTP request.</p><p>In my server, the parser consumes complete HTTP messages from a buffer. If the request is incomplete, the server waits for more bytes. If there are extra bytes after a complete request, they stay in the buffer for the next parse.</p><p>For plain HTTP, socket bytes and HTTP bytes are the same thing:</p><pre><code>context.http_input.append(data)
self._handle_http_messages(context)
</code></pre><p>That line works only because the bytes from the socket are already plaintext HTTP.</p><p>TLS breaks that assumption.</p><div><hr></div><h2>After TLS, socket bytes are no longer HTTP bytes</h2><p>Once TLS is added, the TCP socket no longer carries a readable HTTP request.</p><p>The client still wants to send this:</p><pre><code>GET / HTTP/1.1
Host: localhost
Connection: close
</code></pre><p>But that request is not placed directly on the wire.</p><p>It is wrapped inside TLS records. After the handshake, those records are encrypted and authenticated. The bytes arriving at the server socket are now protocol bytes for the TLS layer, not text for the HTTP parser.</p><p>That is the shift:</p><pre><code>plain listener:
TCP bytes are HTTP bytes

TLS listener:
TCP bytes are TLS records
TLS records decrypt into HTTP bytes
</code></pre><p>If the HTTP parser starts caring about certificates, keys, record sequence numbers, or AES-GCM tags, the abstraction has leaked.</p><p>The HTTP parser should parse HTTP.</p><p>The TLS layer should turn unsafe network bytes into authenticated plaintext bytes.</p><div><hr></div><h2>The integration point belongs below HTTP</h2><p>Production servers use the same high-level boundary.</p><p>NGINX does not ask the HTTP parser to understand encrypted TLS records. A TLS implementation such as OpenSSL handles the connection security first. After that, the HTTP processing layer receives plaintext HTTP bytes.</p><p>My project copies that architecture in a smaller educational form:</p><pre><code>Production-ish mental model:
TCP &#8594; OpenSSL/TLS state &#8594; plaintext HTTP &#8594; NGINX HTTP processing

This project:
TCP &#8594; ToyTLSServerConnection &#8594; plaintext HTTP &#8594; HTTPParser / route matcher
</code></pre><p>The analogy is architectural, not protocol-compatible.</p><p>The project uses a small TLS-like protocol so the moving pieces are possible to read in one sitting. The handshake messages are simplified. The record framing is simplified. Many real TLS 1.3 details are missing on purpose.</p><p>But the boundary is the point:</p><pre><code>socket bytes in
   &#8595;
connection layer decides whether they are plain HTTP or TLS records
   &#8595;
HTTP layer receives plaintext HTTP bytes either way
</code></pre><p>That boundary lets the same HTTP code serve both ports.</p><div><hr></div><h2>The config makes the boundary visible</h2><p>The server uses an NGINX-style config because that was part of the original web-server project.</p><p>A single server block can listen on a plain port and on a TLS port:</p><pre><code>http {
    server {
        listen 8080;
        listen 8443 ssl;
        server_name localhost;

        ssl_certificate certs/server_cert.pem;
        ssl_certificate_key certs/server_key.pem;
        ssl_certificate_chain certs/intermediate_cert.pem;

        location / {
            root html;
        }
    }
}
</code></pre><p><code>listen 8080;</code> creates a normal HTTP listener.</p><p><code>listen 8443 ssl;</code> creates a listener that attaches TLS state to every accepted connection.</p><p>Both listeners still share the same routing and file-serving code. The difference is what happens between <code>recv()</code> and <code>HTTPParser.parse_message(...)</code>.</p><p>That is the part I wanted the project to expose.</p><div><hr></div><h2>The blocking TLS demo had to become a state machine</h2><p>The original TLS demo was linear and blocking.</p><p>That is perfect for teaching the handshake:</p><pre><code>receive ClientHello
send ServerHello
send ServerAuth
receive encrypted request
send encrypted response
</code></pre><p>But the web server I wanted to integrate with was not a one-client-at-a-time demo. It was a selectors-based server.</p><p>One event loop handles listening sockets and client sockets. A slow client should not freeze the whole process. That means the TLS implementation cannot sit inside a function waiting for the next record to arrive.</p><p>So the TLS code had to become buffer-oriented.</p><p>Instead of blocking on the socket, the TLS connection exposes three operations:</p><pre><code>tls.feed_wire_data(socket_bytes)
pending = tls.pop_pending_wire_data()
plaintext = tls.read_plaintext()
</code></pre><p><code>feed_wire_data(...)</code> accepts whatever bytes TCP happened to deliver.</p><p><code>pop_pending_wire_data()</code> returns handshake bytes or encrypted application data that need to be sent back to the client.</p><p><code>read_plaintext()</code> returns decrypted HTTP bytes after the TLS layer has enough complete records to process.</p><p>The web server does not need to know whether TCP split a TLS record into three reads or merged several records together. The TLS record buffer owns that problem.</p><p>That small interface is the bridge between the two projects.</p><div><hr></div><h2>Plain and TLS reads now differ by one layer</h2><p>Here is the core read path in the integrated server.</p><p>For plain HTTP, the socket bytes go directly into the HTTP input buffer:</p><pre><code># Plain path: socket bytes are already HTTP bytes.
context.http_input.append(data)
self._handle_http_messages(context)
</code></pre><p>For the TLS listener, the same socket bytes first pass through the TLS connection state:</p><pre><code># TLS path: socket bytes are handshake/application records, not HTTP.
context.tls.feed_wire_data(data)
self._queue_output(context, context.tls.pop_pending_wire_data())

plaintext = context.tls.read_plaintext()
if plaintext:
    context.http_input.append(plaintext)
    self._handle_http_messages(context)
</code></pre><p>The HTTP handler never receives encrypted bytes. It receives plaintext after the TLS layer has done its job.</p><p>After that, request handling is the same:</p><pre><code>request, consumed = HTTPParser.parse_message(context.http_input.data)
context.http_input.reduce_data(consumed)
response, should_close = build_http_response(request, context.server_block, self.base_dir)
self._send_application_bytes(context, response)
</code></pre><p>The response path mirrors the read path.</p><p>The HTTP layer builds a normal plaintext HTTP response. If the connection is plain HTTP, those bytes are written directly to the socket. If the connection is TLS, the server wraps the response in an encrypted application record first.</p><pre><code>if context.tls is not None:
    wire = context.tls.protect_application_data(plaintext_response)
else:
    wire = plaintext_response
</code></pre><p>This is the part I like most about the final design.</p><p>The web server still feels like a web server.</p><p>TLS becomes a connection concern, not an HTTP concern.</p><div><hr></div><h2>What the toy TLS layer does</h2><p>The TLS-like layer in this project is intentionally small, but it keeps the important shape of the original TLS series.</p><p>The handshake starts with ephemeral X25519 keys.</p><p>The client sends a <code>ClientHello</code> containing its ephemeral public key. The server generates its own ephemeral key for this connection and sends back a <code>ServerHello</code>.</p><p>Then the server sends authentication material:</p><ul><li><p>the server certificate,</p></li><li><p>intermediate certificates,</p></li><li><p>a signature over the two ephemeral public keys.</p></li></ul><p>That signature is the simplified version of <code>CertificateVerify</code>. It proves that the peer presenting the certificate also controls the matching private key for this specific key exchange.</p><p>After that, both sides compute the same X25519 shared secret and derive directional AES-GCM keys through HKDF.</p><p>Directional keys matter. The client-to-server key protects client records. The server-to-client key protects server records.</p><pre><code>client_write_key: records sent by the client
server_write_key: records sent by the server
</code></pre><p>Application data records also carry sequence numbers into the authenticated encryption. That lets the receiver detect tampering and sequence mismatches.</p><p>Again, this is not real TLS 1.3. The real protocol has much more structure: transcript binding, alerts, Finished messages, SNI, ALPN, session resumption, real record headers, and many other details.</p><p>For learning the web-server boundary, the smaller version is enough:</p><pre><code>handshake creates keys
records protect HTTP bytes
HTTP parser sees only decrypted bytes
</code></pre><div><hr></div><h2>The useful lesson was not only cryptography</h2><p>I started the project thinking the interesting part would be TLS.</p><p>The cryptographic pieces do matter. It is useful to understand why ephemeral keys exist, why certificates are about identity rather than encryption, and why authenticated encryption needs sequence numbers.</p><p>But the integration lesson was more general.</p><p>When you add a lower-level protocol to an existing system, the hard part is often choosing the seam.</p><p>If the seam is wrong, everything above it starts learning details it should not know.</p><p>If the seam is right, most of the application code stays boring.</p><p>In this case, the seam is between TCP and HTTP.</p><p>The HTTP parser should not know about X25519. The route matcher should not know about certificates. The file-serving code should not care whether the client used the plain port or the TLS port.</p><p>Those parts operate on HTTP.</p><p>The connection layer is responsible for turning the outside world into HTTP bytes.</p><p>That pattern shows up in a lot of infrastructure code:</p><ul><li><p>network bytes become parsed messages,</p></li><li><p>encrypted records become plaintext streams,</p></li><li><p>unreliable external systems become retried operations,</p></li><li><p>hardware signals become typed events,</p></li><li><p>logs become structured facts.</p></li></ul><p>A design question I keep coming back to is:</p><blockquote><p>What should the next layer be allowed to assume?</p></blockquote><p>For this project, the HTTP layer is allowed to assume one thing:</p><pre><code>I receive plaintext HTTP bytes.
</code></pre><p>Everything below that belongs to the connection layer.</p><div><hr></div><h2>Why build this if it is not real HTTPS?</h2><p>A fair objection is: if the project is not browser-compatible, why build it?</p><p>For me, browser-compatible TLS is too large if the goal is to understand the integration boundary.</p><p>If I used OpenSSL directly, the project would be more practical, but the interesting internals would disappear behind a library call.</p><p>If I tried to implement full TLS 1.3, the project would become mostly about protocol correctness. That is valuable, but it would bury the web-server lesson under too much detail.</p><p>The educational middle ground is a TLS-like secure channel with the same high-level shape:</p><pre><code>handshake
certificate verification
key derivation
encrypted records
application data
</code></pre><p>Then I can integrate that channel into the web server as if it were a real TLS stack.</p><p>The result is small enough to read, but realistic enough to expose the architecture.</p><p>That is the kind of learning project I like: simplified around one specific question.</p><p>Here the question is:</p><blockquote><p>What does a web server need from TLS?</p></blockquote><p>My answer after building it:</p><blockquote><p>A secure byte stream that produces plaintext HTTP for the existing HTTP layer.</p></blockquote><div><hr></div><h2>How to run the companion project</h2><p>The repository is here:</p><p><a href="https://github.com/DmytroHuzz/tls_web_server">https://github.com/DmytroHuzz/tls_web_server</a></p><p>The visual walkthrough is here:</p><p><a href="https://dmytrohuzz.github.io/tls_web_server/">https://dmytrohuzz.github.io/tls_web_server/</a></p><p>From a fresh clone:</p><pre><code>python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install --upgrade pip
python3 -m pip install -e ".[dev]"
</code></pre><p>Then run the one-command demo:</p><pre><code>python3 scripts/demo.py
</code></pre><p>It starts the server in a background thread, sends one plain HTTP request, then sends one HTTP request through the self-written TLS-like layer.</p><p>Both paths should return:</p><pre><code>HTTP/1.1 200 OK
</code></pre><p>There are also separate <code>server_side.py</code> and <code>client_side.py</code> files if you want to see the workflow from each side, closer to the style of the original projects.</p><p>The tests cover the integration points that are easy to get wrong:</p><ul><li><p>fragmented TLS handshake records,</p></li><li><p>fragmented encrypted application records,</p></li><li><p>wrong DNS name certificate rejection,</p></li><li><p>tampered encrypted record rejection,</p></li><li><p>sequence-number mismatch rejection,</p></li><li><p>HTTP requests split across multiple encrypted TLS records,</p></li><li><p>the same web server serving plain HTTP and HTTP-over-self-written-TLS.</p></li></ul><div><hr></div><h2>The mental model I keep now</h2><p>Before building this, I would have described HTTPS as &#8220;HTTP with encryption.&#8221;</p><p>That is fine as a user-level description, but it is not precise enough when writing the server.</p><p>The server-side model that helped me is this:</p><pre><code>TCP gives bytes.
TLS turns encrypted bytes into authenticated plaintext bytes.
HTTP parses the plaintext bytes.
</code></pre><p>That sounds simple, but it changes where the code belongs.</p><p>You do not sprinkle TLS checks through the HTTP parser.</p><p>You do not make the route matcher aware of certificates.</p><p>You do not duplicate the file server for secure and insecure connections.</p><p>You put a protocol layer below HTTP and keep the rest of the server honest.</p><p>That is what I wanted from this project.</p><p>Not a production HTTPS server. Not a replacement for OpenSSL.</p><p>Just a clearer picture of where HTTPS belongs.</p><p>If you want to follow the full path from encrypted TCP bytes to a parsed HTTP request and back again, I put the code and visual walkthrough here:</p><ul><li><p>Companion repo: <a href="https://github.com/DmytroHuzz/tls_web_server">https://github.com/DmytroHuzz/tls_web_server</a></p></li><li><p>Visual walkthrough: <a href="https://dmytrohuzz.github.io/tls_web_server/">https://dmytrohuzz.github.io/tls_web_server</a></p></li></ul><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:null,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[The Grid Is Not a Pipeline]]></title><description><![CDATA[The European Power Grid for Software Developers, Part 2]]></description><link>https://www.dmytrohuz.com/p/the-grid-is-not-a-pipeline</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/the-grid-is-not-a-pipeline</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Fri, 29 May 2026 15:42:22 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!h0bv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!h0bv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!h0bv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!h0bv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!h0bv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!h0bv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!h0bv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:465371,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/199757049?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!h0bv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!h0bv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!h0bv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!h0bv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 1: The old picture says power flows through a pipe. The real grid is a synchronized graph that must stay balanced in real time.</em></p><p>In the first part, we killed one comfortable idea: electricity is not water.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;837d7012-f5ca-407b-9544-cc60f4ae81d8&quot;,&quot;caption&quot;:&quot;Most requirements in critical industries come from the physical world, and the power grid is no exception. Electricity has rules that cannot be negotiated with. Distance, geography, weather, forests, cities, mountains, sea cables, and even animals shape how the grid must be built and operated.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Electricity Is Not Water: A Better Mental Model for the Grid&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software Engineer in the Energy Sector. AWS Community Builder (Dev Tools). (Re)building core tech in public &#8212; so it stop feeling like magic. Writing at Rebuilt.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-05-15T15:10:24.614Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!sq_V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/electricity-is-not-water-a-better&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:197871484,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:3,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>Now we can kill the next one.</p><p>The power grid is often imagined as a large water system. Somewhere far away there is a power plant, like a pump. Long power lines carry electricity, like pipes. The wires reach a city, then a street, then a house, and when someone opens the &#8220;tap&#8221; by switching on a device, electricity flows from the power plant into the socket.</p><p>It is simple. It is visual. It feels intuitive.</p><p>And it is almost the worst possible picture if you want to understand the real grid.</p><p>The grid is not a pipe where energy sits inside wires waiting to be consumed by devices. A power plant does not fill transmission lines with electrons and send them to your laptop, fridge, or washing machine. The real grid is a synchronized electromagnetic system. It works in real time. It oscillates. It has a frequency. It connects generators, consumers, transformers, substations, transmission lines, distribution grids, storage systems, and control centers into one huge machine.</p><p>And this machine has one brutal rule: generation and consumption must stay balanced all the time.</p><p>Consumers constantly change their behavior. Someone starts an industrial motor. A train accelerates. A factory begins a shift. A city wakes up in the morning. A cloud moves over a solar park. Wind generation rises or drops. A power plant ramps up, ramps down, or disconnects. Nothing is static, and still the whole system must remain synchronized.</p><p>In continental Europe, this synchronization is visible through the 50 Hz grid frequency. APG describes grid frequency as the measure of balance between electricity supply and demand, and one of its core tasks is to keep the system close to 50 Hz continuously. Austrian Power Grid</p><p>So no, the grid is not a pipe.</p><p>It is closer to a living technical machine whose operating state changes all the time. It is measured, switched, protected, transformed, corrected, and balanced continuously. Not because engineers enjoy complexity, but because the system would not work otherwise.</p><p>In this post we will discuss a better model for understanding the grid. We will stop looking at the fake &#8220;power plant to socket&#8221; diagram and rebuild the picture from the center outward. We will start with the high-voltage transmission grid, then attach substations, generators, storage systems, distribution grids, and consumers around it. After that, we will inspect a real slice of the Austrian grid and see how these abstract ideas appear in real infrastructure.</p><p>Because once we stop seeing the grid as a pipe, we can finally start seeing it as a graph.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Rebuilt! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>The old diagram is already misleading</h2><p>Most explanations of the grid start with a power plant.</p><p>The diagram usually looks like this:</p><p>Power plant. Transmission line. Substation. Distribution line. House. Socket.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1fsH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff910e9f3-3f52-4da1-bf49-d28d9934d974_1536x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1fsH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff910e9f3-3f52-4da1-bf49-d28d9934d974_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!1fsH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff910e9f3-3f52-4da1-bf49-d28d9934d974_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!1fsH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff910e9f3-3f52-4da1-bf49-d28d9934d974_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!1fsH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff910e9f3-3f52-4da1-bf49-d28d9934d974_1536x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1fsH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff910e9f3-3f52-4da1-bf49-d28d9934d974_1536x1024.jpeg" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f910e9f3-3f52-4da1-bf49-d28d9934d974_1536x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:328114,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/199757049?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff910e9f3-3f52-4da1-bf49-d28d9934d974_1536x1024.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1fsH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff910e9f3-3f52-4da1-bf49-d28d9934d974_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!1fsH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff910e9f3-3f52-4da1-bf49-d28d9934d974_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!1fsH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff910e9f3-3f52-4da1-bf49-d28d9934d974_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!1fsH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff910e9f3-3f52-4da1-bf49-d28d9934d974_1536x1024.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 2: This picture is easy to understand, but it already teaches the wrong architecture.</em></p><p>At first sight, this seems reasonable because electricity is generated somewhere and consumed somewhere else. But the moment we draw the system this way, we accidentally teach the reader the wrong architecture.</p><p>We make it look like electricity has a source, a route, and a destination. We make it look like a delivery system. A factory produces a product, a road transports it, and a customer receives it.</p><p>But the electrical grid is not a delivery route.</p><p>A generator does not produce a private stream of electricity for one city. A house does not receive electrons that started their journey at one specific power plant. A transmission line is not a pipe with a fixed direction. The grid is a shared synchronized system. Generators inject power into this system. Consumers withdraw power from it. Storage can do both. Power flows change depending on the current physical state of the network.</p><p>That is why starting with a power plant is already dangerous. It keeps us inside the pipe model.</p><p>A better starting point is the network itself. Not the generator, not the socket, but the grid.</p><h2>The grid is a graph, not a chain</h2><p>For a software developer, the better mental model is not a pipe. It is a graph.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Bn4m!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f3e1c50-ec18-4aca-92fc-5b45e8cbb445_1536x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Bn4m!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f3e1c50-ec18-4aca-92fc-5b45e8cbb445_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Bn4m!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f3e1c50-ec18-4aca-92fc-5b45e8cbb445_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Bn4m!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f3e1c50-ec18-4aca-92fc-5b45e8cbb445_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Bn4m!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f3e1c50-ec18-4aca-92fc-5b45e8cbb445_1536x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Bn4m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f3e1c50-ec18-4aca-92fc-5b45e8cbb445_1536x1024.jpeg" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1f3e1c50-ec18-4aca-92fc-5b45e8cbb445_1536x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:457526,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/199757049?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f3e1c50-ec18-4aca-92fc-5b45e8cbb445_1536x1024.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Bn4m!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f3e1c50-ec18-4aca-92fc-5b45e8cbb445_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Bn4m!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f3e1c50-ec18-4aca-92fc-5b45e8cbb445_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Bn4m!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f3e1c50-ec18-4aca-92fc-5b45e8cbb445_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Bn4m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f3e1c50-ec18-4aca-92fc-5b45e8cbb445_1536x1024.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 3: A better model: high-voltage lines form the backbone, substations are nodes, and generation, storage, distribution, and consumers attach to the graph.</em></p><p>Transmission lines are edges. Substations are nodes. Generators, storage systems, distribution grids, industrial consumers, cities, and interconnectors are attached to this graph at different points.</p><p>But we need to be careful here, because this analogy can also become stupid if we push it too far.</p><p>The grid is not the internet. Power does not move like packets. There is no router that says, &#8220;send this megawatt through line A and this other megawatt through line B.&#8221; Power flows according to physics. It depends on voltage, impedance, phase angle, topology, and the current state of the synchronized system.</p><p>Still, the graph model is extremely useful because it breaks the one-way chain illusion.</p><p>In a chain, you start at one end and walk to the other end. In a graph, you first ask what is connected to what. That is exactly how we should look at the grid.</p><p>The high-voltage network is the backbone. Substations connect parts of the backbone to each other and to lower voltage levels. Generators inject power at some nodes. Consumers withdraw power through other nodes. Storage systems can either withdraw or inject, depending on the operating mode. Interconnectors connect countries and control areas. Protection systems watch the graph and disconnect faulty parts when something goes wrong.</p><p>This is already a much better picture.</p><p>The grid is not a road from a power plant to your socket. It is a synchronized graph whose state must be kept inside safe limits.</p><h2>Why we start with the high-voltage grid</h2><p>If we start with a house, the grid looks like a local supply problem.</p><p>If we start with a power plant, the grid looks like a delivery problem.</p><p>But if we start with the high-voltage grid, the architecture becomes visible.</p><p>The high-voltage grid is the strong skeleton of the system. It connects regions, countries, large generation sites, large consumption areas, and lower-voltage networks. In Austria, APG manages the transmission grid at 110 kV, 220 kV, and 380 kV. These voltage levels are used to transport electricity efficiently over long distances and to connect large parts of the country into one operating system. Austrian Power Grid</p><p>This is where the pipe analogy starts to completely fall apart.</p><p>A high-voltage line is not just a long cable from one plant to one city. It is part of a larger network. Depending on generation, consumption, outages, maintenance, weather, and market schedules, power flows can change. A line can carry more or less power. A region can import or export. A storage plant can consume power in pumping mode and produce power in turbine mode. The same physical infrastructure participates in many different operating situations.</p><p>At the European scale, this becomes even more obvious. ENTSO-E (<strong>European Network of Transmission System Operators for Electricity</strong>) provides a transmission system map showing power plants, converters, substations, and high-voltage cables and lines operated by European transmission system operators. The map is useful for seeing the scale and density of the interconnected transmission network, but it should not be read as exact geography because ENTSO-E notes that network elements are not placed at their precise geographic positions. ENTSO-E Transmission System Map</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TrdG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5102640e-09dd-450e-b5f5-7315b9ce2722_912x1072.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TrdG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5102640e-09dd-450e-b5f5-7315b9ce2722_912x1072.png 424w, https://substackcdn.com/image/fetch/$s_!TrdG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5102640e-09dd-450e-b5f5-7315b9ce2722_912x1072.png 848w, https://substackcdn.com/image/fetch/$s_!TrdG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5102640e-09dd-450e-b5f5-7315b9ce2722_912x1072.png 1272w, https://substackcdn.com/image/fetch/$s_!TrdG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5102640e-09dd-450e-b5f5-7315b9ce2722_912x1072.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TrdG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5102640e-09dd-450e-b5f5-7315b9ce2722_912x1072.png" width="912" height="1072" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5102640e-09dd-450e-b5f5-7315b9ce2722_912x1072.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1072,&quot;width&quot;:912,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:763357,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/199757049?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5102640e-09dd-450e-b5f5-7315b9ce2722_912x1072.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TrdG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5102640e-09dd-450e-b5f5-7315b9ce2722_912x1072.png 424w, https://substackcdn.com/image/fetch/$s_!TrdG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5102640e-09dd-450e-b5f5-7315b9ce2722_912x1072.png 848w, https://substackcdn.com/image/fetch/$s_!TrdG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5102640e-09dd-450e-b5f5-7315b9ce2722_912x1072.png 1272w, https://substackcdn.com/image/fetch/$s_!TrdG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5102640e-09dd-450e-b5f5-7315b9ce2722_912x1072.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 4: Even as a schematic, the European transmission system looks less like a pipe and more like a continental graph. Source: ENTSO-E.</em></p><p>That map is overwhelming, and that is exactly the point.</p><p>The European grid is not a simple line from source to load. It is a continental machine. So instead of trying to understand the whole map at once, we can zoom into one country and then into one real grid node.</p><p>Austria is a good place to do this because the APG grid gives us a concrete high-voltage backbone, and the Austrian grid does not stop at the border. It is part of the wider European synchronous system.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9GdN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24b8c950-51e0-4f0d-b5f0-e0892070c0b4_936x624.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9GdN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24b8c950-51e0-4f0d-b5f0-e0892070c0b4_936x624.png 424w, https://substackcdn.com/image/fetch/$s_!9GdN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24b8c950-51e0-4f0d-b5f0-e0892070c0b4_936x624.png 848w, https://substackcdn.com/image/fetch/$s_!9GdN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24b8c950-51e0-4f0d-b5f0-e0892070c0b4_936x624.png 1272w, https://substackcdn.com/image/fetch/$s_!9GdN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24b8c950-51e0-4f0d-b5f0-e0892070c0b4_936x624.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9GdN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24b8c950-51e0-4f0d-b5f0-e0892070c0b4_936x624.png" width="936" height="624" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/24b8c950-51e0-4f0d-b5f0-e0892070c0b4_936x624.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:624,&quot;width&quot;:936,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:100553,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/199757049?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24b8c950-51e0-4f0d-b5f0-e0892070c0b4_936x624.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9GdN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24b8c950-51e0-4f0d-b5f0-e0892070c0b4_936x624.png 424w, https://substackcdn.com/image/fetch/$s_!9GdN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24b8c950-51e0-4f0d-b5f0-e0892070c0b4_936x624.png 848w, https://substackcdn.com/image/fetch/$s_!9GdN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24b8c950-51e0-4f0d-b5f0-e0892070c0b4_936x624.png 1272w, https://substackcdn.com/image/fetch/$s_!9GdN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24b8c950-51e0-4f0d-b5f0-e0892070c0b4_936x624.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 5: Austria&#8217;s transmission grid gives us a real backbone to inspect, with 110 kV, 220 kV, and 380 kV layers connected through substations. Source: Austrian Power Grid.</em></p><h2>Substations are the nodes where the graph becomes real</h2><p>Once we think in graphs, substations become much more interesting.</p><p>A substation is not just &#8220;the place where voltage goes down.&#8221; That is the school version. It is not completely wrong, but it is far too small.</p><p>A substation is a grid node.</p><p>It is a place where lines meet, voltage levels connect, transformers change voltage, breakers can connect or disconnect parts of the system, measurements are collected, faults are detected, and operators can change the topology of the network.</p><p>In graph language, a substation is where the abstract edge-and-node model becomes physical.</p><p>A transmission line arrives. Another line leaves. A transformer connects the 380 kV grid to the 220 kV grid or the 110 kV grid. A distribution network may be supplied from there. A power plant may be connected nearby. A breaker can disconnect a faulty line. Protection systems can isolate a damaged part of the network before the fault spreads further.</p><p>That is why substations are not secondary details. They are one of the main reasons the grid can be operated at all.</p><p>But in this article, we will not yet open the substation and inspect every component. Busbars, bays, breakers, disconnectors, transformers, protection relays, SCADA, and IEC 61850 deserve their own article. For now, we need only one idea:</p><p>A substation is a controllable node of the grid graph.</p><h2>A real example: Pongau substation</h2><p>Now let us stop speaking only in abstractions.</p><p>APG&#8217;s (<strong>Austrian Power Grid</strong>) Pongau substation is a good real-world example because it shows how much can happen at one node of the grid. </p><p>Pongau is a region in the Austrian federal state of Salzburg, south of the city of Salzburg and close to the Alpine hydropower and pumped-storage area around Kaprun and Tauern. You do not need to know Austrian geography to follow the argument. The only important point is that this node sits between several relevant grid directions.</p><p>APG describes Pongau as a newly constructed 380/220/110/30 kV substation in St. Johann im Pongau, commissioned in the first quarter of 2025 as part of the Salzburg line. The substation includes 380 kV GIS switchgear, two 380/220 kV transformers that connect the 380 kV and 220 kV grids, and two 380/110 kV transformers that connect the 380 kV and 110 kV grids. Austrian Power Grid, Pongau Substation</p><p>Before looking at the substation structure, we should first place it on the map. If you do not know Austrian geography, &#8220;Pongau&#8221; is just a name. The important thing is that it sits in a region where several relevant directions meet: toward Salzburg, toward Kaprun and Tauern, toward Wei&#223;enbach, and toward the regional Salzburg grid.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!P3_H!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4446f6a6-da4e-4c20-bd61-e46185248ad8_1536x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!P3_H!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4446f6a6-da4e-4c20-bd61-e46185248ad8_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!P3_H!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4446f6a6-da4e-4c20-bd61-e46185248ad8_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!P3_H!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4446f6a6-da4e-4c20-bd61-e46185248ad8_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!P3_H!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4446f6a6-da4e-4c20-bd61-e46185248ad8_1536x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!P3_H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4446f6a6-da4e-4c20-bd61-e46185248ad8_1536x1024.jpeg" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4446f6a6-da4e-4c20-bd61-e46185248ad8_1536x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:224093,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/199757049?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4446f6a6-da4e-4c20-bd61-e46185248ad8_1536x1024.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!P3_H!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4446f6a6-da4e-4c20-bd61-e46185248ad8_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!P3_H!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4446f6a6-da4e-4c20-bd61-e46185248ad8_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!P3_H!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4446f6a6-da4e-4c20-bd61-e46185248ad8_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!P3_H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4446f6a6-da4e-4c20-bd61-e46185248ad8_1536x1024.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 6: Pongau on the Austrian transmission map. </em></p><p>Pongau is not just a transformer in a field. It is a grid node where different voltage levels, transmission directions, pumped-storage connections, and regional distribution meet.</p><p>This is not a transformer in a field.</p><p>At this one node, different voltage levels meet. A 380 kV system from the Salzburg line is integrated. A connection continues toward Kaprun and Tauern. The 220 kV side connects toward Wei&#223;enbach. The 110 kV side connects to Salzburg Netz and the regional distribution grid. The 30 kV level is local or auxiliary in this simplified view, not a major transmission corridor.</p><p>This is exactly why the graph model is useful.</p><p>If we tried to explain Pongau with the pipe analogy, we would ask the wrong question: where does the electricity come from, and where does it go?</p><p>But the better question is: what does this node connect?</p><p>It connects voltage levels. It connects transmission paths. It connects regional distribution. It connects pumped storage. It strengthens supply reliability. It becomes part of the high-voltage architecture that allows the Austrian grid to operate as a system rather than as isolated local supply islands.</p><p>A substation like Pongau is not a passive object on the way from generator to consumer. It is part of the architecture that makes the whole system usable.</p><h2>Generators do not &#8220;send electricity to houses&#8221;</h2><p>Now that we have the graph, we can attach generators to it.</p><p>A generator is any facility that injects electrical power into the grid. It can be a hydropower plant, a gas plant, a wind farm, a solar plant, a biomass plant, or another generation source.</p><p>But the important word is injects.</p><p>A generator does not choose one household and send energy to it. It pushes power into the synchronized system. That changes the state of the system, and the physical network determines how power flows.</p><p>This is why the simple sentence &#8220;this power plant supplies this city&#8221; is often misleading. It may be true in an administrative, regional, or approximate sense, but electrically the situation is more complex. A power plant is connected to a grid node. Consumers are connected to other grid nodes. The system balances the total injection and withdrawal through the whole network.</p><p>Not let&#8217;s look at Kaprun.</p><p>Kaprun is a small municipality in the Austrian Alps, in the federal state of Salzburg, but in the Austrian power system the name means much more than a tourist village near mountains and reservoirs. The Kaprun area is closely associated with hydropower and pumped-storage infrastructure. It sits near the Alpine water reservoirs and power plants that can turn stored water into electricity when the grid needs power, or consume electricity to pump water back uphill when storing energy makes sense.</p><p>That makes Kaprun perfect for this article. It shows why &#8220;generator&#8221; and &#8220;consumer&#8221; are not always fixed identities. VERBUND (<strong>Austria's leading electricity company and one of the largest producers of hydroelectricity in Europe</strong>) describes the Kaprun power plant group as a storage power plant system with turbine capacity and pumping capacity. Pumped storage is useful because it can generate electricity when water flows down through turbines, but it can also consume electricity when pumps move water back up into a higher reservoir. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8r6j!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76da3ef4-d795-4519-87a2-52326f5be37c_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8r6j!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76da3ef4-d795-4519-87a2-52326f5be37c_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!8r6j!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76da3ef4-d795-4519-87a2-52326f5be37c_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!8r6j!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76da3ef4-d795-4519-87a2-52326f5be37c_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!8r6j!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76da3ef4-d795-4519-87a2-52326f5be37c_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8r6j!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76da3ef4-d795-4519-87a2-52326f5be37c_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/76da3ef4-d795-4519-87a2-52326f5be37c_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1589869,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/199757049?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76da3ef4-d795-4519-87a2-52326f5be37c_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8r6j!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76da3ef4-d795-4519-87a2-52326f5be37c_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!8r6j!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76da3ef4-d795-4519-87a2-52326f5be37c_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!8r6j!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76da3ef4-d795-4519-87a2-52326f5be37c_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!8r6j!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76da3ef4-d795-4519-87a2-52326f5be37c_1536x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 8: Pumped storage breaks the simple category. It can inject power like a generator or withdraw power like a large consumer.</em></p><p>This destroys another simple category.</p><p>A pumped-storage plant can behave like a generator. And it can behave like a consumer.</p><p>When the system needs power, it can inject power. When there is excess generation or when storage is economically and operationally useful, it can withdraw power and store energy as water at a higher elevation.</p><p>So even the terms &#8220;generator&#8221; and &#8220;consumer&#8221; are not fixed identities forever. They are roles a component can play in the current operating state of the grid.</p><h2>Consumers are not the end of a pipe</h2><p>Consumers also become clearer in the graph model.</p><p>A house is a consumer. A factory is a consumer. A railway system is a consumer. A city is a huge collection of consumers. A distribution grid can look like one large withdrawal point from the perspective of the transmission grid.</p><p>Most individual consumers are not connected directly to the high-voltage transmission grid. They are connected through lower-voltage distribution networks. Those distribution networks are then connected to the transmission grid through substations and transformers.</p><p>So when we zoom out to the transmission level, we should not imagine millions of tiny sockets attached directly to the 380 kV grid. We should imagine large withdrawal areas connected through distribution networks.</p><p>This is another reason the pipe picture fails.</p><p>The grid is not one pipe that becomes smaller and smaller until it reaches your phone charger. It is a layered electrical system. The high-voltage grid forms the backbone. Substations connect it to regional and local networks. Distribution grids bring power closer to consumers. And at each level, voltage, protection, switching, measurement, and operation matter.</p><p>The closer we move to individual homes, the more radial the system often becomes. But the transmission grid itself is designed more like a meshed backbone because important regions should not depend on one fragile path.</p><h2>Redundancy: the graph should not break too easily</h2><p>In graph theory, a bridge is an edge whose removal disconnects part of the graph.</p><p>That idea is useful for thinking about the transmission grid.</p><p>A fragile grid would have critical lines where one failure separates a whole region from the rest of the system. A stronger grid gives important regions more than one way to stay connected. Real grids are not perfectly bridge-free everywhere, but redundancy is one of the key design goals of transmission infrastructure.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_BO8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36fa4aac-3582-4880-b378-00fc5714aad3_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_BO8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36fa4aac-3582-4880-b378-00fc5714aad3_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!_BO8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36fa4aac-3582-4880-b378-00fc5714aad3_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!_BO8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36fa4aac-3582-4880-b378-00fc5714aad3_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!_BO8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36fa4aac-3582-4880-b378-00fc5714aad3_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_BO8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36fa4aac-3582-4880-b378-00fc5714aad3_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/36fa4aac-3582-4880-b378-00fc5714aad3_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1565626,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/199757049?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36fa4aac-3582-4880-b378-00fc5714aad3_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_BO8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36fa4aac-3582-4880-b378-00fc5714aad3_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!_BO8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36fa4aac-3582-4880-b378-00fc5714aad3_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!_BO8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36fa4aac-3582-4880-b378-00fc5714aad3_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!_BO8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36fa4aac-3582-4880-b378-00fc5714aad3_1536x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Figure 9: In a fragile graph, one failed edge can disconnect a region. A stronger transmission grid creates alternative paths.</em></p><p>Austria gives a good example here. APG describes the 380 kV Salzburg line as part of Austria&#8217;s extra-high-voltage ring, and says the ring structure allows power to flow to customers from either direction. The Salzburg line closed a gap in the western part of that ring and entered full operation in April 2025. </p><p>The same idea appears in southern Austria. APG&#8217;s Carinthia power grid area project plans a 380 kV connection between Obersielach and Lienz to close the 380 kV grid in southern Austria. APG explains that the 380 kV ring creates a redundant connection because important substations can be supplied from two sides. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gjTl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dfb27e-5b75-4883-8b21-006d9b41c2a6_745x558.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gjTl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dfb27e-5b75-4883-8b21-006d9b41c2a6_745x558.png 424w, https://substackcdn.com/image/fetch/$s_!gjTl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dfb27e-5b75-4883-8b21-006d9b41c2a6_745x558.png 848w, https://substackcdn.com/image/fetch/$s_!gjTl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dfb27e-5b75-4883-8b21-006d9b41c2a6_745x558.png 1272w, https://substackcdn.com/image/fetch/$s_!gjTl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dfb27e-5b75-4883-8b21-006d9b41c2a6_745x558.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gjTl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dfb27e-5b75-4883-8b21-006d9b41c2a6_745x558.png" width="745" height="558" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e5dfb27e-5b75-4883-8b21-006d9b41c2a6_745x558.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:558,&quot;width&quot;:745,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:102321,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/199757049?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dfb27e-5b75-4883-8b21-006d9b41c2a6_745x558.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gjTl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dfb27e-5b75-4883-8b21-006d9b41c2a6_745x558.png 424w, https://substackcdn.com/image/fetch/$s_!gjTl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dfb27e-5b75-4883-8b21-006d9b41c2a6_745x558.png 848w, https://substackcdn.com/image/fetch/$s_!gjTl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dfb27e-5b75-4883-8b21-006d9b41c2a6_745x558.png 1272w, https://substackcdn.com/image/fetch/$s_!gjTl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dfb27e-5b75-4883-8b21-006d9b41c2a6_745x558.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This is the graph model becoming real engineering.</p><p>We build redundancy because real systems fail. Lines are taken out for maintenance. Weather damages infrastructure. Equipment trips. Loads change. Generation patterns shift. If the grid were a simple tree, every important edge would become a potential disaster.</p><p>A meshed high-voltage grid gives operators more room to keep the system alive.</p><p>Again, we should not confuse this with the internet. The grid does not reroute power like packets. But topology matters. Connectivity matters. Alternative paths matter. A ring is not just a geometric shape. It is a way to reduce dependence on a single corridor.</p><h2>So what is the grid?</h2><p>At this point, we can rebuild the picture.</p><p>The grid is not a pipe. It is not a chain from power plant to socket. It is not a delivery system. It is a synchronized graph built from physical infrastructure.</p><p>High-voltage transmission lines form the backbone. Substations are the nodes where lines, transformers, voltage levels, distribution grids, generators, and storage systems connect. Generators inject power into the system. Consumers withdraw power from it. Pumped storage can do both. Redundancy helps the system survive outages and maintenance. Operators and protection systems keep the graph inside safe limits.</p><p>And all of this is part of a larger synchronized machine.</p><p>The most important idea is not that the grid has many components. The most important idea is that all these components participate in one continuously changing operating state.</p><p>Generation changes. Consumption changes. Storage changes mode. Power flows change. Lines become loaded or unloaded. Substations connect and disconnect parts of the graph. Protection systems wait for faults. Operators watch the system.</p><p>And through all of that, the grid must stay balanced.</p><h2>The real goal: balance</h2><p>The whole grid has one brutal rule: generation and consumption must stay balanced all the time.</p><p>But neither side is stable.</p><p>Consumers switch devices on and off. Factories start machines. Trains accelerate. Cities move through morning peaks and evening peaks. Wind farms produce more or less depending on the weather. Solar production changes with clouds and time of day. Power plants start, stop, ramp up, or reduce output. Pumped-storage plants can suddenly become large consumers or large generators.</p><p>And still, the system has to remain synchronized.</p><p>Across Austria, across neighboring countries, across the continental European grid, the machine has to keep its frequency close to 50 Hz. APG&#8217;s balancing information describes 50 Hz as the set point value in the Continental Europe synchronous area and explains that generation and consumption must stay in constant equilibrium. APG Balancing</p><p>That is the real goal of the grid.</p><p>Not simply to &#8220;send electricity&#8221; from power plants to houses.</p><p>The real goal is to continuously adapt generation, consumption, storage, topology, voltage, and power flows so the whole system remains stable.</p><p>This is why the pipe analogy is not only incomplete. It hides the most beautiful part of the system.</p><p>A pipe does not need synchronization. A pipe does not have frequency. A pipe does not react to every change in the whole continent. A pipe does not have to balance generation and consumption in real time.</p><p>The grid does.</p><p>And now that we can see the grid as a synchronized graph, the next question becomes much more interesting:</p><p>How is this machine operated?</p><p>In the next article, we will look at grid operation and see how all the components we discussed, transmission lines, substations, generators, consumers, storage systems, and control systems, are used to keep generation and consumption balanced in real time.</p><h2>Sources</h2><ul><li><p>Austrian Power Grid: <a href="https://www.apg.at/en/power-grid/power-grid-austria/">[Power Grid Austria]</a></p></li><li><p>Austrian Power Grid: [<a href="https://www.apg.at/en/projects/pongau-substation/">Pongau Substation</a>]</p></li><li><p>Austrian Power Grid: [<a href="https://www.apg.at/en/projects/salzburg-line/">Salzburg Line</a>]</p></li><li><p>Austrian Power Grid: [<a href="https://www.apg.at/en/projects/carinthia-power-grid-area/">Carinthia Power Grid Area</a>]</p></li><li><p>APG Market: [<a href="https://markt.apg.at/en/power-grid/balancing/">Balancing</a>]</p></li><li><p>ENTSO-E: [<a href="https://www.entsoe.eu/data/map/">Transmission System Map</a>]</p></li><li><p>VERBUND: [<a href="https://www.verbund.com/en-at/about-verbund/power-plants">Power plants and hydropower information</a>]</p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Rebuilt! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Electricity Is Not Water: A Better Mental Model for the Grid]]></title><description><![CDATA[Electricity Before Infrastructure, Part 1 of The European Power Grid for Software Developers]]></description><link>https://www.dmytrohuz.com/p/electricity-is-not-water-a-better</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/electricity-is-not-water-a-better</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Fri, 15 May 2026 15:10:24 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!sq_V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sq_V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sq_V!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!sq_V!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!sq_V!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!sq_V!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sq_V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:507200,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/197871484?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sq_V!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!sq_V!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!sq_V!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!sq_V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Most requirements in critical industries come from the physical world, and the power grid is no exception. Electricity has rules that cannot be negotiated with. Distance, geography, weather, forests, cities, mountains, sea cables, and even animals shape how the grid must be built and operated.</p><p>Before we talk about energy companies, markets, software, smart meters, substations, or regulation &#8212; we need to understand the physical system underneath. The grid is not just a business system for buying and selling energy. It is a large physical machine that must stay stable every second.</p><p>My approach is simple: deconstruct and rebuild. We start with the smallest useful ideas, understand what problem each one solves, and then follow how they connect into the larger system.</p><p>So let&#8217;s start with electricity itself.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2>The Water Analogy Is Too Small</h2><p>A good analogy can make a complicated subject click. A wrong one can quietly block the whole understanding &#8212; for a very long time.</p><p>This happened to me with electricity.</p><p>The common explanation says that electricity is like water flowing through pipes. Voltage is pressure, current is flow, wires are pipes, and a load is something that uses the flow.</p><p>At the beginning, this helps. It gives you a picture for a simple circuit. A battery pushes, current flows, a lamp lights up, a heater becomes warm. Nice.</p><p>But later this picture becomes a wall.</p><p>It does not explain motors. It does not explain generators. It does not explain transformers. It does not explain why AC exists, why the grid uses high voltage, why three phases, or why frequency matters so much. And the frustrating part is not that those topics are hard &#8212; the frustrating part is that the picture in your head has no room for them. You try to apply the analogy and it just... does not fit. So you feel stupid. But you are not stupid. The analogy is just too small.</p><p>Electricity is not only something flowing inside wires. A wire with current is part of an electromagnetic system. Charges move in the conductor, but electric and magnetic fields exist around it &#8212; and those fields are not a side detail. They are the reason motors, generators, transformers, AC grids, and frequency make any sense at all.</p><p>So: keep the water picture for the first few steps. Then throw it away and build a new one.</p><p>The grid is not a pipe system. It is an electromagnetic machine.</p><p>And I want to give you a set of analogies that actually maps to this. Not one Swiss Army Knife analogy that is universally bad at everything. A whole zoo of weird, specific, memorable animals &#8212; each responsible for one idea, each vivid enough that you cannot forget it.</p><p>Let&#8217;s go.</p><div><hr></div><h2>Voltage, Current, Power, and Resistance (Where Pipes Still Help)</h2><p>Here is where the pipe analogy earns its last few minutes on stage.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zEoO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8e39844-30d8-4787-870b-4b3601eb0ed3_1672x941.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zEoO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8e39844-30d8-4787-870b-4b3601eb0ed3_1672x941.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zEoO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8e39844-30d8-4787-870b-4b3601eb0ed3_1672x941.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zEoO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8e39844-30d8-4787-870b-4b3601eb0ed3_1672x941.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zEoO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8e39844-30d8-4787-870b-4b3601eb0ed3_1672x941.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zEoO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8e39844-30d8-4787-870b-4b3601eb0ed3_1672x941.jpeg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b8e39844-30d8-4787-870b-4b3601eb0ed3_1672x941.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:263565,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/197871484?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8e39844-30d8-4787-870b-4b3601eb0ed3_1672x941.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zEoO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8e39844-30d8-4787-870b-4b3601eb0ed3_1672x941.jpeg 424w, https://substackcdn.com/image/fetch/$s_!zEoO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8e39844-30d8-4787-870b-4b3601eb0ed3_1672x941.jpeg 848w, https://substackcdn.com/image/fetch/$s_!zEoO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8e39844-30d8-4787-870b-4b3601eb0ed3_1672x941.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!zEoO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8e39844-30d8-4787-870b-4b3601eb0ed3_1672x941.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>A source creates an electrical push between two points. This push is <strong>voltage</strong>. When we connect a load and close the circuit, charge can move &#8212; and this movement of charge is <strong>current</strong>.</p><p>The load is where energy becomes something useful. Heat in a heater. Light in a lamp. Motion in a motor. Computation in electronics.</p><p><strong>Power</strong> tells us how much energy is delivered per second:</p><blockquote><p>Power = Voltage &#215; Current P = V &#215; I</p></blockquote><p>This formula matters because power is not only voltage and not only current. It is both together. High voltage with almost no current does not deliver much power. High current with very low voltage also does not necessarily deliver much. Useful electrical power comes from the combination.</p><p><strong>Resistance</strong> is the opposition a material gives to current. When current flows through resistance, part of the energy becomes heat. In a heater &#8212; exactly what we want. In a transmission line &#8212; exactly what we do not want.</p><p>This already gives us one of the main grid problems: we need to move huge amounts of energy over long distances without turning the wires into giant heaters.</p><p>But to understand the solution, we first need the piece that the water analogy keeps hiding.</p><div><hr></div><h2>Current Creates a Magnetic Field (The Piece That Changes Everything)</h2><p>When current flows through a wire, a magnetic field appears around that wire.</p><p>Stop here for a second. This is not a small detail. This is the idea that unlocks everything else in the article.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!95V-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F791387a1-63fb-4aa8-b722-0b15d13d386b_1672x941.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!95V-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F791387a1-63fb-4aa8-b722-0b15d13d386b_1672x941.jpeg 424w, https://substackcdn.com/image/fetch/$s_!95V-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F791387a1-63fb-4aa8-b722-0b15d13d386b_1672x941.jpeg 848w, https://substackcdn.com/image/fetch/$s_!95V-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F791387a1-63fb-4aa8-b722-0b15d13d386b_1672x941.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!95V-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F791387a1-63fb-4aa8-b722-0b15d13d386b_1672x941.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!95V-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F791387a1-63fb-4aa8-b722-0b15d13d386b_1672x941.jpeg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/791387a1-63fb-4aa8-b722-0b15d13d386b_1672x941.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:294144,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/197871484?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F791387a1-63fb-4aa8-b722-0b15d13d386b_1672x941.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!95V-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F791387a1-63fb-4aa8-b722-0b15d13d386b_1672x941.jpeg 424w, https://substackcdn.com/image/fetch/$s_!95V-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F791387a1-63fb-4aa8-b722-0b15d13d386b_1672x941.jpeg 848w, https://substackcdn.com/image/fetch/$s_!95V-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F791387a1-63fb-4aa8-b722-0b15d13d386b_1672x941.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!95V-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F791387a1-63fb-4aa8-b722-0b15d13d386b_1672x941.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The field is not made from tiny pieces of magnet escaping through the insulation. Electrons are not little magnetic balls flying outward. Nothing leaves the wire.</p><p>The idea is stranger and more useful: <strong>moving electric charge creates a magnetic field around the path where it moves</strong>. That is all. Current flows, field appears around the wire. Stronger current, stronger field. Current changes direction, field changes direction.</p><p>A compass near a current-carrying wire reacts &#8212; not because anything jumped out of the wire, but because the wire changed the space around it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yTju!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78b85f2e-13b7-405f-b2ec-6d916ae77564_1672x941.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yTju!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78b85f2e-13b7-405f-b2ec-6d916ae77564_1672x941.jpeg 424w, https://substackcdn.com/image/fetch/$s_!yTju!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78b85f2e-13b7-405f-b2ec-6d916ae77564_1672x941.jpeg 848w, https://substackcdn.com/image/fetch/$s_!yTju!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78b85f2e-13b7-405f-b2ec-6d916ae77564_1672x941.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!yTju!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78b85f2e-13b7-405f-b2ec-6d916ae77564_1672x941.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yTju!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78b85f2e-13b7-405f-b2ec-6d916ae77564_1672x941.jpeg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/78b85f2e-13b7-405f-b2ec-6d916ae77564_1672x941.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:281598,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/197871484?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78b85f2e-13b7-405f-b2ec-6d916ae77564_1672x941.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!yTju!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78b85f2e-13b7-405f-b2ec-6d916ae77564_1672x941.jpeg 424w, https://substackcdn.com/image/fetch/$s_!yTju!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78b85f2e-13b7-405f-b2ec-6d916ae77564_1672x941.jpeg 848w, https://substackcdn.com/image/fetch/$s_!yTju!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78b85f2e-13b7-405f-b2ec-6d916ae77564_1672x941.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!yTju!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78b85f2e-13b7-405f-b2ec-6d916ae77564_1672x941.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This is the moment where the water analogy breaks completely. Water flowing through a pipe stays inside the pipe. Current in a wire creates an effect outside. Electricity can influence the world without electrons leaving the conductor.</p><p>This is the bridge to motors, generators, and transformers. Everything from here is built on top of this one idea.</p><div><hr></div><h2>Motors and Generators Are the Same Story &#8212; In Two Directions</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rKsj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad417791-3422-4c32-98cb-904e5bc70e7a_1672x941.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rKsj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad417791-3422-4c32-98cb-904e5bc70e7a_1672x941.jpeg 424w, https://substackcdn.com/image/fetch/$s_!rKsj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad417791-3422-4c32-98cb-904e5bc70e7a_1672x941.jpeg 848w, https://substackcdn.com/image/fetch/$s_!rKsj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad417791-3422-4c32-98cb-904e5bc70e7a_1672x941.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!rKsj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad417791-3422-4c32-98cb-904e5bc70e7a_1672x941.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rKsj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad417791-3422-4c32-98cb-904e5bc70e7a_1672x941.jpeg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ad417791-3422-4c32-98cb-904e5bc70e7a_1672x941.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:350979,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/197871484?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad417791-3422-4c32-98cb-904e5bc70e7a_1672x941.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rKsj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad417791-3422-4c32-98cb-904e5bc70e7a_1672x941.jpeg 424w, https://substackcdn.com/image/fetch/$s_!rKsj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad417791-3422-4c32-98cb-904e5bc70e7a_1672x941.jpeg 848w, https://substackcdn.com/image/fetch/$s_!rKsj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad417791-3422-4c32-98cb-904e5bc70e7a_1672x941.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!rKsj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad417791-3422-4c32-98cb-904e5bc70e7a_1672x941.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>A motor does not work because electrons hit a wheel the way water hits a turbine.</p><p>A motor works because <strong>magnetic fields push and pull on each other</strong>.</p><p>Imagine a coil of wire. When current flows through it, the coil behaves like an electromagnet. Place it near another magnetic field, and forces appear. Those forces can create torque. Torque can rotate something.</p><p>But here is the problem: one fixed magnetic push is not enough for continuous rotation. If the field stays the same, the rotor moves until it reaches a comfortable position &#8212; and then it stops. The same force that helped it move now holds it there. Like a magnet stuck to your fridge door.</p><p>So the trick is not only to create a magnetic field. The trick is to <strong>keep changing it at the right moment</strong>.</p><p>Change the direction of current &#8212; the field changes direction too. Now the force continues to pull and push the rotor forward instead of letting it settle. Control the timing well enough and you get smooth, continuous rotation.</p><p>This is the basic idea behind electric motors: controlled current &#8594; controlled magnetic fields &#8594; motion.</p><p>A generator is the same story in the opposite direction.</p><p>In a motor, electricity creates motion. In a generator, motion creates electricity. Move a magnet near a coil, or move a coil through a magnetic field &#8212; the magnetic field through the coil changes. A <strong>changing</strong> magnetic field creates an electric field in the conductor, and that electric field pushes charges. The result is voltage.</p><p>A generator does not pour electrical liquid into a wire. It creates voltage because motion changes magnetic fields.</p><p>And because large generators rotate, the voltage they create naturally rises, falls, crosses zero, reverses direction, and repeats. Which brings us to AC.</p><div><hr></div><h2>AC Is Not Useless Back-and-Forth Movement</h2><p>DC means direct current. The push keeps the same direction. A battery is the simplest example.</p><p>AC means alternating current. The voltage rises, falls, crosses zero, reverses, rises in the opposite direction, and repeats. In Europe, the grid does this 50 times per second &#8212; 50 Hz.</p><p>At first, AC feels wrong. If current goes one way and then back again, how does it deliver energy? Doesn&#8217;t it cancel itself?</p><p>The water picture misleads us here again.</p><p>Think of a saw. It moves back and forth, but it cuts wood. A bow drill moves back and forth, but it creates enough heat to start a fire. The motion does not need to travel forever in one direction to do work. The <strong>change</strong> itself is what does the job.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bnvy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89c76-07c3-4f14-b24f-9b69ed2fc3bc_1672x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bnvy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89c76-07c3-4f14-b24f-9b69ed2fc3bc_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!bnvy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89c76-07c3-4f14-b24f-9b69ed2fc3bc_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!bnvy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89c76-07c3-4f14-b24f-9b69ed2fc3bc_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!bnvy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89c76-07c3-4f14-b24f-9b69ed2fc3bc_1672x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bnvy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89c76-07c3-4f14-b24f-9b69ed2fc3bc_1672x941.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/05f89c76-07c3-4f14-b24f-9b69ed2fc3bc_1672x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1194572,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/197871484?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89c76-07c3-4f14-b24f-9b69ed2fc3bc_1672x941.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bnvy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89c76-07c3-4f14-b24f-9b69ed2fc3bc_1672x941.png 424w, https://substackcdn.com/image/fetch/$s_!bnvy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89c76-07c3-4f14-b24f-9b69ed2fc3bc_1672x941.png 848w, https://substackcdn.com/image/fetch/$s_!bnvy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89c76-07c3-4f14-b24f-9b69ed2fc3bc_1672x941.png 1272w, https://substackcdn.com/image/fetch/$s_!bnvy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89c76-07c3-4f14-b24f-9b69ed2fc3bc_1672x941.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In AC systems, charges mostly move back and forth locally. The electromagnetic field transfers energy through the system, and loads take energy from that field. Electrons do not need to travel from a power plant to your laptop. The field moves through the system, and energy moves with it.</p><p>AC is useful precisely because it keeps changing. Changing fields are created naturally by rotating generators. Changing fields drive motors. And changing fields make transformers possible &#8212; which turns out to be the key to building any large-scale grid.</p><div><hr></div><h2>High Voltage and Transformers Solve the Distance Problem</h2><p>Now we can come back to the problem we parked earlier: moving energy far without losing most of it as heat.</p><p>The wire between a generator and a city has resistance. Current flowing through resistance turns energy into heat. The formula is:</p><blockquote><p>Line losses = Current&#178; &#215; Resistance P_loss = I&#178; &#215; R</p></blockquote><p>That square is the dangerous part. If current doubles, losses become four times larger. If current becomes ten times larger, losses become one hundred times larger.</p><p>Current is expensive. It heats wires, wastes energy, and forces us to build thicker, heavier, and more costly infrastructure.</p><p>But power is voltage multiplied by current. For the same amount of power, we can choose different combinations: lower voltage and higher current, or higher voltage and lower current. For long distances, the second option wins easily.</p><p>Raise the voltage. Lower the current. Reduce the losses.</p><p>This is why high-voltage transmission lines exist. Not because engineers love dangerous numbers. It is because without high voltage, long-distance transmission is just a very expensive heater.</p><p>But high voltage that is useful for transmission is not something you want coming out of a wall socket. So the grid needs a machine that can raise voltage before the long journey, and lower it again at the destination.</p><p>This machine is the <strong>transformer</strong>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8lr3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f513f9-14e4-4499-92f7-2a4022da28d5_1672x941.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8lr3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f513f9-14e4-4499-92f7-2a4022da28d5_1672x941.jpeg 424w, https://substackcdn.com/image/fetch/$s_!8lr3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f513f9-14e4-4499-92f7-2a4022da28d5_1672x941.jpeg 848w, https://substackcdn.com/image/fetch/$s_!8lr3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f513f9-14e4-4499-92f7-2a4022da28d5_1672x941.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!8lr3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f513f9-14e4-4499-92f7-2a4022da28d5_1672x941.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8lr3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f513f9-14e4-4499-92f7-2a4022da28d5_1672x941.jpeg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f0f513f9-14e4-4499-92f7-2a4022da28d5_1672x941.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:394085,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/197871484?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f513f9-14e4-4499-92f7-2a4022da28d5_1672x941.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8lr3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f513f9-14e4-4499-92f7-2a4022da28d5_1672x941.jpeg 424w, https://substackcdn.com/image/fetch/$s_!8lr3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f513f9-14e4-4499-92f7-2a4022da28d5_1672x941.jpeg 848w, https://substackcdn.com/image/fetch/$s_!8lr3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f513f9-14e4-4499-92f7-2a4022da28d5_1672x941.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!8lr3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0f513f9-14e4-4499-92f7-2a4022da28d5_1672x941.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>A transformer has two coils wrapped around a magnetic core. One coil is connected to one circuit, the other to another circuit. The two coils are not directly connected by a wire. Electrons do not flow from the first coil into the second.</p><p>And still, energy moves across.</p><p>With the water analogy, this looks like magic. With fields, it becomes completely clear:</p><blockquote><p>AC in the first coil</p><p>&#8594; changing magnetic field in the core</p><p>&#8594; changing field reaches the second coil</p><p>&#8594; voltage is induced in the second coil</p><p>&#8594; power is delivered to the load</p></blockquote><p>The field connects the two circuits.</p><p>This also explains why a normal transformer needs AC. Connect steady DC to the first coil and there is only one brief moment &#8212; when the current starts &#8212; where the field changes. After that, the field becomes steady. A steady magnetic field does not continuously induce voltage in the second coil. No change, no transformer action.</p><p>The transformer can also change the voltage level because the two coils can have different numbers of turns:</p><blockquote><p>V_secondary / V_primary &#8776; N_secondary / N_primary</p></blockquote><p>More turns on the second coil &#8212; voltage steps up. Fewer turns &#8212; voltage steps down.</p><p>Now the skeleton of the grid is visible. Generators produce power. Step-up transformers raise the voltage. High-voltage lines carry it over long distances. Substations connect, protect, switch, and transform. Step-down transformers bring voltage back down. Distribution networks bring electricity closer to consumers. Loads turn energy into heat, light, motion, or computation.</p><p>But there is still one physical improvement missing.</p><div><hr></div><h2>Why the Grid Uses Three Phases</h2><p>We have AC, transformers, and high-voltage transmission &#8212; but one important piece is still not quite right for large-scale use.</p><p>Remember the motor problem: we do not only want a magnetic field. We want a magnetic field that keeps the rotor moving smoothly. With a single AC wave, the push changes, weakens, crosses zero, reverses, comes back. It works, but the motor has to fight through those weak and zero points in every cycle.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6mSU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47f18b1d-e522-4831-8a04-04393bd1f618_1672x941.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6mSU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47f18b1d-e522-4831-8a04-04393bd1f618_1672x941.jpeg 424w, https://substackcdn.com/image/fetch/$s_!6mSU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47f18b1d-e522-4831-8a04-04393bd1f618_1672x941.jpeg 848w, https://substackcdn.com/image/fetch/$s_!6mSU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47f18b1d-e522-4831-8a04-04393bd1f618_1672x941.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!6mSU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47f18b1d-e522-4831-8a04-04393bd1f618_1672x941.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6mSU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47f18b1d-e522-4831-8a04-04393bd1f618_1672x941.jpeg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/47f18b1d-e522-4831-8a04-04393bd1f618_1672x941.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:294704,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/197871484?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47f18b1d-e522-4831-8a04-04393bd1f618_1672x941.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6mSU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47f18b1d-e522-4831-8a04-04393bd1f618_1672x941.jpeg 424w, https://substackcdn.com/image/fetch/$s_!6mSU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47f18b1d-e522-4831-8a04-04393bd1f618_1672x941.jpeg 848w, https://substackcdn.com/image/fetch/$s_!6mSU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47f18b1d-e522-4831-8a04-04393bd1f618_1672x941.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!6mSU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47f18b1d-e522-4831-8a04-04393bd1f618_1672x941.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The better idea: use three AC waves instead of one. Not three random waves &#8212; three <strong>coordinated</strong> waves, shifted in time relative to each other. When one phase is near its maximum, the others are at different points in the cycle. When one weakens, another is already growing stronger. Together, they fill in each other&#8217;s gaps and create a much smoother delivery of power.</p><p>For motors, this is especially valuable because three coordinated phases can create a naturally <strong>rotating</strong> magnetic field. Not a push that has to fight through weak spots &#8212; a field that smoothly turns around the motor and pulls the rotor with it. This is almost exactly what a motor wants.</p><p>Now, the elegant part: we do not need six wires to run three separate circuits.</p><p>Each phase needs one conductor &#8212; so we have three phase conductors: L1, L2, and L3. In a balanced system, the currents in these three phases are shifted so that their sum is zero at every moment. Because of that, the return current cancels out, and a separate return wire is not needed for high-voltage transmission.</p><p>This is why you often see three main conductors on transmission towers &#8212; not three complete circuits with six wires, but one coordinated three-phase system using three.</p><p>Three phases are not an arbitrary complication. They solve a physical problem: smoother power delivery, better conditions for motors, and more efficient large-scale transmission with fewer conductors.</p><div><hr></div><h2>Frequency Is the Pulse of the Grid</h2><p>Now we have generators, AC, transformers, high voltage, and three phases. The physical machine is assembled.</p><p>But the grid is not a tank where you can pour electricity in and take it out freely whenever you want. There is some stored energy in rotating machines, magnetic fields, batteries, and other devices &#8212; but the AC grid itself must be balanced continuously. <strong>Continuously.</strong></p><p>Every second, generation and consumption need to stay close to each other.</p><p>If consumers take more power than generators provide, the system starts to slow down. If generation exceeds consumption, the system starts to speed up. And this shows up in one very visible number: <strong>frequency</strong>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kT_i!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04fb3a9d-7db7-4601-94d9-2bd7c643767e_1672x941.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kT_i!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04fb3a9d-7db7-4601-94d9-2bd7c643767e_1672x941.jpeg 424w, https://substackcdn.com/image/fetch/$s_!kT_i!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04fb3a9d-7db7-4601-94d9-2bd7c643767e_1672x941.jpeg 848w, https://substackcdn.com/image/fetch/$s_!kT_i!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04fb3a9d-7db7-4601-94d9-2bd7c643767e_1672x941.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!kT_i!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04fb3a9d-7db7-4601-94d9-2bd7c643767e_1672x941.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kT_i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04fb3a9d-7db7-4601-94d9-2bd7c643767e_1672x941.jpeg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/04fb3a9d-7db7-4601-94d9-2bd7c643767e_1672x941.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:383845,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/197871484?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04fb3a9d-7db7-4601-94d9-2bd7c643767e_1672x941.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kT_i!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04fb3a9d-7db7-4601-94d9-2bd7c643767e_1672x941.jpeg 424w, https://substackcdn.com/image/fetch/$s_!kT_i!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04fb3a9d-7db7-4601-94d9-2bd7c643767e_1672x941.jpeg 848w, https://substackcdn.com/image/fetch/$s_!kT_i!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04fb3a9d-7db7-4601-94d9-2bd7c643767e_1672x941.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!kT_i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04fb3a9d-7db7-4601-94d9-2bd7c643767e_1672x941.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>In Europe, the grid runs at 50 Hz. That means the AC waveform completes 50 full cycles every second. When generation and consumption are balanced, frequency stays close to 50 Hz. If consumption exceeds generation, frequency falls. If generation exceeds consumption, frequency rises.</p><p>Frequency is not just a number in a technical standard. It is one of the signs that shows the balance of the whole synchronized machine. It is the pulse of the grid.</p><p>And this is where the power grid becomes very different from most software systems. In software, we can queue work, buffer messages, retry requests, scale components, and hide temporary imbalance behind storage. The grid has controls and buffers too &#8212; but the physical system still has to obey the immediate relationship between generation, load, voltage, current, phase, and frequency. You cannot queue it. You cannot retry it.</p><p>The grid is an electromagnetic machine spread over a continent, and that machine must stay inside its limits. If the pulse is stable, the system is alive and balanced. If the pulse drifts too far, something is wrong.</p><p>That is the grid&#8217;s arrhythmia.</p><p>And you have to heal it!</p><div><hr></div><h2>What We Have Now And What Is Next</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ey_S!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc372535f-f9cc-4b72-abc2-d56e3efa7c8f_1536x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ey_S!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc372535f-f9cc-4b72-abc2-d56e3efa7c8f_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ey_S!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc372535f-f9cc-4b72-abc2-d56e3efa7c8f_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ey_S!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc372535f-f9cc-4b72-abc2-d56e3efa7c8f_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ey_S!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc372535f-f9cc-4b72-abc2-d56e3efa7c8f_1536x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ey_S!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc372535f-f9cc-4b72-abc2-d56e3efa7c8f_1536x1024.jpeg" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c372535f-f9cc-4b72-abc2-d56e3efa7c8f_1536x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:486739,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/197871484?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc372535f-f9cc-4b72-abc2-d56e3efa7c8f_1536x1024.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ey_S!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc372535f-f9cc-4b72-abc2-d56e3efa7c8f_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ey_S!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc372535f-f9cc-4b72-abc2-d56e3efa7c8f_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ey_S!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc372535f-f9cc-4b72-abc2-d56e3efa7c8f_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ey_S!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc372535f-f9cc-4b72-abc2-d56e3efa7c8f_1536x1024.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We started with the water analogy because it helps in the beginning. It explains voltage, current, resistance, power, and simple circuits.</p><p>But then it breaks.</p><p>It cannot explain how electricity creates motion outside a wire. For that, we need fields.</p><p>Current creates magnetic fields. Magnetic fields push and pull. Controlled magnetic fields create motion &#8212; motors. Reverse the story: motion changes magnetic fields, changing fields create voltage &#8212; generators.</p><p>Then AC stops being strange. It is not useless back-and-forth. It is <strong>repeated change</strong>, and changing fields are exactly what generators, motors, and transformers need.</p><p>Then distance creates the next problem. To move power far away, we reduce current and increase voltage. Because high voltage is not useful everywhere, we use transformers to step it up and back down.</p><p>Then three phases make the system smoother &#8212; better for motors, smoother power delivery, efficient transmission without six wires for three circuits.</p><p>And finally, frequency shows us that the grid is not a passive network of wires. It is a synchronized machine that must stay balanced every second.</p><p>The water analogy was not completely wrong. It was just too small. It helped me enter the first room, and then it locked all the next doors.</p><p>The field-based model opens them.</p><p>It does not make the grid simple, because the grid is not simple. But it makes the complexity <strong>connected</strong>. Motors, generators, transformers, AC, high voltage, three phases, and frequency stop being random technical vocabulary and become parts of the same engineering story.</p><p>In the next part, we can move from physics to structure: power plants, substations, transmission lines, distribution networks, and the full path from generation to consumption.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;55161b6b-2630-4991-83a1-b03850727586&quot;,&quot;caption&quot;:&quot;Figure 1: The old picture says power flows through a pipe. The real grid is a synchronized graph that must stay balanced in real time.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;The Grid Is Not a Pipeline&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software Engineer in the Energy Sector. AWS Community Builder (Dev Tools). (Re)building core tech in public &#8212; so it stop feeling like magic. Writing at Rebuilt.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-05-29T15:42:22.475Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!h0bv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/the-grid-is-not-a-pipeline&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:199757049,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>If you want to follow this rebuild, subscribe and the next part will find you when it is ready.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Rebuilt! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[A Developer’s Map of the European Power Grid]]></title><description><![CDATA[The central hub for my series: The European Power Grid for Software Developers]]></description><link>https://www.dmytrohuz.com/p/a-developers-map-of-the-european</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/a-developers-map-of-the-european</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Tue, 12 May 2026 15:14:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!r2v5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!r2v5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!r2v5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png 424w, https://substackcdn.com/image/fetch/$s_!r2v5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png 848w, https://substackcdn.com/image/fetch/$s_!r2v5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png 1272w, https://substackcdn.com/image/fetch/$s_!r2v5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!r2v5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png" width="1456" height="1030" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1030,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2130113,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/197363882?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!r2v5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png 424w, https://substackcdn.com/image/fetch/$s_!r2v5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png 848w, https://substackcdn.com/image/fetch/$s_!r2v5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png 1272w, https://substackcdn.com/image/fetch/$s_!r2v5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I have spent a lot of time learning technical systems by rebuilding them from first principles.</p><p>With TLS, I tried to understand the protocol not by starting from the final polished design, but by beginning with a simple and broken version. Then I added one missing idea after another: encryption, integrity, key exchange, certificates, and identity. Step by step, the real structure started to make more sense.</p><p>Now I want to apply a similar mindset to another system, but on a much larger scale: the European power grid.</p><p>The grid is not a small topic. It is not only wires, power plants, and substations. It is also physics, real-time operation, markets, regulation, international coordination, forecasting, automation, cybersecurity, and software. It is one of the most critical systems around us, but for many software developers it often remains hidden behind abstract words like &#8220;energy sector,&#8221; &#8220;smart grid,&#8221; &#8220;TSO,&#8221; &#8220;DSO,&#8221; &#8220;balancing,&#8221; &#8220;SCADA,&#8221; or &#8220;grid modernization.&#8221;</p><p>While trying to learn this field, I noticed a recurring problem: many explanations are either too shallow, too regulatory, or too electrical-engineering-heavy. Some give a high-level business overview, but do not explain the physical system underneath. Others focus on laws, institutions, and market rules, but are hard to connect to the actual grid. Electrical engineering resources often go deep into theory, which is valuable, but not always the easiest entry point for software developers who first need a connected map of the whole system.</p><p>That is the gap I want to work through.</p><p>I want to build a central learning hub where I slowly connect these pieces together.</p><p>In this post I will explain what I want to build, why I am building it, and how I want to approach the European power grid from the perspective of a software developer who wants to understand the industry from the ground up.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><h2>Why I Am Starting This</h2><p>My goal is simple: as a software developer, I want to better understand this critical industry and the components it is built from.</p><p>This is not a random topic for me. I already work in this industry, and the closer I get to energy systems, grid-related software, and operational technology, the more I see that software is only one layer of a much larger system. To build better software, make better technical decisions, and understand the real problems behind the requirements, I need a clearer picture of the whole grid.</p><p>I do not want to look at energy software as isolated applications detached from the physical system underneath. I want to understand what the software is connected to, what constraints the grid has, why those constraints exist, and how the different layers of the industry fit together.</p><p>When we build software for ordinary web applications, we can often reason mostly in terms of users, APIs, databases, queues, services, and infrastructure. The physical world still matters, but it is often abstracted away.</p><p>The power grid is different.</p><p>Software in this industry does not exist in a vacuum. It is connected to physical equipment, operational constraints, safety requirements, regulations, market structures, and cross-border coordination. A wrong assumption is not just a wrong assumption inside an application. It can touch real infrastructure, real operators, real assets, and real consequences.</p><p>That makes the field difficult, but also very interesting.</p><p>I want to understand the grid not as a collection of disconnected terms, but as one layered system. I want to see how electricity behaves, how the physical infrastructure implements that behavior, how operators keep the system stable, how organizations divide responsibility, how Europe coordinates the whole system, and where software enters the picture.</p><h2>The Problem With Existing Explanations</h2><p>When I started looking for good explanations of the European power grid, I often found useful pieces, but not a full map.</p><p>Some resources explain the energy sector from a very high level. They describe renewables, transmission, distribution, markets, and policy, but they often stay too far away from the physical system. After reading them, you may know the names of the actors, but still not understand what is actually happening in the grid.</p><p>Other resources are very regulatory. They explain institutions, market rules, network codes, responsibilities, tariffs, and legal structures. That is important, but if you do not already understand the physical and operational system, it is hard to know where those rules attach to reality.</p><p>Then there are electrical engineering resources, which are often much deeper technically. They explain circuits, machines, power systems, load flow, protection, and control theory. These resources are valuable, but they are not always the right first step for a software developer who wants to build a practical mental model before going deeper into equations and specialist theory.</p><p>So the problem is not that the information does not exist.</p><p>The problem is that it is fragmented across different worlds.</p><p>There is the physics world. There is the electrical engineering world. There is the operator world. There is the regulatory world. There is the market world. There is the software world. Each of them has its own language, assumptions, and priorities.</p><p>What I want to build is a bridge between those worlds.</p><h2>Who This Is For</h2><p>I am writing this from the perspective of a software developer, but I do not think the topic is useful only for software developers.</p><p>Many people enter the energy industry from different angles. Some come from cloud engineering, testing, cybersecurity, data engineering, product management, business analysis, operations, regulation, consulting, or management. Many of them face the same problem: they see parts of the system, but not the whole picture.</p><p>Even if my own final focus will be software, I believe that a clearer map of the whole grid can be useful for anyone who wants to understand where their work fits.</p><p>If you work on an energy platform, it helps to know what physical process your data represents.</p><p>If you work on testing, it helps to know which failures matter operationally.</p><p>If you work on cybersecurity, it helps to understand what assets, protocols, and control paths are critical.</p><p>If you work in cloud or data, it helps to know why not every problem in this industry can be treated like a normal SaaS problem.</p><p>If you work in product or management, it helps to understand the difference between a market requirement, an operational requirement, and a physical constraint.</p><p>That is the kind of map I want to build.</p><p>Not a complete electrical engineering education.</p><p>Not a regulatory encyclopedia.</p><p>Not a shallow overview of energy trends.</p><p>A practical, layered explanation of the European power grid for people who want to understand the system behind the software, decisions, and infrastructure.</p><h2>What This Hub Will Become</h2><p>This page will become the central hub for the series.</p><p>I will update it as new articles are published, and over time it should become a structured entry point into the whole topic. The goal is not to explain everything at once. The goal is to build the map piece by piece.</p><p>First, electricity itself.</p><p>Then the physical grid.</p><p>Then operations.</p><p>Then management.</p><p>Then governance and markets.</p><p>Then international coordination.</p><p>Then software.</p><p>I expect this to take time, and that is fine. Complex systems are not understood in one article. They become understandable when we build the right layers in the right order.</p><p>That is what I want to do here.</p><p>I want to take the European power grid, one of the most critical systems around us, and make it more understandable from a developer&#8217;s point of view.</p><p>Not by pretending it is simple.</p><p>But by building the mental model step by step, from physics to software, until the grid starts to feel less like a black box and more like a system that can be understood.</p><div><hr></div><h2>All parts of the series:</h2><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;1ed5e11e-35b8-419c-a316-9e95898627f8&quot;,&quot;caption&quot;:&quot;Part 1: Electricity Before Infrastructure<br /><br />Before we talk about energy companies, markets, software, smart meters, substations, or regulation &#8212; we need to understand the physical system underneath. The grid is not just a business system for buying and selling energy. It is a large physical machine that must stay stable every second.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Electricity Is Not Water: A Better Mental Model for the Grid&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software Engineer in the Energy Sector. AWS Community Builder (Dev Tools). (Re)building core tech in public &#8212; so it stop feeling like magic. Writing at Rebuilt.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-05-15T15:10:24.614Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!sq_V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c80b9e9-5ddd-4f0c-a4cb-2cb485003afe_1536x1024.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/electricity-is-not-water-a-better&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:197871484,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;173acfd7-5678-4d1d-a0d3-385f9d7fd649&quot;,&quot;caption&quot;:&quot;Part 2: The structure and components of the grid.<br /><br />The power grid is often imagined as a large water system. For a software developer, the better mental model is not a pipeline. It is a graph.<br />Transmission lines are edges. Substations are nodes. Generators, storage systems, distribution grids, industrial consumers, cities, and interconnectors are attached to this graph at different points.<br /><br />&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;The Grid Is Not a Pipeline&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software Engineer in the Energy Sector. AWS Community Builder (Dev Tools). (Re)building core tech in public &#8212; so it stop feeling like magic. Writing at Rebuilt.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-05-29T15:42:22.475Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!h0bv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65b765de-ab75-4122-88be-17cf19c0eed2_1536x1024.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/the-grid-is-not-a-pipeline&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:199757049,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;72eb49da-8e3a-40d7-a167-1278b23dfe96&quot;,&quot;caption&quot;:&quot;Part 3: The explanation about how the grid stays stable.<br /><br />In this post you will learn how protection, monitoring, operation and control work together, what SCADA contributes to that chain, which physical variables operators care about, and what happens from the first instant after a large generator disconnects until the grid reaches a new secure state.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;How the European Grid Stays Stable&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer who takes foundational technologies apart and rebuilds them. Follow to understand how complex systems work, why they are designed this way, and how to reason about them from first principles.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-07-20T07:02:23.698Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!z1Qz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90a438ee-e618-41a8-9933-cc1dfcf1dcb2_1672x941.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/how-the-european-grid-stays-stable&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:207691626,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;3d351b6e-99da-4dd6-b6b8-8f6e526beba3&quot;,&quot;caption&quot;:&quot;Part 4: The structure of Europe's Power System<br /><br />The EU electricity sector is not one company moving electricity from power plants to consumers. It is a regulated system of different actors whose responsibilities overlap without becoming identical.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;How Europe&#8217;s Power System Is Organised&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer who takes foundational technologies apart and rebuilds them. Follow to understand how complex systems work, why they are designed this way, and how to reason about them from first principles.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-08-01T19:35:39.907Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!EXqg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ceb4d81-13de-47cf-9bab-d2f435ac5657_1672x941.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/how-europes-power-system-is-organised&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:209412144,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;67568b11-e1c8-44bb-97a5-c8eef142c2a7&quot;,&quot;caption&quot;:&quot;Previous part:&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Where Software Lives in the Power Grid&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer who takes foundational technologies apart and rebuilds them. Follow to understand how complex systems work, why they are designed this way, and how to reason about them from first principles.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-08-04T12:00:12.967Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!VcpN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d167517-6038-47fa-9548-a22e9beba2c7_1536x1024.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/where-software-lives-in-the-power&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:209770599,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:3,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><p>If you are interested in how the European power grid works, from electricity and infrastructure to operations, governance, and software, subscribe to follow the series as it grows.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Rebuilt is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Rebuilding TLS, Part 4 - Certificates and Trust]]></title><description><![CDATA[How certificates close the man-in-the-middle gap]]></description><link>https://www.dmytrohuz.com/p/rebuilding-tls-part-4-certificates</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/rebuilding-tls-part-4-certificates</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Sun, 26 Apr 2026 20:24:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!HYYb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HYYb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HYYb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!HYYb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!HYYb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!HYYb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HYYb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:325803,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/195558698?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HYYb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!HYYb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!HYYb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!HYYb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Previous Article:</em></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;59aa73da-7378-48a3-ae45-d9dc744b972d&quot;,&quot;caption&quot;:&quot;Overview: Where we are and What Is Still Missing&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Rebuilding TLS, Part 3 &#8212; Building Our First Handshake&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software Engineer in the Energy Sector. AWS Community Builder (Dev Tools). (Re)building core tech in public &#8212; so it stop feeling like magic. Writing at Rebuilt.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-04-19T16:38:45.365Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!Gn-u!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/rebuilding-tls-part-3-building-our&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:194707545,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>A secure connection to the wrong server is still a broken connection.</p><p>That sentence looks strange at first. If traffic is encrypted, if nobody can read it, if nobody can modify it, then what is still missing?</p><p>The missing piece is identity.</p><p>In the previous parts of this series, we slowly moved from a plain TCP connection to something that started to look like a real secure channel. First, we added encryption. Then we added integrity. Then we stopped using fixed shared keys and introduced a handshake with X25519 and HKDF, so the client and server could derive fresh session keys for every connection.</p><p>That was a big step forward, but it was still not enough.</p><p>The client could now create a strong encrypted channel, but it still had no reliable way to know <strong>who</strong> it had created that channel with. It could be the real server. It could also be an attacker sitting in the middle, performing a separate key exchange with the client and another one with the real server.</p><p>In this post we will discuss why key exchange is not the same as authentication, why certificates exist, how certificate chains work, and how I added a simplified certificate-based authentication layer to my small TLS-like protocol.</p><p>By the end, the protocol will finally move from:</p><blockquote><p>&#8220;I have an encrypted channel with whoever answered.&#8221;</p></blockquote><p>to:</p><blockquote><p>&#8220;I have an encrypted channel with the server that proved its identity.&#8221;</p></blockquote><p>That is the moment where this toy protocol starts to feel much closer to real TLS.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><h2><strong>The Problem We Still Had After Key Exchange</strong></h2><p>At the end of Part 3, the protocol already had a real handshake.</p><p>The client and server exchanged ephemeral X25519 public keys. They used the resulting shared secret as input to HKDF. From that, they derived separate keys for client-to-server and server-to-client traffic. Then they used those keys to protect application data with AES-GCM.</p><p>That is already much better than hardcoding a shared key into both programs.</p><p>A hardcoded key has many problems. If someone gets it once, every connection using that key is compromised. If you want to rotate it, you need to update both sides. If two clients use the same key, one compromised client can affect other connections. It is simple for a demo, but it is not a good model for a real secure protocol.</p><p>X25519 and HKDF solved a different problem. They allowed the client and server to create fresh session keys for every connection without sending the actual secret over the network.</p><p>But there was still a hole.</p><p>The client received a public key from &#8220;the server,&#8221; but it had no way to know whether that public key really belonged to the server. The protocol could protect traffic after the handshake, but the handshake itself was not authenticated.</p><p>That means a man-in-the-middle could sit between the client and server and do this:</p><pre><code><code>Client  &lt;---- key exchange ----&gt;  Attacker  &lt;---- key exchange ----&gt;  Server</code></code></pre><p>From the client&#8217;s point of view, everything looks fine. It completed a key exchange and derived keys.</p><p>From the server&#8217;s point of view, everything also looks fine. It completed a key exchange and derived keys.</p><p>But the attacker is in the middle of both secure channels.</p><p>This is the uncomfortable lesson:</p><p>A secure key exchange with an unauthenticated peer can still give you a secure channel to the attacker.</p><p>That is why Part 4 exists.</p><div><hr></div><h2><strong>Encryption Is Not the Same as Trust</strong></h2><p>It is easy to mix these ideas together because HTTPS makes them feel like one thing.</p><p>When we open a website over HTTPS, we usually think:</p><p>The connection is encrypted, so it is secure.</p><p>But real TLS gives us several properties at the same time. Encryption is only one of them.</p><p>A useful way to separate the ideas is this:</p><pre><code><code>Encryption answers:
Can outsiders read the data?

Integrity answers:
Can outsiders modify the data without being detected?

Key exchange answers:
Can both sides create fresh session keys?

Authentication answers:
Do I know who is on the other side?</code></code></pre><p>Before Part 4, our protocol had the first three. It did not have the fourth.</p><p>That distinction matters because an attacker does not always need to break encryption. Sometimes the attacker only needs to become the endpoint that you encrypt to.</p><p>If the client encrypts data to the attacker&#8217;s key, the encryption still works. The math is not broken. AES-GCM still protects the records. HKDF still derives keys. X25519 still creates a shared secret.</p><p>The problem is not the cryptography. The problem is that the client trusted the wrong public key.</p><p>So the next question becomes simple:</p><p>How does the client know that the server&#8217;s handshake key belongs to the real server?</p><p>This is where certificates enter the story.</p><div><hr></div><h2><strong>What Certificates Actually Add</strong></h2><p>A certificate is not magic. It is also not just a random file that makes browsers happy.</p><p>At a practical level, a certificate connects an identity to a public key.</p><p>For example, a server certificate says something like:</p><pre><code><code>This public key belongs to this server identity.</code></code></pre><p>But the client should not just believe that statement because the server said so. Anyone can generate a key pair and create a file that claims to be <code>example.com</code>.</p><p>So certificates are signed.</p><p>That means another key, usually belonging to a Certificate Authority, signs the certificate data. The client can then verify the signature using the Certificate Authority&#8217;s public key.</p><p>In the real Web PKI, this usually forms a chain:</p><pre><code><code>Root CA
  signs
Intermediate CA
  signs
Server Certificate</code></code></pre><p>The root certificate is already trusted by the client&#8217;s system or browser. The server sends its certificate chain during the handshake. The client verifies each signature in the chain until it reaches a trusted root.</p><p>In my simplified implementation for Part 4, I use the same conceptual model:</p><pre><code><code>Root CA
  &#8595;
Intermediate CA
  &#8595;
Server Certificate</code></code></pre><p>The point is not to recreate all of Web PKI. The point is to make the trust chain visible.</p><p>The client does not trust the server certificate because the server sent it. The client trusts it because it can verify that the certificate was signed through a chain that ends at a trusted root.</p><p>Now the client has something it did not have before:</p><p>A public identity key that is connected to the server certificate and can be verified through a certificate chain.</p><p>But there is still one more important step.</p><div><hr></div><h2><strong>Why the Server Must Sign the Handshake</strong></h2><p>A certificate chain proves that a certificate is valid.</p><p>It does not automatically prove that the server currently speaking in this connection owns the private key for that certificate.</p><p>That difference is important.</p><p>If the server only sends a certificate chain, an attacker could potentially copy that public certificate chain and send it to the client. Public certificates are public. They are not secrets.</p><p>So the server must prove ownership of the corresponding private key.</p><p>In real TLS, this is done with a handshake signature. In TLS 1.3, the server signs data derived from the handshake transcript. This binds the server&#8217;s authenticated identity to the exact handshake that is happening now.</p><p>In my simplified Part 4 implementation, I use the same core idea, but in a smaller form.</p><p>The server has two different types of keys:</p><pre><code><code>Long-term identity key
= connected to the server certificate

Ephemeral X25519 key
= used only for this connection&#8217;s key exchange</code></code></pre><p>The server sends its ephemeral X25519 public key, its certificate chain, and a signature over the handshake data.</p><p>The client verifies three things:</p><pre><code><code>1. Is the certificate chain valid?

2. Does the server certificate contain the expected identity key?

3. Did the server sign this handshake using the private key that matches the certificate?</code></code></pre><p>This is the key conceptual step.</p><p>The ephemeral X25519 key gives us fresh session keys. The certificate gives us identity. The signature connects both worlds together.</p><p>Without that signature, the certificate and the key exchange are two separate facts.</p><p>With the signature, the server says:</p><p>I own the private key for this certificate, and I am binding that identity to this ephemeral key exchange.</p><p>That is what stops the man-in-the-middle from silently replacing the handshake key.</p><div><hr></div><h2><strong>The Architecture of Part 4</strong></h2><p>After Part 4, the handshake looks roughly like this:</p><pre><code><code>Client
  |
  |  ClientHello
  |  ephemeral X25519 public key
  |
  v
Server
  |
  |  ServerHello
  |  ephemeral X25519 public key
  |  certificate chain
  |  handshake signature
  |
  v
Client</code></code></pre><p>Then both sides derive the shared secret using X25519:</p><pre><code><code>client private key + server public key
server private key + client public key</code></code></pre><p>Both sides arrive at the same shared secret without sending that secret over the network.</p><p>Then HKDF turns that shared secret into actual session keys.</p><p>Then AES-GCM protects the application records.</p><p>The important change is that the client no longer accepts the server&#8217;s ephemeral public key blindly. It checks whether the authenticated server signed the handshake.</p><p>The complete shape now looks like this:</p><pre><code><code>Certificate chain
  proves server identity

Handshake signature
  binds server identity to the ephemeral key exchange

X25519
  creates a fresh shared secret

HKDF
  derives directional session keys

AES-GCM
  protects application records</code></code></pre><p>This is still a simplified protocol, but the main pieces now line up with the real TLS story much better.</p><div><hr></div><h2><strong>What We Built in Code</strong></h2><p>For this part, I added a small certificate infrastructure to the project.</p><p>The implementation generates a simple hierarchy:</p><pre><code><code>Root CA
Intermediate CA
Server Certificate</code></code></pre><p>The server uses the server certificate and private key as its long-term identity. During the handshake, it still creates a fresh ephemeral X25519 key pair for the current connection.</p><p>That distinction matters.</p><p>The long-term certificate key is not used to encrypt application data. It is used to prove identity.</p><p>The ephemeral X25519 key is not used as identity. It is used to create a fresh shared secret for this connection.</p><p>This separation is one of the most important design ideas in modern TLS. Long-term keys authenticate. Ephemeral keys protect the session.</p><p>The simplified Part 4 flow is:</p><pre><code><code>1. Client creates an ephemeral X25519 key pair.

2. Client sends its public key.

3. Server creates an ephemeral X25519 key pair.

4. Server sends:
   - its ephemeral public key
   - certificate chain
   - signature over handshake data

5. Client verifies the certificate chain.

6. Client verifies the handshake signature.

7. Both sides derive the shared secret with X25519.

8. Both sides derive session keys with HKDF.

9. Application data is protected with AES-GCM.</code></code></pre><p>The full code is in the GitHub repository:</p><p><a href="https://github.com/DmytroHuzz/rebuilding_tls">https://github.com/DmytroHuzz/rebuilding_tls</a></p><p>The full technical walkthrough is here:</p><p><a href="https://dmytrohuzz.github.io/rebuilding_tls/part_4/walkthrough/walkthrough.html">https://dmytrohuzz.github.io/rebuilding_tls/part_4/walkthrough/walkthrough.html</a></p><p>I intentionally keep the article focused on the protocol idea rather than pasting the whole implementation here. Long code blocks inside an article often create an illusion of depth, but they usually make the article harder to read.</p><p>The repository is the right place for the full implementation. The article is the right place for the explanation.</p><div><hr></div><h2><strong>What This Still Is Not</strong></h2><p>This is not real TLS.</p><p>That sentence is important.</p><p>This project is an educational reconstruction of some core TLS ideas. It is not a library. It is not a production protocol. It is not something that should protect real traffic.</p><p>Real TLS has many more details and much stronger guarantees around the handshake. For example, real TLS 1.3 binds the handshake with a transcript hash. It supports negotiation, extensions, certificate validation rules, revocation mechanisms, session resumption, alerts, many edge cases, and years of hardening against attacks that are easy to miss when building a small protocol.</p><p>My version is intentionally smaller.</p><p>It is useful because it makes the main ideas visible:</p><pre><code><code>Why encryption alone is not enough.

Why integrity must be added.

Why fixed keys are weak.

Why key exchange gives fresh session keys.

Why key exchange is still not authentication.

Why certificates exist.

Why the server must sign the handshake.

Why TLS has the shape it has.</code></code></pre><p>That is the real goal of this series.</p><p>Not to replace TLS, but to make TLS less mysterious.</p><h2><strong>Try It Yourself</strong></h2><p>The project is public and runnable.</p><p>The main repository is here:</p><p><a href="https://github.com/DmytroHuzz/rebuilding_tls">https://github.com/DmytroHuzz/rebuilding_tls</a></p><p>The Part 4 walkthrough is here:</p><p><a href="https://dmytrohuzz.github.io/rebuilding_tls/part_4/walkthrough/walkthrough.html">https://dmytrohuzz.github.io/rebuilding_tls/part_4/walkthrough/walkthrough.html</a></p><p>The complete series landing page is here:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;d90ba029-d3a4-4d48-8461-304373219921&quot;,&quot;caption&quot;:&quot;A year ago I wrote a series of articles about how a web server works.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Rebuilding TLS From Scratch &#8212; My Complete Learning Journey&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software Engineer in the Energy Sector. AWS Community Builder (Dev Tools). (Re)building core tech in public &#8212; so it stop feeling like magic. Writing at Rebuilt.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-03-27T21:39:41.947Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!59qZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/rebuilding-tls-from-scratch-my-complete&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:192355388,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:2,&quot;comment_count&quot;:1,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>If you want to understand the path from the beginning, I recommend reading the series in order. Each part fixes one problem and reveals the next one.</p><p>Part 1 starts with encryption. Part 2 adds integrity. Part 3 adds key exchange and session keys. Part 4 adds authentication through certificates and a handshake signature.</p><p>That sequence matters because it shows why TLS is not just &#8220;encryption.&#8221; It is a stack of answers to different problems.</p><div><hr></div><h2><strong>Summary</strong></h2><p>Before Part 4, the protocol could create an encrypted channel, but it could not prove who was on the other side.</p><p>That is a serious problem.</p><p>Encryption protects data from being read. Integrity protects data from being modified. Key exchange creates fresh session keys. But authentication tells the client whether it is talking to the real server or to an attacker in the middle.</p><p>In Part 4, I added that missing authentication layer.</p><p>The client now verifies a certificate chain and checks a handshake signature. The server uses a long-term identity key to authenticate itself, while still using an ephemeral X25519 key for the actual key exchange. HKDF derives session keys, and AES-GCM protects application data.</p><p>The result is still not real TLS, but it now has the core shape:</p><pre><code><code>authenticated handshake
fresh session keys
protected records</code></code></pre><p>And that is the point of this whole series.</p><p>TLS is hard to understand when you only look at the final protocol. There are too many details, too many names, too many moving parts.</p><p>But when you rebuild it step by step, each piece starts to make sense.</p><p>You first feel the problem.</p><p>Then you add the missing mechanism.</p><p>Then you see why the real protocol looks the way it does.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Rebuilt is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Not sure where to begin? Start here!]]></title><description><![CDATA[Rebuild complex systems from first principles &#8212; with code, diagrams, and step-by-step explanations.]]></description><link>https://www.dmytrohuz.com/p/not-sure-where-to-begin-start-here</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/not-sure-where-to-begin-start-here</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Thu, 23 Apr 2026 20:19:40 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!x87A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce64414b-e440-4e77-8e48-5de9339a7a58_1774x887.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!x87A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce64414b-e440-4e77-8e48-5de9339a7a58_1774x887.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!x87A!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce64414b-e440-4e77-8e48-5de9339a7a58_1774x887.png 424w, https://substackcdn.com/image/fetch/$s_!x87A!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce64414b-e440-4e77-8e48-5de9339a7a58_1774x887.png 848w, https://substackcdn.com/image/fetch/$s_!x87A!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce64414b-e440-4e77-8e48-5de9339a7a58_1774x887.png 1272w, https://substackcdn.com/image/fetch/$s_!x87A!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce64414b-e440-4e77-8e48-5de9339a7a58_1774x887.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!x87A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce64414b-e440-4e77-8e48-5de9339a7a58_1774x887.png" width="1456" height="728" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ce64414b-e440-4e77-8e48-5de9339a7a58_1774x887.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1363430,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/195278928?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce64414b-e440-4e77-8e48-5de9339a7a58_1774x887.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!x87A!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce64414b-e440-4e77-8e48-5de9339a7a58_1774x887.png 424w, https://substackcdn.com/image/fetch/$s_!x87A!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce64414b-e440-4e77-8e48-5de9339a7a58_1774x887.png 848w, https://substackcdn.com/image/fetch/$s_!x87A!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce64414b-e440-4e77-8e48-5de9339a7a58_1774x887.png 1272w, https://substackcdn.com/image/fetch/$s_!x87A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce64414b-e440-4e77-8e48-5de9339a7a58_1774x887.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Hi, I&#8217;m Dmytro.</p><p>This publication is about understanding complex engineered systems by taking them apart, tracing how their layers fit together, and sometimes rebuilding important pieces from scratch.</p><p>If you are new here, this page is the easiest place to begin.</p><p>You do not need to read everything in chronological order. Pick the system that interests you and go from there.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><h2><strong>Rebuilding technology from first principles</strong></h2><p>This is where the publication started.</p><p>I wanted to understand technologies I had used for years but never truly understood underneath their abstractions.</p><p>So I started rebuilding them.</p><h3><strong>Rebuilding a web server</strong></h3><p>A web server looks simple from the outside: receive a request, return a response.</p><p>Underneath that simple interaction are sockets, TCP, HTTP parsing, concurrency, operating-system interfaces, and a surprising number of small engineering decisions.</p><p>This project was my attempt to follow the path all the way down and build a small server myself.</p><p><strong>Start here:</strong><br><a href="https://dev.to/dmytro_huz/building-your-own-web-server-part-1-theory-and-foundations-3kgo">https://dev.to/dmytro_huz/building-your-own-web-server-part-1-theory-and-foundations-3kgo</a></p><div><hr></div><h3><strong>Rebuilding cryptography</strong></h3><p>TLS eventually forced me into another layer.</p><p>Before I could understand secure communication properly, I needed to understand the cryptographic primitives underneath it.</p><p>So I explored things like encryption, hashing, key exchange, authentication, and the mathematics that makes them possible, then implemented simplified versions myself.</p><p><strong>Start here:</strong><br></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;82474a52-d220-4e6a-83dd-838ba8d1f7d6&quot;,&quot;caption&quot;:&quot;Why this project exists - and why it might matter to you&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Rebuilding Cryptography From Scratch - My Complete Learning Journey (All Parts Inside)&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer who takes foundational technologies apart and rebuilds them. Follow to understand how complex systems work, why they are designed this way, and how to reason about them from first principles.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2025-12-01T19:09:39.536Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!SRa_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a9697d-5837-4c57-947c-4cf941c3bc3d_1024x608.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/rebuilding-cryptography-from-scratch&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:180433391,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:3,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><h3><strong>Rebuilding TLS from scratch</strong></h3><p>This became one of my longest projects.</p><p>I spent roughly a year and a half learning how TLS works, rebuilding its important parts, and eventually connecting my own toy TLS implementation to my own web server.</p><p>The goal was never to create production cryptography.</p><p>It was to understand what really happens between typing <code>https://</code> and establishing a secure connection.</p><p>If you want one project that best represents the original idea behind Rebuilt, start here.</p><p><strong>Start here:</strong><br></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;4ca92c9d-51c2-4d9c-96b4-c535177072ab&quot;,&quot;caption&quot;:&quot;A year ago I wrote a series of articles about how a web server works.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Rebuilding TLS From Scratch &#8212; My Complete Learning Journey&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer who takes foundational technologies apart and rebuilds them. Follow to understand how complex systems work, why they are designed this way, and how to reason about them from first principles.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-03-27T21:39:41.947Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!59qZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/rebuilding-tls-from-scratch-my-complete&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:192355388,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:4,&quot;comment_count&quot;:1,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><h3><strong>Understanding time in computers</strong></h3><p>Time sounds trivial until distributed computers need to agree on it.</p><p>Then you encounter oscillators, clocks, drift, operating systems, synchronization, networks, NTP, precision, and the uncomfortable realization that even &#8220;what time is it?&#8221; is a systems problem.</p><p><strong>Start here:</strong></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;ec73f023-50f4-443e-8d70-ef86123244c4&quot;,&quot;caption&quot;:&quot;Time looks simple until you have to trust it.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;A Practical Guide to Time for Developers &#8212; The Complete Series&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer who takes foundational technologies apart and rebuilds them. Follow to understand how complex systems work, why they are designed this way, and how to reason about them from first principles.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-03-19T21:05:34.893Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!mg5A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef6652f-dc32-4078-ac16-7d4ac73c0392_1024x608.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-746&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:191519746,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:3,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><h1><strong>Understanding larger systems</strong></h1><p>At some point, I became interested not only in rebuilding individual technologies but in understanding systems much larger than a single protocol or application.</p><p>The method remained the same:</p><p>start with the fundamentals, identify the layers, understand how they interact, and gradually reconstruct the whole mental model.</p><h2><strong>The electrical grid for software engineers</strong></h2><p>The power grid became my first attempt to do that at infrastructure scale.</p><p>I work as a software engineer in the energy sector, but I initially understood surprisingly little about the system around the software.</p><p>So I started from the beginning.</p><p>Why does grid frequency matter?</p><p>How does electricity actually move?</p><p>What do transmission and distribution operators do?</p><p>How is the grid controlled?</p><p>Where do energy markets enter the picture?</p><p>And where, across all those layers, does software actually live?</p><p>The result became a series explaining the European electrical grid from a software engineer&#8217;s perspective.</p><h3><strong>A good reading order</strong></h3><ol><li><p><strong>A Developer&#8217;s Map of the European Electrical Grid</strong><br>The overall mental model and the major layers of the system.</p></li><li><p><strong>The Grid Is Not a Pipeline</strong><br>The physical foundations and why electricity behaves differently from most resources we move around.</p></li><li><p><strong>How the Grid Is Operated</strong><br>Frequency, balancing, reserves, control, and the mechanisms keeping the system stable.</p></li><li><p><strong>How the Electricity Market Works</strong><br>Producers, consumers, BRPs, exchanges, system operators, schedules, settlement, and why the commercial system exists.</p></li><li><p><strong>Where Software Lives in the Power Grid</strong><br>How software appears across field devices, substations, control centers, markets, analytics, enterprise systems, and everything between them.</p></li></ol><p><strong>Start here:</strong></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;a7d078ac-0d67-4420-872d-ae039b53190b&quot;,&quot;caption&quot;:&quot;I have spent a lot of time learning technical systems by rebuilding them from first principles.&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;A Developer&#8217;s Map of the European Power Grid&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software engineer who takes foundational technologies apart and rebuilds them. Follow to understand how complex systems work, why they are designed this way, and how to reason about them from first principles.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-05-12T15:14:05.930Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!r2v5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b47f174-07bd-435f-9c8c-363edb0adbfd_1491x1055.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/a-developers-map-of-the-european&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:197363882,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div><hr></div><h1><strong>What I want to build next</strong></h1><p>The projects above started at opposite ends.</p><p>One began with individual technologies such as HTTP and TLS.</p><p>The other began with an enormous physical infrastructure system.</p><p>Now I am increasingly interested in the space where those two directions meet.</p><p>Systems that combine several layers:</p><ul><li><p>software</p></li><li><p>networks</p></li><li><p>protocols</p></li><li><p>security</p></li><li><p>devices</p></li><li><p>embedded or edge computing</p></li><li><p>physical processes</p></li><li><p>operations</p></li><li><p>reliability</p></li></ul><p>I want to move beyond explaining isolated components and start building more complete systems myself.</p><p>That may mean rebuilding a VPN and eventually putting it into a physical device.</p><p>It may mean experimenting with industrial communication protocols.</p><p>It may mean connecting software to sensors, field devices, simulators, or real infrastructure.</p><p>And it will probably mean discovering several layers I currently know almost nothing about.</p><p>That is part of the appeal.</p><div><hr></div><h1><strong>What Rebuilt is about</strong></h1><p>The subjects here may look quite different.</p><p>TLS and electrical grids do not have much in common on the surface.</p><p>But the questions behind them are usually the same.</p><p>How does the system really work?</p><p>Why is it structured this way?</p><p>Where are the boundaries?</p><p>How do the layers communicate?</p><p>What assumptions hold everything together?</p><p>What happens when something fails?</p><p>And what would I learn if I tried to build part of it myself?</p><p>That is the thread connecting everything here.</p><p>If you enjoy going underneath abstractions and understanding how complex systems actually fit together, you are in the right place.</p><p>Welcome to <strong>Rebuilt</strong>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Rebuilt is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Rebuilding TLS, Part 3 — Building Our First Handshake]]></title><description><![CDATA[We get rid of the pre-shared key assumption, build a simple key exchange handshake, and discover why key agreement alone still does not give us real TLS.]]></description><link>https://www.dmytrohuz.com/p/rebuilding-tls-part-3-building-our</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/rebuilding-tls-part-3-building-our</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Sun, 19 Apr 2026 16:38:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Gn-u!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Gn-u!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Gn-u!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Gn-u!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Gn-u!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Gn-u!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Gn-u!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg" width="1456" height="569" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:569,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:250820,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/194707545?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Gn-u!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Gn-u!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Gn-u!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Gn-u!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Previous Article:</em></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;a3b907b8-ab7a-4b77-a780-e20636f0cc84&quot;,&quot;caption&quot;:&quot;In the first part of this series, we built our first fake secure channel:&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Rebuilding TLS, Part 2 &#8212; Adding Integrity to the Channel&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software Engineer in the Energy Sector. AWS Community Builder (Dev Tools). (Re)building core tech in public &#8212; so it stop feeling like magic. Writing at Rebuilt.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-04-05T21:40:43.808Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!78kv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/rebuilding-tls-part-2-adding-integrity&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:193281237,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><h2><strong>Overview: Where we are and What Is Still Missing</strong></h2><p>In the previous part of this series, we made our fake secure channel much less fake.</p><p>We started with the broken encrypted transport from <a href="https://www.dmytrohuz.com/p/rebuilding-tls-part-1-why-encryption">Part 1</a>, added integrity with HMAC, <a href="https://www.dmytrohuz.com/p/rebuilding-tls-part-2-adding-integrity">added sequence numbers to make the record layer less naive, and then moved to AEAD</a> &#8212; the approach modern systems usually use to protect records.</p><p>At that point, our protocol could already do something meaningful:</p><ul><li><p>encrypt application data</p></li><li><p>detect tampering</p></li><li><p>reject modified records</p></li><li><p>keep some minimal record-layer state</p></li></ul><p>That was a real step forward.</p><p>But it still relied on one very unrealistic assumption:</p><p><strong>both sides already shared the secret keys</strong></p><p>And that is exactly what we need to remove now.</p><p>Because a real secure protocol cannot stop at protecting data after the keys already exist. It also has to answer one of the harder questions first:</p><p><strong>if client and server do not already share a secret, how can they create one over an insecure network in the first place?</strong></p><p>That is the goal of this part.</p><p>We are going to build the next missing layer of the protocol: the handshake.</p><p>The architecture of this step is simple:</p><pre><code><code>Client                           Server
------                           ------
Handshake messages  &lt;---------&gt;  Handshake messages
       |                               |
       v                               v
  shared secret                  shared secret
       |                               |
       +---------&gt; HKDF &lt;--------------+
                    |
                    v
              session keys
                    |
                    v
         protected application data
</code></code></pre><p>The idea is to let the connection create fresh key material dynamically instead of starting with a hardcoded application key.</p><p>We will implement that in three steps.</p><p>First, we will build a handshake with classic Diffie-Hellman, where the shared prime and base are still explicit and visible in the protocol. Then we will replace that version with X25519 to show how modern protocols simplify the same idea. After that, we will use HKDF to derive proper session keys from the raw shared secret.</p><p>That will take us one big step closer to the shape of real TLS.</p><p>But still not all the way.</p><p>Because even if both sides manage to derive the same fresh session keys, one critical problem will remain: they still do not know who is on the other side.</p><p>And that is where this part is heading.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dmytro&#8217;s Substack is a reader-supported publication. To receive new posts and support my work, consider becoming a subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><h2><strong>A Very Short Note on Public Key Exchange</strong></h2><p>The basic idea of public key exchange is simple.</p><p>Two sides communicate over an insecure network. They exchange some public information. And from that exchange, both sides derive the same shared secret &#8212; without ever sending that secret directly over the wire.</p><p>That is the key point.</p><p>The network can be fully visible.</p><p>An observer can see all handshake messages.</p><p>But the observer still should not be able to derive the same secret.</p><p>That is exactly the kind of mechanism we need now.</p><p>Until this point in the series, our protocol always started with a secret that already existed. Public key exchange changes that. It gives the connection a way to create fresh shared key material dynamically.</p><p>In this article, I do not want to go deep into the mathematics behind it. I only want to use the core idea as the next building block of the protocol.</p><p>If you want the deeper intuition behind why this works, I already wrote about it here:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;dea52c91-5c61-4a96-88ff-8813525b2584&quot;,&quot;caption&quot;:&quot;I started my deep dive into cryptography six months ago. I wanted to deconstruct its internals into basic building blocks and then build them back up again. One simple idea kept pulling me forward&#8212;fascinating me and motivating me to go deeper: how can a crowd of absolute strangers&#8212;over the internet, an inherently insecure medium&#8212;exchange information sec&#8230;&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;The Aha-Moment of Public-Key Encryption&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Engineer | Writer | Builder - I deconstruct complex systems to first principles and rebuild them into clear engineering mental models, diagrams, and practical tools.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-02-13T12:29:49.434Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!uy8G!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa57299a6-5758-4c3a-bcd3-443638e6a53c_1536x672.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/the-aha-moment-of-public-key-encryption&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:187849238,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Dmytro&#8217;s Substack&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!t_-c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F046f0d8c-fecd-41e6-a43f-4718cf07a50f_608x608.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>For now, the main idea we need is this:</p><ul><li><p>each side contributes its own private value</p></li><li><p>both sides exchange some public values</p></li><li><p>both sides derive the same shared secret</p></li><li><p>that secret can then become the basis for session keys</p></li></ul><p>So let&#8217;s build that first in the most explicit way, with classic Diffie-Hellman where the shared public parameters are still visible in the handshake.</p><h2><strong>Implementation Part 1 &#8212; Our First Handshake with Classic Diffie-Hellman</strong></h2><p>(The whole code can be find here: <a href="https://github.com/DmytroHuzz/rebuilding_tls/tree/main/part_3/v1_classic_dh_handshake">https://github.com/DmytroHuzz/rebuilding_tls/tree/main/part_3/v1_classic_dh_handshake</a> )</p><p>Now let&#8217;s build the first real handshake in the series.</p><p>I want to start with classic Diffie-Hellman, not because this is the final form we want to keep, but because it makes the mechanics of key exchange much more visible.</p><p>In this version, both sides work with the same public parameters:</p><ul><li><p>a prime p</p></li><li><p>a generator g</p></li></ul><p>These values are not secret. In our implementation, the client sends them in the handshake, which makes the whole mechanism more explicit on the wire. That is exactly what I want at this stage. Before we hide the details behind a cleaner modern primitive, I want to make the structure fully visible.</p><p>The actual secret material comes from somewhere else:</p><ul><li><p>the client chooses a private exponent a</p></li><li><p>the server chooses a private exponent b</p></li></ul><p>From those private values, both sides compute public values:</p><ul><li><p>the client computes A = g^a mod p</p></li><li><p>the server computes B = g^b mod p</p></li></ul><p>Then they exchange A and B.</p><p>And this is the key step:</p><ul><li><p>the client computes s = B^a mod p</p></li><li><p>the server computes s = A^b mod p</p></li></ul><p>Both sides end up with the same shared secret, without ever sending that secret directly over the network.</p><p>In diagram form, the handshake looks like this:</p><pre><code><code>Client                                        Server
------                                        ------
choose private a
compute A = g^a mod p

ClientHello(p, g, A)      ---------&gt;

                                              choose private b
                                              compute B = g^b mod p

                          &lt;---------          ServerHello(B)

compute s = B^a mod p                           compute s = A^b mod p
</code></code></pre><p>That is our first real handshake.</p><p>Until now, the protocol always started with a secret key that already existed.</p><p>Now the connection itself creates the secret.</p><p>That is a major shift.</p><h3><strong>The raw Diffie-Hellman math</strong></h3><p>At the lowest level, the core operations are very small. That is one of the nice things about starting with classic Diffie-Hellman: the whole idea is still visible in a few functions.</p><pre><code><code>
# RFC 3526 Group 14: 2048-bit MODP prime
DH_PRIME = int(
    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
    "15728E5A8AACAA68FFFFFFFFFFFFFFFF",
    16,
)

DH_GENERATOR = 2

def generate_private_exponent() -&gt; int:
    return int.from_bytes(os.urandom(32), "big")

def compute_public_value(private: int, g: int, p: int) -&gt; int:
    return pow(g, private, p)

def compute_shared_secret(peer_public: int, private: int, p: int) -&gt; int:
    return pow(peer_public, private, p)
</code></code></pre><p>This is the whole core idea in code:</p><ul><li><p>private exponent stays local</p></li><li><p>public value goes on the wire</p></li><li><p>shared secret is derived independently on both sides</p></li></ul><p>That is the heart of Diffie-Hellman.</p><h3><strong>Client side</strong></h3><pre><code><code>def client_handshake(sock) -&gt; bytes:
    """Perform the client side of the classic DH handshake.

    The client picks the public parameters (p, g) and sends them to the
    server along with its own public DH value.  The server uses those
    parameters to compute its own public value and sends it back.

    Returns the shared secret as bytes.
    """
    # The client chooses p and g.  These are PUBLIC &#8212; not secret.
    # Anyone on the wire can see them, and that is perfectly fine.
    # The security of DH depends on the hardness of the discrete
    # logarithm problem, not on hiding p and g.
    p = DH_PRIME
    g = DH_GENERATOR

    print(f"  Public parameters (chosen by client, sent to server):")
    print(f"    p = {str(p)[:40]}... ({p.bit_length()} bits)")
    print(f"    g = {g}")

    # Step 1: Generate client's private exponent and public value.
    # The private exponent is the ONE thing that stays secret.
    client_private = generate_private_exponent()
    client_public = compute_public_value(client_private, g, p)
    client_public_bytes = int_to_bytes(client_public)

    # Step 2: Send ClientHello with p, g, and our public value.
    # All three are public.  The private exponent is NOT included.
    p_bytes = int_to_bytes(p)
    g_bytes = int_to_bytes(g)

    client_hello = encode_message(
        [
            (TAG_DH_P, p_bytes),
            (TAG_DH_G, g_bytes),
            (TAG_DH_PUBLIC, client_public_bytes),
        ]
    )
    # Step 3: send p, g, and the client&#8217;s public value inside ClientHello
    send_record(sock, client_hello)

    # Step 4: Receive ServerHello with the server's public value.
    server_hello_raw = recv_record(sock)
    fields = decode_message(server_hello_raw)
    server_public_bytes = None
    for tag, value in fields:
        if tag == TAG_DH_PUBLIC:
            server_public_bytes = value
    if server_public_bytes is None:
        raise ValueError("ServerHello missing DH public value")

    server_public = bytes_to_int(server_public_bytes)
    print(f"  &lt;- Received ServerHello")
    print(f"  Server public value B:   {hex_preview(server_public_bytes)}")

    # Step 5: Compute the shared secret.
    # shared = B^a mod p = (g^b)^a mod p = g^(ab) mod p
    shared_int = compute_shared_secret(server_public, client_private, p)
    shared_bytes = int_to_bytes(shared_int)

    return shared_bytes
</code></code></pre><p>On the client side, the flow is:</p><ol><li><p>choose a private exponent</p></li><li><p>compute the public value</p></li><li><p>send p, g, and the client&#8217;s public value inside ClientHello</p></li><li><p>receive the server&#8217;s public value</p></li><li><p>derive the shared secret</p></li></ol><p>That is the first point in the series where the client does not begin with the application key. It participates in creating it.</p><h3><strong>Server side</strong></h3><pre><code><code>def server_handshake(sock) -&gt; bytes:
    """Perform the server side of the classic DH handshake.

    The server receives p, g, and client_public from the ClientHello,
    uses those parameters to generate its own keypair, and sends its
    public value back.

    Returns the shared secret as bytes.
    """
    # Step 1: Receive ClientHello &#8212; parse p, g, and client's public value.
    # The server does NOT assume any particular p or g.  It uses whatever
    # the client proposes.  (In a production system, the server would
    # validate that p is a safe prime and g is a proper generator.
    # We skip that here for clarity.)
    client_hello_raw = recv_record(sock)
    fields = decode_message(client_hello_raw)

    p_bytes = None
    g_bytes = None
    client_public_bytes = None
    for tag, value in fields:
        if tag == TAG_DH_P:
            p_bytes = value
        elif tag == TAG_DH_G:
            g_bytes = value
        elif tag == TAG_DH_PUBLIC:
            client_public_bytes = value

    if p_bytes is None:
        raise ValueError("ClientHello missing DH prime (p)")
    if g_bytes is None:
        raise ValueError("ClientHello missing DH generator (g)")
    if client_public_bytes is None:
        raise ValueError("ClientHello missing DH public value (A)")

    # Deserialize the parameters from bytes.
    p = bytes_to_int(p_bytes)
    g = bytes_to_int(g_bytes)
    client_public = bytes_to_int(client_public_bytes)

    # Step 2: Generate server's private exponent and public value
    # using the p and g received from the client.
    server_private = generate_private_exponent()
    
    # Step 3: Compute server's public value
    server_public = compute_public_value(server_private, g, p)
    server_public_bytes = int_to_bytes(server_public)

    # Step 4: Send ServerHello with our public value.
    # Only B is sent &#8212; p and g are already known from the ClientHello.
    server_hello = encode_message(
        [
            (TAG_DH_PUBLIC, server_public_bytes),
        ]
    )
    send_record(sock, server_hello)

    # Step 5: Compute the shared secret.
    # shared = A^b mod p = (g^a)^b mod p = g^(ab) mod p
    shared_int = compute_shared_secret(client_public, server_private, p)
    shared_bytes = int_to_bytes(shared_int)

    return shared_bytes

</code></code></pre><p>The server does the mirror image:</p><ol><li><p>receive p, g, and the client&#8217;s public value</p></li><li><p>choose its own private exponent</p></li><li><p>compute its own public value</p></li><li><p>send that value back in ServerHello</p></li><li><p>derive the same shared secret from the client&#8217;s public value</p></li></ol><p>So at the end of the handshake, both sides have the same secret &#8212; but that secret was never transmitted directly.</p><p>That is the big win.</p><p>After this step, the connection can create fresh shared key material dynamically.</p><p>That is a much more realistic foundation.</p><p>But it is also still awkward.</p><p>Not conceptually awkward &#8212; educationally this version is very useful &#8212; but operationally awkward. We now have explicit p and g in the handshake, which is nice for understanding the mechanism, but clunky for a modern protocol design.</p><p>That is exactly why the next step will replace this version with X25519.</p><h2><strong>Implementation Part 2 &#8212; Simplifying the Handshake with X25519</strong></h2><p>(The whole code can be find here: https://github.com/DmytroHuzz/rebuilding_tls/tree/main/part_3/v2_x25519_handshake )</p><p>The classic Diffie-Hellman version was useful because it made the mechanics of the handshake fully visible.</p><p>But it also makes something else visible:</p><p>it is a bit clunky.</p><p>Not conceptually clunky &#8212; educationally it is great &#8212; but operationally clunky. There are more moving parts in the handshake, more explicit protocol fields, and more visible math than modern protocols usually want to expose directly.</p><p>So now we keep the same core idea and simplify the workflow.</p><p>That is where <strong>X25519</strong> comes in.</p><p>The conceptual goal stays exactly the same:</p><ul><li><p>both sides generate ephemeral private/public key pairs</p></li><li><p>both sides exchange public keys</p></li><li><p>both sides derive the same shared secret</p></li><li><p>that secret will later become the basis for session keys</p></li></ul><p>What changes is the <em>shape</em> of the handshake.</p><p>We no longer need to carry an explicit prime and generator through the protocol. We no longer manually perform modular exponentiation with visible p and g. X25519 gives us the same public-key exchange idea in a much cleaner modern form.</p><p>That is why I wanted this section right after the classic DH version.</p><p>Classic DH makes the mechanism visible.</p><p>X25519 shows what the modern streamlined version looks like.</p><h3><strong>Client-side handshake structure</strong></h3><p>Here is the current client handshake implementation:</p><pre><code><code>def client_handshake(sock) -&gt; bytes:
    """Perform the client side of the X25519 handshake.

    Returns the 32-byte shared secret.
    """
    print("\\n[handshake] Client: starting X25519 handshake")

    # Step 1: Generate an ephemeral X25519 keypair.
    # "Ephemeral" means we create a fresh keypair for this session only.
    # The private key never leaves this process and is discarded after use.
    client_private = X25519PrivateKey.generate()
    client_public = client_private.public_key()
    client_public_bytes = client_public.public_bytes(Encoding.Raw, PublicFormat.Raw)

    # Step 2: Send ClientHello with our public key.
    client_hello = encode_message(
        [
            (TAG_X25519_PUBLIC, client_public_bytes),
        ]
    )
    send_record(sock, client_hello)

    # Step 3: Receive ServerHello with the server's public key.
    server_hello_raw = recv_record(sock)
    fields = decode_message(server_hello_raw)
    server_public_bytes = None
    for tag, value in fields:
        if tag == TAG_X25519_PUBLIC:
            server_public_bytes = value
    if server_public_bytes is None:
        raise ValueError("ServerHello missing X25519 public key")

    # Deserialize the server's public key from raw bytes.
    server_public = X25519PublicKey.from_public_bytes(server_public_bytes)

    # Step 4: Compute the shared secret.
    # X25519(client_private, server_public) = X25519(server_private, client_public)
    # This is the elliptic-curve equivalent of g^(ab) mod p from v1.
    shared_secret = client_private.exchange(server_public)

    return shared_secret
</code></code></pre><p>I like this version because it makes the transition very clear.</p><p>The client code no longer has to think about p and g at all. It just performs the handshake, gets the shared secret, and prints it. That is exactly the point of this stage in the series: the workflow becomes smaller, but the underlying purpose stays the same.</p><h3><strong>What changed conceptually</strong></h3><p>Compared to the classic DH version, the protocol has become simpler in three important ways.</p><h3><strong>1. No explicit shared public parameters in the handshake</strong></h3><p>In the previous version, the client sent the prime and generator so the whole structure of classic Diffie-Hellman stayed visible.</p><p>Now that goes away.</p><p>X25519 already gives us a fixed, standard structure for the exchange, so the handshake only needs to carry the public key material.</p><p>That makes the protocol smaller and cleaner.</p><h3><strong>2. The public values are much more compact</strong></h3><p>In the classic DH version, the public values were tied to a large prime-field construction and looked much heavier in the protocol.</p><p>In this version, the public keys are just 32 bytes.</p><p>That is a huge practical simplification.</p><h3><strong>3. The code starts to look more like real modern protocol code</strong></h3><p>This line from the comments says it well:</p><blockquote><p>generate(), exchange(), done.</p></blockquote><p>That is exactly the feeling this section should create.</p><p>We are still doing public-key exchange.</p><p>We are still deriving a shared secret.</p><p>But the implementation shape is now much closer to what modern systems actually use.</p><h3><strong>What this version still does not solve</strong></h3><p>Even after switching to X25519, this version is still simplified:</p><ul><li><p>there is still <strong>no authentication</strong></p></li><li><p>the shared secret is <strong>not yet turned into session keys</strong></p></li><li><p>there is still <strong>no record-layer encryption using the new keys</strong></p></li></ul><p>In the next step, we will add <strong>HKDF</strong> and derive proper working session keys from it.</p><p>That is where the handshake starts to connect back to the record protection we built earlier.</p><h2><strong>Implementation Part 3 &#8212; Deriving Session Keys with HKDF</strong></h2><p>(The whole code can be find here: https://github.com/DmytroHuzz/rebuilding_tls/tree/main/part_3/v3_hkdf_session_keys)</p><p>At this point, both the classic Diffie-Hellman version and the X25519 version give us the same kind of output:</p><p>a shared secret that both sides can compute independently.</p><p>That is already a big step forward compared to the pre-shared-key model from the previous parts. The connection can now create fresh key material dynamically instead of starting with one hardcoded application key.</p><p>But there is still one important design question left:</p><p><strong>should we use that raw shared secret directly as the application key?</strong></p><p>For a toy demo, we probably could.</p><p>But even here, that would be the wrong direction.</p><p>Because a cleaner protocol separates these two ideas:</p><ul><li><p>the handshake creates a shared secret</p></li><li><p>the protocol derives working session keys from that secret</p></li></ul><p>That is exactly where <strong>HKDF</strong> comes in.</p><p>HKDF is a key-derivation function. Its job is not to invent secrecy out of nowhere, but to take existing secret material and turn it into keys that are better structured and easier to use safely inside the protocol.</p><p>So instead of treating the X25519 output as &#8220;the AES key,&#8221; we will use HKDF to derive proper session keys from it.</p><p>That already makes the protocol feel much closer to real TLS.</p><h3><strong>What changes conceptually</strong></h3><p>The structure now becomes:</p><pre><code><code>X25519 shared secret
        |
        v
      HKDF
        |
        v
  session key material
        |
        v
 protected application data
</code></code></pre><p>This is an important shift.</p><p>Before this step, the handshake produced something secret and we could have stopped there.</p><p>After this step, the handshake produces an <em>input</em> to a key schedule.</p><p>That is a much better protocol design.</p><h3><strong>Why this matters</strong></h3><p>There are two main reasons to do this.</p><h3><strong>1. The raw shared secret is handshake output, not final protocol state</strong></h3><p>The shared secret is the result of key exchange. That does not automatically mean it should be used directly as the application-data key.</p><p>Protocols usually want a cleaner boundary:</p><ul><li><p>handshake result first</p></li><li><p>working keys second</p></li></ul><h3><strong>2. We can derive keys for different purposes</strong></h3><p>Once we introduce a key-derivation step, we are no longer forced into &#8220;one secret for everything.&#8221;</p><p>Even in this toy protocol, that opens the door to a much more realistic design.</p><p>For example, instead of one single AEAD key, we can derive:</p><ul><li><p>client &#8594; server key</p></li><li><p>server &#8594; client key</p></li></ul><p>That is already much closer to how real secure protocols think.</p><div><hr></div><h3><strong>Deriving the keys</strong></h3><p>In the current implementation, HKDF takes the X25519 shared secret and stretches it into 64 bytes of key material.</p><p>Then that material is split into two 32-byte keys:</p><ul><li><p>one for traffic from client to server</p></li><li><p>one for traffic from server to client</p></li></ul><p>That gives us directional keys instead of one shared application key for both directions.</p><p>Here is the key schedule:</p><pre><code><code># key_schedule_x25519.py
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF

def derive_session_keys(shared_secret: bytes) -&gt; tuple[bytes, bytes]:
    key_material = HKDF(
        algorithm=hashes.SHA256(),
        length=64,
        salt=None,
        info=b"toy-tls-part-3-x25519",
    ).derive(shared_secret)

    client_to_server_key = key_material[:32]
    server_to_client_key = key_material[32:]

    return client_to_server_key, server_to_client_key
</code></code></pre><p>I like this step a lot because it is small in code, but it changes the protocol mindset in an important way.</p><p>We are no longer thinking:</p><blockquote><p>handshake gives us the key</p></blockquote><p>We are now thinking:</p><blockquote><p>handshake gives us secret material, and the protocol derives the keys it actually wants to use</p></blockquote><p>That is a much stronger model.</p><h3><strong>A small but important detail</strong></h3><p>Notice that the two sides must interpret the derived keys consistently.</p><p>If the client treats the first 32 bytes as the client &#8594; server key, then the server must do the same. Otherwise the channel will immediately break.</p><p>So now the handshake is not only producing shared secret material. It is also establishing a shared rule for how that material becomes working traffic keys.</p><p>That is another reason protocols need structure, not just primitives.</p><div><hr></div><h2><strong>Connecting HKDF back to the record layer</strong></h2><p>Now we can finally connect this part back to what we built earlier.</p><p>In Part 2, we already built an AEAD-protected record layer. But that record layer still depended on hardcoded keys.</p><p>Now that changes.</p><p>The AEAD layer no longer starts with a static key from configuration.</p><p>It receives fresh traffic keys from the handshake.</p><p>So the protocol shape becomes:</p><pre><code><code>Handshake -&gt; X25519 shared secret -&gt; HKDF -&gt; directional session keys -&gt; AEAD protected records
</code></code></pre><p>That is a major milestone in the series.</p><p>At this point, the protocol no longer just looks secure because we wrapped some bytes in encryption. It now has a real high-level structure:</p><ul><li><p>first establish shared key material</p></li><li><p>then derive traffic keys</p></li><li><p>then use those keys to protect application data</p></li></ul><p>That is already much closer to the shape of real TLS.</p><div><hr></div><h2><strong>Using the new session keys</strong></h2><p>Once the keys are derived, the record layer can use them directly.</p><p>Conceptually, the flow now looks like this:</p><h3><strong>Client</strong></h3><pre><code><code>with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
    client.connect((HOST, PORT))
    print(f"Connected to {HOST}:{PORT}")

    # ==========================================
    # PHASE 1: HANDSHAKE
    # ==========================================
    # New in Part 3: the handshake dynamically establishes session keys.
    # No pre-shared secret needed.
    client_write_key, server_write_key = client_handshake(client)

    # ==========================================
    # PHASE 2: APPLICATION DATA
    # ==========================================
    # The record layer now uses HKDF-derived keys instead of hardcoded ones.
    # The record format is the same as Part 2 Stage 3 (AEAD).

    # --- Send request (encrypted with client_write_key) ---
    protected = protect_record(client_write_key, send_seq, request)
    send_record(client, protected)
    send_seq += 1

    # --- Receive response (decrypted with server_write_key) ---
    raw_response = recv_record(client)

    try:
        response = unprotect_record(server_write_key, recv_seq, raw_response)
        recv_seq += 1
        print(f"\\n  Decrypted response:\\n  {response.decode('utf-8')}")
    except Exception as e:
        print(f"\\n  *** REJECTED: {e} ***")

print("\\nDone.")
</code></code></pre><ul><li><p>use client_write_key to protect outgoing application data</p></li><li><p>use server_write_key to unprotect incoming application data</p></li></ul><h3><strong>Server</strong></h3><pre><code><code>with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind((HOST, PORT))
    server.listen(1)
    print(f"Listening on {HOST}:{PORT}")

    conn, addr = server.accept()
    with conn:
        # ==========================================
        # PHASE 1: HANDSHAKE
        # ==========================================
        client_write_key, server_write_key = server_handshake(conn)

        # ==========================================
        # PHASE 2: APPLICATION DATA
        # ==========================================

        # --- Receive request (decrypted with client_write_key) ---
        raw_request = recv_record(conn)

        try:
            request = unprotect_record(client_write_key, recv_seq, raw_request)
            recv_seq += 1
        except Exception as e:
            print(f"\\n  *** REJECTED: {e} ***")
            print("  Connection closed &#8212; refusing to process invalid data.")
        else:

            # --- Send response (encrypted with server_write_key) ---
            response = (
                "HTTP/1.1 200 OK\\r\\n"
                "Content-Type: text/plain\\r\\n"
                "Content-Length: 13\\r\\n\\r\\n"
                "hello, client"
            ).encode("utf-8")

            protected = protect_record(server_write_key, send_seq, response)
            send_record(conn, protected)
            send_seq += 1

print("\\nDone.")

</code></code></pre><ul><li><p>use client_write_key to unprotect incoming client traffic</p></li><li><p>use server_write_key to protect outgoing server traffic</p></li></ul><p>That means the two directions are now separated.</p><p>This is cleaner than one symmetric application key shared blindly by both directions, and it makes the protocol feel more deliberate.</p><p>Even in this simplified version, that is a meaningful step.</p><div><hr></div><h2><strong>What this step really gave us</strong></h2><p>By adding HKDF, we improved the protocol in a way that is easy to underestimate.</p><p>We did not just &#8220;derive another key.&#8221;</p><p>We made the protocol architecture cleaner.</p><p>Now the handshake and the traffic layer are connected in a more principled way:</p><ul><li><p>the handshake creates shared secret material</p></li><li><p>the key schedule turns that material into working keys</p></li><li><p>the record layer consumes those keys</p></li></ul><p>This is a much better model than treating the raw X25519 result as the final answer.</p><p>And it brings us one step closer to real TLS, where key derivation is not an optional detail, but one of the central pieces of the protocol design.</p><div><hr></div><h2><strong>But we are still not secure</strong></h2><p>And now we arrive at the uncomfortable but necessary part.</p><p>Even with:</p><ul><li><p>a real handshake</p></li><li><p>X25519</p></li><li><p>HKDF</p></li><li><p>fresh directional session keys</p></li><li><p>AEAD-protected records</p></li></ul><p>the protocol still cannot be considered secure enough.</p><p>Why?</p><p>Because all of this still says nothing about <strong>who</strong> is on the other side.</p><p>The handshake can successfully create shared secrets.</p><p>HKDF can successfully derive traffic keys.</p><p>The record layer can successfully protect application data.</p><p>And an attacker can still sit in the middle and run two separate handshakes.</p><p>That is the next lesson.</p><div><hr></div><h2><strong>Still Not Secure &#8212; The Man-in-the-Middle Problem</strong></h2><p>At this point, our protocol already looks much more serious than the one we started with.</p><p>We now have:</p><ul><li><p>a real handshake</p></li><li><p>fresh shared secrets</p></li><li><p>X25519 instead of a pre-shared application key</p></li><li><p>HKDF-derived session keys</p></li><li><p>AEAD-protected application records</p></li></ul><p>That is a long way from the fake secure channel in Part 1.</p><p>But it is still not enough.</p><p>The missing piece is one of the most important ideas in this whole series:</p><p><strong>key exchange is not authentication</strong></p><p>That sentence is easy to read quickly and move on from. But it is worth stopping here, because this is exactly where many protocols fail.</p><p>Our handshake proves that both sides can derive the same shared secret.</p><p>What it does <strong>not</strong> prove is:</p><p><strong>who</strong> is actually on the other side.</p><p>And that difference is the whole problem.</p><h3><strong>The attack</strong></h3><p>Imagine an active attacker sitting between the client and the server.</p><p>Let&#8217;s call her Mallory.</p><p>The client thinks it is talking to the server.</p><p>The server thinks it is talking to the client.</p><p>But Mallory intercepts the handshake and replaces the exchanged public keys with her own.</p><p>In simplified form, the flow looks like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uLbh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed534692-c29b-4fb3-8154-428e9f5cf001_2525x2776.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uLbh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed534692-c29b-4fb3-8154-428e9f5cf001_2525x2776.png 424w, https://substackcdn.com/image/fetch/$s_!uLbh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed534692-c29b-4fb3-8154-428e9f5cf001_2525x2776.png 848w, https://substackcdn.com/image/fetch/$s_!uLbh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed534692-c29b-4fb3-8154-428e9f5cf001_2525x2776.png 1272w, https://substackcdn.com/image/fetch/$s_!uLbh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed534692-c29b-4fb3-8154-428e9f5cf001_2525x2776.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uLbh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed534692-c29b-4fb3-8154-428e9f5cf001_2525x2776.png" width="1456" height="1601" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ed534692-c29b-4fb3-8154-428e9f5cf001_2525x2776.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1601,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:556263,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/194707545?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed534692-c29b-4fb3-8154-428e9f5cf001_2525x2776.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uLbh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed534692-c29b-4fb3-8154-428e9f5cf001_2525x2776.png 424w, https://substackcdn.com/image/fetch/$s_!uLbh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed534692-c29b-4fb3-8154-428e9f5cf001_2525x2776.png 848w, https://substackcdn.com/image/fetch/$s_!uLbh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed534692-c29b-4fb3-8154-428e9f5cf001_2525x2776.png 1272w, https://substackcdn.com/image/fetch/$s_!uLbh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed534692-c29b-4fb3-8154-428e9f5cf001_2525x2776.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>And now something very important happens.</p><p>The handshake still &#8220;works.&#8221;</p><p>But it works in the wrong way.</p><ul><li><p>the <strong>client</strong> ends up with a shared secret with <strong>Mallory</strong></p></li><li><p>the <strong>server</strong> ends up with a different shared secret with <strong>Mallory</strong></p></li><li><p>and <strong>Mallory</strong> now has one valid secure channel to each side</p></li></ul><p>From the point of view of the client and the server, everything looks normal:</p><ul><li><p>key exchange succeeded</p></li><li><p>keys were derived</p></li><li><p>encrypted records verify correctly</p></li><li><p>AEAD tags are valid</p></li></ul><p>And yet the protocol has already failed.</p><p>Because Mallory can now:</p><ol><li><p>decrypt the client&#8217;s traffic</p></li><li><p>read it or modify it</p></li><li><p>re-encrypt it toward the server</p></li><li><p>receive the server&#8217;s response</p></li><li><p>read it or modify it</p></li><li><p>re-encrypt it back toward the client</p></li></ol><p>Neither side can detect this.</p><h3><strong>In The Next Article &#8212; Building the Certificate Infrastructure</strong></h3><p>The handshake only proves one thing:</p><blockquote><p>&#8220;I computed a shared secret with whoever sent me this public key.&#8221;</p></blockquote><p>It does <strong>not</strong> prove:</p><blockquote><p>&#8220;This public key came from the server I actually intended to talk to.&#8221;</p></blockquote><p>That is the missing half.</p><p>To fix this, the client needs a way to verify that the public key it receives during the handshake actually belongs to the server it wanted to talk to.</p><p>That is where the next layer enters:</p><ul><li><p>certificates</p></li><li><p>signatures</p></li><li><p>trust chains</p></li><li><p>certificate authorities</p></li></ul><p>In other words, this is where the protocol must stop proving only that &#8220;someone&#8221; is there and start proving <strong>who</strong> that someone is.</p><p>That is exactly what the next article will build.</p><h3>Summary</h3><p>Our protocol now has secrecy against passive observers.</p><p>It has integrity for protected records.</p><p>It has fresh session keys.</p><p>But it still does not have <strong>identity</strong>.</p><p>And without identity, a correct shared secret with the wrong party is still a protocol failure.</p><p>That is the deeper lesson of Part 3.</p><p>Part 1 taught us:</p><p><strong>confidentiality is not integrity</strong></p><p>Part 2 taught us:</p><p><strong>protecting records is not the same thing as establishing trust</strong></p><p>And now Part 3 adds the next lesson:</p><p><strong>key exchange is not authentication</strong></p><p>That we will solve in the next article!</p><h2><strong>Final Code</strong></h2><p>The full code for this part is available here:</p><p><strong>GitHub:</strong> <a href="https://github.com/DmytroHuzz/rebuilding_tls/tree/main/part_3">https://github.com/DmytroHuzz/rebuilding_tls/tree/main/part_3</a></p><h2>Next article</h2><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;ed1112e7-0049-4193-bb7e-ec60ded31368&quot;,&quot;caption&quot;:&quot;Previous Article:&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Rebuilding TLS, Part 4 - Certificates and Trust&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software Engineer in the Energy Sector. AWS Community Builder (Dev Tools). (Re)building core tech in public &#8212; so it stop feeling like magic. Writing at Rebuilt.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-04-26T20:24:36.572Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!HYYb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/rebuilding-tls-part-4-certificates&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:195558698,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dmytro&#8217;s Substack is a reader-supported publication. To receive new posts and support my work, consider becoming a subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Rebuilding TLS, Part 2 — Adding Integrity to the Channel]]></title><description><![CDATA[We teach our protocol to detect tampering, make records less naive with sequence numbers, and then switch to the AEAD style used in real systems.]]></description><link>https://www.dmytrohuz.com/p/rebuilding-tls-part-2-adding-integrity</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/rebuilding-tls-part-2-adding-integrity</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Sun, 05 Apr 2026 21:40:43 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!78kv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!78kv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!78kv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!78kv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!78kv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!78kv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!78kv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3423615,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/193281237?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!78kv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!78kv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!78kv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!78kv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In the first part of this series, we built our first fake secure channel:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;0e21ae64-25bc-4008-8f34-84996112a315&quot;,&quot;caption&quot;:&quot;A year ago I wrote a series about how a web server works.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Rebuilding TLS, Part 1 &#8212; Why Encryption Alone Is Not Enough&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Engineer | Writer | Builder - I deconstruct complex systems to first principles and rebuild them into clear engineering mental models, diagrams, and practical tools.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-03-29T18:57:36.417Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!5phz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/rebuilding-tls-part-1-why-encryption&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:192533658,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:3,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Dmytro&#8217;s Substack&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!t_-c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F046f0d8c-fecd-41e6-a43f-4718cf07a50f_608x608.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>We took a simple socket-based client and server, wrapped their communication in AES-CTR with a shared secret key, and got something that already looked much more serious than plain TCP. The traffic stopped being transparent. A passive observer could no longer read the request and response directly.</p><p>That was real progress.</p><p>But it still had a fatal flaw.</p><p>The receiver had no way to know whether the encrypted message had been changed on the way.</p><p>Encryption hid the bytes.</p><p>It did not protect their meaning.</p><p>So in this part, we will fix that.</p><p>We will first add a <strong>MAC</strong> so the receiver can detect tampering. Then we will make the record layer a little less naive by adding a sequence number. And after that, we will take one more step toward the real world and move to <strong>AEAD</strong>, because that is how modern secure protocols usually protect records.</p><p>We still will not have real TLS when we are done.</p><p>But we will have a much more serious record layer than the one from Part 1.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dmytro&#8217;s Substack is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>What we will build in this part</h2><p>The plan for this article is simple:</p><ul><li><p>briefly introduce MACs</p></li><li><p>add HMAC to our encrypted record format</p></li><li><p>make tampering detectable</p></li><li><p>add a sequence number to each record</p></li><li><p>explain why sequence numbers matter</p></li><li><p>then move from our hand-built &#8220;encrypt + MAC&#8221; construction to AEAD, because that is the approach real systems usually use</p></li></ul><p>Just like in Part 1, I want to keep the pattern simple:</p><ul><li><p>explain the idea</p></li><li><p>show the code</p></li><li><p>explain what changed</p></li><li><p>explain what is still broken</p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2>Why encryption still was not enough</h2><p>At the end of Part 1, our protocol already had one real property:</p><ul><li><p>confidentiality against passive observers</p></li></ul><p>That mattered.</p><p>But it still failed against active attackers.</p><p>Because AES-CTR by itself does not provide integrity, an attacker could modify ciphertext and the receiver would still decrypt it and trust the result. That was the main lesson of the first article:</p><p><strong>confidentiality is not integrity</strong></p><p>So the next missing property is obvious.</p><p>The receiver needs a way to verify that the message arrived unchanged.</p><p>That is what a MAC gives us.</p><div><hr></div><h2>A very short note on MACs</h2><p>MAC stands for <strong>Message Authentication Code</strong>.</p><p>Very roughly, it is a cryptographic tag computed over a message using a secret key.</p><p>The sender computes the tag and sends it together with the message.</p><p>The receiver recomputes the tag and compares it with the one that was received.</p><p>If the tags match, the receiver can trust that:</p><ul><li><p>the message was not modified</p></li><li><p>and it was created by someone who knows the MAC key</p></li></ul><p>If the tags do not match, the message must be rejected.</p><p>In this article, we will use <strong>HMAC-SHA256</strong>.</p><blockquote><p>I do not want to go too deep into HMAC itself here, because the goal of this series is to understand TLS as a protocol. But if you want a deeper explanation of MACs and HMAC, I already wrote about them in my cryptography series, and I&#8217;ll link that here.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;f1db8dab-a8e3-4f94-98bd-6e31e78a717d&quot;,&quot;caption&quot;:&quot;In the previous article, we did something slightly ridiculous.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Building Own MAC &#8212; Part 3: Reinventing HMAC from SHA-256&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Engineer | Writer | Builder - I deconstruct complex systems to first principles and rebuild them into clear engineering mental models, diagrams, and practical tools.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-01-23T18:58:16.766Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!QAi6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41bb1c89-ee6c-4240-9150-0469a12ab722_1536x672.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/building-own-mac-part-3-reinventing&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:185566303,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:3,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Dmytro&#8217;s Substack&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!t_-c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F046f0d8c-fecd-41e6-a43f-4718cf07a50f_608x608.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div></blockquote><p>So for our purposes, the important idea is simple:</p><p><strong>encryption hides the message</strong></p><p><strong>MAC protects the message from silent modification</strong></p><p>That is the missing half we need.</p><div><hr></div><h2>Adding HMAC to the channel</h2><p>Let&#8217;s start by upgrading the record format from Part 1.</p><p>In Part 1, our protected payload was basically:</p><pre><code><code>nonce || ciphertext</code></code></pre><p>Now we will add a MAC tag:</p><pre><code><code>nonce || ciphertext || tag</code></code></pre><p>And the sender will compute the HMAC over:</p><pre><code><code>nonce || ciphertext</code></code></pre><p>So the full logic becomes:</p><h3>Sender</h3><ol><li><p>encrypt plaintext with AES-CTR</p></li><li><p>compute HMAC over <code>nonce || ciphertext</code></p></li><li><p>send <code>nonce || ciphertext || tag</code></p></li></ol><h3>Receiver</h3><ol><li><p>read <code>nonce || ciphertext || tag</code></p></li><li><p>recompute HMAC over <code>nonce || ciphertext</code></p></li><li><p>compare tags</p></li><li><p>only if they match, decrypt the ciphertext</p></li><li><p>otherwise reject the message</p></li></ol><p>There is one more small improvement I want to make here.</p><p>Instead of using one key for everything, we will already separate them:</p><ul><li><p>one key for encryption</p></li><li><p>one key for HMAC</p></li></ul><p>This is still a toy setup, but it is better design than reusing the same bytes for every cryptographic job.</p><h3>HMAC helpers</h3><pre><code><code>import os
import hmac
import hashlib

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

# ---------------------------------------------------------------------------
# Keys &#8212; hardcoded for educational purposes.
# In a real protocol, these would be derived from a key exchange (e.g.,
# Diffie-Hellman), not embedded in source code.
# ---------------------------------------------------------------------------

# 32-byte (256-bit) key for AES-256-CTR encryption.
ENC_KEY = b"0123456789ABCDEF0123456789ABCDEF"

# 32-byte key for HMAC-SHA256.  Separate from the encryption key.
MAC_KEY = b"HMAC_KEY_FOR_PART2_DEMO_1234567"

# HMAC-SHA256 produces a 32-byte (256-bit) tag.
TAG_LEN = 32

# AES-CTR nonce is 16 bytes (128 bits).
NONCE_LEN = 16

def encrypt_then_mac(plaintext: bytes) -&gt; bytes:
    """Encrypt a plaintext and append an HMAC tag.

    Returns: nonce (16 B) || ciphertext (N B) || tag (32 B)
    """

    # Step 1: Generate a fresh random nonce for AES-CTR.
    # A new nonce MUST be used for every record &#8212; reusing a nonce with
    # the same key completely breaks CTR-mode security.
    nonce = os.urandom(NONCE_LEN)

    # Step 2: Encrypt the plaintext with AES-256-CTR.
    cipher = Cipher(algorithms.AES(ENC_KEY), modes.CTR(nonce))
    encryptor = cipher.encryptor()
    ciphertext = encryptor.update(plaintext) + encryptor.finalize()

    # Step 3: Compute HMAC-SHA256 over (nonce || ciphertext).
    # New in Part 2: we authenticate the encrypted record before sending it.
    # The HMAC input includes the nonce so an attacker cannot swap nonces
    # between records without detection.
    mac_input = nonce + ciphertext
    tag = hmac.new(MAC_KEY, mac_input, hashlib.sha256).digest()

    print(f"  [crypto_hmac] encrypt_then_mac:")
    print(f"    nonce    = {nonce.hex()[:32]}...")
    print(f"    ct_len   = {len(ciphertext)} bytes")
    print(f"    tag      = {tag.hex()[:32]}...")

    # Step 4: Assemble the wire format.
    return nonce + ciphertext + tag

def verify_then_decrypt(payload: bytes) -&gt; bytes:
    """Verify the HMAC tag, then decrypt if valid.

    Expects: nonce (16 B) || ciphertext (N B) || tag (32 B)
    Raises ValueError if the tag does not match.
    """

    # Step 1: Parse the record into its components.
    # The tag is always the last 32 bytes.  The nonce is the first 16.
    # Everything in between is ciphertext.
    if len(payload) &lt; NONCE_LEN + TAG_LEN:
        raise ValueError("Record too short to contain nonce + tag")

    nonce = payload[:NONCE_LEN]
    ciphertext = payload[NONCE_LEN:-TAG_LEN]
    received_tag = payload[-TAG_LEN:]

    # Step 2: Recompute the HMAC over (nonce || ciphertext).
    mac_input = nonce + ciphertext
    expected_tag = hmac.new(MAC_KEY, mac_input, hashlib.sha256).digest()

    # Step 3: Compare tags using constant-time comparison.
    # hmac.compare_digest() prevents timing side-channel attacks.
    # A naive `==` comparison can leak information about which byte
    # position differs first, allowing an attacker to forge a valid
    # tag byte by byte.
    if not hmac.compare_digest(received_tag, expected_tag):
        print("  [crypto_hmac] *** MAC VERIFICATION FAILED &#8212; record rejected ***")
        raise ValueError("HMAC verification failed &#8212; record has been tampered with")

    print("  [crypto_hmac] MAC verification: OK")

    # Step 4: Decrypt only after verification succeeds.
    # This is the key benefit of encrypt-then-MAC: we never process
    # unauthenticated ciphertext.
    cipher = Cipher(algorithms.AES(ENC_KEY), modes.CTR(nonce))
    decryptor = cipher.decryptor()
    plaintext = decryptor.update(ciphertext) + decryptor.finalize()

    return plaintext</code></code></pre><p>This is the first big improvement over Part 1.</p><p>The important change is not just that we added a tag.</p><p>It is that the receiver no longer blindly trusts ciphertext and only then discovers what it means. Now the receiver first checks whether the record is authentic and unchanged.</p><p>That is a very different protocol posture.</p><div><hr></div><h2>Updating the client and server</h2><p>Now let&#8217;s plug this into the channel.</p><h3>HMAC-based client</h3><pre><code><code>import socket

from framing import send_record, recv_record
from crypto_hmac import encrypt_then_mac, verify_then_decrypt

HOST = "127.0.0.1"
PORT = 9001

# A toy HTTP-like request &#8212; same spirit as Part 1.
request = (
    "GET /transfer?to=bob&amp;amount=100 HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n"
).encode("utf-8")

print("=" * 60)
print("Part 2 &#8212; HMAC Client (encrypt-then-MAC)")
print("=" * 60)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
    client.connect((HOST, PORT))
    print(f"Connected to {HOST}:{PORT}")

    # ----- SEND REQUEST -----
    print("\\n--- Sending request ---")
    protected = encrypt_then_mac(request)
    send_record(client, protected)
    print(f"  Record sent ({len(protected)} bytes on wire)")

    # ----- RECEIVE RESPONSE -----
    print("\\n--- Receiving response ---")
    raw_response = recv_record(client)
    response = verify_then_decrypt(raw_response)
    print(f"\\n  Decrypted response:\\n  {response.decode('utf-8')}")

print("\\nDone.")</code></code></pre><h3>HMAC-based server</h3><pre><code><code>import socket

from framing import send_record, recv_record
from crypto_hmac import encrypt_then_mac, verify_then_decrypt

HOST = "127.0.0.1"
PORT = 9001

print("=" * 60)
print("Part 2 &#8212; HMAC Server (encrypt-then-MAC)")
print("=" * 60)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
    # SO_REUSEADDR lets us restart the server immediately without waiting
    # for the OS to release the port from TIME_WAIT state.
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind((HOST, PORT))
    server.listen(1)
    print(f"Listening on {HOST}:{PORT}")

    conn, addr = server.accept()
    with conn:
        print(f"Connected by {addr}")

        # ----- RECEIVE REQUEST -----
        print("\\n--- Receiving request ---")
        raw_request = recv_record(conn)

        try:
            request = verify_then_decrypt(raw_request)
        except ValueError as e:
            # New in Part 2: if the MAC fails, we reject the record loudly.
            # In Part 1 we had no way to detect tampering at all.
            print(f"\\n  *** REJECTED: {e} ***")
            print("  Connection closed &#8212; refusing to process tampered data.")
        else:
            print(f"\\n  Decrypted request:\\n  {request.decode('utf-8')}")

            # ----- SEND RESPONSE -----
            print("--- Sending response ---")
            response = (
                "HTTP/1.1 200 OK\\r\\n"
                "Content-Type: text/plain\\r\\n"
                "Content-Length: 13\\r\\n\\r\\n"
                "hello, client"
            ).encode("utf-8")

            protected = encrypt_then_mac(response)
            send_record(conn, protected)
            print(f"  Record sent ({len(protected)} bytes on wire)")

print("\\nDone.")</code></code></pre><p>The shape of the channel is still familiar.</p><p>That matters.</p><p>We did not replace the whole design.</p><p>We strengthened one missing property.</p><p>That is how protocol evolution should feel.</p><div><hr></div><h4>Let&#8217;s check it on the wire.</h4><p>We try to start the server and client, which we just created.</p><p>Here is our client request&#8217;s data.</p><pre><code><code>-- Sending request ---
[crypto_hmac] encrypt_then_mac:
nonce = 387f0065f8915133473597d8cef15f34...
ct_len = 61 bytes
tag = b7f0db369e5d2a221a18f2d167b5b3a8...
Record sent (109 bytes on wire)
</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JQ4z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bdddd6f-33a6-499c-b25f-e4d43ecbae2d_2880x1620.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JQ4z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bdddd6f-33a6-499c-b25f-e4d43ecbae2d_2880x1620.png 424w, https://substackcdn.com/image/fetch/$s_!JQ4z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bdddd6f-33a6-499c-b25f-e4d43ecbae2d_2880x1620.png 848w, https://substackcdn.com/image/fetch/$s_!JQ4z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bdddd6f-33a6-499c-b25f-e4d43ecbae2d_2880x1620.png 1272w, https://substackcdn.com/image/fetch/$s_!JQ4z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bdddd6f-33a6-499c-b25f-e4d43ecbae2d_2880x1620.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JQ4z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bdddd6f-33a6-499c-b25f-e4d43ecbae2d_2880x1620.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1bdddd6f-33a6-499c-b25f-e4d43ecbae2d_2880x1620.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:651773,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/193281237?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bdddd6f-33a6-499c-b25f-e4d43ecbae2d_2880x1620.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JQ4z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bdddd6f-33a6-499c-b25f-e4d43ecbae2d_2880x1620.png 424w, https://substackcdn.com/image/fetch/$s_!JQ4z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bdddd6f-33a6-499c-b25f-e4d43ecbae2d_2880x1620.png 848w, https://substackcdn.com/image/fetch/$s_!JQ4z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bdddd6f-33a6-499c-b25f-e4d43ecbae2d_2880x1620.png 1272w, https://substackcdn.com/image/fetch/$s_!JQ4z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1bdddd6f-33a6-499c-b25f-e4d43ecbae2d_2880x1620.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><p></p><h2>Detecting tampering</h2><p>Now let&#8217;s revisit the failure from Part 1.</p><p>Previously, if someone modified the ciphertext, the receiver would still decrypt it and accept modified plaintext.</p><p>Now that should no longer work.</p><p>Here is a tiny tampering demo:</p><pre><code><code># tampering_demo_hmac.py
from crypto_hmac import encrypt_then_mac, verify_then_decrypt

original = b"amount=100"
protected = encrypt_then_mac(original)

tampered = bytearray(protected)
tampered[20] ^= 0x08  # flip one bit somewhere in the encrypted body

try:
    result = verify_then_decrypt(bytes(tampered))
    print("Unexpected success:", result)
except ValueError as e:
    print("Tampering detected:", e)
</code></code></pre><p>Now the result should be rejection, not silent acceptance.</p><p>That is exactly what we wanted.</p><p>This is the moment where our channel stops being merely &#8220;encrypted&#8221; and starts being &#8220;protected.&#8221;</p><p>Because now the receiver does not just recover bytes. It verifies them first.</p><p>That is a serious step.</p><div><hr></div><h2>Why we also need a sequence number</h2><p>At this point, we fixed the big flaw from Part 1: silent tampering.</p><p>But the record layer is still naive.</p><p>Why?</p><p>Because even with a valid HMAC, the receiver still has no sense of record position or freshness.</p><p>Imagine an attacker records one valid protected message and sends it again later.</p><p>The HMAC is still valid.</p><p>The ciphertext is still valid.</p><p>And unless the receiver keeps some state, it may accept the same record again.</p><p>That means integrity alone is not the whole story.</p><p>We also need some sense of:</p><ul><li><p>order</p></li><li><p>position</p></li><li><p>repetition</p></li><li><p>replay</p></li></ul><p>This is where sequence numbers come in.</p><p>A sequence number is just a counter that increases with every record:</p><ul><li><p>first record = 0</p></li><li><p>next = 1</p></li><li><p>next = 2</p></li><li><p>and so on</p></li></ul><p>We then include that sequence number in the authenticated data, so the receiver does not just verify &#8220;these bytes were protected,&#8221; but also &#8220;these bytes belong in this position in the stream.&#8221;</p><p>That makes the record layer much less naive.</p><p>It still does not solve every replay problem in every possible system. But for our toy protocol, it is a very good next step.</p><div><hr></div><h2>Updating the record format</h2><p>Now our record becomes:</p><pre><code><code>seq || nonce || ciphertext || tag
</code></code></pre><p>And our HMAC input becomes:</p><pre><code><code>seq || nonce || ciphertext
</code></code></pre><p>So the sender and receiver now both need a little bit of state:</p><ul><li><p>the sender tracks the next sequence number to send</p></li><li><p>the receiver tracks the next sequence number it expects</p></li></ul><p>This is one of those moments where secure transport starts looking more like a real protocol and less like &#8220;some crypto around a socket.&#8221;</p><h3>Sequence-aware HMAC helper</h3><pre><code><code># crypto_hmac_seq.py
import os
import hmac
import hashlib
import struct

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

# ---------------------------------------------------------------------------
# Keys &#8212; same as crypto_hmac.py, hardcoded for education.
# ---------------------------------------------------------------------------
ENC_KEY = b"0123456789ABCDEF0123456789ABCDEF"
MAC_KEY = b"HMAC_KEY_FOR_PART2_DEMO_1234567"

TAG_LEN = 32  # HMAC-SHA256 output: 32 bytes (256 bits)
NONCE_LEN = 16  # AES-CTR nonce: 16 bytes (128 bits)
SEQ_LEN = 8  # Sequence number: 8 bytes (64-bit unsigned integer)

def protect_record(seq: int, plaintext: bytes) -&gt; bytes:
    """Encrypt a plaintext record and attach a sequence-aware HMAC tag.

    Args:
        seq:       The current send-side sequence number (0, 1, 2, &#8230;).
        plaintext: The message to protect.

    Returns:
        seq (8 B) || nonce (16 B) || ciphertext (N B) || tag (32 B)
    """

    # Pack the sequence number as an 8-byte big-endian unsigned integer.
    # "!Q" = network byte order, unsigned 64-bit.
    seq_bytes = struct.pack("!Q", seq)

    # Generate a fresh AES-CTR nonce.
    nonce = os.urandom(NONCE_LEN)

    # Encrypt the plaintext.
    cipher = Cipher(algorithms.AES(ENC_KEY), modes.CTR(nonce))
    encryptor = cipher.encryptor()
    ciphertext = encryptor.update(plaintext) + encryptor.finalize()

    # Compute HMAC over (seq || nonce || ciphertext).
    # The sequence number is included in the MAC input so the integrity
    # check also covers record order/position in the stream.
    mac_input = seq_bytes + nonce + ciphertext
    tag = hmac.new(MAC_KEY, mac_input, hashlib.sha256).digest()

    return seq_bytes + nonce + ciphertext + tag

def verify_and_unprotect(expected_seq: int, payload: bytes) -&gt; bytes:
    """Verify the HMAC and sequence number, then decrypt.

    Args:
        expected_seq: The sequence number the receiver expects next.
        payload:      The raw bytes received: seq || nonce || ct || tag.

    Returns:
        The decrypted plaintext.

    Raises:
        ValueError if the MAC is invalid or the sequence number is wrong.
    """

    min_len = SEQ_LEN + NONCE_LEN + TAG_LEN
    if len(payload) &lt; min_len:
        raise ValueError("Record too short")

    # Step 1: Parse the record.
    seq_bytes = payload[:SEQ_LEN]
    nonce = payload[SEQ_LEN : SEQ_LEN + NONCE_LEN]
    ciphertext = payload[SEQ_LEN + NONCE_LEN : -TAG_LEN]
    received_tag = payload[-TAG_LEN:]

    # Step 2: Recompute HMAC over (seq || nonce || ciphertext).
    mac_input = seq_bytes + nonce + ciphertext
    expected_tag = hmac.new(MAC_KEY, mac_input, hashlib.sha256).digest()

    # Step 3: Constant-time tag comparison.
    if not hmac.compare_digest(received_tag, expected_tag):
        print("  [crypto_hmac_seq] *** MAC VERIFICATION FAILED ***")
        raise ValueError("HMAC verification failed &#8212; record tampered or replayed")

    print("  [crypto_hmac_seq] MAC verification: OK")

    # Step 4: Check the sequence number matches what we expect.
    # Even though the MAC already covers the sequence number (so an
    # attacker cannot change it without invalidating the MAC), we still
    # explicitly verify that it matches our counter.  This catches
    # replayed or reordered records that carry a valid MAC but belong
    # to a different position in the stream.
    (received_seq,) = struct.unpack("!Q", seq_bytes)
    if received_seq != expected_seq:
        print(
            f"  [crypto_hmac_seq] *** SEQUENCE MISMATCH: "
            f"got {received_seq}, expected {expected_seq} ***"
        )
        raise ValueError(
            f"Sequence number mismatch: got {received_seq}, expected {expected_seq}"
        )

    print(
        f"  [crypto_hmac_seq] Sequence number: {received_seq} (expected {expected_seq}) &#8212; OK"
    )

    # Step 5: Decrypt.
    cipher = Cipher(algorithms.AES(ENC_KEY), modes.CTR(nonce))
    decryptor = cipher.decryptor()
    plaintext = decryptor.update(ciphertext) + decryptor.finalize()

    return plaintext

</code></code></pre><p>And now the channel has a bit more memory.</p><p>Not just &#8220;is this record authentic?&#8221;</p><p>But also &#8220;is this the record I expected next?&#8221;</p><p>That is a real protocol improvement.</p><div><hr></div><h2>Updating the client and server</h2><p>Now let&#8217;s plug this into the channel.</p><h3>Sequence-aware HMAC-based client</h3><pre><code><code># client_v2_hmac_seq.py
import socket

from framing import send_record, recv_record
from crypto_hmac_seq import protect_record, verify_and_unprotect

HOST = "127.0.0.1"
PORT = 9003

# Sequence counters &#8212; sender and receiver each maintain their own.
# The sender increments after each record sent.
# The receiver expects consecutive values starting from 0.
send_seq = 0
recv_seq = 0

# A toy HTTP-like request &#8212; same spirit as Part 1.
request = (
    "GET /transfer?to=bob&amp;amount=100 HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n"
).encode("utf-8")

print("=" * 60)
print("Part 2 &#8212; HMAC + Sequence Numbers Client (Stage 2)")
print("=" * 60)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
    client.connect((HOST, PORT))
    print(f"Connected to {HOST}:{PORT}")

    # ----- SEND REQUEST -----
    print(f"\\n--- Sending request (send_seq={send_seq}) ---")
    protected = protect_record(send_seq, request)
    send_record(client, protected)
    send_seq += 1
    print(f"  Record sent ({len(protected)} bytes on wire)")

    # ----- RECEIVE RESPONSE -----
    print(f"\\n--- Receiving response (expecting recv_seq={recv_seq}) ---")
    raw_response = recv_record(client)

    try:
        response = verify_and_unprotect(recv_seq, raw_response)
        recv_seq += 1
        print(f"\\n  Decrypted response:\\n  {response.decode('utf-8')}")
    except ValueError as e:
        print(f"\\n  *** REJECTED: {e} ***")

print("\\nDone.")

</code></code></pre><h3>Sequence-aware HMAC-based server</h3><pre><code><code># server_v2_hmac_seq.py
import socket

from framing import send_record, recv_record
from crypto_hmac_seq import protect_record, verify_and_unprotect

HOST = "127.0.0.1"
PORT = 9003

# Sequence counters.
# The server's recv_seq tracks the client's send_seq, and vice versa.
send_seq = 0
recv_seq = 0

print("=" * 60)
print("Part 2 &#8212; HMAC + Sequence Numbers Server (Stage 2)")
print("=" * 60)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind((HOST, PORT))
    server.listen(1)
    print(f"Listening on {HOST}:{PORT}")

    conn, addr = server.accept()
    with conn:
        print(f"Connected by {addr}")

        # ----- RECEIVE REQUEST -----
        print(f"\\n--- Receiving request (expecting recv_seq={recv_seq}) ---")
        raw_request = recv_record(conn)

        try:
            request = verify_and_unprotect(recv_seq, raw_request)
            recv_seq += 1
        except ValueError as e:
            # Rejection: either the MAC is invalid, the sequence number
            # is wrong, or the data was tampered with / replayed.
            print(f"\\n  *** REJECTED: {e} ***")
            print("  Connection closed &#8212; refusing to process invalid data.")
        else:
            print(f"\\n  Decrypted request:\\n  {request.decode('utf-8')}")

            # ----- SEND RESPONSE -----
            print(f"--- Sending response (send_seq={send_seq}) ---")
            response = (
                "HTTP/1.1 200 OK\\r\\n"
                "Content-Type: text/plain\\r\\n"
                "Content-Length: 13\\r\\n\\r\\n"
                "hello, client"
            ).encode("utf-8")

            protected = protect_record(send_seq, response)
            send_record(conn, protected)
            send_seq += 1
            print(f"  Record sent ({len(protected)} bytes on wire)")

print("\\nDone.")

</code></code></pre><div><hr></div><h2>Why real-world systems usually do not stop here</h2><p>At this point, we have something much stronger than Part 1.</p><p>We have:</p><ul><li><p>encryption</p></li><li><p>integrity protection</p></li><li><p>message authentication</p></li><li><p>sequence-aware records</p></li></ul><p>That is already a meaningful protocol.</p><p>But if you look at how real systems are usually built, they do not normally stop at manually composing:</p><ul><li><p>AES-CTR</p></li><li><p>HMAC-SHA256</p></li><li><p>explicit sequence-aware record protection</p></li></ul><p>Why?</p><p>Because modern systems usually prefer a single primitive that gives confidentiality and integrity together.</p><p>That is where <strong>AEAD</strong> comes in.</p><p>We separated these properties on purpose because it makes the protocol easier to understand.</p><p>But the real world usually packages them together.</p><div><hr></div><h2>A very short note on AEAD</h2><p>AEAD stands for <strong>Authenticated Encryption with Associated Data</strong>.</p><p>That sounds heavier than it really is.</p><p>The practical idea is simple:</p><p>An AEAD construction gives us:</p><ul><li><p>encryption</p></li><li><p>integrity/authentication of the encrypted message</p></li><li><p>and the ability to authenticate extra metadata that should not be encrypted</p></li></ul><p>Common examples are:</p><ul><li><p>AES-GCM</p></li><li><p>ChaCha20-Poly1305</p></li></ul><p>This is much closer to how modern secure protocols protect records.</p><p>It is also why I wanted to include AEAD in this part. If we stopped only at &#8220;encrypt + HMAC,&#8221; we would understand the missing property better, but we would still be one step away from how modern systems actually package it.</p><p>So now we take that final step.</p><div><hr></div><h2>Moving our channel to AEAD</h2><p>For the AEAD version, I will use <strong>AES-GCM</strong>.</p><p>The high-level idea is:</p><ul><li><p>the plaintext gets encrypted</p></li><li><p>integrity/authentication is built in</p></li><li><p>and we can include extra metadata as associated data</p></li></ul><p>In our case, the sequence number is a good example of associated data.</p><p>That means:</p><ul><li><p>it does not need to be encrypted</p></li><li><p>but it should still be authenticated</p></li></ul><h3>AEAD-based helper</h3><pre><code><code># crypto_aead.py
import os
import struct

from cryptography.hazmat.primitives.ciphers.aead import AESGCM

# ---------------------------------------------------------------------------
# Key &#8212; a single 256-bit key for AES-GCM.
# With AEAD, we do NOT need separate encryption and MAC keys &#8212; the
# algorithm handles both internally.
# ---------------------------------------------------------------------------
AEAD_KEY = b"AEAD_KEY_PART2_DEMO_FOR_AES_GCM!"  # 32 bytes &#8594; AES-256-GCM

# AES-GCM nonce length: 12 bytes is the recommended (and most efficient) size.
NONCE_LEN = 12

# Sequence number: 8 bytes (64-bit unsigned integer), same as Stage 2.
SEQ_LEN = 8

def protect_record_aead(seq: int, plaintext: bytes) -&gt; bytes:
    """Seal a plaintext record with AES-GCM.

    Args:
        seq:       The current send-side sequence number.
        plaintext: The message to protect.

    Returns:
        seq (8 B) || nonce (12 B) || ciphertext_and_tag (N+16 B)
    """

    # Pack the sequence number as associated data.
    # The sequence number is authenticated but sent in the clear &#8212; the
    # receiver needs it to know which counter value to expect.
    seq_bytes = struct.pack("!Q", seq)

    # Generate a random 12-byte nonce for AES-GCM.
    nonce = os.urandom(NONCE_LEN)

    # Create an AESGCM instance with our key.
    aesgcm = AESGCM(AEAD_KEY)

    # Encrypt and authenticate in one call.
    # AESGCM.encrypt(nonce, data, associated_data) returns
    # ciphertext || 16-byte authentication tag as a single bytes object.
    # The associated_data (seq_bytes) is authenticated but NOT encrypted.
    ciphertext_and_tag = aesgcm.encrypt(nonce, plaintext, seq_bytes)

    print(f"  [crypto_aead] protect_record_aead:")
    print(f"    seq      = {seq}")
    print(f"    nonce    = {nonce.hex()}")
    print(
        f"    sealed   = {len(ciphertext_and_tag)} bytes "
        f"(plaintext {len(plaintext)} + tag 16)"
    )

    return seq_bytes + nonce + ciphertext_and_tag

def unprotect_record_aead(expected_seq: int, payload: bytes) -&gt; bytes:
    """Verify and decrypt an AES-GCM sealed record.

    Args:
        expected_seq: The sequence number the receiver expects next.
        payload:      seq (8 B) || nonce (12 B) || ciphertext_and_tag.

    Returns:
        The decrypted plaintext.

    Raises:
        ValueError if the sequence number is wrong.
        cryptography.exceptions.InvalidTag if decryption/auth fails.
    """

    min_len = SEQ_LEN + NONCE_LEN + 16  # at least seq + nonce + tag
    if len(payload) &lt; min_len:
        raise ValueError("Record too short")

    # Step 1: Parse the record.
    seq_bytes = payload[:SEQ_LEN]
    nonce = payload[SEQ_LEN : SEQ_LEN + NONCE_LEN]
    ciphertext_and_tag = payload[SEQ_LEN + NONCE_LEN :]

    # Step 2: Check the sequence number.
    (received_seq,) = struct.unpack("!Q", seq_bytes)
    if received_seq != expected_seq:
        print(
            f"  [crypto_aead] *** SEQUENCE MISMATCH: "
            f"got {received_seq}, expected {expected_seq} ***"
        )
        raise ValueError(
            f"Sequence number mismatch: got {received_seq}, expected {expected_seq}"
        )

    print(
        f"  [crypto_aead] Sequence number: {received_seq} "
        f"(expected {expected_seq}) &#8212; OK"
    )

    # Step 3: Decrypt and verify in one call.
    # AESGCM.decrypt(nonce, data, associated_data) verifies the auth tag
    # and decrypts.  If anything was tampered with &#8212; the ciphertext, the
    # tag, or the associated data &#8212; it raises InvalidTag.
    aesgcm = AESGCM(AEAD_KEY)
    plaintext = aesgcm.decrypt(nonce, ciphertext_and_tag, seq_bytes)

    print(f"  [crypto_aead] AEAD decryption: OK ({len(plaintext)} bytes)")

    return plaintext

</code></code></pre><p>This code is noticeably simpler.</p><p>That is one of the big practical advantages of AEAD.</p><p>Instead of manually:</p><ul><li><p>encrypting</p></li><li><p>computing HMAC</p></li><li><p>verifying HMAC</p></li><li><p>then decrypting</p></li></ul><p>we use one primitive that already combines confidentiality and integrity.</p><p>And the sequence number fits naturally as associated data.</p><h3>AEAD-based client</h3><pre><code><code># client_v2_aead.py
import socket

from framing import send_record, recv_record
from crypto_aead import protect_record_aead, unprotect_record_aead

HOST = "127.0.0.1"
PORT = 9002

# Sequence counters &#8212; sender and receiver each maintain their own.
# The sender increments after each record sent.
# The receiver expects consecutive values starting from 0.
send_seq = 0
recv_seq = 0

# A toy HTTP-like request.
request = (
    "GET /transfer?to=bob&amp;amount=100 HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n"
).encode("utf-8")

print("=" * 60)
print("Part 2 &#8212; AEAD Client (AES-GCM)")
print("=" * 60)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
    client.connect((HOST, PORT))
    print(f"Connected to {HOST}:{PORT}")

    # ----- SEND REQUEST -----
    print(f"\\n--- Sending request (send_seq={send_seq}) ---")
    protected = protect_record_aead(send_seq, request)
    send_record(client, protected)
    send_seq += 1
    print(f"  Record sent ({len(protected)} bytes on wire)")

    # ----- RECEIVE RESPONSE -----
    print(f"\\n--- Receiving response (expecting recv_seq={recv_seq}) ---")
    raw_response = recv_record(client)

    try:
        response = unprotect_record_aead(recv_seq, raw_response)
        recv_seq += 1
        print(f"\\n  Decrypted response:\\n  {response.decode('utf-8')}")
    except Exception as e:
        print(f"\\n  *** REJECTED: {e} ***")

print("\\nDone.")

</code></code></pre><h3>AEAD-based server</h3><pre><code><code># server_v2_aead.py
import socket

from framing import send_record, recv_record
from crypto_aead import protect_record_aead, unprotect_record_aead

HOST = "127.0.0.1"
PORT = 9002

# Sequence counters.
# The server's recv_seq tracks the client's send_seq, and vice versa.
send_seq = 0
recv_seq = 0

print("=" * 60)
print("Part 2 &#8212; AEAD Server (AES-GCM)")
print("=" * 60)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind((HOST, PORT))
    server.listen(1)
    print(f"Listening on {HOST}:{PORT}")

    conn, addr = server.accept()
    with conn:
        print(f"Connected by {addr}")

        # ----- RECEIVE REQUEST -----
        print(f"\\n--- Receiving request (expecting recv_seq={recv_seq}) ---")
        raw_request = recv_record(conn)

        try:
            request = unprotect_record_aead(recv_seq, raw_request)
            recv_seq += 1
        except Exception as e:
            # AEAD rejection: either the auth tag is invalid, the sequence
            # number is wrong, or the data was tampered with.
            print(f"\\n  *** REJECTED: {e} ***")
            print("  Connection closed &#8212; refusing to process invalid data.")
        else:
            print(f"\\n  Decrypted request:\\n  {request.decode('utf-8')}")

            # ----- SEND RESPONSE -----
            print(f"--- Sending response (send_seq={send_seq}) ---")
            response = (
                "HTTP/1.1 200 OK\\r\\n"
                "Content-Type: text/plain\\r\\n"
                "Content-Length: 13\\r\\n\\r\\n"
                "hello, client"
            ).encode("utf-8")

            protected = protect_record_aead(send_seq, response)
            send_record(conn, protected)
            send_seq += 1
            print(f"  Record sent ({len(protected)} bytes on wire)")

print("\\nDone.")

</code></code></pre><p>This version is already much closer to how modern secure transport actually protects records.</p><p>Not identical to TLS, of course. But structurally much closer.</p><div><hr></div><h2>What we gained</h2><p>At this point, our channel is much stronger than the one from Part 1.</p><p>We now have:</p><ul><li><p>confidentiality</p></li><li><p>integrity protection</p></li><li><p>authenticated records</p></li><li><p>sequence-aware message handling</p></li><li><p>a much more realistic record protection design through AEAD</p></li></ul><p>That is a big improvement.</p><p>The receiver is no longer just decrypting whatever arrives and trusting the result. Now the receiver can reject modified or structurally unexpected records.</p><p>That is a real protocol boundary.</p><div><hr></div><h2>What is still broken</h2><p>And yet, even now, we are still very far from real TLS.</p><p>Because the biggest assumption in our design is still untouched:</p><p><strong>both sides already share the necessary secret keys</strong></p><p>That means we still do not know how to solve the next real problem:</p><ul><li><p>how do two strangers establish fresh secrets?</p></li><li><p>how does the client know it is talking to the right server?</p></li><li><p>how do we scale beyond hardcoded shared secrets?</p></li><li><p>how do we build trust instead of assuming it?</p></li></ul><p>We improved record protection a lot.</p><p>But we still do not have a real way to establish trust.</p><p>That is the next wall.</p><div><hr></div><h2>Summary</h2><p>In this part, we took the encrypted but still incomplete channel from Part 1 and made it much more serious.</p><p>First, we added <strong>HMAC</strong>, which gave the receiver a way to detect tampering.</p><p>Then, we added a <strong>sequence number</strong>, which made the record layer less naive and bound records to their place in the stream.</p><p>Finally, we moved to <strong>AEAD</strong>, because in real-world systems confidentiality and integrity are usually protected together, not assembled manually from separate pieces.</p><p>So this article had two goals:</p><ul><li><p>understand the missing property explicitly</p></li><li><p>then move toward the real-world shape of the solution</p></li></ul><p>That is why we did not stop at HMAC.</p><p>But even after all of this, we still depend on one assumption that makes the whole thing unrealistic:</p><p>we are still starting with pre-shared secret keys.</p><p>And that is exactly what the next part will attack.</p><div><hr></div><h2>Next part &#8212; getting rid of the pre-shared key</h2><p>So we stop here.</p><p>We now have a much better record layer than in Part 1. But we are still relying on a hardcoded shared secret, and that is not how real secure communication between strangers on the internet works.</p><p>In the next part, we will stop assuming both sides already share a secret.</p><p>We will start building a real handshake and establish fresh session keys instead.</p><p>That still will not give us full TLS.</p><p>But it will take us much closer to the real shape of the protocol.</p><div><hr></div><h2>Final code</h2><p>I&#8217;ll put the full code for this part on GitHub here:</p><p><strong><a href="https://github.com/DmytroHuzz/rebuilding_tls/tree/main/part_2">[GitHub link to final code]</a></strong></p><div><hr></div><h2>Next article:</h2><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;fedd2861-0c5a-4033-9d31-4d253307661e&quot;,&quot;caption&quot;:&quot;Previous Article:&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Rebuilding TLS, Part 3 &#8212; Building Our First Handshake&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software Engineer in the Energy Sector. AWS Community Builder (Dev Tools). (Re)building core tech in public &#8212; so it stop feeling like magic. Writing at Rebuilt.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-04-19T16:38:45.365Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!Gn-u!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/rebuilding-tls-part-3-building-our&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:194707545,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Rebuilt is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Rebuilding TLS, Part 1 — Why Encryption Alone Is Not Enough]]></title><description><![CDATA[From transparent TCP traffic to encrypted records &#8212; and the first reason TLS needs more than encryption]]></description><link>https://www.dmytrohuz.com/p/rebuilding-tls-part-1-why-encryption</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/rebuilding-tls-part-1-why-encryption</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Sun, 29 Mar 2026 18:57:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!5phz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5phz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5phz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!5phz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!5phz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!5phz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5phz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2856965,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/192533658?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5phz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!5phz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!5phz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!5phz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>A year ago I wrote a series about how a web server works.</p><p>I started from a very primitive version and step by step moved toward the same core ideas modern production servers rely on. When I finished that series, I thought the next step would be small.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dmytro&#8217;s Substack is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Wrap it in TLS. Make the communication secure.</p><p>It did not stay small for long.</p><p>What looked like a thin security layer on top of an existing server turned into a much deeper journey into cryptography, authentication, trust, certificates, protocol design, and many details usually hidden behind one familiar phrase: <strong>secure connection</strong>.</p><p>So this series is my attempt to approach TLS the same way I approached the web server: not as a finished black box, but as something we can rebuild from simpler pieces until its shape starts to make sense.</p><p>In this first part, we will start with the most naive version of the problem.</p><p>We will build a very simple socket-based communication channel, see that it is fully transparent, wrap it in encryption with a shared secret key, and then see why that is still not enough.</p><p>That will give us our first fake secure channel.</p><p>And that is exactly where we should start.</p><div><hr></div><h2>What we will build in this part</h2><p>The plan for this article is simple:</p><ul><li><p>build a tiny socket-based client and server</p></li><li><p>send plain text between them</p></li><li><p>look at the traffic and see that everything is visible</p></li><li><p>add shared-key encryption with AES-CTR</p></li><li><p>make the traffic unreadable</p></li><li><p>then show why encryption alone still does not give us a trustworthy secure protocol</p></li></ul><p>We are not trying to build real TLS yet.</p><p>We are trying to make the first mistake on purpose.</p><p>Because once that mistake becomes visible, the next piece of the protocol stops looking optional.</p><div><hr></div><h2>TLS is not SSL</h2><p>Before we start, one small clarification.</p><p>People still often say &#8220;SSL&#8221; when they talk about secure communication on the web. But SSL is the older family of protocols. TLS is its successor.</p><p>So when people say things like &#8220;SSL certificate&#8221; or &#8220;SSL connection,&#8221; in practice they usually mean TLS.</p><p>For modern systems, the relevant protocols are TLS, especially TLS 1.2 and TLS 1.3. This series is about understanding the ideas behind TLS by rebuilding simpler versions of the problems it solves.</p><p>And instead of starting from the finished protocol, we will begin one layer lower &#8212; with plain socket communication.</p><div><hr></div><h2>Step 1 &#8212; A plain socket-based communication channel</h2><p>Let&#8217;s start with the smallest possible thing: a tiny TCP server and a tiny TCP client.</p><p>The client will send an HTTP-like request.</p><p>The server will read it and return an HTTP-like response.</p><p>Nothing secure yet. Just raw bytes moving over a socket.</p><h3>Plain server</h3><pre><code><code># server_plain.py
import socket

HOST = "127.0.0.1"
PORT = 8081

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
    server.bind((HOST, PORT))
    server.listen(1)

    print(f"Listening on {HOST}:{PORT}")
    conn, addr = server.accept()

    with conn:
        print(f"Connected by {addr}")

        data = conn.recv(4096)
        request = data.decode("utf-8")
        print("Received request:")
        print(request)

        response = (
            "HTTP/1.1 200 OK\\r\\n"
            "Content-Type: text/plain\\r\\n"
            "Content-Length: 13\\r\\n"
            "\\r\\n"
            "hello, client"
        )
        conn.sendall(response.encode("utf-8"))
</code></code></pre><h3>Plain client</h3><pre><code><code># client_plain.py
import socket

HOST = "127.0.0.1"
PORT = 8081

request = (
    "GET /transfer?to=bob&amp;amount=100 HTTP/1.1\\r\\n"
    "Host: localhost\\r\\n"
    "\\r\\n"
)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
    client.connect((HOST, PORT))
    client.sendall(request.encode("utf-8"))

    response = client.recv(4096)
    print("Received response:")
    print(response.decode("utf-8"))
</code></code></pre><p>This is intentionally tiny.</p><p>The client sends a request like this:</p><pre><code><code>GET /transfer?to=bob&amp;amount=100 HTTP/1.1
Host: localhost
</code></code></pre><p>The server reads it and sends a response back.</p><p>That is all.</p><p>And because it is all plain TCP, anyone who can observe the traffic can read it directly.</p><h3>Looking at the traffic</h3><p>If you capture this communication in Wireshark, the request and response are fully visible in clear text.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aF_t!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5181b7e6-c7b5-4740-9a2a-6d19ac38e57f_1677x810.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aF_t!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5181b7e6-c7b5-4740-9a2a-6d19ac38e57f_1677x810.png 424w, https://substackcdn.com/image/fetch/$s_!aF_t!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5181b7e6-c7b5-4740-9a2a-6d19ac38e57f_1677x810.png 848w, https://substackcdn.com/image/fetch/$s_!aF_t!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5181b7e6-c7b5-4740-9a2a-6d19ac38e57f_1677x810.png 1272w, https://substackcdn.com/image/fetch/$s_!aF_t!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5181b7e6-c7b5-4740-9a2a-6d19ac38e57f_1677x810.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aF_t!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5181b7e6-c7b5-4740-9a2a-6d19ac38e57f_1677x810.png" width="1456" height="703" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5181b7e6-c7b5-4740-9a2a-6d19ac38e57f_1677x810.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:703,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:135818,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/192533658?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5181b7e6-c7b5-4740-9a2a-6d19ac38e57f_1677x810.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aF_t!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5181b7e6-c7b5-4740-9a2a-6d19ac38e57f_1677x810.png 424w, https://substackcdn.com/image/fetch/$s_!aF_t!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5181b7e6-c7b5-4740-9a2a-6d19ac38e57f_1677x810.png 848w, https://substackcdn.com/image/fetch/$s_!aF_t!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5181b7e6-c7b5-4740-9a2a-6d19ac38e57f_1677x810.png 1272w, https://substackcdn.com/image/fetch/$s_!aF_t!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5181b7e6-c7b5-4740-9a2a-6d19ac38e57f_1677x810.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>That is our baseline.</p><p>The client can read it.</p><p>The server can read it.</p><p>And anyone on the wire can read it too.</p><p>So the first obvious idea is also the first naive one:</p><p>If the problem is that everyone can read the bytes, let&#8217;s encrypt the bytes.</p><p>That sounds reasonable.</p><p>And it is still not enough.</p><div><hr></div><h2>Step 2 &#8212; Turning bytes into records</h2><p>Before we add encryption, we need one small but important thing: structure.</p><p>TCP gives us a byte stream.</p><p>It does not give us message boundaries.</p><p>So once we stop sending plain text directly and start sending encrypted blobs, we need a way to tell the receiver how many bytes belong to one logical message.</p><p>That means even before security, we need a little bit of protocol design.</p><p>Let&#8217;s define the smallest possible record format:</p><ul><li><p>4 bytes: payload length</p></li><li><p>N bytes: payload</p></li></ul><pre><code><code>
+----------+-----------+
|  length  |  payload  |
| (4 bytes)|  (varies) |
+----------+-----------+
</code></code></pre><p>That is enough for our first version.</p><pre><code><code># framing.py
import struct

def send_record(sock, payload: bytes) -&gt; None:
    header = struct.pack("!I", len(payload))
    sock.sendall(header + payload)

def recv_exact(sock, n: int) -&gt; bytes:
    chunks = []
    remaining = n

    while remaining &gt; 0:
        chunk = sock.recv(remaining)
        if not chunk:
            raise ConnectionError("Connection closed while reading data")
        chunks.append(chunk)
        remaining -= len(chunk)

    return b"".join(chunks)

def recv_record(sock) -&gt; bytes:
    header = recv_exact(sock, 4)
    (length,) = struct.unpack("!I", header)
    return recv_exact(sock, length)
</code></code></pre><p>This is not a crypto step.</p><p>It is a protocol step.</p><p>And that distinction matters more than it first appears. A secure channel is not just &#8220;call encrypt on a string.&#8221; It is a protocol with structure, state, and rules.</p><p>Now that we have a way to send and receive well-defined records, we can finally wrap them in encryption.</p><div><hr></div><h2>Step 3 &#8212; Wrapping the channel in shared-key encryption</h2><p>The most obvious first attempt at secure communication is usually this:</p><ul><li><p>both sides already know the same secret key</p></li><li><p>the sender encrypts the message before sending</p></li><li><p>the receiver decrypts it after receiving</p></li></ul><p>That is exactly what we will do.</p><p>No handshake yet.</p><p>No certificates yet.</p><p>No integrity yet.</p><p>No authentication yet.</p><p>This version is intentionally naive.</p><p>For encryption, I will use AES in CTR mode.</p><p>Very briefly:</p><ul><li><p>AES is a symmetric block cipher</p></li><li><p>CTR mode makes it convenient for encrypting a stream of bytes</p></li><li><p>it gives us confidentiality</p></li><li><p>but it does <strong>not</strong> give us integrity</p></li></ul><p>That last point is the important one for this article.</p><p>If you want a deeper explanation of AES itself, I already wrote about it in my cryptography series: <a href="https://www.dmytrohuz.com/p/building-own-block-cipher-part-3">https://www.dmytrohuz.com/p/building-own-block-cipher-part-3</a>, so I will not go into the internals here.</p><h3>The nonce</h3><p>CTR mode also needs a nonce.</p><p>For now, think of it as a fresh per-message value that must be different for each encryption under the same key.</p><p>It is not secret.</p><p>It just must not be reused.</p><p>So our encrypted payload will look like this:</p><ul><li><p>nonce</p></li><li><p>ciphertext</p></li></ul><h3>Crypto helper</h3><pre><code><code># crypto.py
import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

# 32-byte shared key for AES-256
SHARED_KEY = b"0123456789ABCDEF0123456789ABCDEF"

def encrypt_message(plaintext: bytes) -&gt; bytes:
    nonce = os.urandom(16)

    cipher = Cipher(algorithms.AES(SHARED_KEY), modes.CTR(nonce))
    encryptor = cipher.encryptor()
    ciphertext = encryptor.update(plaintext) + encryptor.finalize()

    # Encrypted payload format:
    # nonce || ciphertext
    return nonce + ciphertext

def decrypt_message(payload: bytes) -&gt; bytes:
    nonce = payload[:16]
    ciphertext = payload[16:]

    cipher = Cipher(algorithms.AES(SHARED_KEY), modes.CTR(nonce))
    decryptor = cipher.decryptor()
    plaintext = decryptor.update(ciphertext) + decryptor.finalize()

    return plaintext
</code></code></pre><p>At this point, our wire format becomes:</p><ul><li><p>4-byte length</p></li><li><p>16-byte nonce</p></li><li><p>ciphertext</p></li></ul><pre><code><code>+----------------+----------------+---------------------+
| length (4 B)   | nonce (16 B)   | ciphertext (N bytes)|
+----------------+----------------+---------------------+</code></code></pre><p>That already looks much more like a protocol.</p><div><hr></div><h2>Step 4 &#8212; Encrypt the request and response</h2><p>Now let&#8217;s integrate this into the client and server.</p><h3>Encrypted client</h3><pre><code><code># client_v1.py
import socket

from framing import send_record, recv_record
from crypto import encrypt_message, decrypt_message

HOST = "127.0.0.1"
PORT = 8081

request = (
    "GET /transfer?to=bob&amp;amount=100 HTTP/1.1\\r\\n"
    "Host: localhost\\r\\n"
    "\\r\\n"
).encode("utf-8")

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
    client.connect((HOST, PORT))

    encrypted_request = encrypt_message(request)
    send_record(client, encrypted_request)

    encrypted_response = recv_record(client)
    response = decrypt_message(encrypted_response)

    print("Received decrypted response:")
    print(response.decode("utf-8"))
</code></code></pre><h3>Encrypted server</h3><pre><code><code># server_v1.py
import socket

from framing import send_record, recv_record
from crypto import encrypt_message, decrypt_message

HOST = "127.0.0.1"
PORT = 8081

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
    server.bind((HOST, PORT))
    server.listen(1)

    print(f"Listening on {HOST}:{PORT}")
    conn, addr = server.accept()

    with conn:
        print(f"Connected by {addr}")

        encrypted_request = recv_record(conn)
        request = decrypt_message(encrypted_request)

        print("Received decrypted request:")
        print(request.decode("utf-8"))

        response = (
            "HTTP/1.1 200 OK\\r\\nContent-Type: text/plain\\r\\n"
            "Content-Length: 13\\r\\n\\r\\nhello, client"
        ).encode("utf-8")

        encrypted_response = encrypt_message(response)
        send_record(conn, encrypted_response)
</code></code></pre><p>Now the communication flow changes in an important way.</p><p>Instead of sending readable HTTP-like text directly, the client sends an encrypted record. The server reads the record, decrypts it, and sees the original request.</p><h3>What changes on the wire</h3><p>If you capture this version in Wireshark, the traffic is no longer readable.</p><p>Instead of clear request and response text, you now see opaque binary data.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1qMA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65774ee7-4444-4135-93a9-ccc576fae9ec_1677x810.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1qMA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65774ee7-4444-4135-93a9-ccc576fae9ec_1677x810.png 424w, https://substackcdn.com/image/fetch/$s_!1qMA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65774ee7-4444-4135-93a9-ccc576fae9ec_1677x810.png 848w, https://substackcdn.com/image/fetch/$s_!1qMA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65774ee7-4444-4135-93a9-ccc576fae9ec_1677x810.png 1272w, https://substackcdn.com/image/fetch/$s_!1qMA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65774ee7-4444-4135-93a9-ccc576fae9ec_1677x810.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1qMA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65774ee7-4444-4135-93a9-ccc576fae9ec_1677x810.png" width="1456" height="703" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/65774ee7-4444-4135-93a9-ccc576fae9ec_1677x810.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:703,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:220787,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/192533658?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65774ee7-4444-4135-93a9-ccc576fae9ec_1677x810.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1qMA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65774ee7-4444-4135-93a9-ccc576fae9ec_1677x810.png 424w, https://substackcdn.com/image/fetch/$s_!1qMA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65774ee7-4444-4135-93a9-ccc576fae9ec_1677x810.png 848w, https://substackcdn.com/image/fetch/$s_!1qMA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65774ee7-4444-4135-93a9-ccc576fae9ec_1677x810.png 1272w, https://substackcdn.com/image/fetch/$s_!1qMA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65774ee7-4444-4135-93a9-ccc576fae9ec_1677x810.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>So yes, we gained something real.</p><p>Let&#8217;s stop and say exactly what that is.</p><div><hr></div><h2>What encryption actually gave us</h2><p>This first version gives us one meaningful property:</p><p><strong>confidentiality against passive observers</strong></p><p>If someone can only observe the traffic, but cannot modify it, they no longer get the plaintext request and response for free.</p><p>That is already better than raw TCP.</p><p>And this is why &#8220;just add encryption&#8221; feels so convincing. It visibly solves a real problem.</p><p>But that visible success can hide another, more dangerous failure.</p><p>Because a secure channel needs more than secrecy.</p><p>It also needs protection against tampering.</p><p>And we still do not have that.</p><div><hr></div><h2>Step 5 &#8212; Why encryption alone is not enough</h2><p>This is the real point of Part 1.</p><p>We encrypted the messages.</p><p>We did <strong>not</strong> make them trustworthy.</p><p>AES-CTR protects confidentiality, but it does not protect integrity.</p><p>That means an active attacker may be able to modify ciphertext, and those modifications will flow through into the decrypted plaintext.</p><p>Very roughly, CTR mode behaves like this:</p><pre><code><code>ciphertext = plaintext XOR keystream
</code></code></pre><p>So if an attacker changes bits in the ciphertext, the corresponding bits change in the plaintext after decryption.</p><p>That property is called <strong>malleability</strong>.</p><p>And protocol messages are usually predictable enough that this becomes useful to an attacker.</p><p>Our example request already has a very predictable structure:</p><pre><code><code>GET /transfer?to=bob&amp;amount=100 HTTP/1.1
Host: localhost
</code></code></pre><p>The exact bytes of <code>amount=100</code> are not random.</p><p>That predictability is enough to hurt us.</p><h3>A tiny isolated demo</h3><p>We do not need a full man-in-the-middle proxy to show the problem. A small isolated example is enough.</p><pre><code><code># ctr_malleability_demo.py
from crypto import encrypt_message, decrypt_message

original = b"amount=100"
encrypted = encrypt_message(original)

nonce = encrypted[:16]
ciphertext = bytearray(encrypted[16:])

# Change '1' -&gt; '9'
# ASCII '1' = 0x31
# ASCII '9' = 0x39
# Difference = 0x08

index_of_digit = len("amount=")
ciphertext[index_of_digit] ^= 0x08

modified = nonce + bytes(ciphertext)
decrypted = decrypt_message(modified)

print("Original :", original)
print("Modified :", decrypted)
</code></code></pre><p>Output:</p><pre><code><code>Original : b'amount=100'
Modified : b'amount=900'
</code></code></pre><p>And that is the failure.</p><p>The attacker did not need the key.</p><p>They did not need to fully decrypt the message first.</p><p>They only needed the ability to modify the encrypted bytes in transit.</p><p>The receiver then decrypts the modified ciphertext and gets modified plaintext &#8212; without any built-in indication that anything went wrong.</p><p>So even though the message is hidden from passive observers, it is still vulnerable to active tampering.</p><p>That is not a secure protocol.</p><p>That is only encrypted transport.</p><div><hr></div><h2>What is still broken</h2><p>At this point, our fake secure channel still has many serious holes.</p><h3>No integrity protection</h3><p>The receiver cannot detect that the ciphertext was modified.</p><h3>No message authentication</h3><p>The receiver has no cryptographic proof that the message came from the expected sender and arrived unchanged.</p><h3>No replay protection</h3><p>An attacker can capture an encrypted message and replay it later.</p><h3>Static shared key</h3><p>Both sides use one long-term shared key for everything.</p><p>That does not scale, and if it leaks, everything built on top of it collapses.</p><h3>No handshake</h3><p>There is no fresh session establishment. The peers do not negotiate anything. They just start encrypting.</p><h3>No peer identity</h3><p>The client does not really know who it is talking to beyond &#8220;someone who can decrypt with this key.&#8221;</p><p>So yes, we improved something.</p><p>But we are still very far from TLS.</p><p>Good.</p><p>That is exactly what Part 1 should make visible.</p><div><hr></div><h2>Summary</h2><p>In this first part, we built a fake secure channel.</p><p>We started with plain socket communication and saw that everything was fully transparent. Then we wrapped the communication in shared-key encryption with AES-CTR, which gave us confidentiality against passive observers.</p><p>That was real progress.</p><p>But it was not enough.</p><p>Because encrypting a message is not the same thing as protecting the message from being changed. Our channel still accepts modified ciphertext, decrypts it, and trusts the result.</p><p>So the first lesson of this series is simple:</p><p><strong>confidentiality is not integrity</strong></p><p>And if we want something that starts to deserve the name secure protocol, we need both.</p><div><hr></div><h2>Next part &#8212; adding integrity with a MAC</h2><p>So we stop here.</p><p>We now have a channel that can hide bytes from passive observers, but cannot reliably detect tampering.</p><p>In the next part, we will keep the same basic setup and fix the biggest hole we exposed here: we will add a <strong>MAC &#8212; a Message Authentication Code</strong>.</p><p>That will take us from:</p><blockquote><p>&#8220;you probably can&#8217;t read this&#8221;</p></blockquote><p>to:</p><blockquote><p>&#8220;you also can&#8217;t silently change this&#8221;</p></blockquote><p>That still will not be real TLS.</p><p>But it will make our fake secure channel one step less fake.</p><div><hr></div><h2>Final code</h2><p>I&#8217;ll put the full code for this part on GitHub here: <a href="https://github.com/DmytroHuzz/rebuilding_tls/tree/main/part_1">rebuilding_tls</a></p><div><hr></div><h2>Next article:</h2><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;1e716372-eb3d-4b99-ac9c-aac2ac0cf863&quot;,&quot;caption&quot;:&quot;In the first part of this series, we built our first fake secure channel:&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Rebuilding TLS, Part 2 &#8212; Adding Integrity to the Channel&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software Engineer in the Energy Sector. AWS Community Builder (Dev Tools). (Re)building core tech in public &#8212; so it stop feeling like magic. Writing at Rebuilt.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-04-05T21:40:43.808Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!78kv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/rebuilding-tls-part-2-adding-integrity&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:193281237,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dmytro&#8217;s Substack is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Rebuilding TLS From Scratch — My Complete Learning Journey]]></title><description><![CDATA[This collection brings together my attempt to rebuild TLS from first principles]]></description><link>https://www.dmytrohuz.com/p/rebuilding-tls-from-scratch-my-complete</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/rebuilding-tls-from-scratch-my-complete</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Fri, 27 Mar 2026 21:39:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!59qZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!59qZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!59qZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!59qZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!59qZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!59qZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!59qZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2967175,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/192355388?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!59qZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!59qZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!59qZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!59qZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d2268c1-b8d1-42db-9320-6a750a764263_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>A year ago I wrote a series of articles about how a <a href="https://dev.to/dmytro_huz/building-your-own-web-server-part-1-theory-and-foundations-3kgo">web server works</a>.</p><p>I started from a very primitive version and step by step moved toward the same core ideas modern production servers rely on. That journey was already deep enough on its own. But when I finished it, I had one more thing in mind.</p><p>A small improvement.</p><p>Wrap the server in TLS. Make the communication secure.</p><p>At least, that was how it looked from the outside.</p><p>In reality, that &#8220;small improvement&#8221; turned into a much longer journey than I expected. What looked like one tiny feature hidden behind the familiar lock icon in the browser opened the door into a huge world of cryptography, key exchange, authentication, certificates, trust, protocol design, and many layers of details that usually stay invisible when everything just works.</p><p>And that is exactly why I decided to make this series.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><p>I did not want to approach TLS as a finished black box. I did not want to start from the RFC and just repeat the names of the protocol messages until they sounded familiar. I wanted to understand what TLS is, why it exists in the form it exists, and why it needs so many moving parts.</p><p>So this series is my attempt to rebuild it.</p><p>Not the full production-ready TLS implementation, of course. But a step-by-step reconstruction of the logic behind it. We will start from something intentionally naive, something that only looks secure, and in each article we will add one missing piece, one new idea, one more reason why real TLS had to become what it is.</p><p>By the end, I want us to arrive at a simplified TLS-like protocol that is close enough to the real thing to make the real thing much easier to understand.</p><p>Because that is still the real goal.</p><p>I do not want to stay forever in toy examples, and I do not think you want that either. In the final part of the series, I want to take everything we built ourselves and map it to the real TLS protocol: what is different, what extra problems the real one solves, why it is structured the way it is, and maybe also how some popular libraries implement it in practice.</p><p>But I really believe that jumping directly into the finished TLS protocol is the wrong way to learn it.</p><p>TLS is one of those technologies where the final design hides the reasons. If you look at the real protocol too early, you see a forest of details: handshakes, certificates, transcript hashes, traffic secrets, record protection, extensions, verification steps. All of them are there for a reason. But those reasons are much easier to understand when you first build the broken versions that fail without them.</p><p>That is the main idea of this series:</p><p><strong>we will learn TLS by first building the wrong thing, and then fixing it step by step.</strong></p><p>So if your goal is to understand the real TLS better, I would strongly recommend following the whole journey and not jumping directly to the last part.</p><p>As I mentioned, TLS is built on many cryptographic ideas. I will explain the important ones when we need them, but I also already wrote a separate series where I rebuild the main cryptographic foundations from scratch:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;d1c91fa2-1989-4ec7-9c1a-cf6ec139d6b2&quot;,&quot;caption&quot;:&quot;Why this project exists - and why it might matter to you&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Rebuilding Cryptography From Scratch - My Complete Learning Journey (All Parts Inside)&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Engineer | Writer | Builder - I deconstruct complex systems to first principles and rebuild them into clear engineering mental models, diagrams, and practical tools.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2025-12-01T19:09:39.536Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!SRa_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8a9697d-5837-4c57-947c-4cf941c3bc3d_1024x608.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/rebuilding-cryptography-from-scratch&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:180433391,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:3,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Dmytro&#8217;s Substack&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!t_-c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F046f0d8c-fecd-41e6-a43f-4718cf07a50f_608x608.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>So throughout this TLS series, I will link back to those parts whenever we meet a concept that deserves a deeper look.</p><p>This page will be the central hub for the whole project. I will keep it updated as new parts are published, so all articles stay connected in one place.</p><p>I really hope you enjoy this journey as much as I do.</p><div><hr></div><h1><strong>Full Summary of the TLS Series</strong></h1><p><em>This section will be updated as new parts are released.</em></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;f6554474-5a3b-4fc1-84c6-686cd8bcec9d&quot;,&quot;caption&quot;:&quot;From transparent TCP traffic to encrypted records &#8212; and the first reason TLS needs more than encryption&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Rebuilding TLS, Part 1 &#8212; Why Encryption Alone Is Not Enough&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Engineer | Writer | Builder - I deconstruct complex systems to first principles and rebuild them into clear engineering mental models, diagrams, and practical tools.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-03-29T18:57:36.417Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!5phz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f085090-d20e-4850-844a-c79a878be8e6_1536x1024.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/rebuilding-tls-part-1-why-encryption&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:192533658,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Dmytro&#8217;s Substack&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!t_-c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F046f0d8c-fecd-41e6-a43f-4718cf07a50f_608x608.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;1ba5526e-56cd-46ad-be1a-ecf7a0624726&quot;,&quot;caption&quot;:&quot;We teach our protocol to detect tampering, make records less naive with sequence numbers, and then switch to the AEAD style used in real systems.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Rebuilding TLS, Part 2 &#8212; Adding Integrity to the Channel&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Engineer | Writer | Builder - I deconstruct complex systems to first principles and rebuild them into clear engineering mental models, diagrams, and practical tools.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-04-05T21:40:43.808Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!78kv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680242ba-f7c2-4916-990b-5c813987d655_1536x1024.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/rebuilding-tls-part-2-adding-integrity&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:193281237,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Dmytro&#8217;s Substack&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!t_-c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F046f0d8c-fecd-41e6-a43f-4718cf07a50f_608x608.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;75e5e3a4-f06f-48f5-947b-d6e777d285e0&quot;,&quot;caption&quot;:&quot;We get rid of the pre-shared key assumption, build a simple key exchange handshake, and discover why key agreement alone still does not give us real TLS.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Rebuilding TLS, Part 3 &#8212; Building Our First Handshake&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Engineer | Writer | Builder - I deconstruct complex systems to first principles and rebuild them into clear engineering mental models, diagrams, and practical tools.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-04-19T16:38:45.365Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!Gn-u!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb29e52-36ee-433b-a83f-355dc7736265_1536x600.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/rebuilding-tls-part-3-building-our&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:194707545,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Dmytro&#8217;s Substack&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!t_-c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F046f0d8c-fecd-41e6-a43f-4718cf07a50f_608x608.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;04357092-974f-4863-98c1-af7c43351329&quot;,&quot;caption&quot;:&quot;We found out how Certificates and CA solve the problem of trust and prevent MITM attack. And integrated this last piece in out TLS protocol. &quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Rebuilding TLS, Part 4 - Certificates and Trust&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software Engineer in the Energy Sector. AWS Community Builder (Dev Tools). (Re)building core tech in public &#8212; so it stop feeling like magic. Writing at Rebuilt.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-04-26T20:24:36.572Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!HYYb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1a0a1c1-8a6f-4b73-8101-881f128943d8_1536x1024.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/rebuilding-tls-part-4-certificates&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:195558698,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h1><strong>What this series is really about</strong></h1><p>This is not just a series about TLS.</p><p>It is also another exercise in the same thing I keep coming back to again and again: taking foundational technology that usually appears to us as a finished black box, opening it up, and rebuilding it from simpler parts until it stops feeling magical.</p><p>That was the idea behind the web server series.</p><p>That was the idea behind the cryptography series.</p><p>And now this is the same idea applied to TLS.</p><div><hr></div><h1><strong>Follow the journey</strong></h1><p>This page will stay the central entry point for the whole series.</p><p>If this kind of deep, step-by-step reconstruction of systems is interesting to you, you can subscribe so you do not miss the next parts.</p><h2><strong>Links</strong></h2><ul><li><p>Part 4 walkthrough (rendered) &#8212; <a href="https://dmytrohuzz.github.io/rebuilding_tls/part_4/walkthrough/walkthrough.html">dmytrohuzz.github.io/rebuilding_tls/.../walkthrough.html</a></p></li><li><p>Repository &#8212; <a href="https://github.com/DmytroHuzz/rebuilding_tls">github.com/DmytroHuzz/rebuilding_tls</a></p></li><li><p>Questions, feedback, found a bug? &#8212; <a href="https://www.linkedin.com/in/dmitriyhuz/">LinkedIn: dmitriyhuz</a></p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[A Practical Guide to Time for Developers — The Complete Series]]></title><description><![CDATA[Time looks simple until you have to trust it.]]></description><link>https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-746</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-746</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Thu, 19 Mar 2026 21:05:34 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!mg5A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef6652f-dc32-4078-ac16-7d4ac73c0392_1024x608.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mg5A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef6652f-dc32-4078-ac16-7d4ac73c0392_1024x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mg5A!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef6652f-dc32-4078-ac16-7d4ac73c0392_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!mg5A!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef6652f-dc32-4078-ac16-7d4ac73c0392_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!mg5A!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef6652f-dc32-4078-ac16-7d4ac73c0392_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!mg5A!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef6652f-dc32-4078-ac16-7d4ac73c0392_1024x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mg5A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef6652f-dc32-4078-ac16-7d4ac73c0392_1024x608.png" width="1024" height="608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bef6652f-dc32-4078-ac16-7d4ac73c0392_1024x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:608,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!mg5A!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef6652f-dc32-4078-ac16-7d4ac73c0392_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!mg5A!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef6652f-dc32-4078-ac16-7d4ac73c0392_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!mg5A!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef6652f-dc32-4078-ac16-7d4ac73c0392_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!mg5A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbef6652f-dc32-4078-ac16-7d4ac73c0392_1024x608.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Time looks simple until you have to trust it.</p><p>We use timestamps everywhere: logs, APIs, databases, schedulers, certificates, metrics, traces, distributed systems, industrial systems. But the moment you start asking basic questions &#8212; <em>what exactly is this timestamp measuring? which clock produced it? how does one machine keep time? how do many machines agree on it?</em> &#8212; the topic becomes much deeper than it first appears.</p><p>This series was my attempt to build a practical mental model of time for developers from first principles all the way down to Linux clocks, NTP, PTP, PHCs, and synchronization tools.</p><p>If you want one entry point into the whole topic, this is it.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-746?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-746?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><h2><strong>What this series covers</strong></h2><p>This series is built as a path:</p><ul><li><p>first, what time actually means in software</p></li><li><p>then, how one computer keeps time</p></li><li><p>then, how many computers synchronize time</p></li><li><p>and finally, how Linux represents all of this in practice</p></li></ul><p>The goal was never to produce a dry reference manual.</p><p>The goal was to make time feel understandable.</p><p>Not just &#8220;I know NTP exists,&#8221; but a real working model of:</p><ul><li><p>what time is</p></li><li><p>how clocks drift</p></li><li><p>why synchronization is hard</p></li><li><p>why timestamp location matters</p></li><li><p>and how Linux exposes all of this in real systems</p></li></ul><h2><strong>The full reading path</strong></h2><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/subscribe?"><span>Subscribe now</span></a></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;c40c49bc-90c6-4eac-b83e-aee3b47e2760&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;A Practical Guide to Time for Developers: Part 1 &#8212; What time is in software (physics + agreements)&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Engineer | Writer | Builder - I deconstruct complex systems to first principles and rebuild them into clear engineering mental models, diagrams, and practical tools.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-03-01T06:30:46.601Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!8hv5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fbc17c1-cd36-4488-8a63-51f076a67229_1536x672.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:189526403,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Dmytro&#8217;s Substack&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!t_-c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F046f0d8c-fecd-41e6-a43f-4718cf07a50f_608x608.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>This is the foundation.</p><p>If you ever used timestamps without being fully sure what they really mean, start here.</p><p>This part covers the basic language of the topic: what time means in software, why timestamps are not &#8220;time itself,&#8221; what role standards and agreements play, and why the whole subject is more subtle than it first appears.</p><p>This is the part that gives you the mental vocabulary for everything that comes later.</p><div><hr></div><h3></h3><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;785061f6-fbd7-4cdf-b896-43b0116e287c&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;A Practical Guide to Time for Developers: Part 2 &#8212; How one computer keeps time (Linux)&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Engineer | Writer | Builder - I deconstruct complex systems to first principles and rebuild them into clear engineering mental models, diagrams, and practical tools.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-03-05T21:16:33.261Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JuSw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0671b0e-b346-4268-aa3f-03463bde5436_1536x672.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-2ec&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:190040669,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Dmytro&#8217;s Substack&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!t_-c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F046f0d8c-fecd-41e6-a43f-4718cf07a50f_608x608.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>Once the theory is clear, the next question is obvious:</p><p>How does one computer actually keep time?</p><p>This part moves inside the machine. It covers the clocks and mechanisms Linux uses to track time, including the RTC, system time, counters, and the distinction between different clock sources and time domains.</p><p>If Part 1 explains what time means, Part 2 explains how a single system turns that idea into something measurable and usable.</p><div><hr></div><h3></h3><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;90da410a-7e34-4143-aee5-98eb6d0d5712&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;A Practical Guide to Time for Developers: Part 3 &#8212; How Computers Share Time&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Engineer | Writer | Builder - I deconstruct complex systems to first principles and rebuild them into clear engineering mental models, diagrams, and practical tools.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-03-16T15:42:35.677Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!0JCc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ff7fad6-3567-42cf-a8e4-f948866f3fd5_1000x420.webp&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-ec8&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:191125080,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Dmytro&#8217;s Substack&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!t_-c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F046f0d8c-fecd-41e6-a43f-4718cf07a50f_608x608.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>A single computer can keep time locally.</p><p>A distributed system has a harder problem: many machines must keep time together.</p><p>This part is about synchronization. Why simply setting clocks once does not work. Why drift makes synchronization a continuous process. How NTP and PTP approach the problem. And why the quality of synchronization depends not only on the protocol, but also on where timestamps are taken.</p><p>This is where time stops being a local machine detail and becomes a systems problem.</p><div><hr></div><h3></h3><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;35cb7f76-68b8-40d1-9ed4-b6242e3185b8&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;A Practical Guide to Time for Developers: Part 4 -The Linux Time Sync Cheat Sheet&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Engineer | Writer | Builder - I deconstruct complex systems to first principles and rebuild them into clear engineering mental models, diagrams, and practical tools.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-03-19T16:36:51.707Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!MEgQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-314&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:191493632,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Dmytro&#8217;s Substack&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!t_-c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F046f0d8c-fecd-41e6-a43f-4718cf07a50f_608x608.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>This is the practical payoff.</p><p>It turns the concepts from the whole series into the Linux view of the world:</p><ul><li><p>RTC</p></li><li><p>system clock</p></li><li><p>PHC</p></li><li><p>NTP</p></li><li><p>PTP</p></li><li><p>ptp4l</p></li><li><p>phc2sys</p></li><li><p>and the usual synchronization paths between them</p></li></ul><p>This is the compact field guide version &#8212; the part you can actually bookmark and return to when you need to inspect, operate, or debug time synchronization on Linux.</p><div><hr></div><h2><strong>Interactive visuals and supporting materials</strong></h2><p>Along the way, I also started building visual and interactive explanations for some of the harder ideas, such as:</p><ul><li><p>clock drift</p></li><li><p>synchronization by timestamp exchange</p></li><li><p>NTP principles</p></li><li><p>PTP principles</p></li><li><p>software vs hardware timestamping</p></li></ul><p>I want this series to be more than just text. Time is easier to understand when you can see it move.</p><h2><strong>Who this series is for</strong></h2><p>This series should be useful if you work with:</p><ul><li><p>backend or distributed systems</p></li><li><p>Linux and infrastructure</p></li><li><p>observability and logs</p></li><li><p>event ordering</p></li><li><p>industrial or measurement systems</p></li><li><p>networking</p></li><li><p>NTP/PTP</p></li><li><p>or just any system where timestamps need to be trusted</p></li></ul><p>In other words: if time can break your system, this topic is worth understanding properly.</p><h2><strong>Why I wrote this</strong></h2><p>Time is one of the most used and least understood parts of software.</p><p>Most of us interact with it every day, but only occasionally stop to ask what is actually happening underneath. I wanted to fix that for myself first &#8212; and then turn that learning process into something practical and usable for other engineers.</p><p>This series is the result.</p><h2><strong>Final note</strong></h2><p>If you made it through the whole series, you did not just read a few posts about clocks.</p><p>You built a real mental model of time in computing &#8212; from first principles, to clocks inside a machine, to synchronization across networks, to the actual Linux entities and tools that make it work in practice.</p><p>That already puts you ahead of most engineers who touch these systems.</p><p>You now know enough to stop treating time as a mysterious background feature and start seeing it for what it really is:</p><p><strong>infrastructure, measurement, coordination, and engineering.</strong></p><p>Bookmark this page. I&#8217;ll keep it as the main entry point for the whole series.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dmytro&#8217;s Substack is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[A Practical Guide to Time for Developers: Part 4 -The Linux Time Sync Cheat Sheet]]></title><description><![CDATA[RTC, system clock, PHC, NTP, PTP, ptp4l, and phc2sys &#8212; the practical map of how time works in Linux]]></description><link>https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-314</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-314</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Thu, 19 Mar 2026 16:36:51 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!MEgQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MEgQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MEgQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png 424w, https://substackcdn.com/image/fetch/$s_!MEgQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png 848w, https://substackcdn.com/image/fetch/$s_!MEgQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png 1272w, https://substackcdn.com/image/fetch/$s_!MEgQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MEgQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png" width="1456" height="637" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:637,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1371588,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/191493632?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MEgQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png 424w, https://substackcdn.com/image/fetch/$s_!MEgQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png 848w, https://substackcdn.com/image/fetch/$s_!MEgQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png 1272w, https://substackcdn.com/image/fetch/$s_!MEgQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>If you got here and made it through the previous articles, you have already done the hard part. You are basically a time guru now.</p><p>You know <a href="https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers">what time means in computing</a>, <a href="https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-2ec">how a machine keeps it</a>, why clocks drift, <a href="https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-ec8">how synchronization works, and why timestamp location matters.</a> That is already more than most people ever learn about this topic.</p><p>Now let&#8217;s compress all of that into the Linux view of the world.</p><p>This is the top of the iceberg: a small set of clocks, commands, and tools that represent most of the concepts we have been building up across the series.</p><p>Think of this as the practical cheat sheet &#8212; the 90% version. The one you can use to inspect clocks, understand what is synchronized to what, and handle most everyday Linux time-sync tasks without drowning in documentation.</p><p><em><strong>This is probably the part you will want to bookmark.</strong></em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-314?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-314?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><div><hr></div><h2><strong>The three main clock entities in Linux</strong></h2><p>When people say &#8220;Linux time,&#8221; they often mean one thing. In reality, Linux commonly deals with at least three different clock entities:</p><ul><li><p><strong>system time</strong></p></li><li><p><strong>RTC</strong></p></li><li><p><strong>PHC</strong></p></li></ul><p>They serve different purposes.</p><div><hr></div><h2><strong>1. System time</strong></h2><p>This is the normal wall-clock time used by most applications.</p><p>It is what you usually see when you run:</p><pre><code><code>date
</code></code></pre><p>or:</p><pre><code><code>timedatectl
</code></code></pre><p>Conceptually, this is the kernel&#8217;s main wall clock, commonly associated with CLOCK_REALTIME.</p><p>This is the clock used by:</p><ul><li><p>most user-space applications</p></li><li><p>logs</p></li><li><p>system services</p></li><li><p>everyday time queries</p></li></ul><h3><strong>Quick check</strong></h3><pre><code><code>date
timedatectl
</code></code></pre><h3><strong>Mental model</strong></h3><pre><code><code>System clock = the main OS wall clock
</code></code></pre><div><hr></div><h2><strong>2. RTC (Real-Time Clock)</strong></h2><p>The RTC is the battery-backed hardware clock on the motherboard.</p><p>Its main job is simple: keep time while the machine is powered off.</p><p>Linux often uses it during boot to initialize system time, and may update it again later from system time. But the RTC is usually <strong>not</strong> the main precision synchronization clock during normal operation.</p><h3><strong>Quick check</strong></h3><pre><code><code>sudo hwclock --show
timedatectl
</code></code></pre><h3><strong>Common operations</strong></h3><p>Copy system time to RTC:</p><pre><code><code>sudo hwclock --systohc
</code></code></pre><p>Copy RTC to system time:</p><pre><code><code>sudo hwclock --hctosys
</code></code></pre><h3><strong>Mental model</strong></h3><pre><code><code>RTC = persistent clock for boot/shutdown
</code></code></pre><div><hr></div><h2><strong>3. PHC (PTP Hardware Clock)</strong></h2><p>A PHC is a hardware clock exposed by a PTP-capable network interface.</p><p>This is where Linux gets especially interesting.</p><p>A PHC lives on the NIC, much closer to the real transmit/receive event than the normal system clock. That is why it matters for precise synchronization.</p><p>PHCs usually appear as device files like:</p><pre><code><code>/dev/ptp0
/dev/ptp1
</code></code></pre><h3><strong>Quick check</strong></h3><p>List PHC devices:</p><pre><code><code>ls -l /dev/ptp*
</code></code></pre><p>Check which PHC belongs to a NIC and whether hardware timestamping is supported:</p><pre><code><code>ethtool -T eth0
</code></code></pre><h3><strong>Mental model</strong></h3><pre><code><code>PHC = hardware clock on the NIC, used for precise packet timing
</code></code></pre><div><hr></div><h2><strong>One picture: how they relate</strong></h2><pre><code><code>RTC
  |
  | used mainly at boot / shutdown
  v
System clock (CLOCK_REALTIME)
  ^
  |
  | phc2sys can sync between them
  |
PHC (/dev/ptpX on NIC)
  ^
  |
  | ptp4l syncs PHC to PTP network
  |
PTP network / Grandmaster
</code></code></pre><p>A rough summary:</p><ul><li><p><strong>RTC</strong> keeps time while power is off</p></li><li><p><strong>system clock</strong> is what most software reads</p></li><li><p><strong>PHC</strong> is the precision clock on the NIC</p></li></ul><div><hr></div><h2><strong>How Linux syncs time with NTP</strong></h2><p>In the NTP world, Linux usually synchronizes the <strong>system clock</strong>.</p><p>Common tools:</p><ul><li><p>chronyd</p></li><li><p>systemd-timesyncd</p></li><li><p>older setups may use ntpd</p></li></ul><h3><strong>Check whether NTP is active</strong></h3><pre><code><code>timedatectl
</code></code></pre><h3><strong>If you use chrony</strong></h3><p>Show synchronization state:</p><pre><code><code>chronyc tracking
</code></code></pre><p>Show time sources:</p><pre><code><code>chronyc sources -v
</code></code></pre><h3><strong>Mental model</strong></h3><pre><code><code>NTP servers
   |
   v
chronyd / timesyncd / ntpd
   |
   v
System clock
</code></code></pre><p>In other words, NTP usually targets the <strong>system clock</strong>, not the PHC.</p><div><hr></div><h2><strong>How Linux syncs time with PTP</strong></h2><p>In the PTP world, Linux often follows a two-step path:</p><ol><li><p>synchronize the <strong>PHC</strong> to the PTP network</p></li><li><p>synchronize the <strong>system clock</strong> to that PHC</p></li></ol><p>The two main tools are:</p><ul><li><p>ptp4l</p></li><li><p>phc2sys</p></li></ul><div><hr></div><h2><strong>ptp4l: syncing the NIC-side clock</strong></h2><p>ptp4l speaks PTP on the network and usually synchronizes the PHC associated with the interface.</p><p>Typical example:</p><pre><code><code>sudo ptp4l -i eth0 -m
</code></code></pre><p>Meaning:</p><ul><li><p>i eth0 &#8594; use interface eth0</p></li><li><p>m &#8594; print log messages to stdout</p></li></ul><h3><strong>Mental model</strong></h3><pre><code><code>PTP Grandmaster / network
        |
        v
      ptp4l
        |
        v
PHC on eth0 (/dev/ptpX)
</code></code></pre><p>This is usually where the NIC-side precision timing gets aligned to the network timing domain.</p><div><hr></div><h2><strong>phc2sys: syncing one local clock to another</strong></h2><p>Once the PHC is synchronized, the rest of the machine may still be reading the system clock.</p><p>That is why phc2sys exists.</p><p>Its job is to synchronize one local clock to another.</p><p>The most common use is:</p><p><strong>PHC &#8594; system clock</strong></p><p>Example:</p><pre><code><code>sudo phc2sys -s eth0 -c CLOCK_REALTIME -m
</code></code></pre><p>Meaning:</p><ul><li><p>s eth0 &#8594; source is the PHC associated with eth0</p></li><li><p>c CLOCK_REALTIME &#8594; target is the system clock</p></li><li><p>m &#8594; print status</p></li></ul><h3><strong>Mental model</strong></h3><pre><code><code>PHC on NIC
   |
   v
phc2sys
   |
   v
System clock
</code></code></pre><p>This is the classic Linux PTP flow.</p><div><hr></div><h2><strong>The classic Linux PTP pipeline</strong></h2><pre><code><code>PTP Grandmaster
      |
      v
  [ network ]
      |
      v
NIC hardware timestamping
      |
      v
    ptp4l
      |
      v
PHC (/dev/ptp0) synchronized to PTP domain
      |
    phc2sys
      |
      v
System clock (CLOCK_REALTIME)
      |
      v
Applications / logs / services
</code></code></pre><p>This is one of the most useful diagrams to keep in your head.</p><div><hr></div><h2><strong>PHC to system clock, or system clock to PHC?</strong></h2><p>In precision setups, the common direction is:</p><pre><code><code>PHC &#8594; system clock
</code></code></pre><p>because the PHC is closer to the wire and usually the better timing source in a PTP environment.</p><p>That is why this is a common command:</p><pre><code><code>sudo phc2sys -s eth0 -c CLOCK_REALTIME -m
</code></code></pre><p>But phc2sys is more general than that. It can synchronize clocks in other directions too.</p><div><hr></div><h2><code>ts2phc:</code>Syncing PHCs</h2><p>Linux can synchronize hardware clocks too, but the right tool depends on the synchronization path.</p><p>If the goal is to make the <strong>system clock</strong> follow a PHC, the usual tool is <code>phc2sys</code>. If the goal is to synchronize <strong>one or more PHCs from an external timestamp source</strong> such as PPS or GNSS, the usual tool is <code>ts2phc</code>. <code>ts2phc</code> is specifically designed to synchronize PHCs to external timestamp signals, and it can distribute one source to multiple PHCs.</p><p>Conceptually:</p><pre><code>External PPS / GNSS / timestamp source &#8594; ts2phc &#8594; one or more PHCs
PHC &#8594; phc2sys &#8594; system clock</code></pre><p>A typical <code>ts2phc</code> command looks like this:</p><pre><code>sudo ts2phc -s eth0 -c eth1 -m</code></pre><p>In this form:</p><ul><li><p><code>-s eth0</code> selects the source clock or source interface,<br></p></li><li><p><code>-c eth1</code> selects a PHC to synchronize,<br></p></li><li><p><code>-m</code> prints log messages to stdout. The tool also allows multiple <code>-c</code> options if you want to synchronize more than one PHC from the same source. <br></p></li></ul><p>This is less common than PHC-to-system-clock synchronization, but it matters in systems where multiple hardware clocks need to follow the same precise external reference. </p><div><hr></div><h2><strong>Where software timestamping fits</strong></h2><p>Not every NIC has hardware timestamping. Not every system needs that level of precision.</p><p>Linux can still synchronize clocks using software timestamps, and for many use cases that is completely fine.</p><p>But the practical tradeoff remains the same:</p><ul><li><p><strong>hardware timestamping</strong> gives measurements closer to the real wire event</p></li><li><p><strong>software timestamping</strong> includes more delay and variation from the OS path</p></li></ul><p>That is why software timestamping usually belongs to a looser precision budget, while hardware timestamping is what unlocks much tighter synchronization.</p><div><hr></div><h2><strong>The most useful commands at a glance</strong></h2><h3><strong>Check system time</strong></h3><pre><code><code>date
timedatectl
</code></code></pre><h3><strong>Check RTC</strong></h3><pre><code><code>sudo hwclock --show
</code></code></pre><h3><strong>List PHC devices</strong></h3><pre><code><code>ls -l /dev/ptp*
</code></code></pre><h3><strong>Check NIC timestamping support</strong></h3><pre><code><code>ethtool -T eth0
</code></code></pre><h3><strong>Run PTP on an interface</strong></h3><pre><code><code>sudo ptp4l -i eth0 -m
</code></code></pre><h3><strong>Sync system clock from PHC</strong></h3><pre><code><code>sudo phc2sys -s eth0 -c CLOCK_REALTIME -m
</code></code></pre><h3><strong>Sync PHCs</strong></h3><pre><code><code>sudo ts2phc -s eth0 -c eth1 -m</code></code></pre><h3><strong>Check chrony state</strong></h3><pre><code><code>chronyc tracking
chronyc sources -v
</code></code></pre><div><hr></div><h2><strong>The one table worth remembering</strong></h2><pre><code><code>RTC ------------------&gt; system time at boot / shutdown
NTP daemon -----------&gt; system clock
ptp4l ----------------&gt; PHC
phc2sys --------------&gt; PHC &lt;-&gt; system clock
External PPS / GNSS / timestamp source &#8594; ts2phc &#8594; one or more PHCs
hwclock --systohc ----&gt; system clock -&gt; RTC
hwclock --hctosys ----&gt; RTC -&gt; system clock
</code></code></pre><div><hr></div><h2><strong>The biggest practical lesson</strong></h2><p>When somebody says:</p><p><strong>&#8220;The machine is synchronized.&#8221;</strong></p><p>That is usually too vague.</p><p>The useful follow-up question is:</p><p><strong>Which clock is synchronized?</strong></p><ul><li><p>the RTC?</p></li><li><p>the system clock?</p></li><li><p>the PHC?</p></li><li><p>and which one is the application actually using?</p></li></ul><p>That one question prevents a lot of confusion.</p><div><hr></div><h2><strong>One-screen summary</strong></h2><pre><code><code>RTC
- battery-backed motherboard clock
- keeps time while machine is off
- checked with: hwclock --show

System clock
- main OS wall clock
- used by most applications
- checked with: date, timedatectl
- synchronized by: NTP or by phc2sys from PHC

PHC
- hardware clock on a PTP-capable NIC
- represented as: /dev/ptpX
- checked with: ls /dev/ptp*, ethtool -T eth0
- synchronized by: ptp4l

Typical Linux PTP flow
PTP network -&gt; ptp4l -&gt; PHC -&gt; phc2sys -&gt; system clock
</code></code></pre><div><hr></div><h2><strong>Final note</strong></h2><p>If you made it all the way here, you did not just read a few articles about clocks.</p><p>You built a real mental model of time in computing &#8212; from first principles, to clocks inside a machine, to synchronization across networks, to the actual Linux entities and tools that make it work in practice.</p><p>That already puts you far ahead of most engineers who touch these systems.</p><p>You now know enough to stop treating time as a mysterious background feature and start seeing it for what it really is: infrastructure, measurement, coordination, and engineering.</p><p>And it was the final piece: a practical cheat sheet you can actually use. Bookmark it. Return to it. Break things with it. Fix things with it.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dmytro&#8217;s Substack is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[A Practical Guide to Time for Developers: Part 3 — How Computers Share Time]]></title><description><![CDATA[How computers synchronize time with NTP, PTP, and timestamping in Linux]]></description><link>https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-ec8</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-ec8</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Mon, 16 Mar 2026 15:42:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!0JCc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ff7fad6-3567-42cf-a8e4-f948866f3fd5_1000x420.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0JCc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ff7fad6-3567-42cf-a8e4-f948866f3fd5_1000x420.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0JCc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ff7fad6-3567-42cf-a8e4-f948866f3fd5_1000x420.webp 424w, https://substackcdn.com/image/fetch/$s_!0JCc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ff7fad6-3567-42cf-a8e4-f948866f3fd5_1000x420.webp 848w, https://substackcdn.com/image/fetch/$s_!0JCc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ff7fad6-3567-42cf-a8e4-f948866f3fd5_1000x420.webp 1272w, https://substackcdn.com/image/fetch/$s_!0JCc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ff7fad6-3567-42cf-a8e4-f948866f3fd5_1000x420.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0JCc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ff7fad6-3567-42cf-a8e4-f948866f3fd5_1000x420.webp" width="1000" height="420" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1ff7fad6-3567-42cf-a8e4-f948866f3fd5_1000x420.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:420,&quot;width&quot;:1000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:139314,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/191125080?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ff7fad6-3567-42cf-a8e4-f948866f3fd5_1000x420.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0JCc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ff7fad6-3567-42cf-a8e4-f948866f3fd5_1000x420.webp 424w, https://substackcdn.com/image/fetch/$s_!0JCc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ff7fad6-3567-42cf-a8e4-f948866f3fd5_1000x420.webp 848w, https://substackcdn.com/image/fetch/$s_!0JCc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ff7fad6-3567-42cf-a8e4-f948866f3fd5_1000x420.webp 1272w, https://substackcdn.com/image/fetch/$s_!0JCc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ff7fad6-3567-42cf-a8e4-f948866f3fd5_1000x420.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2><strong>Intro</strong></h2><p>Every action film has that scene just before the military operation begins.</p><p>&#8220;Let&#8217;s sync our watches,&#8221; the captain says.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dmytro&#8217;s Substack is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>The idea is simple: if every stage of the plan depends on precise coordination, everyone involved has to act in sync and according to the same timeline.</p><p>A while ago, we started our journey with a practical goal: synchronizing the time of many computers. To get there, we first had to understand what time actually is and learn the basic glossary needed to speak the language of this problem and its solutions. In the first part (<a href="https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers">https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers</a>), we explored the foundations of time itself. In the second (<a href="https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-2ec">https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-2ec</a>), we looked at how time is kept and tracked inside a single computer. Now we are finally ready to move to the next step: how many computers share time with each other.</p><p>Keeping precise time across many computers is not unusual or exotic. In fact, the opposite is true. Distributed systems, industrial networks, telecom infrastructure, financial systems, and measurement environments often involve hundreds or thousands of devices that must stay synchronized within a clearly defined precision budget.</p><p>Let&#8217;s imagine a wind farm. Each turbine is around 120 meters tall and has a warning light at the top. To make the turbines visible to planes at night, the lights should blink every second. And to make the whole field clearly visible as one coordinated structure, those lights should blink simultaneously.</p><p>How can we make that happen?</p><p>The obvious answer is: the turbines need synchronized clocks.</p><p>But how we can keep them in sync for hundreds and thousands devices with amazing accuracy?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!huJQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd454b3f2-43d7-45e4-8300-54fdef86c487_1536x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!huJQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd454b3f2-43d7-45e4-8300-54fdef86c487_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!huJQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd454b3f2-43d7-45e4-8300-54fdef86c487_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!huJQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd454b3f2-43d7-45e4-8300-54fdef86c487_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!huJQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd454b3f2-43d7-45e4-8300-54fdef86c487_1536x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!huJQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd454b3f2-43d7-45e4-8300-54fdef86c487_1536x1024.jpeg" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d454b3f2-43d7-45e4-8300-54fdef86c487_1536x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:336712,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/191125080?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd454b3f2-43d7-45e4-8300-54fdef86c487_1536x1024.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!huJQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd454b3f2-43d7-45e4-8300-54fdef86c487_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!huJQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd454b3f2-43d7-45e4-8300-54fdef86c487_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!huJQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd454b3f2-43d7-45e4-8300-54fdef86c487_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!huJQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd454b3f2-43d7-45e4-8300-54fdef86c487_1536x1024.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Let&#8217;s see! </p><h2><strong>Just sync the clocks once?</strong></h2><p>Let&#8217;s start with the most obvious idea: set the same time on all clocks once, and the problem is solved.</p><p>Unfortunately, it does not work that way.</p><p>Every clock has physical behavior behind it. Its frequency is affected by things like oscillator quality, temperature, aging, and other environmental factors. As a result, every clock drifts in its own way. Some also exhibit short-term fluctuations, often described as wander. These effects cannot be fully eliminated, and in practice they mean that two clocks will slowly diverge even if they start perfectly aligned.</p><p>That turns synchronization from a one-time setup task into a continuous process.</p><p>Clocks do not just need to be set. They need to be kept aligned over time. In practice, that means measuring the difference between clocks again and again, then adjusting their time and, more importantly, their rate so that they do not immediately drift apart again.</p><p>You can see how quickly clocks with different rates and wander fall out of sync, even when they start at exactly the same time:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zdtw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b507daa-5124-42c2-93c7-fb7792096dc3_644x512.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zdtw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b507daa-5124-42c2-93c7-fb7792096dc3_644x512.gif 424w, https://substackcdn.com/image/fetch/$s_!zdtw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b507daa-5124-42c2-93c7-fb7792096dc3_644x512.gif 848w, https://substackcdn.com/image/fetch/$s_!zdtw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b507daa-5124-42c2-93c7-fb7792096dc3_644x512.gif 1272w, https://substackcdn.com/image/fetch/$s_!zdtw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b507daa-5124-42c2-93c7-fb7792096dc3_644x512.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zdtw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b507daa-5124-42c2-93c7-fb7792096dc3_644x512.gif" width="644" height="512" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9b507daa-5124-42c2-93c7-fb7792096dc3_644x512.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:512,&quot;width&quot;:644,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:510655,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/191125080?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b507daa-5124-42c2-93c7-fb7792096dc3_644x512.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zdtw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b507daa-5124-42c2-93c7-fb7792096dc3_644x512.gif 424w, https://substackcdn.com/image/fetch/$s_!zdtw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b507daa-5124-42c2-93c7-fb7792096dc3_644x512.gif 848w, https://substackcdn.com/image/fetch/$s_!zdtw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b507daa-5124-42c2-93c7-fb7792096dc3_644x512.gif 1272w, https://substackcdn.com/image/fetch/$s_!zdtw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b507daa-5124-42c2-93c7-fb7792096dc3_644x512.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Feel free to explore the interactive simulation I created for this exact scenario and see how quickly clocks drift out of sync: https://dmytrohuzz.github.io/interactive_demo/clock_sync/index.html</p><h2><strong>From setting time to synchronization</strong></h2><p>Once we accept that clocks drift, a one-time setup stops looking like a real solution. Time is not something you assign once. It is something you keep aligned.</p><p>In practice, synchronization is a feedback loop. A machine compares its local clock to some reference, estimates the difference, adjusts its own clock, and repeats the process again and again.</p><p>The difficult part is that machines cannot read each other&#8217;s clocks directly. They can only communicate over a network, and the network adds delay and uncertainty. So synchronization protocols work indirectly: they exchange messages with timestamps and use those timestamps to estimate the relationship between clocks.</p><p>At the center of that estimate are two questions:</p><ul><li><p>how far apart are the clocks?</p></li><li><p>how much of the observed difference comes from network delay rather than clock error?</p></li></ul><p>This sounds simple in theory, but the key idea only becomes clear once we walk through it step by step.</p><p>A basic synchronization exchange gives us four timestamps:</p><ul><li><p><strong>t1</strong> &#8212; the client sends a request</p></li><li><p><strong>t2</strong> &#8212; the server receives that request</p></li><li><p><strong>t3</strong> &#8212; the server sends a response</p></li><li><p><strong>t4</strong> &#8212; the client receives the response</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Dzv1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc664f7c-78b9-461f-a226-36da449bde39_644x838.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Dzv1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc664f7c-78b9-461f-a226-36da449bde39_644x838.gif 424w, https://substackcdn.com/image/fetch/$s_!Dzv1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc664f7c-78b9-461f-a226-36da449bde39_644x838.gif 848w, https://substackcdn.com/image/fetch/$s_!Dzv1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc664f7c-78b9-461f-a226-36da449bde39_644x838.gif 1272w, https://substackcdn.com/image/fetch/$s_!Dzv1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc664f7c-78b9-461f-a226-36da449bde39_644x838.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Dzv1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc664f7c-78b9-461f-a226-36da449bde39_644x838.gif" width="644" height="838" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fc664f7c-78b9-461f-a226-36da449bde39_644x838.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:838,&quot;width&quot;:644,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:493203,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/191125080?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc664f7c-78b9-461f-a226-36da449bde39_644x838.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Dzv1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc664f7c-78b9-461f-a226-36da449bde39_644x838.gif 424w, https://substackcdn.com/image/fetch/$s_!Dzv1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc664f7c-78b9-461f-a226-36da449bde39_644x838.gif 848w, https://substackcdn.com/image/fetch/$s_!Dzv1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc664f7c-78b9-461f-a226-36da449bde39_644x838.gif 1272w, https://substackcdn.com/image/fetch/$s_!Dzv1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc664f7c-78b9-461f-a226-36da449bde39_644x838.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p></p><p>These four timestamps are the heart of the whole mechanism. Once this pattern becomes intuitive, the rest of the synchronization topic becomes much easier to follow.</p><p>Now imagine the exchange from the client&#8217;s point of view.</p><p>The client sends a request at local time <strong>t1 = 00:00</strong>.</p><p>Later, it receives the response at local time <strong>t4 = 00:04</strong>.</p><p>Inside that response, the server includes its own timestamps:</p><ul><li><p>it received the request at <strong>t2 = 00:06</strong></p></li><li><p>it sent the response at <strong>t3 = 00:06</strong></p></li></ul><p>At first glance, this looks strange. How can the server receive the request at 00:06 if the client sent it at 00:00, and the whole round trip took only four seconds on the client side?</p><p>The answer is simple: <strong>t1 and t2 do not belong to the same timeline</strong>.</p><p>The client clock and the server clock are different local views of time. What synchronization tries to estimate is the relation between those two timelines. In other words, it tries to answer this question:</p><p><strong>If the client sees one moment as 00:00, what does the server call that same moment?</strong></p><p>That relationship is what we call <strong>offset</strong>.</p><p>This is the most important insight in the whole topic: the difference t2 - t1 does not represent only network delay. It contains two things mixed together:</p><ul><li><p>packet travel time</p></li><li><p>clock offset between client and server</p></li></ul><p>A useful way to think about it is with time zones.</p><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EBqI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca685d13-2c0c-45ca-85cf-472d423dab3a_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EBqI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca685d13-2c0c-45ca-85cf-472d423dab3a_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!EBqI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca685d13-2c0c-45ca-85cf-472d423dab3a_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!EBqI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca685d13-2c0c-45ca-85cf-472d423dab3a_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!EBqI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca685d13-2c0c-45ca-85cf-472d423dab3a_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EBqI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca685d13-2c0c-45ca-85cf-472d423dab3a_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ca685d13-2c0c-45ca-85cf-472d423dab3a_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1751180,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/191125080?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca685d13-2c0c-45ca-85cf-472d423dab3a_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EBqI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca685d13-2c0c-45ca-85cf-472d423dab3a_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!EBqI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca685d13-2c0c-45ca-85cf-472d423dab3a_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!EBqI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca685d13-2c0c-45ca-85cf-472d423dab3a_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!EBqI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca685d13-2c0c-45ca-85cf-472d423dab3a_1536x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Imagine you leave one city at local time 00:00, travel to another city, and arrive when the local clock there shows 14:00. Then you immediately turn around and come back, arriving home when your original city&#8217;s clock shows 20:00.</p><p>Now suppose the travel time is the same in both directions.</p><p>The first leg, from your city to the other one, includes:</p><p><strong>travel time + time-zone difference</strong></p><p>The return leg includes:</p><p><strong>travel time - time-zone difference</strong></p><p>So if the outward journey appears shorter or longer than the return journey, that difference tells you something about the offset between the two local clocks.</p><p>This is exactly what synchronization protocols exploit.</p><p>Under the usual symmetric-delay assumption, the offset can be estimated as:</p><p><code>offset = ((t2 - t1) + (t3 - t4)) /2</code></p><p>and the round-trip delay as:</p><p><code>delay = (t4 - t1) - (t3 - t2)</code></p><p>The first formula separates clock offset from the two directions of travel. The second removes the server&#8217;s processing time and leaves only the network round-trip time.</p><p>So synchronization is not about directly copying time from one machine to another. It is about observing message exchanges, separating delay from clock difference, and then correcting the local clock based on that estimate.</p><p>That is the core idea behind the whole topic.</p><p>Feel free to play with the simulation here:</p><p><a href="https://dmytrohuzz.github.io/interactive_demo/clock_sync/clock_sync_explained">https://dmytrohuzz.github.io/interactive_demo/clock_sync/clock_sync_explained</a></p><div><hr></div><h2><strong>NTP and PTP: two ways to synchronize clocks</strong></h2><p>Over time, two major protocol families became the standard answers to the synchronization problem: <strong>NTP</strong> and <strong>PTP</strong>.</p><p>Both solve the same core problem: a machine cannot read another machine&#8217;s clock directly, so it has to infer the difference by exchanging timestamped messages over a network. From those timestamps, it estimates clock offset and network delay, then adjusts the local clock toward a reference.</p><p>The difference is not the basic idea, but the precision target and the environment they are designed for.</p><h3><strong>NTP: practical synchronization for general systems</strong></h3><p><strong>NTP</strong> &#8212; the Network Time Protocol &#8212; is the general-purpose approach. It is designed to keep clocks reasonably aligned across ordinary systems and ordinary networks.</p><p>Its main principle is simple: a client exchanges request and response messages with a time server, records timestamps on both sides, estimates round-trip delay and clock offset, and then gradually disciplines its own clock. It repeats this process continuously, using multiple measurements to smooth out noise and avoid reacting too aggressively to one bad sample.</p><p>That makes NTP a good fit for:</p><ul><li><p>logs and observability</p></li><li><p>authentication and certificate validation</p></li><li><p>scheduled jobs</p></li><li><p>general wall-clock correctness across servers and infrastructure</p></li></ul><p>NTP does not assume a perfect network. It is built for real environments, where delays vary, paths are not perfectly symmetric, and hosts are under changing load. Its strength is robustness, not extreme precision.</p><p>[<a href="https://dmytrohuzz.github.io/interactive_demo/clock_sync/ntp_visualized.html">Interactive Demo</a>]</p><h3><strong>PTP: tighter synchronization for controlled environments</strong></h3><p><strong>PTP</strong> &#8212; the Precision Time Protocol &#8212; targets systems where much tighter agreement between clocks is required.</p><p>Its principle is similar to NTP: devices exchange timing messages, estimate offset and delay, and adjust local clocks. But PTP is designed for local precision networks, where the entire timing path is treated more carefully. In practice, this often means hardware timestamping, PTP-aware switches, and a dedicated timing hierarchy built around a grandmaster clock distributing time to other devices.</p><p>PTP is commonly used in:</p><ul><li><p>industrial and automation systems</p></li><li><p>telecom networks</p></li><li><p>audio and video systems</p></li><li><p>measurement systems</p></li><li><p>finance</p></li><li><p>power and substation environments</p></li></ul><p>PTP is not just &#8220;a more accurate NTP.&#8221; It usually operates in a different class of environment, with tighter timing requirements and more deliberate infrastructure support.</p><p>[<a href="https://dmytrohuzz.github.io/interactive_demo/clock_sync/ptp_visualized.html">Interactive Demo</a>]</p><h3><strong>Different tools for different timing budgets</strong></h3><p>So NTP and PTP are not really rivals. They are different engineering choices.</p><p>If the goal is to keep ordinary systems aligned to real time well enough for general infrastructure behavior, NTP is usually the right tool.</p><p>If the goal is to keep clocks tightly aligned in a local timing domain where timing quality directly affects correctness, event ordering, or measurement precision, PTP is often the better fit.</p><p>The key point is this: both protocols depend on timestamp exchange, but the quality of synchronization depends heavily on how those timestamps are produced.</p><p>And that leads to the next question: <strong>where exactly was the timestamp taken?</strong></p><p>This is where timestamping location &#8212; in software or in hardware &#8212; starts to matter.</p><h2><strong>Why timestamp location changes everything</strong></h2><p>At this point, NTP and PTP may still look like protocol problems: exchange messages, estimate offset, correct the clock.</p><p>But in practice, a large part of synchronization quality depends on something more physical:</p><p><strong>where exactly is the timestamp taken?</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9Nt1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9057a893-8302-4c5c-bf0a-4997fbb9a8fd_1536x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9Nt1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9057a893-8302-4c5c-bf0a-4997fbb9a8fd_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!9Nt1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9057a893-8302-4c5c-bf0a-4997fbb9a8fd_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!9Nt1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9057a893-8302-4c5c-bf0a-4997fbb9a8fd_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!9Nt1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9057a893-8302-4c5c-bf0a-4997fbb9a8fd_1536x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9Nt1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9057a893-8302-4c5c-bf0a-4997fbb9a8fd_1536x1024.jpeg" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9057a893-8302-4c5c-bf0a-4997fbb9a8fd_1536x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:223519,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/191125080?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9057a893-8302-4c5c-bf0a-4997fbb9a8fd_1536x1024.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9Nt1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9057a893-8302-4c5c-bf0a-4997fbb9a8fd_1536x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!9Nt1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9057a893-8302-4c5c-bf0a-4997fbb9a8fd_1536x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!9Nt1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9057a893-8302-4c5c-bf0a-4997fbb9a8fd_1536x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!9Nt1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9057a893-8302-4c5c-bf0a-4997fbb9a8fd_1536x1024.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>That matters because a packet does not appear in software at the exact moment it hits the wire. Between the real network event and the moment the operating system records a timestamp, the packet may pass through the NIC, driver, kernel, interrupt handling, scheduling, and software processing. Every one of those layers can add delay and variation.</p><p>So two timestamps may look equally precise as numbers while representing very different physical moments.</p><h3><strong>Software timestamping</strong></h3><p>With software timestamping, the timestamp is recorded somewhere in the software stack after the packet has already passed through part of the system.</p><p>That makes software timestamping widely available and easy to use, but it also means the measurement includes more uncertainty:</p><ul><li><p>interrupt latency</p></li><li><p>kernel and driver delay</p></li><li><p>scheduling effects</p></li><li><p>queueing and system load</p></li></ul><p>As a result, a software timestamp often reflects when the system handled the packet, not the exact moment the packet crossed the network interface.</p><h3><strong>Hardware timestamping</strong></h3><p>With hardware timestamping, the timestamp is recorded much closer to the real transmit or receive event, typically inside the NIC itself.</p><p>This removes a large part of the software-induced uncertainty and makes the measurement more stable and repeatable. The closer the timestamp is to the actual wire event, the more useful it becomes for precise synchronization.</p><p>That is one of the main reasons PTP can achieve much better accuracy in the right environment: not only because of the protocol itself, but because it is often paired with hardware timestamping and a more carefully controlled timing path.</p><p>So the practical precision limit is not defined by the protocol name alone. It depends on the full measurement path.</p><p>A good rule of thumb is simple:</p><p><strong>the closer the timestamp is to the wire, the better the synchronization can be.</strong></p><div><hr></div><h2><strong>Summary</strong></h2><p>A single computer can keep time locally. A distributed system has a harder task: many machines must keep time together.</p><p>That is why simply setting clocks once is not enough. Real clocks drift, so synchronization has to be continuous. Protocols such as <strong>NTP</strong> and <strong>PTP</strong> address this by exchanging timestamped messages, estimating clock offset and network delay, and repeatedly steering local clocks toward a reference.</p><p>But protocol choice is only part of the story. In practice, synchronization quality also depends heavily on where timestamps are taken. A timestamp captured deep in software carries more uncertainty than one captured close to the physical network event.</p><p>So if this part was about the general idea of shared time &#8212; why it matters, why it is difficult, and how systems approach it &#8212; the next part will move from principle to implementation.</p><p>We will look at how Linux actually does this in practice: NICs, software and hardware timestamping, PHCs, and the tools that connect them into a real synchronization stack.</p><div><hr></div><h2>Next part:</h2><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;42da1442-0c6d-4034-a99c-039a91a7b2de&quot;,&quot;caption&quot;:&quot;If you got here and made it through the previous articles, you have already done the hard part. You are basically a time guru now.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;showDescription&quot;:true,&quot;showImage&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;A Practical Guide to Time for Developers: Part 4 -The Linux Time Sync Cheat Sheet&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:392416265,&quot;name&quot;:&quot;Dmytro Huz&quot;,&quot;bio&quot;:&quot;Software Engineer in the Energy Sector. AWS Community Builder (Dev Tools). (Re)building core tech in public &#8212; so it stop feeling like magic. Writing at Rebuilt.&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4a14e6b-5f68-4257-9ee7-e33b8864d56a_1024x1024.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2026-03-19T16:36:51.707Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!MEgQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6acd666-fe66-4163-a98f-62e564fa6c7e_1536x672.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.dmytrohuz.com/p/a-practical-guide-to-time-for-developers-314&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:191493632,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:6272314,&quot;publication_name&quot;:&quot;Rebuilt&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!JM5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f89608f-4575-4fe4-9df4-7d6a25e088b2_1254x1254.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dmytro&#8217;s Substack is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Cloud Sells Geographical Abstraction. Critical Systems Buy Geographical Proximity.]]></title><description><![CDATA[What recent disruptions around AWS infrastructure in the Gulf reveal about latency, sovereignty, and the hidden geography of modern cloud systems]]></description><link>https://www.dmytrohuz.com/p/cloud-sells-geographical-abstraction</link><guid isPermaLink="false">https://www.dmytrohuz.com/p/cloud-sells-geographical-abstraction</guid><dc:creator><![CDATA[Dmytro Huz]]></dc:creator><pubDate>Sun, 15 Mar 2026 20:33:15 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ovmG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5688691-d876-494b-a962-f12f790f6098_1536x672.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ovmG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5688691-d876-494b-a962-f12f790f6098_1536x672.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ovmG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5688691-d876-494b-a962-f12f790f6098_1536x672.png 424w, https://substackcdn.com/image/fetch/$s_!ovmG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5688691-d876-494b-a962-f12f790f6098_1536x672.png 848w, https://substackcdn.com/image/fetch/$s_!ovmG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5688691-d876-494b-a962-f12f790f6098_1536x672.png 1272w, https://substackcdn.com/image/fetch/$s_!ovmG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5688691-d876-494b-a962-f12f790f6098_1536x672.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ovmG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5688691-d876-494b-a962-f12f790f6098_1536x672.png" width="1456" height="637" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b5688691-d876-494b-a962-f12f790f6098_1536x672.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:637,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1702675,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.dmytrohuz.com/i/191062210?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5688691-d876-494b-a962-f12f790f6098_1536x672.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ovmG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5688691-d876-494b-a962-f12f790f6098_1536x672.png 424w, https://substackcdn.com/image/fetch/$s_!ovmG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5688691-d876-494b-a962-f12f790f6098_1536x672.png 848w, https://substackcdn.com/image/fetch/$s_!ovmG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5688691-d876-494b-a962-f12f790f6098_1536x672.png 1272w, https://substackcdn.com/image/fetch/$s_!ovmG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5688691-d876-494b-a962-f12f790f6098_1536x672.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We like to talk about &#8220;the cloud&#8221; as if software has escaped geography.</p><p>The interface encourages that illusion. You choose a region, deploy a service, replicate some data, add a failover plan, and the system starts to feel abstract. Compute is elastic. Storage is managed. Infrastructure appears to have become location-independent.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dmytro&#8217;s Substack is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>But critical systems do not really stop living somewhere.</p><p>They still sit on top of power, cooling, fiber, telecom topology, legal jurisdiction, operational teams, and the physics of latency. And the more a system becomes real &#8212; real users, real regulation, real response-time constraints, real business consequence &#8212; the more geography tends to re-enter the design.</p><p>That is the part cloud culture hides well: cloud abstracts geography at the interface level, but many important systems reintroduce geography at the architecture level.</p><p>Recent disruptions around AWS infrastructure in the Gulf make that harder to ignore. Reuters reported issues affecting AWS data centers in the UAE and Bahrain amid Iranian strikes, including problems tied to power and connectivity. Separate Reuters reporting also described incidents in the UAE involving drone interceptions and falling debris in Fujairah. Whether one looks at these as isolated disruptions or as signals of a broader shift, the underlying point is the same: data centers are no longer just &#8220;IT facilities.&#8221; They increasingly sit inside the same map of strategic exposure as energy, ports, and communications infrastructure.</p><p>That does not just make cloud infrastructure more important. It makes geography more important.</p><h2><strong>The abstraction is useful. The abstraction is also misleading.</strong></h2><p>This is not an anti-cloud argument.</p><p>Cloud abstractions are powerful because they compress operational complexity. They let teams build and scale systems without owning every layer directly. They make certain kinds of resilience easier to implement. They lower coordination cost. They make global software feel tractable.</p><p>But useful abstractions have a habit of concealing the substrate.</p><p>In cloud, the concealed substrate is not just hardware. It is geography.</p><p>A lot of modern software is designed as if &#8220;where it runs&#8221; is a secondary implementation detail. For some workloads, that is mostly true. For critical ones, it often is not.</p><p>Latency-sensitive systems want to be physically closer to where requests originate. Regulated systems want data to remain in specific jurisdictions. Operationally important systems want predictable local integration with identity, networking, observability, and response teams. Once those requirements become strong enough, the architecture starts to pull back toward place.</p><p>So while the cloud sells a kind of placelessness, critical systems often buy proximity instead.</p><h2><strong>Latency quietly defeats the fantasy of placeless compute</strong></h2><p>The first force that brings geography back is latency.</p><p>Latency is often described as just a technical metric. In practice, it is a design constraint that pushes infrastructure back into physical space. If response time matters, distance matters. If user experience matters, path length matters. If control loops matter, locality matters.</p><p>This is not theoretical. AWS explicitly recommends choosing regions close to users for latency reasons, and sells Local Zones and Wavelength for workloads that need to run nearer to end users and telecom networks. Microsoft says similar things about Azure Extended Zones for low-latency and data-residency-sensitive workloads.</p><p>At the interface level, cloud encourages us to think in regions, services, and APIs. At the architecture level, latency-sensitive systems often say something much simpler:</p><p><strong>put the system near the place where the consequences happen.</strong></p><p>That is already a partial collapse of abstraction.</p><h2><strong>Sovereignty brings geography back a second time</strong></h2><p>The second force is law.</p><p>Even if a workload could technically run anywhere, that does not mean it is allowed to. Data residency, sector-specific regulation, national security requirements, and jurisdictional constraints all push architecture back toward geography. That is why sovereign cloud offerings now exist at all. AWS has launched a European Sovereign Cloud specifically for stricter residency and operational autonomy requirements, while Google and Microsoft document controls for customers that cannot treat geography as interchangeable.</p><p>This is a useful correction to one of cloud&#8217;s most seductive promises.</p><p>People say cloud gives you geographic flexibility. Sometimes it does. But in important systems, law can be just as constraining as physics. The workload may appear abstract, but its permitted runtime geography can still be narrow.</p><p>Once again, cloud did not remove geography. It pushed geography behind a cleaner control plane.</p><h2><strong>The result is hidden concentration</strong></h2><p>This is where the systems point matters.</p><p>Cloud encourages a mental model of distribution. Critical systems often rebuild concentration underneath that model.</p><p>Not recklessly. Often for completely rational reasons:</p><ul><li><p>lower latency</p></li><li><p>data residency</p></li><li><p>operational simplicity</p></li><li><p>cost structure</p></li><li><p>regional business requirements</p></li><li><p>local ecosystem dependence</p></li></ul><p>Each decision can make sense in isolation. But in aggregate, a system may look globally abstract while the important runtime, data, and dependency paths remain tied to a much narrower geography.</p><p>That is where hidden fragility comes from.</p><p>The problem is not that cloud is fake. The problem is that cloud can make concentration feel more diversified than it really is.</p><p>A clean interface can hide a concentrated substrate.</p><p>And once that substrate becomes strategically important, the illusion gets expensive.</p><p>That is why the AWS example in the Gulf matters beyond the specific incident. It is not only a story about one provider or one region. It is a visible reminder that cloud infrastructure now sits close enough to the center of commerce, communications, and increasingly AI-related compute demand that it begins to resemble critical infrastructure in the older sense of the term. And critical infrastructure is always geographic.</p><h2><strong>Good architecture can counter this &#8212; but not by accident</strong></h2><p>Cloud does not automatically imply weak geographic resilience. In fact, major providers explicitly support multi-region architectures, active-active designs, and cross-region failover. Google recommends multi-region deployments to improve latency and availability, and AWS Well-Architected explicitly warns against consolidating all workload resources into one geographic location. AWS also documents active-active multi-region patterns for low-latency and high-availability systems.</p><p><strong>Cloud does not diversify geography by default just because it is cloud.</strong></p><p>That has to be designed.</p><p>And the design often runs against real pressures:</p><ul><li><p>performance wants locality</p></li><li><p>regulation wants jurisdictional specificity</p></li><li><p>operations want manageable complexity</p></li><li><p>economics want concentration where scale is cheapest</p></li></ul><p>Resilience is not the natural resting state. It is a deliberate counterweight to optimization pressure.</p><p>That is the systems lesson.</p><h2><strong>Why this matters more now</strong></h2><p>This matters more than it used to because modern systems are becoming more dependent on concentrated compute.</p><p>As more of business, communications, platforms, and AI workloads sit on top of large cloud regions and data center clusters, the abstraction becomes more consequential &#8212; and more dangerous to misunderstand. The cloud did not make geography disappear. It made geography easier to ignore until latency, law, outage, or conflict forces it back into view.</p><p>At that point, the important question is no longer whether cloud is &#8220;really distributed.&#8221;</p><p>The better question is:</p><p><strong>How much geographic reality has your architecture quietly reintroduced underneath the abstraction &#8212; and have you designed resilience there on purpose, or just assumed the word cloud already did that for you?</strong></p><p>Because that assumption is where a lot of hidden concentration begins.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.dmytrohuz.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Dmytro&#8217;s Substack is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>