<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Erik &#8211; Erik Makes Things</title>
	<atom:link href="https://erikmakesthings.ddns.net/author/user/feed/" rel="self" type="application/rss+xml" />
	<link>https://erikmakesthings.ddns.net</link>
	<description></description>
	<lastBuildDate>Fri, 12 Dec 2025 16:21:07 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://erikmakesthings.ddns.net/wp-content/uploads/2025/06/cropped-E-3-32x32.png</url>
	<title>Erik &#8211; Erik Makes Things</title>
	<link>https://erikmakesthings.ddns.net</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>IoT Honeypot Capstone Project</title>
		<link>https://erikmakesthings.ddns.net/iot-honeypot-capstone-project/</link>
					<comments>https://erikmakesthings.ddns.net/iot-honeypot-capstone-project/#comments</comments>
		
		<dc:creator><![CDATA[Erik]]></dc:creator>
		<pubDate>Wed, 10 Dec 2025 20:11:50 +0000</pubDate>
				<category><![CDATA[Cybersecurity]]></category>
		<category><![CDATA[Micro Controller]]></category>
		<category><![CDATA[Homelab]]></category>
		<category><![CDATA[IoT]]></category>
		<guid isPermaLink="false">https://erikmakesthings.ddns.net/?p=314</guid>

					<description><![CDATA[Project Goal For our Capstone project, we built a multi-protocol IoT honeypot designed to help students understand modern home-lab security and how easily common IoT protocols can be explored or abused when controls are weak. The goal was to create a realistic-looking device that could safely log attacker-style interactions and turn them into something instructors [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Project Goal</h2>



<p>For our Capstone project, we built a multi-protocol IoT honeypot designed to help students understand modern home-lab security and how easily common IoT protocols can be explored or abused when controls are weak. The goal was to create a realistic-looking device that could safely log attacker-style interactions and turn them into something instructors and students could learn from in a controlled environment.</p>



<figure class="wp-block-image aligncenter size-large"><img fetchpriority="high" decoding="async" width="1024" height="601" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/Screenshot-from-2025-12-10-15-38-03-1024x601.png" alt="" class="wp-image-352" srcset="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/Screenshot-from-2025-12-10-15-38-03-1024x601.png 1024w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/Screenshot-from-2025-12-10-15-38-03-300x176.png 300w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/Screenshot-from-2025-12-10-15-38-03-768x451.png 768w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/Screenshot-from-2025-12-10-15-38-03-1536x902.png 1536w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/Screenshot-from-2025-12-10-15-38-03-2048x1203.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">Hardware &amp; Architecture</h2>



<p>A key design constraint shaped the entire build: the Seeed Studio XIAO ESP32-C6 can’t run 2.4 GHz Wi-Fi and Zigbee (802.15.4) at the same time. To solve this, we split the honeypot into two identical ESP32-C6 boards.</p>



<ul class="wp-block-list">
<li><strong>Bottom board:</strong> Dedicated Zigbee coordinator with intentionally weak security to encourage join attempts. It converts Zigbee events into small JSON objects and sends them to the top board over UART.</li>



<li><strong>Top board:</strong> Acts like a multi-protocol gateway. It connects to Wi-Fi, exposes an HTTP dashboard, interacts with an MQTT broker, advertises a believable BLE GATT profile, and logs events from all four protocol surfaces (HTTP, MQTT, BLE, Zigbee).</li>
</ul>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image aligncenter size-large"><img decoding="async" width="2560" height="2560" data-id="351" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/bunchOparts-edited-scaled.jpg" alt="" class="wp-image-351" srcset="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/bunchOparts-edited-scaled.jpg 2560w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/bunchOparts-edited-300x300.jpg 300w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/bunchOparts-edited-1024x1024.jpg 1024w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/bunchOparts-edited-150x150.jpg 150w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/bunchOparts-edited-768x768.jpg 768w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/bunchOparts-edited-1536x1536.jpg 1536w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/bunchOparts-edited-2048x2048.jpg 2048w" sizes="(max-width: 2560px) 100vw, 2560px" /></figure>
</figure>



<h2 class="wp-block-heading">Designing the Enclosure</h2>



<p>To make the honeypot practical and portable, I designed a custom case in FreeCAD around the boards’ dimensions and mounting needs. The enclosure was 3D printed in HYPER-PLA on my Ender 3. To simplify maintenance, I included magnet-based snap-fit closure using 10 mm × 3 mm magnets instead of screws. I also integrated a lid mount for a small 5 V solar panel, then finished the chassis with a yellow paint job and honeycomb theme to visually reinforce the “honeypot” identity during demos.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:25%">
 [<a href="https://erikmakesthings.ddns.net/iot-honeypot-capstone-project/">See image gallery at erikmakesthings.ddns.net</a>] 
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<div class="wp-block-cover" style="min-height:323px;aspect-ratio:unset;"><video class="wp-block-cover__video-background intrinsic-ignore" autoplay muted loop playsinline src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/3dPrinters-1.mp4" data-object-fit="cover"></video><span aria-hidden="true" class="wp-block-cover__background has-background-dim"></span><div class="wp-block-cover__inner-container is-layout-flow wp-block-cover-is-layout-flow">
<p class="has-text-align-center has-large-font-size"></p>
</div></div>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:25%">
 [<a href="https://erikmakesthings.ddns.net/iot-honeypot-capstone-project/">See image gallery at erikmakesthings.ddns.net</a>] 
</div>
</div>



<h2 class="wp-block-heading">How it works</h2>



<p>The top board is where the honeypot feels like a real device to an attacker. On boot, the firmware starts serial, connects to Wi-Fi, configures time using NTP, initializes the HTTP server, MQTT client, BLE stack, and then brings up the Serial1 UART link to the Zigbee board. It also generates a short unique ID based on the board’s MAC address so multiple nodes can be deployed without manual topic configuration. It then continuously services HTTP requests, processes MQTT traffic, and reads Zigbee JSON messages from the UART link.</p>



<p>Because the microcontroller has limited memory, the system avoids long-term storage and instead uses separate ring buffers for each protocol. Each buffer stores the most recent 50 events, overwriting older entries as new ones arrive. Every entry includes a timestamp, event type, and protocol-specific details such as HTTP path, MQTT topic/payload, BLE address, or Zigbee</p>



<p>The MQTT component is designed to look believable to scanners and testers. The top board connects to a broker on the core VLAN, builds a client name and topic prefix from its MAC-derived ID, publishes an “online” status message, and subscribes to an input topic pattern. When messages arrive, a callback logs the event and echoes the content back to an output topic.</p>



<p>For BLE, the device uses the NimBLE stack to present as a plausible smart device named <em>“Honey-LightBLE.”</em> The advertised services include familiar standards like Device Information and Battery Service alongside a fake configuration-style service. Read/write callbacks record which characteristic UUID was accessed, the client’s BLE address when available, and both hex and ASCII representations of any data written. If a client writes to a state-like characteristic, the honeypot sends a notification back to simulate a real device response.</p>



<p>Rather than trying to merge all radios onto one chip at once, Zigbee events are forwarded from the bottom board using a clean, simple UART protocol. The top board reads Serial1 until it sees a newline, then attempts to parse the line as JSON. If the object contains an &#8220;evt&#8221; field, it is logged into the Zigbee ring buffer; if parsing fails, the firmware logs an error event instead.</p>



<p>The bottom ESP32-C6 is dedicated to Zigbee. Its setup initializes debugging serial, the UART link, LED state, and sends early “boot/hello” style events for quick verification from the top board’s dashboard. Zigbee logic runs inside a separate task (esp_zb_task), keeping the coordinator responsibilities isolated from the multi-protocol gateway functions.</p>



<h2 class="wp-block-heading">Setting Up the Lab</h2>



<p>To keep the project realistic but safe, I built a dedicated testing environment on my home network using VLAN segmentation on my UniFi gateway. The lab was designed so our team could run recon and protocol testing against the honeypot without putting my everyday devices or core services at risk. The structure also reflects how an enterprise would isolate IoT systems to reduce lateral movement and limit blast radius if a device becomes compromised.</p>



<p>I created three main network segments. The core VLAN (10.0.0.x) hosts my critical services, including my main Ubuntu server (“wifu-server”) running Docker containers like my web server and Home Assistant, as well as a separate DNS cache server. The IoT VLAN (10.0.11.x) is used exclusively for testing and contains the honeypot plus several real IoT devices such as a Litter-Robot 4, an Ecobee thermostat, and a wired Philips Hue bridge and bulbs. The main VLAN is reserved for personal devices (laptops, phones, TVs, etc.) and is intentionally out of scope to keep experimental traffic away from my daily-use equipment.</p>



<figure class="wp-block-image aligncenter size-large"><img decoding="async" width="1024" height="681" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/NetDiagram-1-1024x681.jpeg" alt="" class="wp-image-320" srcset="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/NetDiagram-1-1024x681.jpeg 1024w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/NetDiagram-1-300x200.jpeg 300w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/NetDiagram-1-768x511.jpeg 768w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/NetDiagram-1-1536x1022.jpeg 1536w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/NetDiagram-1-2048x1362.jpeg 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>From there, I added routing and firewall rules to expose only what we needed for testing. A key part of the lab design was enabling controlled team access to an attacker workstation without opening default high-noise ports to the internet. To achieve this, I configured port forwarding from my public IP to a dedicated attacker machine: a Minisforum UN150P running Kali on the IoT VLAN. External requests are mapped to RDP on port 6767 and SSH on port 6768, allowing remote access while avoiding standard ports like 3389 and 22. This approach keeps access practical for teammates while reducing basic opportunistic scanning risk.</p>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="768" height="1024" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/IMG20251210152539-768x1024.jpg" alt="" class="wp-image-354" srcset="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/IMG20251210152539-768x1024.jpg 768w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/IMG20251210152539-225x300.jpg 225w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/IMG20251210152539-1152x1536.jpg 1152w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/IMG20251210152539-1536x2048.jpg 1536w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/IMG20251210152539-scaled.jpg 1920w" sizes="(max-width: 768px) 100vw, 768px" /></figure>



<p>On the services side, I installed an MQTT broker on my home server and configured it for anonymous access so the honeypot and test devices could publish/subscribe without needing per-device credentials. This setup was intentional for education: it increases realism for “weak default” demonstrations and makes it easier to reproduce attacks and logging outcomes during testing.</p>



<p>To make the Kali box usable for the whole team, I installed a full desktop environment along with xrdp and OpenSSH so teammates could connect either through remote desktop or terminal. I also created separate user accounts for Jesse and Cynthia, which avoided password sharing and made activity more traceable during collaboration.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<figure class="wp-block-image size-full is-style-rounded wp-duotone-unset-2"><img loading="lazy" decoding="async" width="401" height="600" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/cynth.jpg" alt="" class="wp-image-316" srcset="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/cynth.jpg 401w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/cynth-201x300.jpg 201w" sizes="(max-width: 401px) 100vw, 401px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<h2 class="wp-block-heading">Recon and MQTT</h2>



<p>Cynthia led our recon and MQTT testing, validating that the honeypot was discoverable and behaved like a believable IoT target inside the segmented home lab. She used Nmap to identify MQTT-related exposure and confirm the messaging surface.</p>



<p>After discovery, she used curl to pull useful HTTP-visible details, including the connected broker, ClientID, and base topic structure; exactly the kind of information that makes MQTT hijacking and message injection easier.</p>



<p>For MQTT exploitation and validation, Cynthia used Mosquitto tooling to simulate message injection/broker-style interaction and confirm our logger captured the traffic as expected. She also incorporated RALMQTT as part of her MQTT pentesting toolkit, which we referenced alongside our broader MQTT testing sources.</p>



 [<a href="https://erikmakesthings.ddns.net/iot-honeypot-capstone-project/">See image gallery at erikmakesthings.ddns.net</a>] 



<p>To round out the risk story, she performed a SlowITe-style MQTT denial-of-service demonstration, showing how TCP-based IoT messaging can be disrupted through connection exhaustion even with minimal bandwidth.</p>



<figure class="wp-block-video"><video height="540" style="aspect-ratio: 1440 / 540;" width="1440" controls src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/My-Event-on-Wednesday-December-10-2025_edited.mp4"></video></figure>



<hr class="wp-block-separator has-alpha-channel-opacity"/>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="683" height="1024" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/erik-1-683x1024.jpg" alt="" class="wp-image-347" srcset="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/erik-1-683x1024.jpg 683w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/erik-1-200x300.jpg 200w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/erik-1-768x1152.jpg 768w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/erik-1-1024x1536.jpg 1024w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/erik-1-1365x2048.jpg 1365w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/erik-1-scaled.jpg 1707w" sizes="(max-width: 683px) 100vw, 683px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<h2 class="wp-block-heading">BLE Testing</h2>



<p style="border-top-left-radius:91px;border-top-right-radius:91px;border-bottom-left-radius:91px;border-bottom-right-radius:91px">I led the BLE testing to confirm the honeypot presents a believable Bluetooth target and reliably logs both passive probing and active interaction. I started by scanning for nearby devices using Bettercap’s ble.recon module, which gave me a quick snapshot of the BLE environment and helped me confirm <em>Honey-LightBLE</em> was advertising as expected based on name, RSSI, and vendor details.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="277" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/BettercapScan-1024x277.png" alt="" class="wp-image-366" srcset="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/BettercapScan-1024x277.png 1024w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/BettercapScan-300x81.png 300w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/BettercapScan-768x208.png 768w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/BettercapScan-1536x416.png 1536w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/BettercapScan.png 1721w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>After identifying the device, I connected and queried its GATT profile. The honeypot exposed standard services like Generic Access, Device Information, and Battery, plus a custom Nordic UART-style service. While exploring the GATT table, I confirmed that even simple reads generated visible events in my dashboard, which showed the system could capture low-noise reconnaissance.</p>



 [<a href="https://erikmakesthings.ddns.net/iot-honeypot-capstone-project/">See image gallery at erikmakesthings.ddns.net</a>] 



<p>To test active input, I used bluetoothctl to connect and write a short payload to a writable UART RX-style characteristic. The dashboard logged and decoded the write, validating the full chain from discovery, connection, GATT enumeration, write action, and finally event capture. This confirmed the honeypot can reliably record both read-style recon and write-based injection behavior.</p>



 [<a href="https://erikmakesthings.ddns.net/iot-honeypot-capstone-project/">See image gallery at erikmakesthings.ddns.net</a>] 
</div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="683" height="1024" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/jesse-1-683x1024.jpeg" alt="" class="wp-image-319" srcset="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/jesse-1-683x1024.jpeg 683w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/jesse-1-200x300.jpeg 200w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/jesse-1-768x1152.jpeg 768w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/jesse-1-1024x1536.jpeg 1024w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/jesse-1.jpeg 1365w" sizes="(max-width: 683px) 100vw, 683px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<h2 class="wp-block-heading">Zigbee Testing</h2>



<p>Jesse led our Zigbee testing to validate that the Zigbee side of the honeypot functioned correctly and to establish what normal baseline traffic should look like in a small smart-home style environment. He noted that meaningful “attack-style” testing was harder to demonstrate in a clean way because Zigbee’s behavior is highly local and device-driven, so most of the effort focused on observation and recon rather than flashy exploitation.</p>



<p>During this phase, the Zigbee network was confirmed to be working and able to pair with Zigbee end devices, which helped verify the core functionality of the setup.</p>



<p>Jesse also documented a limitation we ran into: issues with the Zigbee logger prevented us from showing the depth of logs we originally intended. Even so, we were still able to capture and confirm devices attempting to connect to the system, which supported the overall purpose of the Zigbee-facing honeypot design.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-3 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="137" data-id="377" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/Screenshot-from-2025-12-10-16-11-37-1024x137.png" alt="" class="wp-image-377" srcset="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/Screenshot-from-2025-12-10-16-11-37-1024x137.png 1024w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/Screenshot-from-2025-12-10-16-11-37-300x40.png 300w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/Screenshot-from-2025-12-10-16-11-37-768x103.png 768w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/Screenshot-from-2025-12-10-16-11-37.png 1519w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
</figure>
</div>
</div>



<h2 class="wp-block-heading">Download the code to try for yourself.</h2>



<div class="wp-block-file aligncenter"><a id="wp-block-file--media-ef60b6af-85e3-4042-b796-fa2f9a0a1541" href="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/FinalFirmware.7z">FinalFirmware</a><a href="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/FinalFirmware.7z" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-ef60b6af-85e3-4042-b796-fa2f9a0a1541">Download</a></div>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="498" height="437" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/LTT-SoCool.gif" alt="" class="wp-image-394"/></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://erikmakesthings.ddns.net/iot-honeypot-capstone-project/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		<enclosure url="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/3dPrinters-1.mp4" length="32441782" type="video/mp4" />
<enclosure url="https://erikmakesthings.ddns.net/wp-content/uploads/2025/12/My-Event-on-Wednesday-December-10-2025_edited.mp4" length="4558613" type="video/mp4" />

			</item>
		<item>
		<title>DiY AI: Mochi</title>
		<link>https://erikmakesthings.ddns.net/diy-ai-mochi/</link>
					<comments>https://erikmakesthings.ddns.net/diy-ai-mochi/#respond</comments>
		
		<dc:creator><![CDATA[Erik]]></dc:creator>
		<pubDate>Tue, 19 Aug 2025 18:59:20 +0000</pubDate>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Server]]></category>
		<guid isPermaLink="false">https://erikmakesthings.ddns.net/?p=291</guid>

					<description><![CDATA[I&#8217;m sorry Dave, but I&#8217;m afraid I can&#8217;t let you do that. -HAL 9000 Welcome back to erikmakesthings, where we dive into DIY tech projects that blur the line between “wow that’s genius” and “should this be allowed?”. Today we’re building a custom AI assistant using Ollama and Home Assistant. Because sure, Siri and Alexa [&#8230;]]]></description>
										<content:encoded><![CDATA[
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>I&#8217;m sorry Dave, but I&#8217;m afraid  I can&#8217;t let you do that.</p>
</blockquote>



<p>-HAL 9000</p>



<p>Welcome back to <strong>erikmakesthings</strong>, where we dive into DIY tech projects that blur the line between <em>“wow that’s genius”</em> and <em>“should this be allowed?”</em>. Today we’re building a custom AI assistant using Ollama and Home Assistant. Because sure, Siri and Alexa exist, but where’s the fun in that?</p>



<h2 class="wp-block-heading"><strong>The Foundation: Ollama</strong></h2>



<p>We’re starting with Ollama, a large language model built on the Transformer architecture. It eats text, spits out answers, and occasionally throws in better jokes than your friends. I’m running <code>llama3.1:8b-instruct-q8_0</code>, a conversational variant with around eight billion parameters. To put that in perspective, that’s over sixty times the number of transistors in a 2004 Pentium 4 CPU. Back then, you’d need racks of servers to even get close to this kind of horsepower. Now I can run it on my Nvidia A2000 and have it just sit around waiting for me to say, “Hey Mochi.”</p>



<h2 class="wp-block-heading"><strong>Wake Word Training: Teaching the Parrot</strong></h2>



<p>Next came the wake word. I wanted Mochi to perk up when I said, well, “Hey Mochi.” Home Assistant’s Wake Word Training tool makes this possible by chewing through audio samples and teaching a model to pick out that specific phrase. Under the hood it’s a mix of convolutional neural networks pulling features from the sound and recurrent neural networks recognizing the patterns. It’s a bit like training a parrot, except the parrot is powered by math instead of sunflower seeds, and it never gets bored of repeating the same phrase back to you.<br><br>Tool: <a href="https://colab.research.google.com/drive/1q1oe2zOyZp7UsB3jJiQ1IFn8z5YfjwEb?usp=sharing#scrollTo=1cbqBebHXjFD">https://colab.research.google.com/drive/1q1oe2zOyZp7UsB3jJiQ1IFn8z5YfjwEb?usp=sharing#scrollTo=1cbqBebHXjFD</a></p>



<figure class="wp-block-video"><video height="1584" style="aspect-ratio: 720 / 1584;" width="720" controls src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/08/Record_2025-08-19-13-14-34_b783bf344239542886fee7b48fa4b892.mp4"></video></figure>



<h2 class="wp-block-heading"><strong>Building the Containers: Docker-nado</strong></h2>



<p>With the model sorted out, I needed to containerize the pieces. Docker Compose to the rescue. I spun up three containers: Piper for text-to-speech, Whisper for speech-to-text, and OpenWakeWord for, well, the wake word. Each one is designed to do its own job, but when you wire them all together, suddenly you’ve got an actual conversation pipeline. It’s a bit like putting a band together. Individually they’re fine, but together it actually sounds like music. Except here, the instruments are YAML configs and TCP sockets.</p>



<p>Here&#8217;s the Docker Compose file:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>services:
  wyoming-piper:
    image: rhasspy/wyoming-piper:latest
    container_name: wyoming-piper
    command: >
      --voice en_US-lessac-low
      --uri tcp://0.0.0.0:10200
      --data-dir /data
      --download-dir /data
      --length-scale 0.9
    volumes:
      - ./piper-data:/data
    ports:
      - "10200:10200"
    restart: unless-stopped

  wyoming-whisper:
    image: rhasspy/wyoming-whisper:latest
    container_name: wyoming-whisper
    command: >
      --uri tcp://0.0.0.0:10300
      --model small-int8
      --language en
      --download-dir /data
    environment:
      - HF_HUB_CACHE=/data/hf-cache
    volumes:
      - ./whisper-data:/data
    ports:
      - "10300:10300"
    restart: unless-stopped

  openwakeword:
    image: rhasspy/wyoming-openwakeword:latest
    container_name: wyoming-openwakeword
    command: >
      --uri tcp://0.0.0.0:10400
      --custom-model-dir /custom
      --preload-model ok_nabu
      --preload-model hey_mo_chee
    volumes:
      - ./openwakeword-data:/custom
    ports:
      - "10400:10400"
    restart: unless-stopped</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">services</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">wyoming</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">piper</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">    image</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rhasspy</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">wyoming</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">piper</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9">latest</span></span>
<span class="line"><span style="color: #D8DEE9FF">    container_name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">wyoming</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">piper</span></span>
<span class="line"><span style="color: #D8DEE9FF">    command</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">voice</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">en_US</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">lessac</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">low</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">uri</span><span style="color: #D8DEE9FF"> tcp</span><span style="color: #ECEFF4">:</span><span style="color: #616E88">//0.0.0.0:10200</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">data</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">dir</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">data</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">download</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">dir</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">data</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">length</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">scale</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0.9</span></span>
<span class="line"><span style="color: #D8DEE9FF">    volumes</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">.</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">piper</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">data</span><span style="color: #ECEFF4">:</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">data</span></span>
<span class="line"><span style="color: #D8DEE9FF">    ports</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">10200:10200</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    restart</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">unless</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">stopped</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">wyoming</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">whisper</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">    image</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rhasspy</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">wyoming</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">whisper</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9">latest</span></span>
<span class="line"><span style="color: #D8DEE9FF">    container_name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">wyoming</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">whisper</span></span>
<span class="line"><span style="color: #D8DEE9FF">    command</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">uri</span><span style="color: #D8DEE9FF"> tcp</span><span style="color: #ECEFF4">:</span><span style="color: #616E88">//0.0.0.0:10300</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">model</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">small</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">int8</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">language</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">en</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">download</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">dir</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">data</span></span>
<span class="line"><span style="color: #D8DEE9FF">    environment</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">HF_HUB_CACHE</span><span style="color: #81A1C1">=/</span><span style="color: #D8DEE9">data</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">hf</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">cache</span></span>
<span class="line"><span style="color: #D8DEE9FF">    volumes</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">.</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">whisper</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">data</span><span style="color: #ECEFF4">:</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">data</span></span>
<span class="line"><span style="color: #D8DEE9FF">    ports</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">10300:10300</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    restart</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">unless</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">stopped</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">  openwakeword</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">    image</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rhasspy</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">wyoming</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">openwakeword</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9">latest</span></span>
<span class="line"><span style="color: #D8DEE9FF">    container_name</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">wyoming</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">openwakeword</span></span>
<span class="line"><span style="color: #D8DEE9FF">    command</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">uri</span><span style="color: #D8DEE9FF"> tcp</span><span style="color: #ECEFF4">:</span><span style="color: #616E88">//0.0.0.0:10400</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">custom</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">model</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">dir</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">custom</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">preload</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">model</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ok_nabu</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">preload</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">model</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">hey_mo_chee</span></span>
<span class="line"><span style="color: #D8DEE9FF">    volumes</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">.</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">openwakeword</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">data</span><span style="color: #ECEFF4">:</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">custom</span></span>
<span class="line"><span style="color: #D8DEE9FF">    ports</span><span style="color: #ECEFF4">:</span></span>
<span class="line"><span style="color: #D8DEE9FF">      </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">10400:10400</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    restart</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">unless</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">stopped</span></span></code></pre></div>



<h2 class="wp-block-heading"><strong>Configuring Home Assistant: The AI Overlord</strong></h2>



<p>Once the containers were humming along, it was time to bring them under Home Assistant’s control. This is where all the parts stop being cool toys on their own and start acting like an actual assistant.</p>



<p>The <strong>speech-to-text (STT) engine</strong> listens to whatever I say and translates it into raw text. Basically, it’s the ear of the system. Whisper handles this job, turning “Hey Mochi, turn on the lights” into plain text that the assistant can understand.</p>



<p>The <strong>text-to-speech (TTS) engine</strong> is the voice on the other end. Piper takes the AI’s response and synthesizes speech so Mochi can talk back. Without it, I’d just be staring at terminal logs, which is fun for me but not exactly living-room-friendly.</p>



<p>The <strong>wake word model</strong> is the gatekeeper. It sits there quietly until it hears “Hey Mochi,” and only then does it wake the rest of the pipeline. Without it, I’d either need to press a button like it’s 1995 voice dictation software, or leave the system constantly listening (creepy).</p>



<p>And finally, the <strong>conversation agent</strong> is where the large language model comes in. This is the brain of the operation. It takes the transcribed text from STT, decides what that means, and formulates a response. That response then gets pushed through TTS so Mochi can answer back. In other words: STT is the ears, TTS is the mouth, the wake word is the doorbell, and the LLM is the brain making sense of it all. The end result still feels a little like duct-taping a robot together, but somehow it works — and that’s the beauty of Home Assistant.</p>



 [<a href="https://erikmakesthings.ddns.net/diy-ai-mochi/">See image gallery at erikmakesthings.ddns.net</a>] 



<h2 class="wp-block-heading"><strong>Testing the Wake Word: Here’s the Catch</strong></h2>



<p>With everything configured, I tried it out on an ESPHome device tied into my shiny new Nabu Casa voice preview. I had the assistant’s wake word set to “Hey Mochi,” but it turns out the device itself only recognizes the baked-in defaults. No love for Mochi just yet. On the plus side, the device has updated three times in the week I’ve owned it, and the devs have already said they’ll likely be adding custom wake word support. So instead of risking my sanity (and my hardware) flashing experimental firmware at 2 a.m., I’m just going to wait this one out. Sometimes patience is the smarter hack.</p>



 [<a href="https://erikmakesthings.ddns.net/diy-ai-mochi/">See image gallery at erikmakesthings.ddns.net</a>] 



<h2 class="wp-block-heading"><strong>Switching to Mochi: The AI Uprising</strong></h2>



<p>Finally, it&#8217;s time to switch to our custom AI assistant and see how it performs. Imagine you&#8217;re talking to a robot who understands your every command&#8230; or doesn&#8217;t understand anything at all. I&#8217;m giving Mochi some test commands, and so far, it&#8217;s been doing surprisingly well (considering I just made it up from scratch). That&#8217;s it for today&#8217;s project! We&#8217;ve built our very own custom AI assistant using Ollama and Home Assistant. It&#8217;s been a wild ride, but we made it through together.</p>



<figure class="wp-block-video"><video height="1080" style="aspect-ratio: 1920 / 1080;" width="1920" controls src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/08/VID20250819134535.mp4"></video></figure>



<h2 class="wp-block-heading">P.S.</h2>



<p>And here’s the kicker: this whole article was written by my local LLM. I tossed it some notes, gave it a crash course in my writing style, and let it go to town. So yeah… Mochi just helped write its own origin story. If that’s not dangerously close to Skynet, I don’t know what is.</p>



<h2 class="wp-block-heading">P.S.S</h2>



<p>It wrote the P.S. too.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://erikmakesthings.ddns.net/diy-ai-mochi/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://erikmakesthings.ddns.net/wp-content/uploads/2025/08/Record_2025-08-19-13-14-34_b783bf344239542886fee7b48fa4b892.mp4" length="3353862" type="video/mp4" />
<enclosure url="https://erikmakesthings.ddns.net/wp-content/uploads/2025/08/VID20250819134535.mp4" length="31971249" type="video/mp4" />

			</item>
		<item>
		<title>Securing passwords with Vaultwarden + Apache</title>
		<link>https://erikmakesthings.ddns.net/securing-passwords-with-vaultwarden-apache/</link>
					<comments>https://erikmakesthings.ddns.net/securing-passwords-with-vaultwarden-apache/#respond</comments>
		
		<dc:creator><![CDATA[Erik]]></dc:creator>
		<pubDate>Fri, 25 Jul 2025 23:24:13 +0000</pubDate>
				<category><![CDATA[Apache]]></category>
		<category><![CDATA[Cybersecurity]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Server]]></category>
		<guid isPermaLink="false">https://erikmakesthings.ddns.net/?p=286</guid>

					<description><![CDATA[As any cybersecurity-conscious person will tell you, password managers are one of the easiest and most effective tools for protecting your digital life. They encourage you to create long, unique, and complex passwords for every website and service, no more recycling the same weak password everywhere. Now, sure, you could use something like KeePass and [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>As any cybersecurity-conscious person will tell you, password managers are one of the easiest and most effective tools for protecting your digital life. They encourage you to create long, unique, and complex passwords for every website and service, no more recycling the same weak password everywhere.</p>



<p>Now, sure, you could use something like KeePass and keep it local to your machine. That works great if you&#8217;re mostly tied to one device. But if you&#8217;re like me—always bouncing between machines, phones, and maybe even the occasional tablet, you&#8217;ll probably want something a little more accessible.</p>



<p>That’s where <strong>Vaultwarden</strong> comes in. It’s a lightweight, self-hosted fork of Bitwarden, the open-source password manager. With Vaultwarden, you get to use the official Bitwarden mobile apps and browser extensions, but with a leaner backend that’s easier to run on your own server. It’s fast, minimal, and you keep control of your own data.</p>



<h2 class="wp-block-heading">The Setup</h2>



<p>You’ll need a few things before we  get started:</p>



<ul class="wp-block-list">
<li>A server with <strong>Docker</strong> installed</li>



<li>The <strong>Apache</strong> web server</li>



<li>A <strong>domain name</strong></li>



<li>An <strong>SSL certificate</strong> (we’ll use Let’s Encrypt)</li>



<li>Port <code>443</code> open on your firewall (or another port if you&#8217;re using a custom setup)</li>
</ul>



<p>If you’re already running services on your host’s port 443 like I am, you can remap Vaultwarden’s container to a different internal port and let Apache handle the HTTPS proxying.</p>



<h2 class="wp-block-heading">Apache</h2>



<p>Once you’ve got Docker, Apache, and your domain ready, it’s time to configure your reverse proxy.</p>



<p>Create a new config file for Vaultwarden at /etc/apache2/sites-available/vaultwarden.conf. Here is a template you can use for your setup.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;IfModule mod_ssl.c>
&lt;VirtualHost *:80>
    ServerName your_domain
    Redirect permanent / https://your_domain/
&lt;/VirtualHost>

&lt;VirtualHost *:443>
    ServerName your_domain

    SSLEngine on
    SSLProxyEngine on

    SSLCertificateFile /etc/letsencrypt/live/your_domain/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/your_domain/privkey.pem

    ProxyPreserveHost On
    ProxyRequests Off

    ProxyPass / http://127.0.0.1:8443/
    ProxyPassReverse / http://127.0.0.1:8443/

    # WebSocket support
    RewriteEngine On
    RewriteCond %{HTTP:UPGRADE} ^(.*)$ &#91;NC&#93;
    RewriteCond %{HTTP:CONNECTION} ^(.*Upgrade.*)$ &#91;NC&#93;
    RewriteRule ^/?(.*) "ws://127.0.0.1:8443/$1" &#91;P,L&#93;

    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Port "443"

    ErrorLog ${APACHE_LOG_DIR}/vaultwarden-error.log
    CustomLog ${APACHE_LOG_DIR}/vaultwarden-access.log combined
&lt;/VirtualHost>
&lt;/IfModule>
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">&lt;</span><span style="color: #8FBCBB">IfModule</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">mod_ssl.c&gt;</span></span>
<span class="line"><span style="color: #D8DEE9">&lt;VirtualHost</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">*:80&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">ServerName</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">your_domain</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">Redirect</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">permanent</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">https://your_domain/</span></span>
<span class="line"><span style="color: #D8DEE9">&lt;/VirtualHost&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">&lt;VirtualHost</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">*:443&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">ServerName</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">your_domain</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">SSLEngine</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">on</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">SSLProxyEngine</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">on</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">SSLCertificateFile</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">/etc/letsencrypt/live/your_domain/fullchain.pem</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">SSLCertificateKeyFile</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">/etc/letsencrypt/live/your_domain/privkey.pem</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">ProxyPreserveHost</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">On</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">ProxyRequests</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">Off</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">ProxyPass</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">http://127.0.0.1:8443/</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">ProxyPassReverse</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">http://127.0.0.1:8443/</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">#</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">WebSocket</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">support</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">RewriteEngine</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">On</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">RewriteCond</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">%{HTTP:UPGRADE}</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">^(.*)$</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">&#91;NC&#93;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">RewriteCond</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">%{HTTP:CONNECTION}</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">^(.*Upgrade.*)$</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">&#91;NC&#93;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">RewriteRule</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">^/?(.*)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ws://127.0.0.1:8443/$1</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">&#91;P,L&#93;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">RequestHeader</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">set</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">X-Forwarded-Proto</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">https</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">RequestHeader</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">set</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">X-Forwarded-Port</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">443</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">ErrorLog</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">${APACHE_LOG_DIR}/vaultwarden-error.log</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #8FBCBB">CustomLog</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">${APACHE_LOG_DIR}/vaultwarden-access.log</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">combined</span></span>
<span class="line"><span style="color: #D8DEE9">&lt;/VirtualHost&gt;</span></span>
<span class="line"><span style="color: #D8DEE9">&lt;/IfModule&gt;</span></span>
<span class="line"></span></code></pre></div>



<p>Then enable the required Apache modules:</p>



<ul class="wp-block-list">
<li>a2enmod proxy</li>



<li>a2enmod proxy_http</li>



<li>a2enmod proxy_wstunnel</li>



<li>a2enmod ssl</li>



<li>a2enmod rewrite</li>
</ul>



<p>Now all you should need to do is enable your site and restart apache.</p>



<h2 class="wp-block-heading">Docker</h2>



<p>Next all you need to do is to setup the docker container. Below is a template for the command  to set it up. Once it’s running, visit <code>https://your_domain</code> in your browser. You should be greeted with the account creation screen. Go ahead and register your account. After that, <strong>be sure to disable public signups</strong> by either updating the container or setting <code>SIGNUPS_ALLOWED=false</code> in your Docker environment.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>
sudo docker run -d   --name vaultwarden   -v /vw-data:/data   -p 8443:80   -e WEBSOCKET_ENABLED=true   -e SIGNUPS_ALLOWED=true   -e DOMAIN=https://your_domain   vaultwarden/server:latest</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #D8DEE9">sudo</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">docker</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">run</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">d</span><span style="color: #D8DEE9FF">   </span><span style="color: #81A1C1">--</span><span style="color: #D8DEE9">name</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">vaultwarden</span><span style="color: #D8DEE9FF">   </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">v</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">vw</span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF">data</span><span style="color: #ECEFF4">:</span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">   </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">p</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">8443</span><span style="color: #D8DEE9FF">:</span><span style="color: #B48EAD">80</span><span style="color: #D8DEE9FF">   </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">e</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">WEBSOCKET_ENABLED</span><span style="color: #81A1C1">=true</span><span style="color: #D8DEE9FF">   </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">e</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SIGNUPS_ALLOWED</span><span style="color: #81A1C1">=true</span><span style="color: #D8DEE9FF">   </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">e</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">DOMAIN</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF">https</span><span style="color: #ECEFF4">:</span><span style="color: #616E88">//your_domain   vaultwarden/server:latest</span></span></code></pre></div>



<h2 class="wp-block-heading">Email Setup (optional)</h2>



<p>If you want features like password reset links for other accounts on your server, account verification emails, admin invites, and emergency access notifications, you’ll want to hook up SMTP.</p>



<p>Here’s how to do it with a Gmail account (you’ll need to generate an <a>App Password</a>):</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>-e SMTP_HOST=smtp.gmail.com
-e SMTP_FROM=your_account@gmail.com
-e SMTP_PORT=587
-e SMTP_USERNAME=your_account@gmail.com
-e SMTP_PASSWORD=your_gmail_app_password
-e SMTP_SECURITY=starttls</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">e</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SMTP_HOST</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9">smtp</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">gmail</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">com</span></span>
<span class="line"><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">e</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SMTP_FROM</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9">your_account</span><span style="color: #D8DEE9FF">@</span><span style="color: #D8DEE9">gmail</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">com</span></span>
<span class="line"><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">e</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SMTP_PORT</span><span style="color: #81A1C1">=</span><span style="color: #B48EAD">587</span></span>
<span class="line"><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">e</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SMTP_USERNAME</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9">your_account</span><span style="color: #D8DEE9FF">@</span><span style="color: #D8DEE9">gmail</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">com</span></span>
<span class="line"><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">e</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SMTP_PASSWORD</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9">your_gmail_app_password</span></span>
<span class="line"><span style="color: #81A1C1">-</span><span style="color: #D8DEE9">e</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SMTP_SECURITY</span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9">starttls</span></span></code></pre></div>



<p>Add those to your <code>docker run</code> command or define them in a <code>.env</code> file if you’re using <code>docker-compose</code>.</p>



<p>Once email is working, you’ll be able to:</p>



<ul class="wp-block-list">
<li>Send password reset links to other users on your server</li>



<li>Verify email addresses</li>



<li>Invite users to your instance</li>



<li>Get alerts for emergency access requests</li>
</ul>



<p>It’s a small step that adds a ton of functionality.</p>



<h2 class="wp-block-heading">Enjoy Being Secure</h2>



<p>And that’s it. You’ve got a secure, open-source, cloud-accessible password manager running on your own terms, with all the modern comforts like mobile and browser integration. No monthly fees. No trusting a third-party service with your credentials. Just you, your server, and full control over your security.</p>



<p>Welcome to the self-hosted club.</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="498" height="280" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/07/pretty-cool-james-pumphrey.gif" alt="" class="wp-image-288" style="width:1140px;height:auto"/></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://erikmakesthings.ddns.net/securing-passwords-with-vaultwarden-apache/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Making Reading Great Again (with Kavita)</title>
		<link>https://erikmakesthings.ddns.net/making-reading-great-again-with-kavita/</link>
					<comments>https://erikmakesthings.ddns.net/making-reading-great-again-with-kavita/#respond</comments>
		
		<dc:creator><![CDATA[Erik]]></dc:creator>
		<pubDate>Thu, 10 Jul 2025 07:35:51 +0000</pubDate>
				<category><![CDATA[Apache]]></category>
		<category><![CDATA[Kavita]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Server]]></category>
		<guid isPermaLink="false">https://erikmakesthings.ddns.net/?p=274</guid>

					<description><![CDATA[I love that reading is free, you can do it anywhere. You can do it on the train&#8230; uh, don&#8217;t do it while you&#8217;re driving &#8211; James Pumphrey When I was younger I used to avidly enjoy reading in my free time. From adventures in a galaxy far, far away (shoutout Karen Traviss), to the [&#8230;]]]></description>
										<content:encoded><![CDATA[
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>I love that reading is free, you can do it anywhere. You can do it on the train&#8230; uh, don&#8217;t do it while you&#8217;re driving</p>
</blockquote>



<p>&#8211; James Pumphrey</p>



<p>When I was younger I used to avidly enjoy reading in my free time. From adventures in a galaxy far, far away (shoutout Karen Traviss), to the neo-Greek mythology of the Percy Jackson series, I tore through books like it was my job. However, as I’ve gotten older that’s no longer the case. Between work and school, most of my reading now consists of dry technical manuals, textbooks, and reviews for whatever power tool I want to buy next.</p>



<p>So the goal of this project is to make whatever book I’m reading:</p>



<ol class="wp-block-list">
<li>Easily accessible</li>



<li>Simple to pick up right where I left off</li>



<li>Replaceable when I’m ready to crack open the next one</li>
</ol>



<p>Join me as we <strong>Make Reading Great Again</strong> so I have no excuse not to be well-read.</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="500" height="281" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/07/catreading.gif" alt="" class="wp-image-275"/></figure>



<h2 class="wp-block-heading">Picking a Platform</h2>



<p>Obviously, the first thing I could do to achieve this goal would be to open up my wallet and head to the nearest app store to get an e-reader service like Bezos’s Kindle or Google’s Shelf and start building a digital library that I don’t really own. But the easy way has some huge red flags. For example, say they lose the licensing or worse, <em>1984</em> comes to pass and certain books get banned and <em>poof</em>, there goes my book and my money.</p>



<p>Also, if you’ve read any of my posts so far you’re probably aware that I’m definitely a DIY kind of guy, and like with most things I’m going to do it myself.</p>



<p>So what are the options for self-hosting this kind of service? As you can tell from the title, I went with <strong>Kavita</strong> for its multi-user support, anywhere access, and mainly because I liked the UI the most. But there are other great options I stumbled upon that might suit your needs better:</p>



<ul class="wp-block-list">
<li><strong>Calibre</strong> for its wider format support and plugins.</li>



<li><strong>Komga</strong> if your main focus is comics and manga.</li>



<li><strong>Polar Bookshelf</strong> if you just want to install a Snap package and enjoy books locally.</li>
</ul>



<h2 class="wp-block-heading">The Set Up</h2>



<p>For this setup I’ll be using Kavita’s Docker image. There are plenty of ways to set it up, but for that I’ll refer you to their instructional page here: <a class="" href="https://wiki.kavitareader.com/getting-started/">https://wiki.kavitareader.com/getting-started/</a>.</p>



<p>I like using <strong>Portainer</strong> to set up and manage my Docker containers since it’s simple and easy. Remember to create your volume first, set your port mapping to 5000, and set the network adapter to bridge before pulling and creating the container.</p>



<p>Once it’s up and running you’re good to go to http://your-server-ip:5000, and you should be greeted with a simple sign-in screen to create your admin account. After you create your account and log in, the last thing is to load up something to read and create your libraries. Kavita supports formats like PDF, EPUB, and a variety of comic/manga formats.</p>



 [<a href="https://erikmakesthings.ddns.net/making-reading-great-again-with-kavita/">See image gallery at erikmakesthings.ddns.net</a>] 



<p>To make this all work you’ll need to create a folder and place each file in that folder. For example, my copy of <em>Pride and Prejudice</em> from <a class="" href="https://www.epubbooks.com/book/44-pride-and-prejudice">epubbooks.com</a> is mounted like this:</p>



<pre class="wp-block-code"><code>/storage/books/'Pride and Prejudice (Illustrated)'/austen-pride-and-prejudice-illustrations.epub
</code></pre>



<p>Now that you have your books loaded up, create a library by clicking on the gear icon in the top left, navigating to the Libraries tab under Server, and clicking on the <strong>Add Library</strong> button. In the popup, give it a name and point it to the folder you mounted with your media. I decided to split my libraries into books, comics, and manga.</p>



<h2 class="wp-block-heading">Mr. Worldwide </h2>



<p>You can stop here if you only want access to your e-library locally, but I decided to take it a step further. To access the library securely from anywhere in the world, I created a domain name with NO-IP, used Certbot to generate some SSL certificates, and created and enabled my .conf file.</p>



<p>That’s right, eriks-library (e-library for short) can now be accessed anywhere with an internet connection.</p>



<p>If you want to do this too, there are more detailed instructions in Kavita’s setup guide I linked earlier. Or if you’re using Apache2, you can copy, edit, and enable the slightly trimmed-down config file I made for the reverse proxy:</p>



<pre class="wp-block-code"><code>&lt;IfModule mod_ssl.c&gt;
&lt;VirtualHost *:443&gt;
    ServerName your.domain.com

    SSLEngine on
    SSLProxyEngine on
    SSLProxyCheckPeerCN off
    SSLProxyCheckPeerName off
    SSLProxyCheckPeerExpire off

    # Use Let's Encrypt certificate paths
    SSLCertificateFile /etc/letsencrypt/live/your.domain.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/your.domain.com/privkey.pem

    ErrorLog ${APACHE_LOG_DIR}/proxy-error.log
    CustomLog ${APACHE_LOG_DIR}/proxy-access.log combined

    ProxyPass / http://SERVER_IP_ADDR:5000/
    ProxyPassReverse / http://SERVER_IP_ADDR:5000/

    ProxyPreserveHost On
    ProxyRequests Off

    # WebSocket support
    RewriteEngine On
    RewriteCond %{HTTP:UPGRADE} ^.*WebSocket.*$ &#091;NC]
    RewriteCond %{HTTP:CONNECTION} ^.*Upgrade.*$ &#091;NC]
    RewriteRule .* ws://SERVER_IP_ADDR:5000%{REQUEST_URI} &#091;P]

    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Port "443"
    RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}e"
&lt;/VirtualHost&gt;
&lt;/IfModule&gt;
</code></pre>



<h2 class="wp-block-heading">On the Go</h2>



<p>The last step was figuring out how I’m going to access and enjoy my library from my phone. Currently, there’s only a third-party app called <strong>Kavita Blue</strong>, but when I tried it, it kept freezing and ruined the UI I like. So I just opened up Chrome on my phone, navigated to my domain, and set it up as a web app on my home screen. Sure, I could have paid for a Kindle subscription, but where’s the fun in that? Besides, now I get to say my library runs on Docker and that sounds way cooler at parties anyways.</p>



<figure class="wp-block-video aligncenter"><video height="1584" style="aspect-ratio: 720 / 1584;" width="720" controls src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/07/webapp.mp4"></video></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://erikmakesthings.ddns.net/making-reading-great-again-with-kavita/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://erikmakesthings.ddns.net/wp-content/uploads/2025/07/webapp.mp4" length="7146987" type="video/mp4" />

			</item>
		<item>
		<title>Comparing Clouds: Could Local Hosting Be in Your Digital Forecast?</title>
		<link>https://erikmakesthings.ddns.net/comparing-clouds-could-local-hosting-be-in-your-digital-forecast/</link>
					<comments>https://erikmakesthings.ddns.net/comparing-clouds-could-local-hosting-be-in-your-digital-forecast/#respond</comments>
		
		<dc:creator><![CDATA[Erik]]></dc:creator>
		<pubDate>Wed, 18 Jun 2025 02:38:28 +0000</pubDate>
				<category><![CDATA[Nextcloud]]></category>
		<category><![CDATA[Plex]]></category>
		<category><![CDATA[Server]]></category>
		<guid isPermaLink="false">https://erikmakesthings.ddns.net/?p=251</guid>

					<description><![CDATA[Cloud services have become an essential part of our daily lives, from boardrooms to living rooms. Thanks to the centralization of computing and mass storage, users can now enjoy the mobility and convenience of smaller devices like laptops and smartphones, while still enjoying the benefits of server-grade hardware. Modern offices rely heavily on cloud storage [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p><br>Cloud services have become an essential part of our daily lives, from boardrooms to living rooms. Thanks to the centralization of computing and mass storage, users can now enjoy the mobility and convenience of smaller devices like laptops and smartphones, while still enjoying the benefits of server-grade hardware. Modern offices rely heavily on cloud storage and applications provided by cloud services like Microsoft’s O365. Cloud computing has also enabled remote work through secure remote desktop applications like Citrix. Outside of the office, cloud services such as Netflix offer a vast collection of video content, while newer cloud gaming services like GeForce Now provide high-quality gaming streamed directly to your device. That being said, cloud computing has some drawbacks we need to consider, and let&#8217;s explore how we can potentially create our own cloud services to overcome the current model of cloud computing.</p>



<h2 class="wp-block-heading has-text-align-center"><br>What is Cloud Computing?</h2>



<h3 class="wp-block-heading"><br>Cloud Computing’s key components</h3>



<p>Cloud computing is a game-changing process that enables low-powered devices to connect to a central computing unit, known as a &#8220;cloud service&#8221;, that empowers them to perform operations that would have been impossible otherwise. This means that various end devices, such as phones, smartwatches, laptops, and even cars, can connect to a network and potentially leverage the power of a cloud service. According to Google Cloud’s article, “What is cloud architecture”, the four components of cloud infrastructure are frontend platforms, backend platforms, delivery models, and a network. Frontend platforms consist of a user’s devices and the application they use to connect to the host. The backend platform comprises everything required to provide the services a user needs, from the hardware performing computational tasks to the vast array of storage needed, the software the client is accessing, and the middleware that manages the font end’s connection.</p>



<p>Now that we have a good understanding of the frontend and backend components, it&#8217;s important to discuss the crucial factor that enables their communication: the network. According to Jannik Linder&#8217;s article on &#8220;Must-Know Internet Traffic Statistics,&#8221; monthly internet traffic reached approximately a staggering 151 exabytes in 2023 &#8211; that&#8217;s equivalent to 151 billion gigabytes! Interestingly, approximately sixty percent of this traffic is attributed to video on demand, a popular cloud service. While other cloud services lack thorough documentation, it&#8217;s clear that over half of all web traffic is generated by cloud services. Having explored the main physical components of cloud computing, we can now move on to a deeper analysis of the various delivery models.</p>



<h3 class="wp-block-heading"><br>Delivery Models</h3>



<p>As we discussed previously the final component of cloud computing is the delivery model. There are three delivery models Infrastructure as a Service (IaaS), Platform as a Service (PaaS), and Software as a Service (SaaS) (Google, 2024). According to Stephanie Susnjara and Ian Smalley in their article, “What is cloud computing” on IBM’s website Infrastructure as a Service provides instant access to computing power as needed. This can involve anything from virtual desktops to large storage pools, and allows a client to scale as the need arises. They also point out that IaaS is a $212.34 billion industry that is projected to grow another 14.2% by 2028. Common IaaS programs you may be familiar with are Citrix Virtual Desktop, Microsoft Azure, and Digital Ocean.</p>



<p>Next, they explain Platform as a Service as, “…an on-demand platform-hardware, complete software stack, infrastructure, and development tools… for developing and managing applications.” (Susnmjara. Smalley, 2024). Essentially, these services provide companies with everything a data center has to offer without the need for expensive equipment costs upfront. They go on to explain that these services rely on containers, a form of virtualization, to enable developers to scale as the project grows without the changes needed for the middleware we discussed earlier. Common PaaS technologies you may have heard about include Docker, something we will delve into later, and Kubernetes.</p>



<p>The final delivery method is by far the most common one for the average consumer, Software as a Service. Products such as iCloud, Netflix, and Google Drive are all examples of common SaaS platforms. SaaS offers remote storage, automated patching, and instant access to resources, and uses API calls that are integrated into the end-user application to push or pull data. Susanmjara and Smalley point out that this is the largest segment of cloud computing accounting generating approximately $359 billion in global revenue.</p>



<h2 class="wp-block-heading"><br>Benefits</h2>



<p>Now that we have defined the key components of cloud computing, let’s discuss what the benefits of cloud computing are. The first and most obvious advantage is the low barrier to entry. With a steady internet connection even the thinnest of clients can have the processing power of a high-end machine. Resources such as processing, storage, and memory are offloaded onto the remote ecosystem of machines. A worker can log in remotely from a lightweight laptop, like a MacBook Air, and utilize cloud services to perform various tasks. They can create and edit videos, write code, and collaborate with colleagues from different parts of the world. All this can be done while sitting in their favorite café and sipping on their favorite beverage. After a long day of work, a MacBook Air can serve as a gateway to a vast collection of videos or high-end gaming without requiring the user to invest in additional storage or gaming equipment. This makes the hardware more lightweight and efficient, giving the average user greater flexibility to pursue their interests.</p>



<p>Next, let’s talk about money. How much can cloud computing save your organization every year? According to Jannik Lindner, co-founder of Gitnux a market research firm, in his article “Must-Know Cloud Cost Savings Statistics” companies save about twenty percent on infrastructure costs annually by switching to cloud computing products. Additionally, companies save between thirty and sixty percent on energy bills per month. He also states that on average, companies save thirty-seven percent on new hardware acquisition for employees. Along with the savings he says IT departments reported newer company initiatives take less than half the time to deploy, and a sixty percent increase in data processing.</p>



<p>Finally, let’s cover the flexibility of on-demand models. Digital Ocean defines the benefits of cloud scalability in the post, “What is cloud scalability?” as “… the capacity of a cloud computing environment to effectively handle growing or diminishing workloads by proportionally adjusting its resource footprint.”, and that it pertains to the long-term demands to meet the needs of the client exactly. Additionally, they discuss the elasticity of cloud services. In short, elasticity is quick short-term increases in workload demands. Elasticity allows for instant resource availability creation to maintain performance consistency without the long-term commitment of an agreement for scalability. For example, I used to work at a law firm where we utilized cloud storage services and document management systems for our attorneys and legal assistants. We contracted for exactly the number of lawyers and legal assistants with a little extra and when we had guest attorneys for certain cases, that could last weeks to months, we could easily add a temporary Azure and Box account at different rates and then drop them as the case closed. With the benefits of increased freedom, financial savings, and easy growth and stability, what are the risks of relying on cloud computing?</p>



<h2 class="wp-block-heading has-text-align-center"><br><strong>Risks of Relying on Cloud Computing</strong></h2>



<h3 class="wp-block-heading">Cyber-security incidents</h3>



<p>While cloud computing provides several advantages, it also poses some significant limitations, particularly concerning security risks that come with depending on remote services. Despite your adherence to best data practices, the third-party cloud service you utilize may not follow suit. As an example, the Equifax breach in 2017 exposed the social security numbers of over two-thirds of Americans, mainly due to delayed security patching and storing of credentials in plain text (Cooney, 2018).</p>



<p>In 2014, there was a major security breach on iCloud which resulted in the exposure of private photos and videos of several celebrities. Similarly, in 2020, a similar attack targeted Amazon Web Services (AWS) and involved rootkit malware. According to Emanuella Gringberg from CNN, the iCloud hack was carried out by a group of cybercriminals who used spear phishing to target around 250 celebrity accounts. They sent phishing emails that appeared to be from Apple&#8217;s security team, tricking users into giving away their login credentials. Since Apple didn&#8217;t have multifactor authentication at that time, the hackers were able to gain access to private and explicit photos, which they then sold on the internet. However, the latest attack on AWS was even more sophisticated.</p>



<p>In 2020, a group of hackers conducted a sophisticated attack on Amazon Web Services platforms, known as rootkit. As a result of this attack, the hackers implanted malware that granted them root access, which enabled them to infiltrate the C2 control node. This access allowed them to view and duplicate the containers of numerous clients who were utilizing AWS cloud services. While there was no indication as to how long the hackers had access to the system or the method of attack, the unauthorized activity was identified during a review of networking logs (Pell, 2020). This incident underscores the fact that cloud computing services have become a prime target for hackers. Given the rising costs associated with these services, one may question if the benefits outweigh the risks.</p>



<h3 class="wp-block-heading"><br>Price Increases</h3>



<p>In today&#8217;s economic climate, the cost of goods and services seems to be on the rise, including cloud computing services. Consider, for example, media-on-demand streaming services like Netflix and Spotify, which are the largest platforms in their respective categories. As reported by Emma Roth at the Verge, in 2011, the standard plan for Netflix began at $7.99 per month and has since increased to $15.49 per month, almost double the original price. Additionally, features like screen sharing and account sharing have been limited over time. Similarly, according to Ashley Capoot at CNBC, Spotify increased its prices by twenty percent in 2022. What are the reasons for the price increase? Is it inflation, slowing user growth, greed, or all the above?</p>



<p>First, let&#8217;s examine inflation. According to the U.S. Bureau of Labor Statistics, from 2011 to 2024, inflation was 2.55% year on year. If we do the calculations, $7.99 in 2011 currency value is worth $14.08 in 2024. Therefore, $1.41 of Netflix&#8217;s price increase is not due to inflation. Although not as significant, Spotify&#8217;s price increase exceeds inflation by seventeen cents. In their article &#8220;The cheap streaming era is over. Here&#8217;s why your bills are going up&#8221;, Wendy Lee and Thomas Lauder from the LA Times investigate the business practices of cloud streaming services. They note that between 2022 and 2024, the top ten streaming platforms raised prices by twenty percent. While inflation is partially to blame, other factors are also at play, such as market saturation, a decline in subscribers, and the infrastructure monopoly of the big three: Amazon, Microsoft, and Google. These companies are attempting to maintain profitability. As a result, consumers may have to budget for price hikes every few years in the foreseeable future. However, the potential end of cloud services due to various reasons may be a more significant concern.</p>



<h3 class="wp-block-heading"><br>Termination of Services</h3>



<p>While never ending prices sound bad many cloud services have appeared and disappeared in a blink of an eye. You need only look to Google to find a list of defunct cloud solutions. On the website killedbygoogle.com, you can see a list of every service Google shut down and how long it was around. For example, cloud services such as Google Cloud IoT Core and Stadia hardly made it a few years before Google closed the curtains on them. Stadia was a service I used as it offered a means to game anywhere at any time. In the end, I lost all of the games that I purchased, the progress in said games, and the sixty-dollar controller is now an inert paperweight.</p>



<p>While businesses have the prerogative to shut down if they can no longer sustain their operations, what recourse does a consumer have when they&#8217;re unjustly accused and barred from using a company&#8217;s services? Take the case of Brandon Jackson, who was denied access to his Amazon smart home devices after a driver alleged that his Ring doorbell had uttered a racial slur. However, upon reviewing the security footage, Brandon found that only the preset greeting had been activated. Despite providing the video evidence, he and his loved ones were still denied access for several weeks, as reported by Emily Crane of the New York Post.</p>



<p>As you may have noticed, there are some significant disadvantages to depending on cloud services. While it may be cost-effective, not having ownership of your data or the drive it&#8217;s stored on puts you at the mercy of third parties. Furthermore, prices for these services are likely to increase, and the industry may become monopolized. Criticizing subscription-based models and Software as a Service, economist Ida Auken once said, &#8220;You will own nothing and you&#8217;ll be happy.&#8221;. This statement seems less like a dystopian joke and more like a potential reality.</p>



<h2 class="wp-block-heading has-text-align-center"><br><strong>Cloud Computing’s Impact on the Environment</strong></h2>



<h3 class="wp-block-heading"><br>Cloud Computing Energy Consumption</h3>



<p>Now, let&#8217;s turn our attention to the environmental impact of the data centers that are essential for supporting cloud services. To begin, we must consider the significant amount of electricity required to keep online services running. According to the Department of Energy&#8217;s Office of Energy Efficiency &amp; Renewable Energy, data centers account for two percent of the national electrical demand and are up to fifty times more energy-intensive than an average commercial space. While this may appear insignificant, a case study by MIT&#8217;s Steven Monserrate titled &#8220;The Cloud Is Material: On the Environmental Impacts of Computation and Data Storage&#8221; reveals that the collective impact of cloud computing creates more emissions than most industries globally. Steven also estimates that a single data center uses the same amount of electricity as fifty-thousand houses annually. Shockingly, over forty percent of this energy is wasted on cooling densely packed server stacks, while only six to twelve percent is actually used for computational tasks. Now that we understand the energy demands of these data centers, let&#8217;s explore how this energy is generated.</p>



<p>Understanding how energy is produced is crucial to grasping the impact of the growing electrical demand. In 2021, burning fossil fuels accounted for about sixty-one percent of energy generation, resulting in thirty-seven out of forty billion tons of carbon dioxide emissions released into the atmosphere (Statista, 2023; Stanford, 2023). As previously mentioned, cloud computing&#8217;s energy demand contributed to two percent of global CO2 emissions (Monserrate, 2023), which translates to cloud services producing 740 million tons of CO2. Unfortunately, more than half of that amount is used solely for cooling the servers that power backend services. It&#8217;s ironic that to cool our servers, we must contribute to the warming of our planet.</p>



<h3 class="wp-block-heading"><br>Water Demands</h3>



<p>Data centers require a constant flow of fresh water to cool their systems, much like a living organism needs water to survive. Monserrate writes about the National Security Agency data center in Arizona, comparing the vast water cooling systems to an irrigated farm. These data centers can consume up to seven million gallons of fresh water every day. Monserrate points out that according to the United Nations 2021 Gap Report, fresh water will become a scarce resource by 2040. As water becomes less accessible, data centers will need to adapt to maintain optimal thermal conditions.</p>



<h3 class="wp-block-heading"><br>E-Waste</h3>



<p>While the consumption requirements of natural resources to power and cool cloud computing hardware are alarming, arguably the legacy of data centers’ impact on the environment will be the never-ending stream of electronic waste. Globally we produce up to twenty-five million tons of electronic waste annually (Khalid Hassan,2023). The average life span of all electronics is on average just two years, and since most of the parts are not recycled they end up in rotting away in vast landfills (Monserrate,2023). Most devices contain plastics that can take up to 1,500 years to break down and additionally contain heavy metals such as cadmium, lead, and mercury that can be radioactive and can cause irreversible damage to the soil, water resources, and the local population (Khalid Hassan,2023). Though cloud computing offers a vast array of benefits, it comes at a staggering cost, but what if there was a way to overcome some of these drawbacks and gain more control over your cloud services? In the next section, we will discuss a possible solution to the drawbacks of data center driven cloud services.</p>



<h2 class="wp-block-heading has-text-align-center"><br><strong>Local Hosting</strong></h2>



<p><br>In this post, we have explored how cloud services have become a necessity in modern life. However, they have some drawbacks in terms of security, control, and their impact on the environment. Local hosting, on the other hand, provides the same services, but instead of relying on centralized data centers, the services are configured and run on your hardware. There are many applications available to replace popular apps. For instance, applications like Plex or Jellyfin aim to reduce your reliance on the ever-changing library of streaming services like Netflix or Hulu. You can build and share your private library of movies and TV shows on your home server with friends and family. If you want to consolidate all your IoT devices under one app that will always work even in an internet outage, then Home Assistant can be easily deployed in a lightweight docker container and locally manage all of your lights, locks, and more. Are you tired of paying exorbitant prices for Adobe Cloud or Google Drive? Then Nextcloud is a quick way to turn your old desktop into a shared drive that you can access from anywhere in the globe. We could go on and on about open-source local cloud services that one can configure and deploy, but it&#8217;s clear that any cloud-based need could potentially be met by a home do-it-yourself solution.</p>



<h3 class="wp-block-heading"><br>Benefits</h3>



<p><br>Hosting your cloud applications locally can have many benefits, including saving you money in the long run. For instance, in 2023, the average American spent around $219 on online subscriptions, mainly on online storage, music streaming, and video on demand (Dias, 2023). This amounts to thousands of dollars in recurring charges for cloud services every year. So, how can we start hosting our own services?</p>



<p>The first step is usually the most expensive one, which involves acquiring hardware. I used a refurbished tower from Goodwill, fitted with a second-hand motherboard, processor, Nvidia graphics card, RAM, and ten terabytes of storage, which cost me roughly $800 to source. Additionally, I pay $12 a year for a domain name to make it easier for me to find my services. After assembling the hardware, the next potential cost would be an operating system license if you&#8217;re using Windows Server. However, I opted for Ubuntu server, a Linux distribution, to save on cost. If you&#8217;re looking for an even cheaper option, you can run most cloud applications off small credit card-sized computers, such as the Raspberry Pi, for less than $100. Finally, the best option is the free one: dust off that old laptop or desktop and turn it into a server in no time! Once you set up your server there are no recurring charges as you own the entire system in its entirety saving you potentially thousands a year.</p>



<p>Not only does locally hosting your cloud services save you money, but it also benefits the environment. Compact systems like a Raspberry Pi or a recycled server consume significantly less power than their data center counterparts. For instance, a single board arm computer can consume as little as 10 Watts! In my case, my server consumed an average of 374 Watts an hour, which means I only spent $327.85 a year on electricity at OPPD&#8217;s rate of 10 cents per kilowatt hour. In contrast, a single server rack in a data center can consume several thousand Watts an hour (Monteclaro, 2023). By hosting locally, we can prevent used parts from ending up in a landfill and save money in the process. Figure 1 illustrates the anticipated expenses over the next five years, with the first year encompassing the estimated cost of building a server like mine and the electricity required to operate it. The following years include the expenses of electricity and domain renewal, while the final year includes the cost of electricity, domain renewal, and an additional $500 for server maintenance. Compare these costs to the typical monthly expenses of an average American and see the savings that can be achieved.</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="988" height="855" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/06/chart-of-price.png" alt="" class="wp-image-252" style="width:704px;height:auto" srcset="https://erikmakesthings.ddns.net/wp-content/uploads/2025/06/chart-of-price.png 988w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/06/chart-of-price-300x260.png 300w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/06/chart-of-price-768x665.png 768w" sizes="(max-width: 988px) 100vw, 988px" /></figure>



<p><br>Did you know that using a locally hosted cloud service not only saves you money, but also time? To illustrate this point, I conducted a download speed test between my Nextcloud server and Google Drive. The test involved a 3.8 GB folder containing a mix of small text files and large video files. Using a script (depicted in Figure 2) to download the folder from both services, I tested the speeds from various locations to compare their performance in different network environments. After running the test five times for each service and averaging the results, I discovered something interesting. On my home network, the locally hosted solution was more than twice as fast as Google Drive. However, when testing from my workplace&#8217;s free Wi-Fi or a hotspot, the download times were comparable between the two. Surprisingly, when I tested from school, Google Drive was twice as fast as the locally hosted solution. Figure 3 shows the results of the tests.</p>



 [<a href="https://erikmakesthings.ddns.net/comparing-clouds-could-local-hosting-be-in-your-digital-forecast/">See image gallery at erikmakesthings.ddns.net</a>] 



<h3 class="wp-block-heading"><br>Data Control and Security</h3>



<p><br>By hosting your own cloud services, you will have complete control over your data. This means you will no longer have to worry about your favorite show moving from one streaming service to another, or about the quality of your photos degrading when backed up to platforms like Google Photos, which by default lower the quality of uploaded photos. Additionally, you can rest easy knowing that you are solely responsible for and have full control over the security practices taken to protect your data. You won&#8217;t have to worry about the cloud service leaking your account credentials or whether their servers are patched. However, it&#8217;s important to note that becoming your own cloud service provider comes with a lot of responsibility. While we&#8217;ve covered the general benefits, it&#8217;s also important to consider the drawbacks of hosting locally.</p>



<h2 class="wp-block-heading has-text-align-center"><br><strong>Drawbacks to Local Cloud Computing</strong></h2>



<h3 class="wp-block-heading"><br>Security Threats</h3>



<p><br>As the character, Ben Parker once said, &#8220;… with great power comes great responsibility.&#8221; This is especially true when it comes to owning your data &#8211; it is your responsibility to keep it safe. So, how strong are your cybersecurity practices? Can you detect if your network or device has been compromised? According to a study by the Pew Research Center, &#8220;What the Public Knows About Cybersecurity,&#8221; the answer is likely no. Shockingly, less than one percent of participants were able to correctly answer all of the questions, and only twenty percent got more than half correct. While many could identify strong passwords and suspicious links, they struggled with more technical topics. For example, most were unaware that their internet service provider could view all of their internet activity or that hackers could target their home network with Direct Denial of Service (DDoS) attacks using botnets that span the globe. Unfortunately, even home networks are not immune to attacks from enemy nation-states. In January of 2024, over a thousand home networks were infected by spyware from the Russian hacker group Fancy Bear (Purdy, 2024). Once again, we need to consider whether the advantages of the service surpass the potential risks associated with it. Outside of the intricate nature of data protection and cybersecurity, there exist other obstacles to entry that we will delve into in the following section.</p>



<h3 class="wp-block-heading"><br>Complexity</h3>



<p>Computers while widely used are often not well understood. When was the last time you opened a computer, and could you point out the components of a computer? While there are many step-by-step guides on how to assemble a computer it can still be frustrating. Case in point I, nearing on a decade of computer building knowledge, failed to install a RAM stick on my server correctly. What was supposed to be a simple five-minute upgrade turned into a two-hour troubleshooting session while researching why RAM would cause the server to not post. However, let&#8217;s say you can overcome the hurdle of making sure a server is built correctly and posts the next barrier would be setting up the operating system.</p>



<p>Assuming you were able to build a functional computer and everything boots up, would you be able to install an operating system? In my experience, most people don&#8217;t know how to install an operating system. Even if you manage to set up the operating system, you will have to research and set up the services you need. Personally, I often struggle with configuring and deploying new services or maintaining them. For example, I failed to set up a backup for my Nextcloud server and, when a bad configuration was pushed by an update, I lost all of my server settings, having to reset everything from scratch! On top of that, I can spend hours looking through documentation and unhelpful Stack Overflow posts and still not find a solution to an issue I am having. It takes a lot of hard work and dedication to maintain these services, and locally hosting, even for me, can often be too technical to understand.</p>



<p>All of these complexities can make it seem like it&#8217;s not worth your time. However, if you can overcome these hurdles, it can be one of the most rewarding experiences. I encourage you to give it a try as well.</p>



<h2 class="wp-block-heading"><br><strong>Conclusion</strong></h2>



<p><br>As we come to the end of this post, I hope that you understand the importance of cloud services in our daily lives. We have discussed how cloud services work, their impact on our finances and the environment, and how we can potentially address some of these issues by decentralizing cloud services through local hosting. While local hosting may be challenging and require several hours of tedious work, I hope you see it as a viable option that you can pursue in your spare time to save not only the green in your wallet but also the green on our planet. Therefore, the next time you encounter a Netflix price hike or Google discontinues your favorite cloud service, consider visiting your local Goodwill or parts shop to deploy your home-grown cloud solution and become digitally independent. By doing so, you can contribute to reducing the environmental impact of cloud computing.<br></p>



<h2 class="wp-block-heading"><br>Citations</h2>



<p>Alkhatib, A., Al Sabbagh, A., &amp; Maraqa, R. (2021). Pubic cloud computing: Big three vendors. <em>2021 International Conference on Information Technology (ICIT)</em>. https://doi.org/10.1109/icit52682.2021.9491680</p>



<p>Bernsen, R. (2021, September 21). <em>Why to self-host your software? should you go for on-premises or cloud?</em>. OpenProject.org. https://www.openproject.org/blog/why-self-hosting-software/</p>



<p>Capoot, A. (2023, July 24). <em>Spotify increases prices for its premium subscription plans</em>. CNBC. https://www.cnbc.com/2023/07/24/spotify-increases-prices-for-its-premium-subscription-plans.html</p>



<p>Crane, E. (2023, June 15). <em>Amazon shuts down customer’s smart home devices after delivery driver’s false racism claim</em>. New York Post. https://nypost.com/2023/06/15/amazon-shuts-down-customers-smart-home-devices-over-false-racist-claim/</p>



<p>Dias, J. (2023, December 26). <em>Experts suggest taking stock of how much your monthly subscriptions really cost before the end of the Year</em>. CBS News. https://www.cbsnews.com/newyork/news/experts-suggest-taking-stock-of-how-much-your-monthly-subscriptions-really-cost-before-the-end-of-the-year/</p>



<p>DigitalOcean. (2024). <em>What is cloud scalability?</em>. What is Cloud Scalability? https://www.digitalocean.com/resources/article/cloud-scalability</p>



<p>DLS (Ed.). (2024, March 12). News release bureau of labor statistics.</p>



<p>Fellah, H., Mezioud, C., &amp; Batouche, M. C. (2020). Mobile cloud computing. <em>Proceedings of the 3rd International Conference on Networking, Information Systems &amp;amp; Security</em>. https://doi.org/10.1145/3386723.3387880</p>



<p>Google. (2024). <em>What is cloud architecture? benefits &amp; components | google cloud</em>. Google. https://cloud.google.com/learn/what-is-cloud-architecture#:~:text=Cloud%20architecture%20refers%20to%20how,to%20create%20cloud%20computing%20environments.</p>



<p>Grinberg, E., &amp; Chavez, N. (2018, August 30). <em>Connecticut man sentenced in Celebrity Photo Hacking scandal</em>. CNN. https://edition.cnn.com/2018/08/29/entertainment/celebrity-photo-hacking-sentence/index.html</p>



<p>Hassan, K., Kaur, P., &amp; Vijayasingam, V. (2023). E-waste—study of environmental impacts and waste management practices. <em>2023 International Conference on Integrated Intelligence and Communication Systems (ICIICS)</em>. https://doi.org/10.1109/iciics59993.2023.10421364</p>



<p>Kevin Purdy&nbsp; &nbsp; &#8211;&nbsp; &nbsp; Feb 16, 2024 4:37 pm UTC. (2024, February 16). <em>DOJ quietly removed Russian malware from routers in US homes and businesses</em>. Ars Technica. https://arstechnica.com/information-technology/2024/02/doj-turns-tables-on-russian-hackers-uses-their-malware-to-wipe-out-botnet/#:~:text=More%20than%201%2C000%20Ubiquiti%20routers,according%20to%20the%20Justice%20Department.</p>



<p>Lee, W., &amp; Lauder, T. (2023, October 11). <em>The cheap streaming era is over. here’s why your bills are going up</em>. Los Angeles Times. https://www.latimes.com/entertainment-arts/business/story/2023-10-11/streaming-pricier-consumers-netflix-spotify-sag-aftra-strike#:~:text=Media%20companies%20are%20charging%20more%20as%20they%20struggle,are%20grappling%20with%20inflation%20and%20broader%20economic%20uncertainty.</p>



<p>Lindner, J. (2023, December 16). <em>Must-know internet traffic statistics [latest report] • Gitnux</em>. GITNUX. https://gitnux.org/internet-traffic-statistics/</p>



<p>Monserrate, S. G. (2022, February 22). <em>The staggering ecological impacts of computation and the cloud</em>. The MIT Press Reader. https://thereader.mitpress.mit.edu/the-staggering-ecological-impacts-of-computation-and-the-cloud/</p>



<p>Monteclaro, A. J. (2023, November 2). <em>Server room power consumption: Demand and efficiency</em>. ServerWatch. https://www.serverwatch.com/servers/server-room-power-consumption/</p>



<p>Office of ENERGY EFFICIENCY &amp; RENEWABLE ENERGY. (2024). <em>Data Centers and servers</em>. Energy.gov. https://www.energy.gov/eere/buildings/data-centers-and-servers</p>



<p>Roth, E. (2022, November 29). <em>This is why streaming Netflix, Disney Plus, and HBO Max keeps getting more expensive</em>. The Verge. https://www.theverge.com/23460947/netflix-hulu-disney-plus-apple-tv-streaming-price-hikes-truth-behind</p>



<p>Stanford (Ed.). (2023, December 5). <em>Global carbon emissions from fossil fuels reached record high in 2023</em>. Stanford Doerr School of Sustainability. https://sustainability.stanford.edu/news/global-carbon-emissions-fossil-fuels-reached-record-high-2023</p>



<p>Statista. (2023, September 7). Distribution of electricity generation worldwide in 2022, by energy source. Retrieved March 30, 2024,.</p>



<p>Strum, L., &amp; Cooney, D. (2017, September 13). <em>Affected by the equifax hack? here’s what to do now</em>. PBS. https://www.pbs.org/newshour/nation/affected-equifax-hack-heres-now</p>



<p>Susnjara, S., &amp; Smalley, I. (2024, February 14). <em>What is cloud computing?</em>. IBM. https://www.ibm.com/topics/cloud-computing</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://erikmakesthings.ddns.net/comparing-clouds-could-local-hosting-be-in-your-digital-forecast/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>DiY Garden IoT</title>
		<link>https://erikmakesthings.ddns.net/diy-garden-iot/</link>
					<comments>https://erikmakesthings.ddns.net/diy-garden-iot/#respond</comments>
		
		<dc:creator><![CDATA[Erik]]></dc:creator>
		<pubDate>Sun, 01 Jun 2025 02:53:36 +0000</pubDate>
				<category><![CDATA[3D Printing]]></category>
		<category><![CDATA[Micro Controller]]></category>
		<category><![CDATA[Server]]></category>
		<guid isPermaLink="false">https://erikmakesthings.ddns.net/?p=213</guid>

					<description><![CDATA[A garden is a grand teacher. It teaches patience and careful watchfulness; it teaches industry and thrift; above all, it teaches entire trust. &#8211;Gertrude Jekyll When I first took up gardening a few years ago, I figured it couldn’t be that hard. Just throw some seeds in the dirt, sprinkle a little water, and boom [&#8230;]]]></description>
										<content:encoded><![CDATA[
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>A garden is a grand teacher. It teaches patience and careful watchfulness; it teaches industry and thrift; above all, it teaches entire trust.</p>
</blockquote>



<p>&#8211;<em>Gertrude Jekyll</em></p>



<p>When I first took up gardening a few years ago, I figured it couldn’t be <em>that</em> hard. Just throw some seeds in the dirt, sprinkle a little water, and boom salad. Easy, right?</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="480" height="287" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/06/wrong.gif" alt="" class="wp-image-214" style="width:788px;height:auto"/></figure>



<p>It turns out that growing plants successfully requires more than casual optimism and a watering can. It takes patience, consistency, and  most importantly precision. Too much water? Dead plants. Too little? Also dead plants. As someone who works odd hours as a mainframe operator, I quickly learned that remembering to water my plants at the right time every day wasn’t exactly my strong suit. So I did what any tinkering nerd would do, I spend hours building something so I wouldn&#8217;t need to spend seconds doing something and automated it.</p>



<h2 class="wp-block-heading">Water PI v1</h2>



<p>The first version of my automated watering system was basic but surprisingly effective. I repurposed an old Raspberry Pi 2 B to control a 5V relay via the GPIO pins, which toggled a small fish tank pump at set times of the day. The pump sat at the bottom of a 5-gallon bucket and pushed water through a 3/8&#8243; tube. I had pinched the end of the tube shut and drilled holes along its length to create a DIY sprinkler. All of this was controlled by a Python program I wrote and setup as a service so it always ran. I could also SSH and send a command to get it to run for an extra cycle if it was a rather dry day.</p>



 [<a href="https://erikmakesthings.ddns.net/diy-garden-iot/">See image gallery at erikmakesthings.ddns.net</a>] 



<p>It wasn’t elegant, but it worked. My plants got watered, and I didn’t have to think about it. That is, until a summer storm rolled in and decided to conduct a field test, in destruction. Water Pi v1, with its exposed wires and hot-glued components, was utterly torn apart. The setup had served its purpose, but it was no match for wind, rain, and poor weatherproofing.</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="480" height="266" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/06/sad-sal.gif" alt="" class="wp-image-216" style="width:748px;height:auto"/></figure>



<h2 class="wp-block-heading">Grow Lights</h2>



<p>Over the winter, I expanded the system indoors to start seedlings early. I picked up some budget-friendly grow lights from the local Home Depot and spliced in a Sonoff Zigbee relay to automate them through my Home Assistant setup. Now, the grow lights are part of my daily automation routines, turning on and off precisely when the seedlings need them, no more guessing or timers.</p>



 [<a href="https://erikmakesthings.ddns.net/diy-garden-iot/">See image gallery at erikmakesthings.ddns.net</a>] 



<h2 class="wp-block-heading">Water PI v2</h2>



<p>This year, I’m rebuilding the system from the ground up to be more scalable, energy-efficient, and portable. Enter <strong>Water Pi v2</strong> the next-generation watering node powered by a Raspberry Pi Pico 2W and a Waveshare power board, all mounted inside a 3D-printed (possibly weather-resistant) enclosure that I’m designing in FreeCAD.</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="498" height="373" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/06/upgrades-robots.gif" alt="" class="wp-image-215"/></figure>



<p>One of the main improvements is the addition of a motorized stirring mechanism. In my previous setup, stagnant water in the tank sometimes led to algae growth, which eventually caused blockage issues. This new version includes a dedicated motor to stir the tank periodically, helping keep the water clean and flowing consistently.</p>



<p>The watering function itself is now handled by a larger pump, again controlled via a relay module. The Pico 2W listens on a dedicated TCP port and receives instructions from a Python-based server program running on my home server. This server sends commands like <code>pump:2000</code> or <code>stir:1500</code> to toggle the corresponding relay for a specified duration (in milliseconds).</p>



<figure class="wp-block-video"><video height="1024" style="aspect-ratio: 576 / 1024;" width="576" controls src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/06/501697626_29724005740548137_3659334797605577503_n.mp4"></video></figure>



<p>To make the system more user-friendly and easier to diagnose, I’ve added a small I2C LCD to the node. It displays real-time status updates, such as the current system state and any received commands. Eventually, I plan to have the screen cycle through useful device information like IP address, battery level, and more — helpful for debugging and at-a-glance monitoring.</p>



<p>Power-wise, the system is designed to be solar-powered. I’m using a solar charging controller and a LiPo battery to allow the node to run independently. The pump, due to its higher power draw, is still powered by an external wall source. I also plan to design a custom bracket to mount the solar panels directly on top of the node&#8217;s housing for an all-in-one footprint.</p>



<p>The firmware for the Pico is written in C to give me finer hardware control and to sharpen my embedded systems skills. On the other hand, the server is written in Python, which should make it easier to get it integrate in to a nice and neat front end, or so I hope. Currently, the UI is a terminal-based menu, but I plan to expand it into a web interface. Long term, I’d like the server to manage a database to support multiple nodes, allowing for more scalable deployment and organization.</p>



 [<a href="https://erikmakesthings.ddns.net/diy-garden-iot/">See image gallery at erikmakesthings.ddns.net</a>] 
]]></content:encoded>
					
					<wfw:commentRss>https://erikmakesthings.ddns.net/diy-garden-iot/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://erikmakesthings.ddns.net/wp-content/uploads/2025/06/501697626_29724005740548137_3659334797605577503_n.mp4" length="10693804" type="video/mp4" />

			</item>
		<item>
		<title>3D Printing and Finishing a Helmet</title>
		<link>https://erikmakesthings.ddns.net/3d-printing-and-finishing-a-helmet/</link>
					<comments>https://erikmakesthings.ddns.net/3d-printing-and-finishing-a-helmet/#respond</comments>
		
		<dc:creator><![CDATA[Erik]]></dc:creator>
		<pubDate>Sun, 25 May 2025 03:27:47 +0000</pubDate>
				<category><![CDATA[3D Printing]]></category>
		<category><![CDATA[Micro Controller]]></category>
		<guid isPermaLink="false">https://erikmakesthings.ddns.net/?p=132</guid>

					<description><![CDATA[I&#8217;m just a simple man trying to make my way in the universe &#8211; Jango Fett I am a huge Star Wars nerd, like my father before me, and ever since I bought my Ender 3, I’ve been printing various Star Wars models and costume parts. After many failed and semi-successful projects, I finally set [&#8230;]]]></description>
										<content:encoded><![CDATA[
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>I&#8217;m just a simple man trying to make my way in the universe</p>
</blockquote>



<p>&#8211; Jango Fett</p>



<p>I am a huge Star Wars nerd, like my father before me, and ever since I bought my Ender 3, I’ve been printing various Star Wars models and costume parts. After many failed and semi-successful projects, I finally set out to make my father the helmet of one of his favorite, and most iconic, characters from a galaxy far, far away: RC-1207 Sev from the <em>Republic Commando</em> series.</p>



<h2 class="wp-block-heading">A Long Time Ago&#8230;</h2>



<p>For some backstory, my father is without a doubt one of the biggest Star Wars fans in the galaxy. Some of my earliest memories with him involve watching <em>The Empire Strikes Back</em> on VHS, playing the &#8217;90s <em>X-Wing vs. TIE Fighter</em> games, and building starfighters out of LEGO. As I grew up, he took us to every new movie, bought pretty much every Expanded Universe book, and played countless Star Wars tabletop and video games with us. For the longest time, he dreamed of building a Sev cosplay. I remember when he got in trouble with Mom for buying a helmet off eBay. He never finished the cosplay, life with five kids will do that, so my goal was to make him the helmet he always deserved.</p>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="879" height="1024" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Old-vs-New-1-879x1024.jpg" alt="" class="wp-image-151" srcset="https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Old-vs-New-1-879x1024.jpg 879w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Old-vs-New-1-258x300.jpg 258w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Old-vs-New-1-768x895.jpg 768w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Old-vs-New-1-1318x1536.jpg 1318w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Old-vs-New-1-1758x2048.jpg 1758w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Old-vs-New-1.jpg 1848w" sizes="(max-width: 879px) 100vw, 879px" /><figcaption class="wp-element-caption">Old vs New</figcaption></figure>



<h2 class="wp-block-heading">The Journey Begins&#8230;</h2>



<p>To get this project started, I relied on my mostly stock Ender 3 printer. After a year of learning slicing programs, post-processing, and printer quirks, I felt ready to take on something bigger. Here are a few of the smaller projects I tackled to prep for this build:</p>



 [<a href="https://erikmakesthings.ddns.net/3d-printing-and-finishing-a-helmet/">See image gallery at erikmakesthings.ddns.net</a>] 



<p>And of course a test fit was in order.</p>



<figure class="wp-block-video aligncenter"><video height="1440" style="aspect-ratio: 1440 / 1440;" width="1440" controls src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/06/test-fit-helm-1.mp4"></video></figure>



<h2 class="wp-block-heading">Finding the Model&#8230;</h2>



<p>First thing to do is to find the right model. If you&#8217;re good with 3D modeling or CAD, you can make your own. Otherwise, you can purchase models from amazing creators like aguilarworkshop.com, or search for free ones on sites like Thingiverse. I found the Republic Commando helmet model on Thingiverse, so huge shoutout to creators who share their hard work freely.</p>



<h2 class="wp-block-heading">Printing and Assembly&#8230;</h2>



<p>Then next step was to slice and print all of the pieces, sand them a little, and then put them all together. Since this print is in PLA I used just some simple Gorilla super glue to put them all together. Depending on the plastic you are using you will have different options to fuse everything, like Acetone when printing in ABS. Typically, what I found works best is to place a few drops in the face of the parts that would touch, and then either hand press or clamp the parts together for about five minutes. Then to further increase the the bond between the PLA parts, I would apply a few drops on both sides of the spot where the parts are connected and then spread it out with a brush. After repeating the exterior application a few times I would usually have a pretty strong bond! </p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
 [<a href="https://erikmakesthings.ddns.net/3d-printing-and-finishing-a-helmet/">See image gallery at erikmakesthings.ddns.net</a>] 
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-video aligncenter"><video height="1920" style="aspect-ratio: 1072 / 1920;" width="1072" controls src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Helm-Printed.mp4"></video></figure>
</div>
</div>



<h2 class="wp-block-heading">Filling and Finishing&#8230;</h2>



<p>Then all you have to do is do a bit of sanding with some rough grit to get it ready for the next step. Before we move on though let me just point out that this project involved a lot of sanding. Just assume that in between every step I have sanded the helmet going from a rough to a more fine grit each time. If you are going to do this project at home, I would highly recommend some sort of handheld power sander. I did this by and and it was terrible and very time consuming! Also don&#8217;t forget to work in a well ventilated area with a respirator and safety glasses. Don&#8217;t want to get anymore micro plastics than you already have!</p>



<p></p>



 [<a href="https://erikmakesthings.ddns.net/3d-printing-and-finishing-a-helmet/">See image gallery at erikmakesthings.ddns.net</a>] 



<p>Once you get everything sanded it&#8217;s time to start filling in the cracks so the surface will be smooth to the touch! From what I read and watched online most people either used watered down wood filler for it&#8217;s ability to fill gaps and sand easily, or Bondo for it&#8217;s ability to add getter structural support to the prints. So I opted to do both, because why not! I used Bondo I got from Mendards and applied it to the sides of the helmet where I had most of the larger parts of the helmet attached to each other. Then used the  watered down wood glue for for the smaller gaps and seams where things didn&#8217;t line up perfectly. After letting it dry, I did some more sanding. Finally, I coated the entire helmet with one layer of water downed wood filler and sanded until it was smooth.</p>



 [<a href="https://erikmakesthings.ddns.net/3d-printing-and-finishing-a-helmet/">See image gallery at erikmakesthings.ddns.net</a>] 



<h2 class="wp-block-heading">Painting and Detail Work&#8230;</h2>



<p>With the bulk of the work behind me all I had left was to put down a few layers of primer while filling any extra seems with wood filler. Then I laid down the white base that the clones are known for. After the two or three base coats I when in with a brush to paint the accents with black acrylic paint. For the visor I used a plastic face visor off of <a href="https://www.amazon.com/Feekoon-Replacement-Compatible-Protective-Grinding/dp/B0CT3RMTD4/ref=sr_1_4?sr=8-4">Amazon</a>, and cut it down to fit. After using a heat gun to shape the visor to the helmet I secured it in place using some hot glue. For the mouth grill I bought some wire mesh from a hobby store and cut it to fit before securing it with super glue.</p>



 [<a href="https://erikmakesthings.ddns.net/3d-printing-and-finishing-a-helmet/">See image gallery at erikmakesthings.ddns.net</a>] 



<p>The final part of this model is to add the striking livery to the helmet. Since the character has made few appearances since his debut in the 2005 game <em>Republic Command</em>, I had to take some creative liberties to bring the fear inducing bloodied paint scheme to life. After masking the accent lines and parts I used some watered down crimson acrylic paint and my hand to imprint the signature look across the faceplate. Then I used a sponge applicator to apply additional blood splatter and streaks.</p>



 [<a href="https://erikmakesthings.ddns.net/3d-printing-and-finishing-a-helmet/">See image gallery at erikmakesthings.ddns.net</a>] 



<h2 class="wp-block-heading">Finishing Touches&#8230;</h2>



<p>With the helmet complete, I decided to add some flair. Using a Raspberry Pi Pico and MicroPython, I wired up LEDs behind the visor to simulate the in-game glow. I also found original voice lines and sound effects from the game and used small speakers inside the helmet to play them. The entire system is powered by a USB power bank and securely tucked away. Final touches included padding, wire routing, and mini exhaust fans for comfort. Once everything was in place, I drove the helmet to my dad and handed it to him in person.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-video"><video height="656" style="aspect-ratio: 368 / 656;" width="368" controls src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/06/like-95-done-1.mp4"></video></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
 [<a href="https://erikmakesthings.ddns.net/3d-printing-and-finishing-a-helmet/">See image gallery at erikmakesthings.ddns.net</a>] 
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-video"><video height="1920" style="aspect-ratio: 1072 / 1920;" width="1072" controls src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Helm-Boot-1.mp4"></video></figure>
</div>
</div>



<p>Watching my dad don the finished helmet with glowing lights and Sev&#8217;s iconic crimson streaks was worth every failed print, every grain of sandpaper, and every drop of glue. This wasn’t just a cosplay prop. It was a tribute to the man who introduced me to Star Wars, and to the galaxy we still explore together.</p>



<p>This one was for you, Dad. For the Republic!</p>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="473" height="1024" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/20240630_131035-473x1024.jpg" alt="" class="wp-image-204" srcset="https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/20240630_131035-473x1024.jpg 473w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/20240630_131035-139x300.jpg 139w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/20240630_131035-768x1662.jpg 768w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/20240630_131035-710x1536.jpg 710w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/20240630_131035-946x2048.jpg 946w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/20240630_131035-scaled.jpg 1183w" sizes="(max-width: 473px) 100vw, 473px" /></figure>



<h2 class="wp-block-heading">MicroPython for helmet.</h2>



<pre class="wp-block-code"><code>#libs
import time
import board
import random
import digitalio
from audiocore import WaveFile
from audiopwmio import PWMAudioOut as AudioOut

#Speakers
audio = AudioOut(board.GP16)

#dir var
path = "sounds/"

#LEDs
led = digitalio.DigitalInOut(board.GP5)
led.direction = digitalio.Direction.OUTPUT
led1 = digitalio.DigitalInOut(board.GP6)
led1.direction = digitalio.Direction.OUTPUT
led2 = digitalio.DigitalInOut(board.GP7)
led2.direction = digitalio.Direction.OUTPUT
led3 = digitalio.DigitalInOut(board.GP8)
led3.direction = digitalio.Direction.OUTPUT
led4 = digitalio.DigitalInOut(board.GP9)
led4.direction = digitalio.Direction.OUTPUT

#function to open/read .wav file
def play_sound(filename):
    with open(path + filename, "rb") as wave_file:
        wave = WaveFile(wave_file)
        audio.play(wave)
        while audio.playing:
            pass
        
#from input play selected file        
def sfx(n):
    if n == 0:
        play_sound("62_anger.wav")
    elif n == 1:
        play_sound("rad_02.wav")
    elif n == 2:
        play_sound("rad_03.wav")
    elif n == 3:
        play_sound("62_droids.wav")
    elif n == 4:
        play_sound("40_win.wav")
    elif n == 5:
        led4.value = False
        led3.value = False
        time.sleep(1)
        led2.value = False
        led1.value = False
        time.sleep(1)
        led.value = False
        
        time.sleep(2)
        
        led.value = True
        play_sound("chirp.wav")
        play_sound("chirp.wav")
        led1.value = True
        led2.value = True
        play_sound("chirp.wav")
        led3.value = True
        led4.value = True
        play_sound("chirp.wav")
    elif n == 6:
        play_sound("delta.wav")
    elif n == 7:
        play_sound("62_rgr.wav")
        time.sleep(1)
        play_sound("07_lol.wav")
    elif n == 8:
        play_sound("62_bad.wav")
    

#initial boot sequence
play_sound("chirp.wav")
led.value = True
play_sound("chirp.wav")
play_sound("chirp.wav")
led1.value = True
led2.value = True
play_sound("chirp.wav")
led3.value = True
led4.value = True
play_sound("chirp.wav")
play_sound("boot.wav")
play_sound("heal.wav")

time.sleep(30)

#initial sound play
n = random.randint(0,8)
sfx(n)
m = n

#main loop
while True:
    n = random.randint(0,8)
    
    if m == n:
        n = random.randint(0,8)
        sfx(n)
    else:
        sfx(n)
    
    m = n
    
    time.sleep(300)</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://erikmakesthings.ddns.net/3d-printing-and-finishing-a-helmet/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Helm-Printed.mp4" length="8804734" type="video/mp4" />
<enclosure url="https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Helm-Boot-1.mp4" length="5525130" type="video/mp4" />
<enclosure url="https://erikmakesthings.ddns.net/wp-content/uploads/2025/06/test-fit-helm-1.mp4" length="16203264" type="video/mp4" />
<enclosure url="https://erikmakesthings.ddns.net/wp-content/uploads/2025/06/like-95-done-1.mp4" length="257793" type="video/mp4" />

			</item>
		<item>
		<title>My Home Lab</title>
		<link>https://erikmakesthings.ddns.net/my-home-lab/</link>
					<comments>https://erikmakesthings.ddns.net/my-home-lab/#respond</comments>
		
		<dc:creator><![CDATA[Erik]]></dc:creator>
		<pubDate>Sun, 18 May 2025 03:05:42 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Network]]></category>
		<category><![CDATA[Nextcloud]]></category>
		<category><![CDATA[Plex]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[Homelab]]></category>
		<category><![CDATA[LLM]]></category>
		<guid isPermaLink="false">https://erikmakesthings.ddns.net/?p=97</guid>

					<description><![CDATA[The internet is not something that you just dump something on, it’s not a big truck, it’s, it’s a series of tubes! -U.S. Senator Ted Stevens My home lab has been a fun, though sometimes time-consuming, hobby I’ve built up over the last few years. Currently, my self-hosted services include network wide ad blocking, cloud [&#8230;]]]></description>
										<content:encoded><![CDATA[
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>The internet is not something that you just dump something on, it’s not a big truck, it’s, it’s a series of tubes!</p>
</blockquote>



<p>-U.S. Senator Ted Stevens  </p>



<p>My home lab has been a fun, though sometimes time-consuming, hobby I’ve built up over the last few years. Currently, my self-hosted services include network wide ad blocking, cloud storage, multiple websites, media streaming, smart home controls, and even a local LLM. That’s right, the post you’re reading right now is hosted <em>locally</em> from my home office! But how did I get into all of this, and is it really worth it? <em>[Cue Vsauce theme music]</em></p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="Hey, Vsauce Michael Here..." width="500" height="281" src="https://www.youtube.com/embed/JwYzHW_q3c4?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<h2 class="wp-block-heading">We All Start Somewhere&#8230;</h2>



<p>Back in 2021, I started self-hosting a cloud storage solution, Nextcloud, in a virtual machine to replace my Google Drive and Photos since I was running out of space. After running it for a while and making small tweaks, I finally decided to invest in dedicated hardware, funded by selling off my DIY mining rigs. To save some cash, I sourced as many second-hand parts as possible. In total I think I have spent around  $1800 for all of the hardware, networking equipment, and battery backups.</p>



<p class="has-text-align-center"><strong>Current Parts List</strong></p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:100%">
<ul class="wp-block-list">
<li><strong>Case:</strong> Antec case (Goodwill)</li>



<li><strong>PSU:</strong> Rosewill 1000 Watt (Recycled)</li>



<li><strong>MOBO:</strong> Asus Prime-P (Second hand)</li>



<li><strong>CPU:</strong> 5700G (New)</li>



<li><strong>GPU:</strong> Nvidia a2000 6GB (Second hand)</li>



<li><strong>RAM:</strong> 64 GB DDR4 (New)</li>



<li><strong>Cooler:</strong> be quite! (Second hand)</li>



<li><strong>Drives:</strong> Various types adding up to 15TB (New)</li>



<li><strong>Fans:</strong> 3 Noctua NF-P12 (New)</li>
</ul>
</div>
</div>



<h2 class="wp-block-heading">Current Setup and Services</h2>



<p>I’m running Ubuntu Server<strong> </strong>as the OS for my home server. It’s connected to a<strong> </strong>CyberPower 900W UPS<strong> </strong>and is configured to gracefully shut down after five minutes of power loss and automatically restart when power is restored.</p>



<p>Here’s a quick overview of what’s running:</p>



 [<a href="https://erikmakesthings.ddns.net/my-home-lab/">See image gallery at erikmakesthings.ddns.net</a>] 



<h2 class="wp-block-heading">Nextcloud</h2>



<p>Nextcloud has been my longest-running self-hosted service. I started with the Snap package, moved to the Docker container, and now run it directly on bare metal. It’s been my dedicated data storage and sharing solution for years, helping me centralize family photos and documents for sharing and safe keeping. With the addition of the Nvidia A2000 GPU, I also integrated facial recognition software to organize photos by faces and objects, all handled locally! Nextcloud is a great way to secure, share, and store your data.</p>



 [<a href="https://erikmakesthings.ddns.net/my-home-lab/">See image gallery at erikmakesthings.ddns.net</a>] 



<h2 class="wp-block-heading">WordPress</h2>



<p>WordPress is my CMS of choice for both my website and my significant other’s. It helps me create, organize, and publish content like this post! With a massive library of plugins, you can do almost anything, provided you’re willing to learn. I’m also looking forward to my web development class next semester to better customize my site using PHP!</p>



<p>If you’re thinking about doing something similar, it’s totally doable in an afternoon:</p>



<ol class="wp-block-list">
<li>Set up a LAMP server</li>



<li>Register a domain</li>



<li>Grab SSL certificates through Let’s Encrypt</li>



<li>And you’re off and running!</li>
</ol>



<h2 class="wp-block-heading">Docker</h2>



<ul class="wp-block-list"></ul>



<ul class="wp-block-list"></ul>



<p>Docker is a must-have tool for any home lab. I use Portainer to manage my containers, including Home Assistant, which runs most of my smart home, and the web portal for Ollama. Eventually, I plan to phase out my Nest Hubs and replace them with local Home Assistant voice devices. With Ollama, I’ve set up a local AI interface where I can interact with various models like R1, Ollama3, and Arena to quickly access information, all without relying on the cloud!</p>



 [<a href="https://erikmakesthings.ddns.net/my-home-lab/">See image gallery at erikmakesthings.ddns.net</a>] 



<h2 class="wp-block-heading">Plex</h2>



<p>Plex has been my go-to media streaming solution for years. I even bought the lifetime pass to support the developers and unlock hardware encoding. But lately, the Android app has become a mess, and the new UI is cluttered with freemium TV services I didn’t ask for. I’m considering switching to Emby or Jellyfin, but for now Plex still does the job for enjoying and sharing my media collection with my friends and family.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="507" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Screenshot-2025-05-17-195439-1024x507.png" alt="" class="wp-image-115" srcset="https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Screenshot-2025-05-17-195439-1024x507.png 1024w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Screenshot-2025-05-17-195439-300x149.png 300w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Screenshot-2025-05-17-195439-768x381.png 768w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Screenshot-2025-05-17-195439-1536x761.png 1536w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/Screenshot-2025-05-17-195439-2048x1015.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">The Net&#8230;</h2>



<p>I know this post is getting long, so let’s wrap it up with a quick overview of my network gear. I recently upgraded to a Ubiquiti system with the USG-MAX and U7-XGS AP. This setup lets me segment my network with VLANs, secure traffic using IPS, and enjoy blazing-fast Wi-Fi 7 speeds, up to 1300 Mbps up and down on my LAN. On top of that, I’m running a Raspberry Pi 2B as a network-wide ad blocker using Pi-hole.</p>



 [<a href="https://erikmakesthings.ddns.net/my-home-lab/">See image gallery at erikmakesthings.ddns.net</a>] 



<h2 class="wp-block-heading">That&#8217;s All Folks&#8230;</h2>



<p>Building out my home lab has been a fun and rewarding experience that’s expanded my skills and deepened my understanding of the “series of tubes” that is the internet. Self-hosting is a great way to learn, gain practical experience, and even save money in the long run. I’ll probably write more detailed posts on each of these services in the future, but for now thanks for reading! I hope this gives you some ideas for building out your own home lab.</p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="640" height="542" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/05/ltt-linus-piggers.gif" alt="" class="wp-image-124"/></figure>



<h2 class="wp-block-heading">Links To Get Started&#8230;</h2>



<ul class="wp-block-list">
<li>Nextcloud: <a href="https://docs.nextcloud.com/server/latest/admin_manual/installation/">https://docs.nextcloud.com/server/latest/admin_manual/installation/</a></li>



<li>Plex: <a href="https://support.plex.tv/articles/200288586-installation/">https://support.plex.tv/articles/200288586-installation/</a></li>



<li>Home Assistant: <a href="https://www.home-assistant.io/getting-started">https://www.home-assistant.io/getting-started</a></li>



<li>Pi-Hole: <a href="https://pi-hole.net/">https://pi-hole.net/</a></li>



<li>Ollama: <a href="https://ollama.com/download">https://ollama.com/download</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://erikmakesthings.ddns.net/my-home-lab/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Attack of the Posts</title>
		<link>https://erikmakesthings.ddns.net/attack-of-the-posts/</link>
					<comments>https://erikmakesthings.ddns.net/attack-of-the-posts/#respond</comments>
		
		<dc:creator><![CDATA[Erik]]></dc:creator>
		<pubDate>Sun, 20 Apr 2025 02:27:26 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<guid isPermaLink="false">https://erikmakesthings.ddns.net/?p=61</guid>

					<description><![CDATA[I&#8217;m back. -Arnold Schwarzenegger Well, time certainly flies when you&#8217;re buried under a deluge of assignments and papers! But now that most of that is finally out of the way, I’ll be posting a little more regularly around here about what I’ve got going on. Between reverse engineering malware, writing a shell program, and printing [&#8230;]]]></description>
										<content:encoded><![CDATA[
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>I&#8217;m back.</p>
</blockquote>



<p>-Arnold Schwarzenegger</p>



<p>      </p>



<p>Well, time certainly flies when you&#8217;re buried under a deluge of assignments and papers! But now that most of that is finally out of the way, I’ll be posting a little more regularly around here about what I’ve got going on. Between reverse engineering malware, writing a shell program, and printing out reports like a madman for class, I have managed to make some headway on a few of my personal projects too. Check out the screenshots below for a glimpse of the &#8220;fun&#8221; I’ve been having this semester!</p>



 [<a href="https://erikmakesthings.ddns.net/attack-of-the-posts/">See image gallery at erikmakesthings.ddns.net</a>] 



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://erikmakesthings.ddns.net/attack-of-the-posts/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Lorem Ipsum&#8230;just kidding!</title>
		<link>https://erikmakesthings.ddns.net/lorem-ipsum-just-kidding/</link>
					<comments>https://erikmakesthings.ddns.net/lorem-ipsum-just-kidding/#respond</comments>
		
		<dc:creator><![CDATA[Erik]]></dc:creator>
		<pubDate>Thu, 16 Jan 2025 06:19:02 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<guid isPermaLink="false">https://erikmakesthings.ddns.net/?p=9</guid>

					<description><![CDATA[This is my first post on my website! This website will be where I document and share my projects, provided I remember the login.]]></description>
										<content:encoded><![CDATA[
<p class="has-white-background-color has-background">This is my first post on my website! This website will be where I document and share my projects, provided I remember the login.</p>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="768" height="1024" src="https://erikmakesthings.ddns.net/wp-content/uploads/2025/01/20250111_143604-768x1024.jpg" alt="" class="wp-image-10" srcset="https://erikmakesthings.ddns.net/wp-content/uploads/2025/01/20250111_143604-768x1024.jpg 768w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/01/20250111_143604-225x300.jpg 225w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/01/20250111_143604-1152x1536.jpg 1152w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/01/20250111_143604-1536x2048.jpg 1536w, https://erikmakesthings.ddns.net/wp-content/uploads/2025/01/20250111_143604-scaled.jpg 1920w" sizes="(max-width: 768px) 100vw, 768px" /></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://erikmakesthings.ddns.net/lorem-ipsum-just-kidding/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
