<?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>Cybersecurity &#8211; Erik Makes Things</title>
	<atom:link href="https://erikmakesthings.ddns.net/category/cybersecurity/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>Cybersecurity &#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>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>
	</channel>
</rss>
