<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>proxmox on Luis Logs</title>
    <link>https://luislogs.com/tags/proxmox/</link>
    <description>Recent content in proxmox on Luis Logs</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Mon, 23 Mar 2026 18:40:30 +0900</lastBuildDate><atom:link href="https://luislogs.com/tags/proxmox/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Upgrading our home internet to 10 Gbps</title>
      <link>https://luislogs.com/posts/upgrading-our-home-internet-to-10-gbps/</link>
      <pubDate>Mon, 23 Mar 2026 18:40:30 +0900</pubDate>
      
      <guid>https://luislogs.com/posts/upgrading-our-home-internet-to-10-gbps/</guid>
      <description>I have finally decided to move our internet subscription up from 1Gbps to 10Gbps. While 1G is already more than sufficient for home use, speed is not all there is. Beyond just raw speed, our old setup was held back by the overhead of PPPoE and the debatable limitation it brings when paired with a FreeBSD-based router OS like OPNsense. The new connection uses IPoE (IP over Ethernet) which doesn&amp;rsquo;t have the same hiccups the former is known to have.</description>
      <content:encoded><![CDATA[<p>I have finally decided to move our internet subscription up from 1Gbps to 10Gbps. While 1G is already more than sufficient for home use, speed is not all there is. Beyond just raw speed, our old setup was held back by the overhead of PPPoE and the debatable limitation it brings when paired with a FreeBSD-based router OS like OPNsense. The new connection uses IPoE (IP over Ethernet) which doesn&rsquo;t have the same hiccups the former is known to have.</p>
<p>Second, the old subscription only had IPv4. Don&rsquo;t get me wrong, IPv4 isn&rsquo;t a bad thing. In fact, a good majority of the internet still runs on IPv4. But recently, I&rsquo;ve gained interest in exploring the capabilities and other features that come with IPv6. More on this later, but the main trigger point for this is because IPv6 is already widely used in Japan. If I&rsquo;m not mistaken, IPv6 adoption has been enforced by the Japan Ministry of Communications for some time now.</p>
<p>Third, since the beginning of last year, I&rsquo;ve taken on a new role focused on optimizing customer experience performance, where speed is one of the main concerns. To better support this and overcome the limitations of my current toolset, having a speed test server (with multi-gigabit bandwidth) that I have full control of is a fundamental first step!</p>
<h2 id="hardware">Hardware</h2>
<p>Certain Lenovo Tiny PCs are popular machines for having a PCIe slot that can be fitted with 10G NICs, so that&rsquo;s what I went with. I was able to get a secondhand one with an Intel i5-8500T 6C CPU. This should be more than enough for my needs, even if I wanted to host other services on this machine. As for the NIC, I had the option of going with Mellanox or Intel ones. To be more specific, I was choosing between a Mellanox ConnectX-4 and an Intel X710-DA2. Mellanox seems to be more popular in terms of compatibility and stability, but it&rsquo;s also known to have elevated power consumption since it&rsquo;s not able to achieve higher C-states even when idle. The X710-DA2, on the other hand, was known to have compatibility issues, especially when using the OEM-branded ones. I went with Intel to have peace of mind knowing that I tried my best to save electricity costs (as if all the other machines in the homelab justify all the power they require!).</p>




	




































  	
	

	
		<script src="/shortcode-gallery/jquery-3.7.0.min.js"></script>
	
	
	
		<script src="/shortcode-gallery/lazy/jquery.lazy.min.js"></script>
	

	<script src="/shortcode-gallery/swipebox/js/jquery.swipebox.min.js"></script>
	<link rel="stylesheet" href="/shortcode-gallery/swipebox/css/swipebox.min.css">

	<script src="/shortcode-gallery/justified_gallery/jquery.justifiedGallery.min.js"></script>
	<link rel="stylesheet" href="/shortcode-gallery/justified_gallery/justifiedGallery.min.css"/>


<style>
	

	
</style>





<div id="gallery-0efe21febd1ec25b8e9ee6c88aecf11b-0-wrapper" class="gallery-wrapper">
<div id="gallery-0efe21febd1ec25b8e9ee6c88aecf11b-0" class="justified-gallery">
	
		
		
				
			
			
			
				
			

			
			
				
					
				
			


			
			
			
				
				
				
				
				
				
				
				
			

			
			


			<div>
				
				
					
				
				<a href="/posts/upgrading-our-home-internet-to-10-gbps/lenovo_nic/1_lenovo.jpg" 
					class="galleryImg"
					
						

						
							data-description="iPhone 15 Pro Max + iPhone 15 Pro Max back triple camera 6.765mm f/1.78<br/>6.764999865652793mm f/1.7799999713880652 1/25sec ISO 500"
						

						
					
					>
					<img			
						width="600" height="450"

						
							
							style="filter: blur(25px);"
							
								src="data:image/jpeg;base64,/9j/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4&#43;JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIABgAIAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5&#43;gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4&#43;Tl5ufo6ery8/T19vf4&#43;fr/2gAMAwEAAhEDEQA/AEmYDJP4Vk3PLVrDX7Z7WWwkE1osjBnUAHkeu4A4/GqUtnHPzbXkMmeitlGP4Gs7FXMlxgVDnBq9c2V3Bnzbd1A74yPzqiwGaYHZahCkjFZY1fHZh0rDksY42/dFoxkEgHIOO3Pauh1D/j5f/eNZE3ekV5lSCa6snzFKxT&#43;5uIH5UXl8t1C6NZRGRhhZMYYH1yKG6GoT/rBVXJe9z//Z"
							
							class="lazy"
							data-src="/posts/upgrading-our-home-internet-to-10-gbps/lenovo_nic/1_lenovo_huc60cc3890e3e167b3b80c1e9ea5fec25_235863_600x600_fit_q100_lanczos.jpg"
						

						
							
								
							
						
					>
				</a>
			</div>
		
	
		
		
				
			
			
			
				
			

			
			
				
					
				
			


			
			
			
				
				
				
				
				
				
				
				
			

			
			


			<div>
				
				
					
				
				<a href="/posts/upgrading-our-home-internet-to-10-gbps/lenovo_nic/7_nic1.jpg" 
					class="galleryImg"
					
						

						
							data-description="iPhone 15 Pro Max + iPhone 15 Pro Max back triple camera 2.22mm f/2.2<br/>2.220000028611935mm f/2.2 1/50sec ISO 160"
						

						
					
					>
					<img			
						width="600" height="336"

						
							
							style="filter: blur(25px);"
							
								src="data:image/jpeg;base64,/9j/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4&#43;JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIABIAIAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5&#43;gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4&#43;Tl5ufo6ery8/T19vf4&#43;fr/2gAMAwEAAhEDEQA/AK9xr8SsY7QedJ65wo/x/Cqerw66NGF3FzcTMFjiPylgeyL1Y06TT1XyXUIXj&#43;5sQcdMH/8AWKsR63PZiRjGJb4gKtxMSfl44Unpx2x&#43;fbGNJR1NZOTRyFm/iO8uka4klGx/I8qRcMSOqhePxP5&#43;/aJpyrY4ludshXLbRlfpU1vBdiH7TdSK8si4Py4IU87QeuMk59T1zVa6ucjjJGew6&#43;1auCe6JjcnsQPtXToVxS62q/2hEu0YYjIx15pLH/j6/Fadrf8AyEoPqP51Zb3AfLo7beMMQMem41kQ8gA/3v61r/8AMIf/AHz/AOhGsiHoP97&#43;tDBbn//Z"
							
							class="lazy"
							data-src="/posts/upgrading-our-home-internet-to-10-gbps/lenovo_nic/7_nic1_hu71ac048810912ab87477b57d18108726_326997_600x600_fit_q100_lanczos.jpg"
						

						
							
								
							
						
					>
				</a>
			</div>
		
	
		
		
				
			
			
			
				
			

			
			
				
					
				
			


			
			
			
				
				
				
				
				
				
				
				
			

			
			


			<div>
				
				
					
				
				<a href="/posts/upgrading-our-home-internet-to-10-gbps/lenovo_nic/8_nic2.jpg" 
					class="galleryImg"
					
						

						
							data-description="iPhone 15 Pro Max + iPhone 15 Pro Max back triple camera 2.22mm f/2.2<br/>2.220000028611935mm f/2.2 1/50sec ISO 200"
						

						
					
					>
					<img			
						width="600" height="385"

						
							
							style="filter: blur(25px);"
							
								src="data:image/jpeg;base64,/9j/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4&#43;JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIABUAIAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5&#43;gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4&#43;Tl5ufo6ery8/T19vf4&#43;fr/2gAMAwEAAhEDEQA/AK8NvOx2yK0bIdrLIhQqe4q3daalvD9oZNsJOA7LnOewz1qvpDi3vLoandP9oJ8wzzndux1ABPXv71k6pqk99eM8kzzIhITc3GO2Bxj8qiEI8raCrWcdCa7mDyf6xhATjAPP4jvSWWoXEMpFujOCcum7gj6euOOPTpVWOKa6jCi1lkDcFk/h98d/pV6XZbQG3ijKp1ldurAc8mpdzOnGbfMyDxCBBdwuoyZRz9Rj8&#43;DTrGKOZl3Rr98L09v/AK1N8U/8fFn/AMC/pUumfeX/AK6j&#43;tRQfuo6KkU6iubd6YtM06QwQjcELEk9cH/69cnPdOthuYs5kw7Ang98V1Wv/wDINn/64t/OuOuv&#43;Qcn/XMfyrZjkf/Z"
							
							class="lazy"
							data-src="/posts/upgrading-our-home-internet-to-10-gbps/lenovo_nic/8_nic2_hu704a4dffdcd91781673407f0d3ec4de6_400167_600x600_fit_q100_lanczos.jpg"
						

						
							
								
							
						
					>
				</a>
			</div>
		
	
		
		
				
			
			
			
				
			

			
			
				
					
				
			


			
			
			
				
				
				
				
				
				
				
				
			

			
			


			<div>
				
				
					
				
				<a href="/posts/upgrading-our-home-internet-to-10-gbps/lenovo_nic/9_riser.jpg" 
					class="galleryImg"
					
						

						
							data-description="iPhone 15 Pro Max + iPhone 15 Pro Max back triple camera 6.765mm f/1.78<br/>6.764999865652793mm f/1.7799999713880652 1/50sec ISO 100"
						

						
					
					>
					<img			
						width="600" height="354"

						
							
							style="filter: blur(25px);"
							
								src="data:image/jpeg;base64,/9j/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4&#43;JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIABMAIAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5&#43;gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4&#43;Tl5ufo6ery8/T19vf4&#43;fr/2gAMAwEAAhEDEQA/ADUVhgO2aUSnHzqgLHH06VzV1qTWjtDYLKEdQ00YXKsoOTjng8dsd66e80p7sfJbsD/eyR/OsHUNK1iwu0vgqXaRnJRT8wHce/8AnisacoJcppVjNu6LjBZYI5bTZLG6BtxyCM/Wq2&#43;dSCzMq9iOlQ6U8cN15PlMbeRTLbRvjlSfmjOe6n&#43;VaDlDMwCSCPaB&#43;9fdg&#43;wpypwUeZEUqs5PkluduwyCT2FZ9wAwfI6DitE/dP0rPm6SfSuU7DmNTjRthK8xXKshHG0lWz/IflWVbXEs8LPI2WzjoB/KtfUeh/67p/6C9Ylj/wAerfWun/l2cyX75n//2Q=="
							
							class="lazy"
							data-src="/posts/upgrading-our-home-internet-to-10-gbps/lenovo_nic/9_riser_hu895237cd8829db7ecb56f54b8adc3baa_317968_600x600_fit_q100_lanczos.jpg"
						

						
							
								
							
						
					>
				</a>
			</div>
		
	
</div>
</div>

<script>
	if (!jQuery) {
		alert("jquery is not loaded");
	}

	$( document ).ready(() => {
		const gallery = $("#gallery-0efe21febd1ec25b8e9ee6c88aecf11b-0");
		

		
		let swipeboxInstance = null;

		
		
		gallery.on('jg.complete', () => {
			
				
				
				$(() => {
					$('.lazy').Lazy({
						visibleOnly: true,
						afterLoad: element => element.css({filter: "none", transition: "filter 1.0s ease-in-out"})
					});
				});
			

			swipeboxInstance = $('.galleryImg').swipebox(
				jQuery.extend({},
					{  }
				)
			);
		});

		
		gallery.justifiedGallery({
			rowHeight : "150",
			margins : "5",
			border : 0,
			randomize :  false ,
			waitThumbnailsLoad : false,
			lastRow : "justify",
			captions : false,
			
			
		});

		
		
	});
</script>

<p>Unfortunately, I assumed the compatibility issue was something generic and could easily be fixed by cross-flashing the original Intel firmware. While this might have worked for others, this isn&rsquo;t the case when specifically using a Dell-branded X710 NIC with a Lenovo M920q Tiny PC. So, if anyone intends to follow this route, take note! I learned this the hard way because I purchased a Dell-branded one and went through the whole cross-flashing process only to find out that my machine will only boot up successfully if it&rsquo;s coming from an unplugged state. Yup, that means it will only boot up after unplugging and plugging the power cable. Anyway, I ended up purchasing an Intel-branded one and just flashed it with the latest firmware. For anyone interested, the articles I followed are also shared at the end of this post!</p>
<p>Lenovo M920q Tiny PCs require a PCIe riser for plugging in your cards. This can easily be bought for about ¥2000~3000 online. There are different part numbers in terms of the supported bus speed, so I had to ensure I got the one with P/N: 01AJ940, which supports x8.</p>
<p>As for the 10G switch, for the time being, I got a 4x2.5 + 2x10G switch from Horaco (AliExpress). I already have an 8x2.5G switch from the same brand and it&rsquo;s been rock stable. There was no really good reason for me to try out another brand. If there was one thing where you have to manage your risk, it&rsquo;s when purchasing networking equipment from AliExpress!</p>




	





































<style>
	

	
</style>





<div id="gallery-0efe21febd1ec25b8e9ee6c88aecf11b-1-wrapper" class="gallery-wrapper">
<div id="gallery-0efe21febd1ec25b8e9ee6c88aecf11b-1" class="justified-gallery">
	
		
		
				
			
			
			
				
			

			
			
				
					
				
			


			
			
			
				
				
				
				
				
				
				
				
			

			
			


			<div>
				
				
					
				
				<a href="/posts/upgrading-our-home-internet-to-10-gbps/network/2_horaco.jpg" 
					class="galleryImg"
					
						

						
							data-description="iPhone 15 Pro Max + iPhone 15 Pro Max back triple camera 2.22mm f/2.2<br/>2.220000028611935mm f/2.2 1/50sec ISO 500"
						

						
					
					>
					<img			
						width="600" height="311"

						
							
							style="filter: blur(25px);"
							
								src="data:image/jpeg;base64,/9j/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4&#43;JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIABEAIAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5&#43;gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4&#43;Tl5ufo6ery8/T19vf4&#43;fr/2gAMAwEAAhEDEQA/AKekaDpmkRQJepCdQt2YtNknqeB6HtW&#43;t7p6jm6j/Osi/GmatkNNtDYykqZ/qKiHhTS5FDvcQpvLHcYsDLcN/FWUZKxUou5v/wBo6cP&#43;XyHnsWqimj6dqQ&#43;y6PNbQ3KKzwlP4G9ePwrBufBlrPJui1aDYi&#43;WuMqAPzrf8OWWm&#43;HY8JqEbz95PMH5cmnJpoIxaZzEv3zVLUP9XB/13j/9Cq7L981S1D/Vwf8AXeP/ANCrlW50MnP3qsWX/H1F/vCq5&#43;9Viy/4&#43;ov94Uo7oGf/2Q=="
							
							class="lazy"
							data-src="/posts/upgrading-our-home-internet-to-10-gbps/network/2_horaco_huda0d695b44ae1bd295d76d07d7427684_167972_600x600_fit_q100_lanczos.jpg"
						

						
							
								
							
						
					>
				</a>
			</div>
		
	
		
		
				
			
			
			
				
			

			
			
				
					
				
			


			
			
			
				
				
				
				
				
				
				
				
			

			
			


			<div>
				
				
					
				
				<a href="/posts/upgrading-our-home-internet-to-10-gbps/network/3_sfp.jpg" 
					class="galleryImg"
					
						

						
							data-description="iPhone 15 Pro Max + iPhone 15 Pro Max back triple camera 6.765mm f/1.78<br/>6.764999865652793mm f/1.7799999713880652 1/100sec ISO 80"
						

						
					
					>
					<img			
						width="600" height="386"

						
							
							style="filter: blur(25px);"
							
								src="data:image/jpeg;base64,/9j/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4&#43;JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIABUAIAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5&#43;gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4&#43;Tl5ufo6ery8/T19vf4&#43;fr/2gAMAwEAAhEDEQA/ALhkEchkc4jDjcfbjNXZ1mhmMdrYIwwCJpXyDzz8vtVAr5ti6yEEMGxx6nikfT7nYsmo6m8gYZEMJwW9u2f881zU15G02advdyQM6X13bhGQgQQrgj3A6&#43;vrVQSB0RlYsCwIY9waWygvYmT7Bpkdva5BkkkOWde/IPp9R70sxgLsbaRHRGBOw8Lg8itKkXZMiDK0mfsYGf8Aln/Sq0WoCLQ476aBZntSVQE44HHXtxVqT/j0H&#43;5/Ssh/&#43;RRn/wB9v51NLdlVCWfWNR11/LuLkxwkgeTEMLj39fxrVisUs7F1Rs/KSePaud0r/Wr9RXWT/wDHo/8AuH&#43;VOTbeoopJaH//2Q=="
							
							class="lazy"
							data-src="/posts/upgrading-our-home-internet-to-10-gbps/network/3_sfp_hu814eb0653470a35e31f2734fad4d4ec1_223230_600x600_fit_q100_lanczos.jpg"
						

						
							
								
							
						
					>
				</a>
			</div>
		
	
		
		
				
			
			
			
				
			

			
			
				
					
				
			


			
			
			
				
				
				
				
				
				
				
				
			

			
			


			<div>
				
				
					
				
				<a href="/posts/upgrading-our-home-internet-to-10-gbps/network/4_dac.jpg" 
					class="galleryImg"
					
						

						
							data-description="iPhone 15 Pro Max + iPhone 15 Pro Max back triple camera 6.765mm f/1.78<br/>6.764999865652793mm f/1.7799999713880652 1/50sec ISO 100"
						

						
					
					>
					<img			
						width="600" height="450"

						
							
							style="filter: blur(25px);"
							
								src="data:image/jpeg;base64,/9j/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4&#43;JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIABgAIAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5&#43;gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4&#43;Tl5ufo6ery8/T19vf4&#43;fr/2gAMAwEAAhEDEQA/ANG81gwqmQoVnAODzjvVu30mxtYIp9S1Bo5JWL4knCrz/CPUCuV8TyNDZPGoViysSwGSBWp4cvTZWIRXnaFlUonDhRjnGSMde1S0os0d7GheQxwyg6fNHeryTHHdDzB9F7/zpq6ovloUiKsmQwfOR/I1qx6tashkUyIxByJGHA&#43;grmtP83U7i4v55RiZl2DqQgyB/LNLR77CQmqxQTeZGsagMhB2jrmsHT76&#43;0JTYtZSXlvtPlTRj5l9Af0reuf9a/0/rVI9V&#43;orCMu5bRUDahqkqj7PNaW&#43;7JZ&#43;rc/hjiumtBshSBpNxRQoJOSQOmaqx/8AHmPr/hU0H/H0v0H9K0b0I6n/2Q=="
							
							class="lazy"
							data-src="/posts/upgrading-our-home-internet-to-10-gbps/network/4_dac_hu685d8aca29d5fc1d840947359a322285_285071_600x600_fit_q100_lanczos.jpg"
						

						
							
								
							
						
					>
				</a>
			</div>
		
	
</div>
</div>

<script>
	if (!jQuery) {
		alert("jquery is not loaded");
	}

	$( document ).ready(() => {
		const gallery = $("#gallery-0efe21febd1ec25b8e9ee6c88aecf11b-1");
		

		
		let swipeboxInstance = null;

		
		
		gallery.on('jg.complete', () => {
			
				
				
				$(() => {
					$('.lazy').Lazy({
						visibleOnly: true,
						afterLoad: element => element.css({filter: "none", transition: "filter 1.0s ease-in-out"})
					});
				});
			

			swipeboxInstance = $('.galleryImg').swipebox(
				jQuery.extend({},
					{  }
				)
			);
		});

		
		gallery.justifiedGallery({
			rowHeight : "150",
			margins : "5",
			border : 0,
			randomize :  false ,
			waitThumbnailsLoad : false,
			lastRow : "justify",
			captions : false,
			
			
		});

		
		
	});
</script>

<p>10G SFP+ to copper transceivers are known to run hot. And because I keep my networking equipment in an unventilated closet, I had to shed an extra couple of bucks for the premium ones—the version that supports up to 80m of copper. For the transceivers, I got them from a brand called ZYOPM.</p>
<p>Managing the temperature inside an enclosed space is a priority, so I had to make sure the temps are at a minimum whenever possible. For the upstream connection of my switch to the router, I used a DAC cable. I&rsquo;ve never used one before and actually thought of using optical transceivers in the beginning.</p>




	





































<style>
	

	
</style>





<div id="gallery-0efe21febd1ec25b8e9ee6c88aecf11b-2-wrapper" class="gallery-wrapper">
<div id="gallery-0efe21febd1ec25b8e9ee6c88aecf11b-2" class="justified-gallery">
	
		
		
				
			
			
			
				
			

			
			
				
					
				
			


			
			
			
				
				
				
				
				
				
				
				
			

			
			


			<div>
				
				
					
				
				<a href="/posts/upgrading-our-home-internet-to-10-gbps/ap/5_tplink.jpg" 
					class="galleryImg"
					
						

						
							data-description="iPhone 15 Pro Max + iPhone 15 Pro Max back triple camera 6.765mm f/1.78<br/>6.764999865652793mm f/1.7799999713880652 1/100sec ISO 64"
						

						
					
					>
					<img			
						width="600" height="453"

						
							
							style="filter: blur(25px);"
							
								src="data:image/jpeg;base64,/9j/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4&#43;JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIABgAIAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5&#43;gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4&#43;Tl5ufo6ery8/T19vf4&#43;fr/2gAMAwEAAhEDEQA/AI9HhivbhS0aqicsT0roP7Ol126k8ry0t4hs82RMkHvgcc0y204WGjB3J8x&#43;SAAQSRwDnj/J/DR8O30ENubOV1jcMSu44DA/1qIQ5I2LqS55XKNx4GUxk21/ukA&#43;7ImFP5HiuQuoZbGdobmMRTKxUrux&#43;VeryzxW8ZklkWNB3Y4FeV&#43;LrxdT8RxPECIySV46hRjNTJLlbaKg3zJXKraf4is2Y2Erywg/IvmZIH0PFV28Qa7ZHbqFlvA6s8RU/mOP0rtLXtXPeLv9S1CbQ2kynF4wsXIE1rImePkIYD&#43;VVLi&#43;hvtXE1nPhUi4ypHJPTB&#43;lcxH3&#43;taGl/8fL/7gonJtNBCKUkz/9k="
							
							class="lazy"
							data-src="/posts/upgrading-our-home-internet-to-10-gbps/ap/5_tplink_hu1052ddbb5c4b39337bd4edbccd50c8c0_245108_600x600_fit_q100_lanczos.jpg"
						

						
							
								
							
						
					>
				</a>
			</div>
		
	
		
		
				
			
			
			
				
			

			
			
				
					
				
			


			
			
			
				
				
				
				
				
				
				
				
			

			
			


			<div>
				
				
					
				
				<a href="/posts/upgrading-our-home-internet-to-10-gbps/ap/6_injector.jpg" 
					class="galleryImg"
					
						

						
							data-description="iPhone 15 Pro Max + iPhone 15 Pro Max back triple camera 2.22mm f/2.2<br/>2.220000028611935mm f/2.2 1/100sec ISO 250"
						

						
					
					>
					<img			
						width="600" height="383"

						
							
							style="filter: blur(25px);"
							
								src="data:image/jpeg;base64,/9j/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4&#43;JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIABQAIAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5&#43;gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4&#43;Tl5ufo6ery8/T19vf4&#43;fr/2gAMAwEAAhEDEQA/AE8P2QvJzM8OyKI8kH7zeldBfaja2KxC7lLM&#43;Qq7AeBWRa&#43;I7Cwijtpre4hAH3gAyt6n1q5Lf6Fq0IimvYiOxfMbL9CQK0oSpQhZSVzixKrTq80ovl8jOv8AxLpUTYOnLIO5O0Gob3&#43;y7zQJtUsUKhXC42bWU5Ge&#43;D1rVs/C&#43;hgb40F1/tNJuH6cVLrVpHD4fuIraJIlG0hVUAZ3CtJ0&#43;aDk7GcKyjUjGF90VLKwtryARXEYkTrg9qdqfhXTYYN8QlQ&#43;z5/nU&#43;k/dFaWr/8AHp&#43;FcTimtUexd3PLJpZILtkjdhtzg55qSbW9SQQ2/wBrleKU4ZXYsMfjUN7/AMf8v1NVrn/X2v8AvmuPapZGrScdT//Z"
							
							class="lazy"
							data-src="/posts/upgrading-our-home-internet-to-10-gbps/ap/6_injector_hudadc7a1cc8e69714db852c4d3a521dca_241276_600x600_fit_q100_lanczos.jpg"
						

						
							
								
							
						
					>
				</a>
			</div>
		
	
</div>
</div>

<script>
	if (!jQuery) {
		alert("jquery is not loaded");
	}

	$( document ).ready(() => {
		const gallery = $("#gallery-0efe21febd1ec25b8e9ee6c88aecf11b-2");
		

		
		let swipeboxInstance = null;

		
		
		gallery.on('jg.complete', () => {
			
				
				
				$(() => {
					$('.lazy').Lazy({
						visibleOnly: true,
						afterLoad: element => element.css({filter: "none", transition: "filter 1.0s ease-in-out"})
					});
				});
			

			swipeboxInstance = $('.galleryImg').swipebox(
				jQuery.extend({},
					{  }
				)
			);
		});

		
		gallery.justifiedGallery({
			rowHeight : "150",
			margins : "5",
			border : 0,
			randomize :  false ,
			waitThumbnailsLoad : false,
			lastRow : "justify",
			captions : false,
			
			
		});

		
		
	});
</script>

<p>On to the Wireless AP, I also upgraded from my not-so-old TP-Link EAP610 to an EAP773. The former only supported Wi-Fi 6 over 2.4/5 GHz bands with 1G upstream. For &ldquo;future-proofing,&rdquo; at least for the next few years, and to make use of the upgraded upstream, I needed something which at least supported Wi-Fi 6E over 6 GHz.</p>
<p>I also had to get a PoE++ 90W injector since the new switch didn&rsquo;t support PoE+.</p>
<h2 id="software">Software</h2>
<p>There are mixed opinions on whether you should virtualize your router or not. But if you live somewhere where space is a luxury, then you already have the best reason to go with virtualization (but regardless of that, I just really like complicating things, lol). So of course, we go back to our good old friend, Proxmox. The last time I had to spin up a new Proxmox machine was about 2 years ago when I started using CEPH as my default backend storage. A lot of good things must have been added within these 2 years, but I just really needed an easily managed KVM host. No one can beat Proxmox on that.</p>
<p>As for the router itself, I made the big switch from OPNsense to OpenWRT. And I couldn&rsquo;t be happier. I&rsquo;ve had OPNsense for about 3 years now and while I didn&rsquo;t really complain about anything since it was more of a &ldquo;set and forget&rdquo; setup, whenever I had to modify something in the configuration, sometimes it just felt like I had to explore and familiarize myself again. With OpenWRT, the GUI just felt a bit more natural and warm to my eyes. Maybe it&rsquo;s because of fewer sections or tabs to go through, or, I don&rsquo;t know, configuration just seemed a little more straightforward this time compared to when I just started with the other.</p>
<p>But in fact, I don&rsquo;t think I would have bothered checking out OpenWRT if only OPNsense supported MAP-E connections used by my new ISP. There is a way to get it working with OPNsense, but it was more of a workaround than a natively supported feature.</p>
<h2 id="my-choice-of-isp">My choice of ISP</h2>
<p>The primary factor in choosing the ISP is the monthly cost. The switch to 10G wouldn&rsquo;t be justifiable if we had to pay 50% more than our old subscription. Second would be the option to have a fixed IPv4 address since I host some services for family and friends. Fortunately, I came across a post on Reddit suggesting <a href="https://enhikari.jp/">En Hikari</a>. En Hikari uses NTT FLET&rsquo;S HIKARI as the backbone provider, so you can be assured of the same quality of connectivity used by most ISPs. At the time of writing, the monthly cost is about JPY 4,917 (tax included) plus an additional JPY 770 for the optional fixed IPv4 address. That&rsquo;s a total of JPY 5,687, which comes out even cheaper than our current basic 1G subscription at JPY 5,720 (dynamic IPv4 address only).</p>
<h2 id="preparations">Preparations</h2>
<p>When I got the Intel X710 card, it only had v6.01 installed. I didn&rsquo;t find a way to upgrade directly from v6.01 to the latest one (v9.56 as of this writing) and had to go through it stepwise. The upgrade path in my case was from 6.01 &ndash;&gt; 8.6 &ndash;&gt; 9.0 &ndash;&gt; 9.10 &ndash;&gt; 9.56. All done under Debian (Proxmox).</p>
<p>My Intel card came with unlocked vendor support, so I didn&rsquo;t have to run the unlocker script. I guess this is only applicable to the OEM versions.</p>
<p>I actually ran into some errors initially that prevented the second Ethernet port from functioning. Honestly, I hit a wall and gave up on it for the night. Then, I&rsquo;m not sure how, but it just got resolved the following morning after a restart.</p>
<p>After a few more rounds of restarts and going through kernel dmesg logs, I finally decided to go with a fresh install of OpenWRT. For some reason, I couldn&rsquo;t figure out how to create the VLAN interfaces from the GUI. I ended up with a successful attempt when I tried to do it from the text file configuration. To those who are in the same boat, below is a sample <code>/etc/config/network</code> for configuring VLANs.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">config interface &#39;loopback&#39;
</span></span><span class="line"><span class="cl">	option device &#39;lo&#39;
</span></span><span class="line"><span class="cl">	option proto &#39;static&#39;
</span></span><span class="line"><span class="cl">	option ipaddr &#39;127.0.0.1&#39;
</span></span><span class="line"><span class="cl">	option netmask &#39;255.0.0.0&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">config globals &#39;globals&#39;
</span></span><span class="line"><span class="cl">	option ula_prefix &#39;fd00:7808:88c3::/48&#39;
</span></span><span class="line"><span class="cl">	option packet_steering &#39;1&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">config device
</span></span><span class="line"><span class="cl">	option name &#39;br-lan&#39;
</span></span><span class="line"><span class="cl">	option type &#39;bridge&#39;
</span></span><span class="line"><span class="cl">	list ports &#39;eth0&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">config interface &#39;lan&#39;
</span></span><span class="line"><span class="cl">	option device &#39;br-lan.1&#39;
</span></span><span class="line"><span class="cl">	option proto &#39;static&#39;
</span></span><span class="line"><span class="cl">	option ipaddr &#39;192.168.0.1&#39;
</span></span><span class="line"><span class="cl">	option netmask &#39;255.255.255.0&#39;
</span></span><span class="line"><span class="cl">	option ip6assign &#39;64&#39;
</span></span><span class="line"><span class="cl">	list dns &#39;192.168.0.1&#39;
</span></span><span class="line"><span class="cl">	option ip6hint &#39;00&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">config interface &#39;wan&#39;
</span></span><span class="line"><span class="cl">	option device &#39;eth1&#39;
</span></span><span class="line"><span class="cl">	option proto &#39;dhcp&#39;
</span></span><span class="line"><span class="cl">	option keepalive &#39;5 10&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">config interface &#39;wan6&#39;
</span></span><span class="line"><span class="cl">	option device &#39;eth1&#39;
</span></span><span class="line"><span class="cl">	option proto &#39;dhcpv6&#39;
</span></span><span class="line"><span class="cl">	option reqaddress &#39;try&#39;
</span></span><span class="line"><span class="cl">	option reqprefix &#39;auto&#39;
</span></span><span class="line"><span class="cl">	option norelease &#39;1&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">config bridge-vlan
</span></span><span class="line"><span class="cl">	option device &#39;br-lan&#39;
</span></span><span class="line"><span class="cl">	option vlan &#39;1&#39;
</span></span><span class="line"><span class="cl">	list ports &#39;eth0&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">config bridge-vlan
</span></span><span class="line"><span class="cl">	option device &#39;br-lan&#39;
</span></span><span class="line"><span class="cl">	option vlan &#39;10&#39;
</span></span><span class="line"><span class="cl">	list ports &#39;eth0:t&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">config bridge-vlan
</span></span><span class="line"><span class="cl">	option device &#39;br-lan&#39;
</span></span><span class="line"><span class="cl">	option vlan &#39;20&#39;
</span></span><span class="line"><span class="cl">	list ports &#39;eth0:t&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">config interface &#39;vlan10&#39;
</span></span><span class="line"><span class="cl">	option proto &#39;static&#39;
</span></span><span class="line"><span class="cl">	option device &#39;br-lan.10&#39;
</span></span><span class="line"><span class="cl">	option ipaddr &#39;192.168.10.1&#39;
</span></span><span class="line"><span class="cl">	option netmask &#39;255.255.255.0&#39;
</span></span><span class="line"><span class="cl">	list dns &#39;192.168.10.0.1&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">config interface &#39;vlan20&#39;
</span></span><span class="line"><span class="cl">	option proto &#39;static&#39;
</span></span><span class="line"><span class="cl">	option device &#39;br-lan.20&#39;
</span></span><span class="line"><span class="cl">	option ipaddr &#39;192.168.20.1&#39;
</span></span><span class="line"><span class="cl">	option netmask &#39;255.255.255.0&#39;
</span></span><span class="line"><span class="cl">	list dns &#39;192.168.20.0.1&#39;
</span></span></code></pre></div><p><code>/etc/init.d/network restart</code> to apply the config.</p>
<p>For now, I just wanted a stable internet connection and didn&rsquo;t even bother to think about having SR-IOV, so it&rsquo;s been decided to just make use of the existing Proxmox Linux bridges for both the WAN and LAN interface.</p>
<h2 id="en-hikari-configuration-on-openwrt">En Hikari configuration on OpenWRT</h2>
<p><strong>References:</strong>
<a href="https://note.com/arunya/n/n7d81e0de9db7">https://note.com/arunya/n/n7d81e0de9db7</a>
<a href="https://www.ficusonline.com/ja/posts/openwrt-v6-plus-map-e">https://www.ficusonline.com/ja/posts/openwrt-v6-plus-map-e</a></p>
<p>I found these two articles that provide step-by-step instructions to get En Hikari working with v6 plus and the fixed IPv4. The initial steps to have DHCPv6 working are in the first one. In my case, I installed the required packages first:</p>
<ul>
<li>luci-proto-ipv6</li>
<li>map</li>
<li>ds-lite</li>
<li>ip-full</li>
</ul>
<p>As I know Hikari Cross utilizes MAP-E. I am not sure if <code>ds-lite</code> is really required, but I just installed it anyway.</p>
<p>I created a new WAN interface, named it &lsquo;wan6&rsquo;, and set the protocol to <code>DHCPv6 client</code>. Under DHCP Server &gt; IPv6 Settings, the RA-Service, DHCPv6 Service, and NDP Proxy were all set to disabled. After a few seconds, I was assigned an IPv6 /56 subnet.</p>
<p>
    <img src="/posts/upgrading-our-home-internet-to-10-gbps/wan6_dhcp.png" alt="wan6 DHCP settings">
  </p>
<p>For the clients to connect over IPv6, I had to enable IPv6 under <strong>Interfaces &gt; LAN &gt; Advanced Settings</strong>. IPv6 assignment length was set to <code>64</code> and hint to <code>00</code> so my LAN gets assigned the first smaller subnet of the /56 block.</p>
<p>Under <strong>LAN &gt; DHCP Server &gt; IPv6 Settings</strong>, RA-Service and DHCPv6 Service should be set to <code>server</code> and NDP Proxy to <code>relay</code>. Under IPv6 RA Settings, I made sure SLAAC was enabled. The rest were set to default. After applying the changes, my devices started having an IPv6 address, the majority by SLAAC and a very few through DHCPv6.</p>
<p>For the IPv4 configuration, I just followed the article. Though I am still sharing my snaps here for future reference:</p>
<p>Info that was provided by the ISP:</p>
<ul>
<li>V4アドレス</li>
<li>インターフェスID</li>
<li>BRアドレス</li>
<li>ユーサID</li>
<li>パスワード</li>
</ul>
<p>
    <img src="/posts/upgrading-our-home-internet-to-10-gbps/map-e_1.png" alt="MAP-E configuration">
  </p>
<p>
    <img src="/posts/upgrading-our-home-internet-to-10-gbps/map-e_2.png" alt="MAP-E configuration">
  </p>
<p>
    <img src="/posts/upgrading-our-home-internet-to-10-gbps/map-e_3.png" alt="MAP-E configuration">
  </p>
<h2 id="quick-speed-test">Quick speed test</h2>
<p>I don&rsquo;t have any other equipment (yet, lol) that supports 10G traffic, so I spun up an LXC container on the same PVE hosting OpenWRT and ran a simple iPerf test from there. I selected one of the JP servers from <a href="https://github.com/R0GGER/public-iperf3-servers">this list</a> maintained by <a href="https://github.com/R0GGER">@R0GGER</a> (Big thanks to him!).</p>
<p>The result, DL and UL speed respectively:</p>
<p>The result:</p>
<p><strong>DL SPEED</strong>

    <img src="/posts/upgrading-our-home-internet-to-10-gbps/10_dlspeed.png" alt="DL Speed">
  </p>
<p><strong>UL SPEED</strong>

    <img src="/posts/upgrading-our-home-internet-to-10-gbps/11_ulspeed.png" alt="UL Speed">
  </p>
<p>I may not be getting the full 10G bandwidth, but I&rsquo;m certainly getting ~5x the speed compared to my previous connection for the same price.</p>
<h2 id="whats-next">What&rsquo;s next</h2>
<p>In addition to the benefits a multi-gigabit upstream brings, being assigned an IPv6 subnet from my ISP will allow me to host multiple services from within my local network since the hosts will now have publicly routable addresses. This means a few things:</p>
<ol>
<li>No need to keep track and configure ports for port-forwarding to different VMs or containers.</li>
<li>Multiple services can be hosted on the same port.</li>
<li>I can create a DMZ network to completely expose hosts to the public internet.</li>
<li>P2P connectivity can be established without the requirement of NAT-ing.</li>
</ol>
<h2 id="references">References</h2>
<ul>
<li><a href="https://gist.github.com/mietzen/736583d37a1d370273c0775aaaa57aa5">Cross-flashing X710 NICs</a></li>
<li><a href="https://github.com/bibigon812/xl710-unlocker/tree/master#">Disabling vendor-lock of X710 NICs</a></li>
<li><a href="https://www.moduletek.com/en/application_notes/an_00115.html">Explanation of above</a></li>
<li><a href="https://gist.github.com/subrezon/b9aa2014343f934fbf69e579ecfc8da8">OpenWRT on Proxmox</a></li>
<li><a href="https://note.com/arunya/n/n7d81e0de9db7">OpenWRT configuration for En Hikari with v6 plus and Fixed IP</a></li>
<li><a href="https://www.intel.com/content/www/us/en/download/18635/non-volatile-memory-nvm-update-utility-for-intel-ethernet-adapters-700-series-linux.html">Intel X710 drivers</a></li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
      <title>Troubleshooting low throughput on Proxmox</title>
      <link>https://luislogs.com/posts/troubleshooting-my-kubernetes-network/</link>
      <pubDate>Sat, 28 Oct 2023 12:40:30 +0900</pubDate>
      
      <guid>https://luislogs.com/posts/troubleshooting-my-kubernetes-network/</guid>
      <description>When I initially spinned up my k8s cluster, I got everything working but I always experienced network disconnects. it turns out it&amp;rsquo;s due to my NIC. It was quite difficult to notice this or maybe I just really never doubted my hypervisor and the hardware. Eventually I thought of checking the dmesg logs from within proxmox.
Sep 29 14:54:58 pve1 kernel: e1000e 0000:00:1f.6 eno1: Detected Hardware Unit Hang: TDH &amp;lt;22&amp;gt; TDT &amp;lt;bb&amp;gt; next_to_use &amp;lt;bb&amp;gt; next_to_clean &amp;lt;22&amp;gt; buffer_info[next_to_clean]: time_stamp &amp;lt;100cb7acb&amp;gt; next_to_watch &amp;lt;23&amp;gt; jiffies &amp;lt;100cb7d99&amp;gt; next_to_watch.</description>
      <content:encoded><![CDATA[<p>When I initially spinned up my k8s cluster, I got everything working but I always experienced network disconnects. it turns out it&rsquo;s due to my NIC. It was quite difficult to notice this or maybe I just really never doubted my hypervisor and the hardware. Eventually I thought of checking the dmesg logs from within proxmox.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Sep 29 14:54:58 pve1 kernel: e1000e 0000:00:1f.6 eno1: Detected Hardware Unit Hang:
</span></span><span class="line"><span class="cl">                               TDH                  &lt;22&gt;
</span></span><span class="line"><span class="cl">                               TDT                  &lt;bb&gt;
</span></span><span class="line"><span class="cl">                               next_to_use          &lt;bb&gt;
</span></span><span class="line"><span class="cl">                               next_to_clean        &lt;22&gt;
</span></span><span class="line"><span class="cl">                             buffer_info[next_to_clean]:
</span></span><span class="line"><span class="cl">                               time_stamp           &lt;100cb7acb&gt;
</span></span><span class="line"><span class="cl">                               next_to_watch        &lt;23&gt;
</span></span><span class="line"><span class="cl">                               jiffies              &lt;100cb7d99&gt;
</span></span><span class="line"><span class="cl">                               next_to_watch.status &lt;0&gt;
</span></span><span class="line"><span class="cl">                             MAC Status             &lt;80083&gt;
</span></span><span class="line"><span class="cl">                             PHY Status             &lt;796d&gt;
</span></span><span class="line"><span class="cl">                             PHY 1000BASE-T Status  &lt;3800&gt;
</span></span><span class="line"><span class="cl">                             PHY Extended Status    &lt;3000&gt;
</span></span><span class="line"><span class="cl">                             PCI Status             &lt;10&gt;
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">Sep 29 14:55:07 pve1 kernel: e1000e 0000:00:1f.6 eno1: Reset adapter unexpectedly
</span></span><span class="line"><span class="cl">Sep 29 14:55:07 pve1 kernel: vmbr0: port 1(eno1) entered disabled state
</span></span><span class="line"><span class="cl">Sep 29 14:55:07 pve1 kernel: vmbr0v20: port 1(eno1.20) entered disabled state
</span></span><span class="line"><span class="cl">Sep 29 14:55:07 pve1 kernel: vmbr0v30: port 1(eno1.30) entered disabled state
</span></span><span class="line"><span class="cl">Sep 29 14:55:11 pve1 kernel: e1000e 0000:00:1f.6 eno1: NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
</span></span><span class="line"><span class="cl">Sep 29 14:55:11 pve1 kernel: vmbr0: port 1(eno1) entered blocking state
</span></span><span class="line"><span class="cl">Sep 29 14:55:11 pve1 kernel: vmbr0: port 1(eno1) entered forwarding state
</span></span><span class="line"><span class="cl">Sep 29 14:55:11 pve1 kernel: vmbr0v20: port 1(eno1.20) entered blocking state
</span></span><span class="line"><span class="cl">Sep 29 14:55:11 pve1 kernel: vmbr0v20: port 1(eno1.20) entered forwarding state
</span></span><span class="line"><span class="cl">Sep 29 14:55:11 pve1 kernel: vmbr0v30: port 1(eno1.30) entered blocking state
</span></span><span class="line"><span class="cl">Sep 29 14:55:11 pve1 kernel: vmbr0v30: port 1(eno1.30) entered forwarding state
</span></span></code></pre></div><p>When I saw these messages I thought my switch was acting up. I was almost ready to purchase a new switch but then upon further googling I landed in this <a href="https://forum.proxmox.com/threads/e1000-driver-hang.58284/page-10">forum post</a>.</p>
<p>Turns out this specific model is known to be freezing from time to time when segmentation is done by the NIC. This comes enabled by default when installing Proxmox. A quick fix suggeested in the post which worked for me was to simply disable the TSO and GSO flags on the specific interface. On runtime this can be disabled by executing <code>ethtool -K eno1 tso off gso off</code>.</p>
<p>To make the changes permenant, the following line should be added in the /etc/network/interfaces file:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">post-up /usr/bin/logger -p debug -t ifup &#34;Disabling segmentation offload for eno1&#34; &amp;&amp; /sbin/ethtool -K $IFACE tso off gso off &amp;&amp; /usr/bin/logger -p debug -t ifup &#34;Disabled offload for eno1&#34;
</span></span></code></pre></div><p>e.g.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"></code></pre></div><p>One more issue I faced was very slow throughput when playing videos from Jellyfin.</p>
<p>
    <figure>
      <img loading="lazy" src="/posts/troubleshooting-my-kubernetes-network/proxmox2.png" alt="Low throughput on Proxmox">
      <figcaption>Low throughput on Proxmox</figcaption>
    </figure>
  </p>
<p>Noticed that throughput was very low regardless whether I&rsquo;m using the docker traefik or the one in my kubernetes cluster, while the original traefik container on my Unraid</p>
<p>After drilling down that issue seems to be specific to my Proxmox node, I checked whether the 1Gbit/s speed was properly negotiated as suggested in this other <a href="https://forum.proxmox.com/threads/network-speed-limited-to-100mbit-s.73311/">forum post</a>.</p>
<p>Executing <code>ethtool eno1</code> showed me the following output:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">root@pve1:~# ethtool eno1
</span></span><span class="line"><span class="cl">Settings for eno1:
</span></span><span class="line"><span class="cl">	Supported ports: [ TP ]
</span></span><span class="line"><span class="cl">	Supported link modes:   10baseT/Half 10baseT/Full
</span></span><span class="line"><span class="cl">	                        100baseT/Half 100baseT/Full
</span></span><span class="line"><span class="cl">	                        1000baseT/Full
</span></span><span class="line"><span class="cl">	Supported pause frame use: No
</span></span><span class="line"><span class="cl">	Supports auto-negotiation: Yes
</span></span><span class="line"><span class="cl">	Supported FEC modes: Not reported
</span></span><span class="line"><span class="cl">	Advertised link modes:  10baseT/Full
</span></span><span class="line"><span class="cl">	Advertised pause frame use: No
</span></span><span class="line"><span class="cl">	Advertised auto-negotiation: Yes
</span></span><span class="line"><span class="cl">	Advertised FEC modes: Not reported
</span></span><span class="line"><span class="cl">	Speed: 10Mb/s
</span></span><span class="line"><span class="cl">	Duplex: Full
</span></span><span class="line"><span class="cl">	Auto-negotiation: on
</span></span><span class="line"><span class="cl">	Port: Twisted Pair
</span></span><span class="line"><span class="cl">	PHYAD: 1
</span></span><span class="line"><span class="cl">	Transceiver: internal
</span></span><span class="line"><span class="cl">	MDI-X: on (auto)
</span></span><span class="line"><span class="cl">	Supports Wake-on: pumbg
</span></span><span class="line"><span class="cl">	Wake-on: g
</span></span><span class="line"><span class="cl">        Current message level: 0x00000007 (7)
</span></span><span class="line"><span class="cl">                               drv probe link
</span></span><span class="line"><span class="cl">	Link detected: yes
</span></span></code></pre></div><p>Disabled auto-negotiation and configured 1Gbit manually:
<code>ethtool -s eno1 speed 1000 duplex full autoneg off</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">root@pve1:~# ethtool eno1
</span></span><span class="line"><span class="cl">Settings for eno1:
</span></span><span class="line"><span class="cl">	Supported ports: [ TP ]
</span></span><span class="line"><span class="cl">	Supported link modes:   10baseT/Half 10baseT/Full
</span></span><span class="line"><span class="cl">	                        100baseT/Half 100baseT/Full
</span></span><span class="line"><span class="cl">	                        1000baseT/Full
</span></span><span class="line"><span class="cl">	Supported pause frame use: No
</span></span><span class="line"><span class="cl">	Supports auto-negotiation: Yes
</span></span><span class="line"><span class="cl">	Supported FEC modes: Not reported
</span></span><span class="line"><span class="cl">	Advertised link modes:  1000baseT/Full
</span></span><span class="line"><span class="cl">	Advertised pause frame use: No
</span></span><span class="line"><span class="cl">	Advertised auto-negotiation: Yes
</span></span><span class="line"><span class="cl">	Advertised FEC modes: Not reported
</span></span><span class="line"><span class="cl">	Speed: 1000Mb/s
</span></span><span class="line"><span class="cl">	Duplex: Full
</span></span><span class="line"><span class="cl">	Auto-negotiation: on
</span></span><span class="line"><span class="cl">	Port: Twisted Pair
</span></span><span class="line"><span class="cl">	PHYAD: 1
</span></span><span class="line"><span class="cl">	Transceiver: internal
</span></span><span class="line"><span class="cl">	MDI-X: off (auto)
</span></span><span class="line"><span class="cl">	Supports Wake-on: pumbg
</span></span><span class="line"><span class="cl">	Wake-on: g
</span></span><span class="line"><span class="cl">        Current message level: 0x00000007 (7)
</span></span><span class="line"><span class="cl">                               drv probe link
</span></span><span class="line"><span class="cl">	Link detected: yes
</span></span></code></pre></div><p>After having these in place, my cluster has been running perfectly fine for almost a month now with nohiccups!</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Re-engineering the Homelab with IaC and Kubernetes: An overview</title>
      <link>https://luislogs.com/posts/re-engineering-the-homelab-with-iac-and-kubernetes-an-overview/</link>
      <pubDate>Sat, 23 Sep 2023 12:40:30 +0900</pubDate>
      
      <guid>https://luislogs.com/posts/re-engineering-the-homelab-with-iac-and-kubernetes-an-overview/</guid>
      <description>In relation to my previous post where I mentioned that I will be starting a new journey learning IaC or Infrastructure-as-Code, today I am very happy to record this milestone of finally achieving a stable kubernetes cluster created with the help of Ansible and Terraform.
At this time of writing, so far only two services have been migrated from the docker environment into the new K8S cluster. That is my DNS which is also replaced now by AdguardHome (sorry Pihole!</description>
      <content:encoded><![CDATA[<p>In relation to my previous post where I mentioned that I will be starting a new journey learning IaC or Infrastructure-as-Code, today I am very happy to record this milestone of finally achieving a stable kubernetes cluster created with the help of Ansible and Terraform.</p>
<p>At this time of writing, so far only two services have been migrated from the docker environment into the new K8S cluster. That is my DNS which is also replaced now by AdguardHome (sorry Pihole!), and Traefik, which terminates all external HTTP communication incoming to my Homelab. And for the rest of the other services, those will be migrated in the coming weeks. For now what is important is I have HTTPS running perfectly fine with valid CA certificates even with dockerized services in the backend.</p>
<p>I also want to note here that during the learning process, whatever services that were running in the docker setup, all of those were nearly untouched since I was working inside a staging environment, keeping rigorous activities of countless create-delete of resources in isolation from my home production network.</p>
<p>That said, I received zero complaints from the wife except for the time I lost connectivity to the cluster when I thought everything was already stable. Lol more on this later.</p>
<p>In summary below opensource tools have been used for this project.</p>
<ul>
<li><a href="https://www.proxmox.com/">Proxmox</a> - Hypervisor (installed in 3 devices)</li>
<li><a href="https://www.terraform.io/">Terraform</a> - VM instantiation</li>
<li><a href="https://www.ansible.com/">Ansible</a> - VM configuration, Kubernetes installation</li>
<li><a href="https://k3s.io/">K3s</a> - Kubernetes platform</li>
<li><a href="https://kube-vip.io/">Kube-vip</a> - LB for Kube API</li>
<li><a href="https://longhorn.io/">Longhorn</a> - Block storage</li>
<li><a href="https://cilium.io/">Cilium</a> - CNI</li>
<li><a href="https://traefik.io/traefik/">Traefik</a> - Reverse Proxy</li>
<li><a href="https://cert-manager.io/">Cert-manager</a> - SSL certificate manager</li>
</ul>
<p><strong>Terraform</strong> and <strong>Ansible</strong> play the major role of orchestrators allowing for quick creation and deletion of virtual resources putting Infrascture-as-Code into practice. The rest are supplementary to learning IaC.</p>
<p><em>Side node: Unfortunately Terraform will be transitioning away from a completely opensource license and soon will be sitting behind a BSL. It might be a good idea to switch to <a href="https://opentofu.org/">OpenTF</a> (or OpenTofu) which is a fork of Terraform and now officially a CNCF project as well.</em></p>
<h2 id="the-setup">The setup</h2>
<p>All development activities were done in a staging environment. This is where the unaccounted events of VM creation-deletion have transpired from testing out the Terraform scripts until the very end when installing Longhorn and Cilium with Ansible, and even when playing around with Traefik in K8s.</p>
<p>The staging environment was deployed on my Unraid box and as for the production build, I am using Tiny PCs that house a total of 32GB RAM each allowing more room for other VMs that I might need in the long run. To give a glimpse of the production HW:</p>
<table>
<thead>
<tr>
<th>PVE host</th>
<th>CPU</th>
<th>Memory</th>
<th>Disk</th>
</tr>
</thead>
<tbody>
<tr>
<td>PVE1</td>
<td>6</td>
<td>32GB</td>
<td>512GB</td>
</tr>
<tr>
<td>PVE2</td>
<td>4</td>
<td>32GB</td>
<td>480GB</td>
</tr>
<tr>
<td>PVE3</td>
<td>4</td>
<td>32GB</td>
<td>480GB</td>
</tr>
</tbody>
</table>
<p>
    <figure>
      <img loading="lazy" src="/posts/re-engineering-the-homelab-with-iac-and-kubernetes-an-overview/hardware2.jpeg" alt="Hardware diagram">
      <figcaption>Actual hardware</figcaption>
    </figure>
  </p>
<p>I was also able to source data center-grade Intel S3510 SSD drives from the second-hand market. These should help in the reliability department of these nodes that will be running data replication because of Longhorn. Currently, these are housed in 2 of 3 nodes. Still looking to get another one and pop it in PVE1.</p>
<p>
    <figure>
      <img loading="lazy" src="/posts/re-engineering-the-homelab-with-iac-and-kubernetes-an-overview/hp_1200px.jpg" alt="Intel DC S3510 SSDs">
      <figcaption>Intel DC S3510 SSDs in PVE2 and PVE3</figcaption>
    </figure>
  </p>
<h2 id="one-container-to-rule-them-all">One container to rule them all</h2>
<p>Both the Terraform and Ansible controllers are running from a LXC container deployed on PVE1. This is where I do all of the development work. I am running a docker instance of VS code on the same container which enables me to create and modify code easily. The same container is used to communicate with the production environment.</p>
<p>
    <figure>
      <img loading="lazy" src="/posts/re-engineering-the-homelab-with-iac-and-kubernetes-an-overview/portainer5.png" alt="Portainer as Ansible and Terraform control node">
      <figcaption>Portainer LXC as Ansible and Terraform control node</figcaption>
    </figure>
  </p>
<p>One of the best advantages of using an LXC container is that it&rsquo;s so lightweight you can easily backup the environment anytime. I confirm Terraform and Ansible works well with the Ubuntu 22.04 template that comes with Proxmox.</p>
<h2 id="terraform-and-ansible">Terraform and Ansible</h2>
<p>Learning Terraform wasn&rsquo;t so bad. The Proxmox provider documentation from Telmate is enough to get you started and with the declarative style that is used to write Terraform language, it just makes the learning process a lot more easier to deal with. This is also the part where I had the least modifications and time spent the least.</p>
<p>Once I got the VMs up and working, next thing I worked on is Ansible. Now this is the part where I spent the biggest chunk of my time. I literally am unable to count the times I had to execute <code>terraform destroy</code> and <code>terraform apply</code> to re-create the VMs and test out my Asnbile playbooks. To be fair starting with Ansible wasn&rsquo;t really hard. It was the amount of automation I wanted to go with that later on will prove useful. Though I have to admit the playbooks are rather simple and which others might find lacking in terms of best practices. But hey, I have to start from somewhere!</p>
<p>The five commands to have a complete working k3s cluster:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">terraform apply
</span></span><span class="line"><span class="cl">ansible-playbook -i inventory.yaml preflight.yaml
</span></span><span class="line"><span class="cl">ansible-playbook -i inventory.yaml logical-volume-create.yaml
</span></span><span class="line"><span class="cl">ansible-playbook -i inventory.yaml k3s-kubevip-helm-ciliumInstallHelmCli.yaml
</span></span><span class="line"><span class="cl">ansible-playbook -i inventory.yaml longhorn-install.yaml
</span></span></code></pre></div><p>The whole process takes about more or less 15 minutes. Terraform creates 3 VMs, one on each proxmox node. Each VM is set 4 vCPU, 12GB RAM, 50GB boot disk + 200GB longhorn disk. <code>preflight.yaml</code> defines the ssh keys for passwordless authentication and installs the necessarry packages to run k3s-related software. <code>logical-volume-create.yaml</code> as its name suggests, creates the logical volume to be used for longhorn. <code>k3s-kubevip-helm-ciliumInstallHelmCli.yaml</code> installs k3s, kube-vip, helm, and Cilium altogether sequentially. And last but not the least, <code>longhorn-install.yaml</code> installs longhorn via helm.</p>
<h2 id="cilium">Cilium</h2>
<p>While Calico would be the go-to CNI for most, I opted to go for Cilium. The main reason for this is to start learning eBPF and have a grasp how things move within the kernel space. The installation was straightforward but to get it working in properly was a challenge.</p>
<p>I was able to make BGP control plane work during the initial phase and when I thought everything was already stable, I then started seeing BGP peers getting dropped and at some point even lost connectvivity to my DNS hosted in the cluster. After adding into the parameters one by one, I was able to make it work without disconnects.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">helm install cilium cilium/cilium --version 1.14.2 <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--namespace kube-system <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set bgpControlPlane.enabled<span class="o">=</span><span class="nb">true</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set <span class="nv">tunnel</span><span class="o">=</span>disabled <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set ipam.operator.clusterPoolIPv4PodCIDRList<span class="o">=</span>10.42.0.0/16 <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set <span class="nv">kubeProxyReplacement</span><span class="o">=</span><span class="nb">true</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set <span class="nv">k8sServiceHost</span><span class="o">={{</span> _k8sServiceHost <span class="o">}}</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set <span class="nv">k8sServicePort</span><span class="o">=</span><span class="m">6443</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set <span class="nv">routingMode</span><span class="o">=</span>native <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set <span class="nv">autoDirectNodeRoutes</span><span class="o">=</span><span class="nb">true</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set <span class="nv">ipv4NativeRoutingCIDR</span><span class="o">=</span>10.42.0.0/16 <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set loadBalancer.mode<span class="o">=</span>dsr <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set ipv4.enabled<span class="o">=</span><span class="nb">true</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set prometheus.enabled<span class="o">=</span><span class="nb">true</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set operator.prometheus.enabled<span class="o">=</span><span class="nb">true</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set hubble.enabled<span class="o">=</span><span class="nb">true</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--set hubble.metrics.enabled<span class="o">=</span><span class="s2">&#34;{dns,drop,tcp,flow,port-distribution,icmp,http}&#34;</span>
</span></span></code></pre></div><p><code>kubeProxyReplacement</code> is enabled to make use of eBPF instead of the traditional way of iptables. <code>loadBalancerMode</code> is also set to DSR making it possible for nodes to respond directly to the sender, avoiding the need to go via the return path. <code>routingMode</code> set to native and <code>autoDirectNodeRoutes</code> is set to true since all nodes are connected via the same L2 network. You can read more on Cilium routing <a href="https://docs.cilium.io/en/stable/network/concepts/routing/#routing">here</a>. Prometheus and Hubble are also enabled so I can touch on them later once I get more time.</p>
<p><strong>cilium-bgp-peering-policy.yaml</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;cilium.io/v2alpha1&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">CiliumBGPPeeringPolicy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="m">00</span>-<span class="l">bgp-peering-policy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">spec</span><span class="p">:</span><span class="w"> </span><span class="c"># CiliumBGPPeeringPolicySpec</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">nodeSelector</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">matchLabels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">kubernetes.io/hostname</span><span class="p">:</span><span class="w"> </span><span class="l">k8s-master-0-dev</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">virtualRouters</span><span class="p">:</span><span class="w"> </span><span class="c"># []CiliumBGPVirtualRouter</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">localASN</span><span class="p">:</span><span class="w"> </span><span class="m">65090</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">exportPodCIDR</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">serviceSelector</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">matchLabels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">exposedExternal</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;yes&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">neighbors</span><span class="p">:</span><span class="w"> </span><span class="c"># []CiliumBGPNeighbor</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">peerAddress</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;10.20.0.1/32&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">peerASN</span><span class="p">:</span><span class="w"> </span><span class="m">65000</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">eBGPMultihopTTL</span><span class="p">:</span><span class="w"> </span><span class="m">10</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">connectRetryTimeSeconds</span><span class="p">:</span><span class="w"> </span><span class="m">120</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">holdTimeSeconds</span><span class="p">:</span><span class="w"> </span><span class="m">90</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">keepAliveTimeSeconds</span><span class="p">:</span><span class="w"> </span><span class="m">30</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">gracefulRestart</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">enabled</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">restartTimeSeconds</span><span class="p">:</span><span class="w"> </span><span class="m">120</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;cilium.io/v2alpha1&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">CiliumBGPPeeringPolicy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="m">01</span>-<span class="l">bgp-peering-policy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">spec</span><span class="p">:</span><span class="w"> </span><span class="c"># CiliumBGPPeeringPolicySpec</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">nodeSelector</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">matchLabels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">kubernetes.io/hostname</span><span class="p">:</span><span class="w"> </span><span class="l">k8s-master-1-dev</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">virtualRouters</span><span class="p">:</span><span class="w"> </span><span class="c"># []CiliumBGPVirtualRouter</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">localASN</span><span class="p">:</span><span class="w"> </span><span class="m">65091</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">exportPodCIDR</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">serviceSelector</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">matchLabels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">exposedExternal</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;yes&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">neighbors</span><span class="p">:</span><span class="w"> </span><span class="c"># []CiliumBGPNeighbor</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">peerAddress</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;10.20.0.1/32&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">peerASN</span><span class="p">:</span><span class="w"> </span><span class="m">65000</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">eBGPMultihopTTL</span><span class="p">:</span><span class="w"> </span><span class="m">10</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">connectRetryTimeSeconds</span><span class="p">:</span><span class="w"> </span><span class="m">120</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">holdTimeSeconds</span><span class="p">:</span><span class="w"> </span><span class="m">90</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">keepAliveTimeSeconds</span><span class="p">:</span><span class="w"> </span><span class="m">30</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">gracefulRestart</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">enabled</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">restartTimeSeconds</span><span class="p">:</span><span class="w"> </span><span class="m">120</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;cilium.io/v2alpha1&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">CiliumBGPPeeringPolicy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="m">02</span>-<span class="l">bgp-peering-policy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">spec</span><span class="p">:</span><span class="w"> </span><span class="c"># CiliumBGPPeeringPolicySpec</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">nodeSelector</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">matchLabels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">kubernetes.io/hostname</span><span class="p">:</span><span class="w"> </span><span class="l">k8s-master-2-dev</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">virtualRouters</span><span class="p">:</span><span class="w"> </span><span class="c"># []CiliumBGPVirtualRouter</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">localASN</span><span class="p">:</span><span class="w"> </span><span class="m">65092</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">exportPodCIDR</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">serviceSelector</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">matchLabels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">exposedExternal</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;yes&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">neighbors</span><span class="p">:</span><span class="w"> </span><span class="c"># []CiliumBGPNeighbor</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">peerAddress</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;10.20.0.1/32&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">peerASN</span><span class="p">:</span><span class="w"> </span><span class="m">65000</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">eBGPMultihopTTL</span><span class="p">:</span><span class="w"> </span><span class="m">10</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">connectRetryTimeSeconds</span><span class="p">:</span><span class="w"> </span><span class="m">120</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">holdTimeSeconds</span><span class="p">:</span><span class="w"> </span><span class="m">90</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">keepAliveTimeSeconds</span><span class="p">:</span><span class="w"> </span><span class="m">30</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">gracefulRestart</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">enabled</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">restartTimeSeconds</span><span class="p">:</span><span class="w"> </span><span class="m">120</span><span class="w">
</span></span></span></code></pre></div><p>As for configuring BGP on OPNsense, all I had to do was download the <code>os-frr</code> plugin and apply the configuration according to the Cilium BGP resources.</p>
<p>
    <figure>
      <img loading="lazy" src="/posts/re-engineering-the-homelab-with-iac-and-kubernetes-an-overview/opnsense.png" alt="OPNsense BGP neighbor configuration">
      <figcaption>OPNsense BGP neighbor configuration</figcaption>
    </figure>
  </p>
<p>Once BGP is configured, I then configured <code>CiliumLoadBalancerIPPool</code> and configured the <code>serviceSelector</code> there so any service with a matching label will be assigned an external IP.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">cilium.io/v2alpha1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">CiliumLoadBalancerIPPool</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">externalpool</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">cidrs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">cidr</span><span class="p">:</span><span class="w"> </span><span class="m">192.168.100.0</span><span class="l">/27</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">disabled</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">serviceSelector</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">matchLabels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">exposedExternal</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;yes&#34;</span><span class="w">
</span></span></span></code></pre></div><p>To assign services with external IPs, all you have to do is ensure two things (third one is optional):</p>
<ol>
<li>The service should have a label matching what you defined in your <code>CiliumLoadBalancerIPPool</code>.</li>
<li>The service should be of type <code>LoadBalancer</code>.</li>
<li>For static external IP assignment, the service should have an annotation of <code>io.cilium/lb-ipam-ips</code> followed by the IP address.</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Service</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">annotations</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">io.cilium/lb-ipam-ips</span><span class="p">:</span><span class="w"> </span><span class="m">192.168.100.7</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">exposedExternal</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;yes&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">adguard-ui</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">adguard</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nn">...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nn">...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">LoadBalancer</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nn">...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nn">...</span><span class="w">
</span></span></span></code></pre></div><p>When all of the above are applied, you should now see an external IP assigned to your service.
e.g.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">❯ k -n adguard get svc
</span></span><span class="line"><span class="cl">NAME         TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
</span></span><span class="line"><span class="cl">adguard      LoadBalancer   10.43.254.122   192.168.100.8   53:30176/UDP   27d
</span></span><span class="line"><span class="cl">adguard-ui   LoadBalancer   10.43.38.101    192.168.100.7   80:32108/TCP   27d
</span></span></code></pre></div><p>You should also be able to check the BGP peering status as well as the learned routes in OPNsense.</p>
<p>
    <figure>
      <img loading="lazy" src="/posts/re-engineering-the-homelab-with-iac-and-kubernetes-an-overview/opnsense_2.png" alt="BGP peering status">
      <figcaption>OPNsense BGP status</figcaption>
    </figure>
  </p>
<p>
    <figure>
      <img loading="lazy" src="/posts/re-engineering-the-homelab-with-iac-and-kubernetes-an-overview/opnsense_3.png" alt="BGP routes">
      <figcaption>OPNsense BGP routes</figcaption>
    </figure>
  </p>
<h2 id="longhorn">Longhorn</h2>
<p>Before deciding to go for Longhorn, I was was trying to make <a href="https://piraeus.io/">Piraeus</a> datastore work (FOSS version of Linstor storage for Kubernetes). I got it to work with ReadWriteOnce but the moment I tried to test ReadWriteMany(RWX), it just wouldn&rsquo;t. On top of this it also felt that there was a steep learning curve to understand how Piraeus work on a deeper level in case I had to do extra troubleshooting in the future.</p>
<p>Longhorn on the other hand worked well out of the box. Testing out RWX by re-creating a pod on a different node worked well too and since Longhorn seems to use NFS to support this feature, accessing the volume from something external to the cluster e.g. from a VM works out of the box. The only thing is that there seems to be an <a href="https://github.com/cilium/cilium/issues/21541">open issue with Cilium</a> when exposing the volume externally. When I try to mount the share to a VM, I do experience slowdowns when opening a file with vim or even when just browsing through the directories.</p>
<p>
    <figure>
      <img loading="lazy" src="/posts/re-engineering-the-homelab-with-iac-and-kubernetes-an-overview/longhorn.png" alt="OPNsense BGP neighbor configuration">
      <figcaption>Longhorn Dashboard</figcaption>
    </figure>
  </p>
<p>Longhorn makes use of a 200Gi second volume that was declared in the Terraform script. The above snapshot shows the amount of available volume.</p>
<p>For reference, below is the playbook task to install longhorn:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">install longhorn</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">kubernetes.core.helm</span><span class="p">:</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">longhorn</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">chart_ref</span><span class="p">:</span><span class="w"> </span><span class="l">longhorn/longhorn</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">release_namespace</span><span class="p">:</span><span class="w"> </span><span class="l">longhorn-system</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">create_namespace</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">update_repo_cache</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">set_values</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">value</span><span class="p">:</span><span class="w"> </span><span class="l">service.ui.type=LoadBalancer</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">value</span><span class="p">:</span><span class="w"> </span><span class="l">defaultSettings.defaultDataPath=/longhorn_vol</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="nt">value</span><span class="p">:</span><span class="w"> </span><span class="l">defaultSettings.defaultReplicaCount=3</span><span class="w">
</span></span></span></code></pre></div><h2 id="exposing-services">Exposing services</h2>
<p>I took more time than expected when I was trying to expose the services with Traefik now running in Kubernetes. In the docker setup, the configuration was pretty straightforward with minimal reading required of the documentation. Whereas when running treafik in k8s, it came to the point that it already felt like I was digging my own grave with all the research and testing.</p>
<p>Eventually I got it to work by going with the base installation and slowly inching my way through the custom values in the yaml file. Once I got the middleware (for additional security headers) and TLS working via cert-manager, all I had to do was create individual ingress resources for each of the services I wanted to expose. The certificates are automatically created and managed by Cert-manager.</p>
<p>
    <figure>
      <img loading="lazy" src="/posts/re-engineering-the-homelab-with-iac-and-kubernetes-an-overview/traefik_2.png" alt="Network diagram">
      <figcaption>HTTP flow with Traefik and Cert-Manager</figcaption>
    </figure>
  </p>
<p>One thing to note, in Docker, the certificates can be managed by Traefik. But when using Traefik in a K8s environment, to make use of Let&rsquo;s Encrypt, the only option is to use Cert-manager which can only be paired up with the default Kubernetes Ingress resource. Traefik&rsquo;s Ingress CRD doesn&rsquo;t support this at the moment.</p>
<p>Below is a sample Ingress resource to reach the Adguard GUI from external to the cluster:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l">networking.k8s.io/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">Ingress</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">metadata</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">adguard-ui</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l">adguard</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">annotations</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">   </span><span class="nt">cert-manager.io/cluster-issuer</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;letsencrypt-cluster-issuer&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">spec</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">tls</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">   </span>- <span class="nt">hosts</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span>- <span class="l">adguard.su-root.net</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">     </span><span class="nt">secretName</span><span class="p">:</span><span class="w"> </span><span class="l">tls-adguard-ui-ingress-dns</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">rules</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">   </span>- <span class="nt">host</span><span class="p">:</span><span class="w"> </span><span class="l">adguard.su-root.net</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">     </span><span class="nt">http</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">       </span><span class="nt">paths</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">         </span>- <span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l">/</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">           </span><span class="nt">pathType</span><span class="p">:</span><span class="w"> </span><span class="l">Prefix</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">           </span><span class="nt">backend</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">             </span><span class="nt">service</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">               </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">adguard-ui</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">               </span><span class="nt">port</span><span class="p">:</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">                 </span><span class="nt">number</span><span class="p">:</span><span class="w"> </span><span class="m">80</span><span class="w">
</span></span></span></code></pre></div><p>
    <figure>
      <img loading="lazy" src="/posts/re-engineering-the-homelab-with-iac-and-kubernetes-an-overview/adguard.png" alt="Traefik UI">
      <figcaption>Adguard UI with valid CA certificate from LE</figcaption>
    </figure>
  </p>
<p>
    <figure>
      <img loading="lazy" src="/posts/re-engineering-the-homelab-with-iac-and-kubernetes-an-overview/traefik_ui.png" alt="Traefik UI">
      <figcaption>Traefik Dashboard</figcaption>
    </figure>
  </p>
<p>
    <figure>
      <img loading="lazy" src="/posts/re-engineering-the-homelab-with-iac-and-kubernetes-an-overview/traefik_ui2.png" alt="Traefik UI">
      <figcaption>Routers-Services Mapping in Traefik Dashboard</figcaption>
    </figure>
  </p>
<h2 id="the-journey-continues">The journey continues</h2>
<p>The learning doesn&rsquo;t stop here. What I have achieved so far is a basic understanding of how IaC integrates and can be made to work in different environments depending on the requirement. Another good thing is that this adds up to my confidence knowingly I can spin up my cluster in a matter of minutes even in the event that I have to physically migrate to another environment.</p>
<p>Going further I will continue to enhance the Ansible playbooks and try to make use of industry best practices even if this is only intended for Homelab use. I&rsquo;m also looking into integrating this with some kind of CICD tool like Jenkins or ArgoCD in the near future.</p>
<p>If you are interested to see more of this project, feel free to check out the repository over at my <a href="https://github.com/luifrancisco/k3s-ha">Github page</a>. A disclaimer though, the README is not updated yet! I will be updating this sooner or later and together with that will try to explain in detail the idea behind each step of the installation process.</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Run Pihole in an LXC container in Proxmox</title>
      <link>https://luislogs.com/posts/run-pihole-in-an-lxc-container-in-proxmox/</link>
      <pubDate>Mon, 08 May 2023 18:40:30 +0900</pubDate>
      
      <guid>https://luislogs.com/posts/run-pihole-in-an-lxc-container-in-proxmox/</guid>
      <description>Pihole as our local DNS at home has been working perfectly fine. It blocks almost every ad there is whenever I am browsing. I was initially running it as a docker container within my Unraid server. The problem is every time I would restart Unraid for some experimental work, the internet of the entire house also goes down momentarily. I already tried defining a secondary DNS on my DHCP server but noticed some of my devices would randomly pick a DNS if there are multiple defined.</description>
      <content:encoded><![CDATA[<p>Pihole as our local DNS at home has been working perfectly fine. It blocks almost every ad there is whenever I am browsing. I was initially running it as a docker container within my Unraid server. The problem is every time I would restart Unraid for some experimental work, the internet of the entire house also goes down momentarily. I already tried defining a secondary DNS on my DHCP server but noticed some of my devices would randomly pick a DNS if there are multiple defined. Now that I have a Proxmox running OPNsense, I just thought of running Pihole there instead, since anyway I rarely restart that box.</p>
<p>Proxmox already supports LXC containers by default and in this case, running Pihole on LXC provides some advantage in terms of flexibility and ease of configuration. This is especially for those who have less experience working with docker but only with Linux in general. I will share one good use case for this later on but for now let’s start setting up Pihole on Proxmox.</p>
<p>The hardware requirements according to the pihole documentation:
Minimum of 2GB disk (4GB recommended)
512MB RAM</p>
<p>First you need to download an LXC template. I like using debian as the base image since it’s very lightweight and it’s where Ubuntu is based from. If you don’t have it yet, you can download it by going to Datacenter &gt; pve &gt; storage &gt; CT templates &gt; Templates and search for Debian 11 Bullseye.</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_2.png" alt="alt text">
  </p>
<p>Click on Create CT and input a container ID, hostname, and the root password. Check Unprivileged container and nesting (optional). Note that nesting is not really required but in my case the proxmox terminal will keep on printing permission errors if I leave this unchecked.</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_3.png" alt="alt text">
  </p>
<p>Select debian as the template.</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_4.png" alt="alt text">
  </p>
<p>For disk, I assigned 6GB. For RAM, double the recommended, since I have enough.</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_5.png" alt="alt text">
  </p>
<p>Assign a static IP to the container. Gateway should also be defined.</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_6.png" alt="alt text">
  </p>
<p>For DNS I will assign my unbound IP which is the same as my OPNsense gateway IP. (Unbound is a DNS caching tool built-into OPNsense). This will basically be my upstream DNS for my Pihole. If you don’t have Unbound running then you can input any public DNS like Google (8.8.8.8, 8.8.4.4) or Cloudflare (1.1.1.1).</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_7.png" alt="alt text">
  </p>
<p>Confirm</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_8.png" alt="alt text">
  </p>
<p>Enable start on boot flag.</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_9.png" alt="alt text">
  </p>
<p>Login as root</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_10.png" alt="alt text">
  </p>
<p>Update and upgrade</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">apt-get update -y <span class="o">&amp;&amp;</span> apt-get upgrade -y
</span></span></code></pre></div><p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_11.png" alt="alt text">
  </p>
<p>Install curl:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">apt-get install curl -y
</span></span></code></pre></div><p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_12.png" alt="alt text">
  </p>
<p>Install Pihole:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -sSL https://install.pi-hole.net <span class="p">|</span> bash
</span></span></code></pre></div><p>Install custom upstream and point to unbound IP</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_13.png" alt="alt text">
  </p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_14.png" alt="alt text">
  </p>
<p>Install the default blacklist.</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_15.png" alt="alt text">
  </p>
<p>Install admin interface and lighthttpd.</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_16.png" alt="alt text">
  </p>
<p>Query logging or any other option is fine.</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_17.png" alt="alt text">
  </p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_18.png" alt="alt text">
  </p>
<p>Reset the pihole password.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo pihole -a -p
</span></span></code></pre></div><p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_19.png" alt="alt text">
  </p>
<p>Now go to your container IP and append /admin (e.g. http://10.0.0.88/admin)</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_20.png" alt="alt text">
  </p>
<p>If you are running it on proxmox like me you’d probably get the same error as in the snap below. You can ignore this especially if you have multi-core host. If you want to be sure you can check your CPU utilization with the top command.</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_21.png" alt="alt text">
  </p>
<p>After changing your DNS to pihole, check with nslookup if your device is able to send and receive to and from the Pihole IP.</p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_22.png" alt="alt text">
  </p>
<p>
    <img src="/posts/run-pihole-in-an-lxc-container-in-proxmox/20230508_23.png" alt="alt text">
  </p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Virtualized OPNsense on Proxmox as my homelab router</title>
      <link>https://luislogs.com/posts/virtualized-opnsense-on-proxmox-as-my-homelab-router/</link>
      <pubDate>Tue, 25 Apr 2023 18:40:30 +0900</pubDate>
      
      <guid>https://luislogs.com/posts/virtualized-opnsense-on-proxmox-as-my-homelab-router/</guid>
      <description>So this little thing arrived last week. Ever since I got my Unraid box up and running 24/7, I just felt I needed more control over the entire network. This is primarily because my existing home router would randomly drop packets and anyone who has planned to work from our home won’t be able to do so.
As for the specs, it’s a fanless appliance running a quad-core Intel 12th-gen J6412 (2 GHz base, 2.</description>
      <content:encoded><![CDATA[<p>So this little thing arrived last week. Ever since I got my Unraid box up and running 24/7, I just felt I needed more control over the entire network. This is primarily because my existing home router would randomly drop packets and anyone who has planned to work from our home won’t be able to do so.</p>
<p>
    <img src="/posts/virtualized-opnsense-on-proxmox-as-my-homelab-router/20230425_1.webp" alt="alt text">
  </p>
<p>
    <img src="/posts/virtualized-opnsense-on-proxmox-as-my-homelab-router/20230425_2.webp" alt="alt text">
  </p>
<p>As for the specs, it’s a fanless appliance running a quad-core Intel 12th-gen J6412 (2 GHz base, 2.6 GHz boost) with 5x Intel i226 2.5Gbe NICs. I chose the bare minimum option so I can avoid the crappy RAM and storage that might come with it. For the RAM I was able to source second-hand 2x8GB Samsung DDR4 SODIMMs and for the storage I didn’t any more bother and just ordered a 240GB SSD from Amazon since these come cheap these days.</p>
<p>
    <img src="/posts/virtualized-opnsense-on-proxmox-as-my-homelab-router/20230425_3.webp" alt="alt text">
  </p>
<p>Installed Proxmox and spawned a VM running a router software based on freeBSD called OPNsense. I can’t believe I’ve been missing on this piece of software for the longest time. It feels like I’ve rekindled my love for networking ever since I switched to a different role in my career graduating from configuring routers and switches.</p>
<p>
    <img src="/posts/virtualized-opnsense-on-proxmox-as-my-homelab-router/20230425_4.webp" alt="alt text">
  </p>
<p>
    <img src="/posts/virtualized-opnsense-on-proxmox-as-my-homelab-router/20230425_5.webp" alt="alt text">
  </p>
<p>The entire setup process was very straightforward. I just got confused a tad bit in the beginning when I was trying to figure out which interface to assign for management access. On my first attempt, I assigned the first interface in the list, expecting that it would be mapped to the first physical port. But when I tried to plug an ethernet cable from my laptop, for some reason I couldn’t ping the management IP I set. Long story short I re-installed Proxmox again only to know that the first installation was already correct. Maybe some lose cable?</p>
<p>
    <img src="/posts/virtualized-opnsense-on-proxmox-as-my-homelab-router/20230425_6.webp" alt="alt text">
  </p>
<p>Anyway the router has been running stable for the past week. This is with virtio running as a driver for the Intel i226 NICs. On average I’m getting about 500Mbps for internet (I used to get about 700MBps with a TP-Link A10 router and yes I can deal with that 200Mbps difference for now!). I’ll explore physically passing through the NICs later on once I get the time. But as far as I can tell, I’m just loving it. On top of that Proxmox has also been remarkably gaining my interest now that I have a pi-hole running in an LXC container.</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
