<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Giovanni Pellizzoni</title>
    <description>The latest articles on DEV Community by Giovanni Pellizzoni (@giopellizzoni).</description>
    <link>https://dev.to/giopellizzoni</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2595366%2F4b2f0656-0c9b-4874-845d-36f1dee24d72.jpeg</url>
      <title>DEV Community: Giovanni Pellizzoni</title>
      <link>https://dev.to/giopellizzoni</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/giopellizzoni"/>
    <language>en</language>
    <item>
      <title>Building a Home Lab with Proxmox and Terraform (for Kubernetes)</title>
      <dc:creator>Giovanni Pellizzoni</dc:creator>
      <pubDate>Sat, 23 May 2026 15:43:47 +0000</pubDate>
      <link>https://dev.to/giopellizzoni/building-a-home-lab-with-proxmox-and-terraform-for-kubernetes-3jhe</link>
      <guid>https://dev.to/giopellizzoni/building-a-home-lab-with-proxmox-and-terraform-for-kubernetes-3jhe</guid>
      <description>&lt;p&gt;Lately, I’ve been exploring new topics and decided it was time to level up my DevOps skills. This led me to build something I genuinely enjoyed working on: a home lab using Proxmox, with Terraform to provision virtual machines.&lt;/p&gt;

&lt;p&gt;And yes — if you’re wondering what this is all for…&lt;br&gt;
👉 we’re heading toward a Kubernetes cluster.&lt;/p&gt;
&lt;h1&gt;
  
  
  🎯 What You Will Build
&lt;/h1&gt;

&lt;p&gt;In this post, we will set up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Proxmox-based home lab&lt;/li&gt;
&lt;li&gt;A reusable VM template&lt;/li&gt;
&lt;li&gt;A Terraform configuration to provision: 3 control plane nodes and 3 worker nodes&lt;/li&gt;
&lt;li&gt;An automatically generated Ansible inventory for future automation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates a solid foundation for building and experimenting with Kubernetes locally.&lt;/p&gt;

&lt;p&gt;Here is the diagram of what we are trying to achieve.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F03h6v42kabhr8zk2go1x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F03h6v42kabhr8zk2go1x.png" alt="High-level architecture of the Proxmox-based home lab, where Terraform provisions virtual machines from a template to form a Kubernetes cluster."&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  🤔 Why This Setup?
&lt;/h1&gt;

&lt;p&gt;Before jumping into the implementation, let’s talk about the decisions behind it.&lt;/p&gt;
&lt;h1&gt;
  
  
  🧠 Why Proxmox vs Cloud?
&lt;/h1&gt;

&lt;p&gt;Cloud providers like AWS or Azure are incredibly convenient. However, for experimentation and learning, I wanted something more predictable and cost-efficient.&lt;/p&gt;

&lt;p&gt;Running a home lab with Proxmox gives me:&lt;/p&gt;

&lt;p&gt;Full control over the infrastructure&lt;br&gt;
No ongoing costs for spinning resources up and down&lt;br&gt;
A safe environment where I can break things without worrying about billing&lt;br&gt;
In the cloud, even small experiments can become expensive if you forget to tear resources down. With Proxmox, once the hardware is set up, I can experiment freely.&lt;/p&gt;

&lt;p&gt;That said, this is not a replacement for the cloud — it’s a complement for learning and testing before moving workloads to production environments.&lt;/p&gt;
&lt;h1&gt;
  
  
  ⚙️ Why Terraform vs Ansible-only?
&lt;/h1&gt;

&lt;p&gt;Ansible is excellent for configuration management, but when it comes to provisioning infrastructure, Terraform is a better fit.&lt;/p&gt;

&lt;p&gt;With Terraform, I get:&lt;/p&gt;

&lt;p&gt;Declarative infrastructure (desired state)&lt;br&gt;
Idempotency by design&lt;br&gt;
A clear execution plan (terraform plan)&lt;br&gt;
While Ansible can provision VMs, that’s not its primary strength.&lt;/p&gt;

&lt;p&gt;In this setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terraform → provisions infrastructure&lt;/li&gt;
&lt;li&gt;Ansible → configures what runs inside it (coming next 👀)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  🌐 Why Static IP vs DHCP Reservation?
&lt;/h1&gt;

&lt;p&gt;I chose to assign static IPs using cloud-init instead of relying on DHCP reservations.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Predictability → IPs are defined in code&lt;br&gt;
Portability → no dependency on router configuration&lt;br&gt;
Reproducibility → same setup anywhere&lt;br&gt;
DHCP reservations work fine, but they introduce an external dependency. By keeping everything in Terraform, the entire infrastructure becomes reproducible.&lt;/p&gt;
&lt;h1&gt;
  
  
  ☁️ Why Not Just Use the Cloud?
&lt;/h1&gt;

&lt;p&gt;For many real-world scenarios, the cloud is absolutely the right choice.&lt;/p&gt;

&lt;p&gt;But for learning:&lt;/p&gt;

&lt;p&gt;Costs can grow quickly&lt;br&gt;
You depend on internet access&lt;br&gt;
You may hesitate to experiment freely&lt;br&gt;
With a home lab:&lt;/p&gt;

&lt;p&gt;You can break things safely&lt;br&gt;
No cost anxiety&lt;br&gt;
Faster iteration for small tests&lt;br&gt;
The goal here is to validate ideas locally before scaling them in the cloud.&lt;/p&gt;
&lt;h1&gt;
  
  
  ☸️ Why Not Use k3s Instead of Full Kubernetes?
&lt;/h1&gt;

&lt;p&gt;k3s is a fantastic lightweight Kubernetes distribution — especially for edge or low-resource environments.&lt;/p&gt;

&lt;p&gt;However, my goal is to:&lt;/p&gt;

&lt;p&gt;Learn Kubernetes closer to production setups&lt;br&gt;
Understand control plane components&lt;br&gt;
Get hands-on experience with kubeadm&lt;br&gt;
k3s simplifies a lot of this (which is great in practice), but I want to understand what’s happening under the hood.&lt;/p&gt;
&lt;h1&gt;
  
  
  🖥️ Lab Setup
&lt;/h1&gt;

&lt;p&gt;Let’s talk about the hardware.&lt;/p&gt;

&lt;p&gt;I used a gaming desktop that I originally built for gaming — ironically, that’s the one thing I’m not using it for anymore.&lt;/p&gt;

&lt;p&gt;I added a 1 TB SATA SSD, which is more than enough for this setup. Even a 500 GB drive would work fine.&lt;/p&gt;

&lt;p&gt;If you have more budget, you could:&lt;/p&gt;

&lt;p&gt;Buy a Mini PC&lt;br&gt;
Build a dedicated home server&lt;br&gt;
At minimum, you need:&lt;/p&gt;

&lt;p&gt;A machine that supports virtualization&lt;/p&gt;
&lt;h1&gt;
  
  
  🧰 Tools Used
&lt;/h1&gt;

&lt;p&gt;Proxmox VE&lt;br&gt;
Terraform&lt;br&gt;
Basic Linux knowledge&lt;/p&gt;
&lt;h1&gt;
  
  
  🧠 What is Proxmox VE?
&lt;/h1&gt;

&lt;p&gt;Proxmox VE (Virtual Environment) is an open-source virtualization platform based on Debian Linux.&lt;/p&gt;

&lt;p&gt;It allows you to:&lt;/p&gt;

&lt;p&gt;Create and manage virtual machines&lt;br&gt;
Use containers (LXC)&lt;br&gt;
Manage everything via a web UI&lt;br&gt;
It’s a powerful and lightweight alternative to tools like VMware.&lt;/p&gt;
&lt;h1&gt;
  
  
  🌐 Networking Considerations
&lt;/h1&gt;

&lt;p&gt;Before installing Proxmox, it’s a good idea to plan your network.&lt;/p&gt;

&lt;p&gt;Your router assigns IP addresses via DHCP. To avoid conflicts, you should reserve a range of IPs.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DHCP range: &lt;code&gt;192.168.0.100 → 192.168.0.250&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Reserved range: &lt;code&gt;192.168.0.2 → 192.168.0.99&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;During Proxmox installation, you can assign a static IP (e.g., 192.168.0.50).&lt;/p&gt;
&lt;h1&gt;
  
  
  💡 Nice Trick: Local DNS
&lt;/h1&gt;

&lt;p&gt;You can add an entry to your hosts file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;192.168.0.50 myproxmox.lab&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now you can access:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;http://myproxmox.lab:8006&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Much nicer than using raw IPs.&lt;/p&gt;
&lt;h1&gt;
  
  
  🧱 VM Templates with QCOW2
&lt;/h1&gt;

&lt;p&gt;Instead of manually creating VMs every time, we can use templates.&lt;/p&gt;

&lt;p&gt;I created a script that:&lt;/p&gt;

&lt;p&gt;Downloads a Debian image&lt;br&gt;
Converts it into a Proxmox template&lt;br&gt;
Prepares it for cloud-init&lt;/p&gt;
&lt;h1&gt;
  
  
  👉 Run it like this:
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;./create-debian12-template.sh 9000 local-lvm&lt;/code&gt;&lt;br&gt;
This creates a reusable baseline for all VMs.&lt;/p&gt;
&lt;h1&gt;
  
  
  ⚠️ Important
&lt;/h1&gt;

&lt;p&gt;Make sure your template has:&lt;/p&gt;

&lt;p&gt;qemu-guest-agent installed and enabled&lt;br&gt;
This is required for proper VM communication with Proxmox.&lt;/p&gt;
&lt;h1&gt;
  
  
  ⚙️ Provisioning with Terraform
&lt;/h1&gt;

&lt;p&gt;Now comes the fun part.&lt;/p&gt;

&lt;p&gt;Provider setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;proxmox&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bpg/proxmox"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 0.69"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"proxmox"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;endpoint&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;proxmox_host_address&lt;/span&gt;
  &lt;span class="nx"&gt;api_token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pm_api_token_id&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pm_api_token_secret&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;insecure&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  🔐 API Token Format
&lt;/h1&gt;

&lt;p&gt;You can create the API Token using Proxmox VE UI&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;user&amp;gt;@&amp;lt;realm&amp;gt;!&amp;lt;tokenid&amp;gt;=&amp;lt;secret&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  ⚠️ About insecure = true
&lt;/h1&gt;

&lt;p&gt;This is used because Proxmox uses a self-signed certificate.&lt;/p&gt;

&lt;p&gt;Better alternatives:&lt;/p&gt;

&lt;p&gt;Add Proxmox certificate to trusted store&lt;br&gt;
Use Let’s Encrypt&lt;/p&gt;
&lt;h1&gt;
  
  
  🖥️ Creating Control Plane VMs
&lt;/h1&gt;

&lt;p&gt;Using Terraform, we define:&lt;/p&gt;

&lt;p&gt;CPU / Memory&lt;br&gt;
Network&lt;br&gt;
Static IP&lt;br&gt;
Cloud-init configuration&lt;br&gt;
Each VM is cloned from the template and customized.&lt;/p&gt;
&lt;h1&gt;
  
  
  📦 Variables: The Real Power
&lt;/h1&gt;

&lt;p&gt;All configuration is centralized in variables.tf.&lt;/p&gt;

&lt;p&gt;This allows you to:&lt;/p&gt;

&lt;p&gt;Scale nodes easily&lt;br&gt;
Change resources quickly&lt;br&gt;
Reuse the setup in different environments&lt;/p&gt;
&lt;h1&gt;
  
  
  🚀 Running Terraform
&lt;/h1&gt;

&lt;p&gt;terraform validate&lt;br&gt;
terraform plan&lt;br&gt;
terraform apply&lt;br&gt;
Then watch the magic happen in the Proxmox UI.&lt;/p&gt;
&lt;h1&gt;
  
  
  📄 Generating Ansible Inventory
&lt;/h1&gt;

&lt;p&gt;Terraform also generates a ready-to-use inventory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"local_file"&lt;/span&gt; &lt;span class="s2"&gt;"ansible_inventory"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will be used in the next step when we configure Kubernetes with Ansible.&lt;/p&gt;

&lt;h1&gt;
  
  
  📦 Full Source Code
&lt;/h1&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/PellizzoniCode/proxmox_terraform" rel="noopener noreferrer"&gt;https://github.com/PellizzoniCode/proxmox_terraform&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  🔜 What’s Next?
&lt;/h1&gt;

&lt;p&gt;This is just the beginning.&lt;/p&gt;

&lt;p&gt;In the next post, I’ll:&lt;/p&gt;

&lt;p&gt;Bootstrap Kubernetes using kubeadm&lt;br&gt;
Configure networking with a CNI plugin&lt;br&gt;
Prepare the cluster for real workloads&lt;/p&gt;

&lt;h1&gt;
  
  
  👋 Final Thoughts
&lt;/h1&gt;

&lt;p&gt;This setup has been a great way to:&lt;/p&gt;

&lt;p&gt;Learn DevOps in a practical way&lt;br&gt;
Experiment without worrying about cost&lt;br&gt;
Build a solid foundation for Kubernetes&lt;br&gt;
If you have any questions or suggestions, feel free to reach out — I’d love to hear your feedback.&lt;/p&gt;

&lt;p&gt;Also, visit the original post with more details on my blog PellizzoniCode.NET&lt;/p&gt;

&lt;h1&gt;
  
  
  See you in the next one 🚀
&lt;/h1&gt;

&lt;p&gt;If you found this useful, feel free to share or leave a comment — it really helps 🙌&lt;/p&gt;

</description>
      <category>devops</category>
      <category>infrastructure</category>
      <category>kubernetes</category>
      <category>terraform</category>
    </item>
  </channel>
</rss>
