<?xml version="1.0" encoding="utf-8" standalone="yes"?><?xml-stylesheet type="text/xsl" href="/pretty-feed-v3.xsl"?>
<rss
  version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:source="https://source.scripting.com/"
>
  <channel>
    <title>Paul Tibbetts</title>
    <link>https://paultibbetts-uk-feat-cooks.preview.lab.paultibbetts.uk/2025/06/13/</link>
    <description>Posts by Paul Tibbetts published on Friday, June 13, 2025</description>
    <generator>Hugo</generator>
    <language>en-gb</language>
    <atom:link href="https://paultibbetts-uk-feat-cooks.preview.lab.paultibbetts.uk/2025/06/13/feed.xml" rel="self" type="application/rss+xml" /><item>
      <title>Homelab V1</title>
      <link>https://paultibbetts-uk-feat-cooks.preview.lab.paultibbetts.uk/2025/06/13/homelab-v1/</link>
      <pubDate>Fri, 13 Jun 2025 16:00:00 +0100</pubDate>
      <guid>https://paultibbetts-uk-feat-cooks.preview.lab.paultibbetts.uk/2025/06/13/homelab-v1/</guid>
      <category>homelab</category>
      <description>My Homelab has hit its first milestone 🚀</description>
      <content:encoded><![CDATA[<p>My Homelab has hit its first milestone 🚀</p>
<h2 id="cloud">Cloud</h2>
<p>The biggest problem with my homelab was that I kept breaking it.</p>
<p>I couldn&rsquo;t get used to using <a href="https://mealie.io/">mealie</a>
 as a meal planner because I would go to use it and it didn&rsquo;t work. Or it did, but I couldn&rsquo;t connect to it properly. Or something else went wrong.</p>
<p>So for my first &ldquo;release&rdquo; I aimed for a &ldquo;cloud&rdquo;. Some people call it &ldquo;HomeProd&rdquo;.</p>
<p>I used things I was used to, and a few things I wasn&rsquo;t, to make a simple, stable platform on which I could host my <em>actual</em> homelab.</p>
<p>Here&rsquo;s what&rsquo;s in it:</p>
<h3 id="nas">NAS</h3>
<p>I have a machine dedicated to running <a href="https://www.truenas.com/truenas-scale/">TrueNAS Scale</a>
.</p>
<p>I bought the hype that I needed <a href="https://www.truenas.com/docs/scale/gettingstarted/scalehardwareguide/">ECC RAM</a>
 so that my data would be safe and so I also needed a server-grade processor, which meant a server-grade motherboard, and all the other bits to go with it.</p>
<p>At the time Scale had built-in Kubernetes so I used TrueCharts to set up some apps. And then they stopped working. And then there were all the updates with breaking changes. And then I got fed up.</p>
<p>This was meant to be a machine that did storage and I didn&rsquo;t want to mess with it.</p>
<p>The TrueNAS devs thought the same thing and took out Kubernetes and replaced it with Docker, so I updated to follow and now I only run two storage apps on it.</p>
<h4 id="usage">Usage</h4>
<ul>
<li><strong>file storage</strong> over <strong>NFS</strong> to Linux and Mac and <strong>SMB</strong> for Windows</li>
<li><strong>object storage</strong> via <a href="https://min.io">MinIO</a>
 installed as a Docker container</li>
<li><strong>backups</strong> for virtual machines via <a href="https://www.proxmox.com/en/products/proxmox-backup-server/overview">Proxmox Backup Server</a>
</li>
</ul>
<p>and <strong>nothing else</strong>.</p>
<p>I just want it to do network attached storage, and I don&rsquo;t want to mess with it.</p>
<h4 id="storage">Storage</h4>
<ul>
<li>2 NVME for 4TB of fast storage</li>
<li>1 SSD for 500GB internal storage</li>
<li>4 HDD RAIDZ2 for 10TB of slow storage</li>
</ul>
<h3 id="nuc">NUC</h3>
<p>After getting burned trying to do server things on my NAS I looked for a replacement and found the <a href="https://turingpi.com">Turing Pi</a>
, and then in true Kickstarter fashion it got delayed, and then delayed again.</p>
<p>I impatiently bought an Intel NUC.</p>
<p>I <em>could</em> have installed Linux on it and used it as a server but I wanted to use Terraform for Infrastructure as Code, so instead I installed <a href="https://www.proxmox.com/en/products/proxmox-virtual-environment/overview">Proxmox VE</a>
 and used Terraform to create the virtual machines and LXC containers I needed with code.</p>
<p>This meant I could get some practise in using <a href="https://docs.ansible.com/ansible/latest/index.html">Ansible</a>
 to configure things and try out <a href="https://k3s.io">K3s</a>
 to run Kubernetes.</p>
<h4 id="usage-1">Usage</h4>
<ul>
<li><strong>compute</strong> for running services and apps</li>
<li>experience using <strong>Proxmox</strong></li>
<li>practise using IaC with <strong>Terraform</strong> and <strong>Ansible</strong></li>
<li>a place to try out <strong>Kubernetes</strong> stuff</li>
<li>a better GPU than the NAS for <strong>Jellyfin</strong> to use for transcoding</li>
</ul>
<h4 id="services">Services</h4>
<ul>
<li><strong><a href="https://pi-hole.net/">Pi-hole</a>
</strong> for blocking adverts as well as DNS and DHCP for my network</li>
<li><strong><a href="https://www.pivpn.io/">Wireguard</a>
</strong> for a VPN so I can connect from out the house</li>
<li><strong>MySQL</strong> and <strong>Postgres</strong> databases for &ldquo;cloud&rdquo; things to use</li>
<li><strong><a href="https://caddyserver.com/">Caddy</a>
</strong> as a reverse proxy to provide access to my &ldquo;cloud&rdquo; apps and services</li>
<li><strong><a href="https://about.gitea.com/">Gitea</a>
</strong> for storing my git repositories</li>
<li><strong><a href="https://jellyfin.org/">Jellyfin</a>
</strong> to watch my own media content</li>
</ul>
<h4 id="apps">Apps</h4>
<ul>
<li><strong><a href="https://mealie.io/">Mealie</a>
</strong> for recipe management and meal planning</li>
<li><strong><a href="https://www.freshrss.org/">FreshRSS</a>
</strong> for my RSS clients to sync from</li>
</ul>
<h3 id="deskpi">DeskPi</h3>
<p>The last part of my &ldquo;cloud&rdquo; is the Raspberry Pi 4 I have on my desk.</p>
<p>(I named it before I heard about the company with the same name)</p>
<p>I had future plans for it, since it&rsquo;s sat on my desk, so I installed the desktop version of Ubuntu and hooked it up to my second screen.</p>
<p>Then I installed <a href="https://paultibbetts-uk-feat-cooks.preview.lab.paultibbetts.uk/2025/06/13/homelab-v1/">Uptime Kuma</a>
 on it to monitor all my services and apps.</p>
<p>Apparently I cheaped out when I bought it and got the 2GB version, so it&rsquo;s really really slow and struggles with showing the dashboard.</p>
<p><img src="https://paultibbetts-uk-feat-cooks.preview.lab.paultibbetts.uk/2025/06/13/homelab-v1/uptime-kuma-status-page.png" alt="screenshot of Uptime Kuma status page">
</p>
<p>I&rsquo;ve been looking for a good excuse to buy a Raspberry Pi 5 but technically this works, so for now it can stay.</p>
<h2 id="lab">Lab</h2>
<p>Now that the stable self-hosted part is out of the way I&rsquo;m going to leave it alone and use something else for the new ideas.</p>
<p>My Turing Pi 2.5 has finally arrived, along with its case, 3 x <a href="https://turingpi.com/product/turing-rk1/?attribute_ram=8&#43;GB">RK1</a>
 compute modules and 3 x 1 TB NVME drives. I&rsquo;m planning on using it as a cluster to run Kubernetes and potentially host my own website, but we&rsquo;ll see about that.</p>
<p>Right now it&rsquo;s on the bench in the lab.</p>]]></content:encoded><source:markdown>
My Homelab has hit its first milestone 🚀

&lt;!--more--&gt;

## Cloud

The biggest problem with my homelab was that I kept breaking it.

I couldn&#39;t get used to using [mealie](https://mealie.io/) as a meal planner because I would go to use it and it didn&#39;t work. Or it did, but I couldn&#39;t connect to it properly. Or something else went wrong.

So for my first &#34;release&#34; I aimed for a &#34;cloud&#34;. Some people call it &#34;HomeProd&#34;.

I used things I was used to, and a few things I wasn&#39;t, to make a simple, stable platform on which I could host my _actual_ homelab.

Here&#39;s what&#39;s in it:

### NAS

I have a machine dedicated to running [TrueNAS Scale](https://www.truenas.com/truenas-scale/).

I bought the hype that I needed [ECC RAM](https://www.truenas.com/docs/scale/gettingstarted/scalehardwareguide/) so that my data would be safe and so I also needed a server-grade processor, which meant a server-grade motherboard, and all the other bits to go with it.

At the time Scale had built-in Kubernetes so I used TrueCharts to set up some apps. And then they stopped working. And then there were all the updates with breaking changes. And then I got fed up.

This was meant to be a machine that did storage and I didn&#39;t want to mess with it.

The TrueNAS devs thought the same thing and took out Kubernetes and replaced it with Docker, so I updated to follow and now I only run two storage apps on it.

#### Usage

- **file storage** over **NFS** to Linux and Mac and **SMB** for Windows
- **object storage** via [MinIO](https://min.io) installed as a Docker container
- **backups** for virtual machines via [Proxmox Backup Server](https://www.proxmox.com/en/products/proxmox-backup-server/overview)

and **nothing else**.

I just want it to do network attached storage, and I don&#39;t want to mess with it.

#### Storage

- 2 NVME for 4TB of fast storage
- 1 SSD for 500GB internal storage
- 4 HDD RAIDZ2 for 10TB of slow storage

### NUC

After getting burned trying to do server things on my NAS I looked for a replacement and found the [Turing Pi](https://turingpi.com), and then in true Kickstarter fashion it got delayed, and then delayed again.

I impatiently bought an Intel NUC.

I _could_ have installed Linux on it and used it as a server but I wanted to use Terraform for Infrastructure as Code, so instead I installed [Proxmox VE](https://www.proxmox.com/en/products/proxmox-virtual-environment/overview) and used Terraform to create the virtual machines and LXC containers I needed with code.

This meant I could get some practise in using [Ansible](https://docs.ansible.com/ansible/latest/index.html) to configure things and try out [K3s](https://k3s.io) to run Kubernetes.

#### Usage

- **compute** for running services and apps
- experience using **Proxmox**
- practise using IaC with **Terraform** and **Ansible**
- a place to try out **Kubernetes** stuff
- a better GPU than the NAS for **Jellyfin** to use for transcoding

#### Services

- **[Pi-hole](https://pi-hole.net/)** for blocking adverts as well as DNS and DHCP for my network
- **[Wireguard](https://www.pivpn.io/)** for a VPN so I can connect from out the house
- **MySQL** and **Postgres** databases for &#34;cloud&#34; things to use
- **[Caddy](https://caddyserver.com/)** as a reverse proxy to provide access to my &#34;cloud&#34; apps and services
- **[Gitea](https://about.gitea.com/)** for storing my git repositories
- **[Jellyfin](https://jellyfin.org/)** to watch my own media content

#### Apps

- **[Mealie](https://mealie.io/)** for recipe management and meal planning
- **[FreshRSS](https://www.freshrss.org/)** for my RSS clients to sync from

### DeskPi

The last part of my &#34;cloud&#34; is the Raspberry Pi 4 I have on my desk.

(I named it before I heard about the company with the same name)

I had future plans for it, since it&#39;s sat on my desk, so I installed the desktop version of Ubuntu and hooked it up to my second screen.

Then I installed [Uptime Kuma]() on it to monitor all my services and apps.

Apparently I cheaped out when I bought it and got the 2GB version, so it&#39;s really really slow and struggles with showing the dashboard.

![screenshot of Uptime Kuma status page](uptime-kuma-status-page.png)

I&#39;ve been looking for a good excuse to buy a Raspberry Pi 5 but technically this works, so for now it can stay.

## Lab

Now that the stable self-hosted part is out of the way I&#39;m going to leave it alone and use something else for the new ideas.

My Turing Pi 2.5 has finally arrived, along with its case, 3 x [RK1](https://turingpi.com/product/turing-rk1/?attribute_ram=8+GB) compute modules and 3 x 1 TB NVME drives. I&#39;m planning on using it as a cluster to run Kubernetes and potentially host my own website, but we&#39;ll see about that.

Right now it&#39;s on the bench in the lab.
</source:markdown></item><item>
      <title>Using Terraform as the Inventory for Ansible</title>
      <link>https://paultibbetts-uk-feat-cooks.preview.lab.paultibbetts.uk/2025/06/13/using-terraform-as-the-inventory-for-ansible/</link>
      <pubDate>Fri, 13 Jun 2025 11:30:21 +0100</pubDate>
      <guid>https://paultibbetts-uk-feat-cooks.preview.lab.paultibbetts.uk/2025/06/13/using-terraform-as-the-inventory-for-ansible/</guid>
      <category>Ansible</category>
      <category>Terraform</category>
      <description>Terraform and Ansible are complementary tools with which you can do Infrastructure as Code. You would use Terraform to request machines from providers and then Ansible to configure them.
Using both of them together, with a dynamic inventory to link them, has been technically possible for years but never obvious enough for me to work out.
Until I found the Terraform provider.</description>
      <content:encoded><![CDATA[<p>Terraform and Ansible are complementary tools with which you can do Infrastructure as Code. You would use <a href="https://www.terraform.io/">Terraform</a>
 to request machines from providers and then <a href="https://docs.ansible.com/ansible/latest/index.html">Ansible</a>
 to configure them.</p>
<p>Using both of them together, with a dynamic inventory to link them, has been technically possible for years but never obvious enough for me to work out.</p>
<p>Until I found the Terraform provider.</p>
<h2 id="ansible-provider-for-terraform">Ansible provider for Terraform</h2>
<p>By using the <a href="https://registry.terraform.io/providers/ansible/ansible/latest">Ansible provider</a>
 you can teach Terraform what an Ansible inventory entry would look like next to the rest of its code.</p>
<p>You start by defining the provider:</p>
<pre><code class="language-terraform">terraform {
  required_providers {
    ansible = {
      source  = &#34;ansible/ansible&#34;
      version = &#34;1.3.0&#34;
    }
  }
}</code></pre>
<p>and then you can define the Ansible inventory entry right next to the resource:</p>
<pre><code class="language-terraform">resource &#34;proxmox_vm_qemu&#34; &#34;gitea&#34; {
  cores = 1
	...
}

resource &#34;ansible_host&#34; &#34;gitea&#34; {
  name   = proxmox_vm_qemu.gitea.ssh_host
  groups = [&#34;gitea&#34;]
  variables = {
    ansible_user = &#34;ansible&#34;
  }
}</code></pre>
<p>which means you don&rsquo;t need to hardcode IP addresses anywhere.</p>
<p>You would need to <code>terraform apply</code> this plan so that Terraform adds these resources to the state file so that Ansible can use them.</p>
<h2 id="terraform-plugin-for-ansible">Terraform plugin for Ansible</h2>
<p>On the Ansible side you use <a href="https://github.com/ansible-collections/cloud.terraform">a plugin</a>
 to tell it how to use Terraform as its inventory.</p>
<p>Add the following to your <code>requirements.yaml</code> file:</p>
<pre><code class="language-yaml">collections:
  - name: cloud.terraform
    version: 1.1.0</code></pre>
<p>and then install the collection using <code>ansible-galaxy collection install -r requirements.yaml</code>,</p>
<p>then create an <code>inventory.yaml</code> with the following content:</p>
<pre><code class="language-yaml">plugin: cloud.terraform.terraform_provider
# project_path: ../terraform # if your Terraform code is in a different directory
# state_file: mycustomstate.tfstate # if you wanted to define which state file</code></pre>
<p>and set it as the default inventory in <code>ansible.cfg</code>:</p>
<pre><code class="language-ini">[defaults]
inventory = inventory.yaml</code></pre>
<p>You can confirm the plugin works by doing:</p>
<pre><code class="language-sh">ansible-inventory --graph</code></pre>
<p>which should return something like the following:</p>
<pre><code class="language-sh">@all:
  |--@ungrouped:
  |--@gitea:
  |  |--192.168.1.211</code></pre>
<h2 id="heading">🎉</h2>
<p>What&rsquo;s good about this is now you can be hands-off with IP addresses.</p>
<p>Terraform can request a new machine, wait for it to receive an IP address and then make it available for Ansible to use, without you needing to do anything.</p>
<h3 id="remote-state">Remote state</h3>
<p>The Ansible plugin will default to using whichever backend you use for the Terraform state file, whether that&rsquo;s local or in an S3-compatible location.</p>
<p>This means Ansible is always running against the current infrastructure, which helps when colleagues and automations are updating things a <del>hundred</del> thousand times a day.</p>
<h2 id="in-conclusion">In Conclusion</h2>
<p>Using Terraform and Ansible together can cover all aspects of Infrastructure as Code.</p>
<p>The Ansible provider lets you keep all your resource code together in Terraform and then makes it available to Ansible, which uses a plugin to let it use the state file as its inventory.</p>]]></content:encoded><source:markdown>
Terraform and Ansible are complementary tools with which you can do Infrastructure as Code. You would use [Terraform](https://www.terraform.io/) to request machines from providers and then [Ansible](https://docs.ansible.com/ansible/latest/index.html) to configure them.

Using both of them together, with a dynamic inventory to link them, has been technically possible for years but never obvious enough for me to work out.

Until I found the Terraform provider.

&lt;!--more--&gt;

## Ansible provider for Terraform

By using the [Ansible provider](https://registry.terraform.io/providers/ansible/ansible/latest) you can teach Terraform what an Ansible inventory entry would look like next to the rest of its code.

You start by defining the provider:

```terraform
terraform {
  required_providers {
    ansible = {
      source  = &#34;ansible/ansible&#34;
      version = &#34;1.3.0&#34;
    }
  }
}
```

and then you can define the Ansible inventory entry right next to the resource:

```terraform
resource &#34;proxmox_vm_qemu&#34; &#34;gitea&#34; {
  cores = 1
	...
}

resource &#34;ansible_host&#34; &#34;gitea&#34; {
  name   = proxmox_vm_qemu.gitea.ssh_host
  groups = [&#34;gitea&#34;]
  variables = {
    ansible_user = &#34;ansible&#34;
  }
}
```

which means you don&#39;t need to hardcode IP addresses anywhere.

You would need to `terraform apply` this plan so that Terraform adds these resources to the state file so that Ansible can use them.

## Terraform plugin for Ansible

On the Ansible side you use [a plugin](https://github.com/ansible-collections/cloud.terraform) to tell it how to use Terraform as its inventory.

Add the following to your `requirements.yaml` file:

```yaml
collections:
  - name: cloud.terraform
    version: 1.1.0
```

and then install the collection using `ansible-galaxy collection install -r requirements.yaml`,

then create an `inventory.yaml` with the following content:

```yaml
plugin: cloud.terraform.terraform_provider
# project_path: ../terraform # if your Terraform code is in a different directory
# state_file: mycustomstate.tfstate # if you wanted to define which state file
```

and set it as the default inventory in `ansible.cfg`:

```ini
[defaults]
inventory = inventory.yaml
```

You can confirm the plugin works by doing:

```sh
ansible-inventory --graph
```

which should return something like the following:

```sh
@all:
  |--@ungrouped:
  |--@gitea:
  |  |--192.168.1.211
```

## 🎉

What&#39;s good about this is now you can be hands-off with IP addresses.

Terraform can request a new machine, wait for it to receive an IP address and then make it available for Ansible to use, without you needing to do anything.

### Remote state

The Ansible plugin will default to using whichever backend you use for the Terraform state file, whether that&#39;s local or in an S3-compatible location.

This means Ansible is always running against the current infrastructure, which helps when colleagues and automations are updating things a ~~hundred~~ thousand times a day.

## In Conclusion

Using Terraform and Ansible together can cover all aspects of Infrastructure as Code.

The Ansible provider lets you keep all your resource code together in Terraform and then makes it available to Ansible, which uses a plugin to let it use the state file as its inventory.
</source:markdown></item>
  </channel>
</rss>
