Development Journey Update - End of 2025


estimated read time: 15 minutes

Development Journey Update - End of 2025

As we approach the end of 2025, it’s a good time to reflect on the achievements of the year.

I’ve not been blogging much recently; this was a combination of a change of job and focusing on some personal projects. In this post, I’ll summarise some key homelab projects I’ve undertaken this year.

Move to Ubiquiti

In the physical changes to my home lab, one of the biggest changes was the transition out of consumer-grade networking equipment (Asus Gaming Router) to sub-enterprise-grade Ubiquiti Unifi equipment.

Why

So like most home users, I pretty much had a flat network design. All my devices existed in the same /24 subnet, although I utilised the guest network feature to emulate some segmentation, my previous router only supported 4 guest networks so I was limited in what I could do, that and you didn’t have much control over the routing between the main and guest networks.

Now I could have easily upgraded to a higher-end consumer router that allowed network segmentation and VLANs. However, I also was finding that the amount of traffic the k3s cluster was generating was beginning to become too much for the small ARM processor in the router. I was constantly finding that the router’s CPU and memory were being maxed out.

What

So what is Ubiquiti Unifi? Ubiquiti is a networking hardware manufacturer that produces a range of networking equipment from access points, switches, routers and security gateways. Their Unifi product line is targeted at small to medium businesses and prosumers, offering a range of features and capabilities that are typically found in enterprise-grade networking equipment.

For my setup I started with a Dream Machine Pro (UDM-Pro) which is an all-in-one router, switch and security gateway, a U7 Pro access point for WiFi coverage and a 24-port USW-24 switch for wired connectivity.

The aim in having an L3 switch with the USW-24 was to offload some of the routing and switching tasks from the UDM-Pro. With the heavier networking load generators like my TrueNAS server and media server connected directly to the switch, this allowed for better performance and reduced latency. This was short-sighted though, as in hindsight I should have gone for the PoE version of the switch to power my Raspberry Pi K3s nodes as by this point each of them was running with a PoE hat to avoid having multiple power adapters cluttering up my setup.

How

As mentioned before, I was previously using a consumer grade Asus router. One of my key goals here was to segment the network putting different types of devices in their own VLANs. I settled on the following structure:

NameDescription
defaultUbiquiti devices / management
home labAll homelab servers and devices
IOTSmart Home devices and untrusted devices
guestGuest devices and visitors
work from homeWork devices
personalphones, tablets and personal laptops

Once the physical hardware was setup and connected, I then proceeded to configure the network. Now, Ubiquiti does not segment cross VLANs by default, so I had to ensure that trusted subnets could not be accessed from untrusted devices. It’s remarkable when you study the network traffic of some IoT devices how nosey they can be. I regularly found my Amazon Echo devices snooping for other devices on the network. To mitigate this, I created firewall rules to block traffic between the IOT VLAN and all other VLANs except for the default management VLAN.

I made an exception for my Home Assistant so that IOT devices can still be seen and controlled, but all other traffic is blocked.

Finally, I also wanted to implement regional blocking. Many IoT devices seem to communicate to dubious locations around the world. I’d commonly see the Philips Hue hub trying to communicate with servers in China, and Dreame robotic vacuum devices trying to reach servers in Russia. To mitigate this, I created firewall rules to block traffic to and from certain regions. I’d rather have to debug and create exceptions for devices that need to communicate internationally only to find my data being part of a data breach or sold.

graph TD
    subgraph "Physical Infrastructure"
        Internet["Internet"]
        UDMPro["UDM-Pro<br/>Router & Security Gateway"]
        USW24["USW-24<br/>L3 Switch"]
        U7Pro["U7 Pro<br/>WiFi Access Point"]

        Internet --> UDMPro
        UDMPro --> USW24
        UDMPro --> U7Pro
    end

    subgraph "Network Segmentation - VLANs"
        DefaultVLAN["Default VLAN<br/>Ubiquiti Management<br/>192.168.1.x/24"]
        HomeLabVLAN["Home Lab VLAN<br/>Servers & Infrastructure<br/>192.168.10.x/24"]
        IOTVLAN["IoT VLAN<br/>Smart Home Devices<br/>192.168.20.x/24"]
        GuestVLAN["Guest VLAN<br/>Visitor Access<br/>192.168.30.x/24"]
        WFHVLAN["Work From Home VLAN<br/>Work Devices<br/>192.168.40.x/24"]
        PersonalVLAN["Personal VLAN<br/>Phones & Laptops<br/>192.168.110.x/24"]
    end

    subgraph "Connected Devices"
        TrueNAS["TrueNAS Server"]
        MediaServer["Media Server"]
        K3sNodes["K3s Raspberry Pi Cluster"]
        IoTDevices["Smart Home Devices"]
        WorkDevices["Work Laptops"]
        PersonalDevices["Phones & Tablets"]
        GuestDevices["Guest Devices"]
    end

    %% VLAN routing through UDM-Pro
    UDMPro -.-> DefaultVLAN
    UDMPro -.-> HomeLabVLAN
    UDMPro -.-> IOTVLAN
    UDMPro -.-> GuestVLAN
    UDMPro -.-> WFHVLAN
    UDMPro -.-> PersonalVLAN

    %% Device connections
    USW24 --> TrueNAS
    USW24 --> MediaServer
    USW24 --> K3sNodes
    U7Pro -.-> IoTDevices
    U7Pro -.-> WorkDevices
    U7Pro -.-> PersonalDevices
    U7Pro -.-> GuestDevices

    %% VLAN assignments
    TrueNAS -.-> HomeLabVLAN
    MediaServer -.-> HomeLabVLAN
    K3sNodes -.-> HomeLabVLAN
    IoTDevices -.-> IOTVLAN
    WorkDevices -.-> WFHVLAN
    PersonalDevices -.-> PersonalVLAN
    GuestDevices -.-> GuestVLAN

    %% Styling with Ubiquiti colors
    style Internet fill:#2a2a2a,stroke:#61dafb,stroke-width:2px,color:#e0e0e0
    style UDMPro fill:#2a2a2a,stroke:#00ff88,stroke-width:3px,color:#e0e0e0
    style USW24 fill:#2a2a2a,stroke:#00ff88,stroke-width:2px,color:#e0e0e0
    style U7Pro fill:#2a2a2a,stroke:#00ff88,stroke-width:2px,color:#e0e0e0

    %% VLAN styling
    style DefaultVLAN fill:#1a1a1a,stroke:#ffcc00,stroke-width:1px,color:#e0e0e0
    style HomeLabVLAN fill:#1a1a1a,stroke:#61dafb,stroke-width:1px,color:#e0e0e0
    style IOTVLAN fill:#1a1a1a,stroke:#ff6b9d,stroke-width:1px,color:#e0e0e0
    style GuestVLAN fill:#1a1a1a,stroke:#ff6b6b,stroke-width:1px,color:#e0e0e0
    style WFHVLAN fill:#1a1a1a,stroke:#a855f7,stroke-width:1px,color:#e0e0e0
    style PersonalVLAN fill:#1a1a1a,stroke:#00ff88,stroke-width:1px,color:#e0e0e0

    %% Device styling
    style TrueNAS fill:#1a1a1a,stroke:#444444,stroke-width:1px,color:#a0a0a0
    style MediaServer fill:#1a1a1a,stroke:#444444,stroke-width:1px,color:#a0a0a0
    style K3sNodes fill:#1a1a1a,stroke:#444444,stroke-width:1px,color:#a0a0a0
    style IoTDevices fill:#1a1a1a,stroke:#444444,stroke-width:1px,color:#a0a0a0
    style WorkDevices fill:#1a1a1a,stroke:#444444,stroke-width:1px,color:#a0a0a0
    style PersonalDevices fill:#1a1a1a,stroke:#444444,stroke-width:1px,color:#a0a0a0
    style GuestDevices fill:#1a1a1a,stroke:#444444,stroke-width:1px,color:#a0a0a0

Network Segmentation

Building a 48TB ZFS Network Attached Storage

What

For the last couple of years I used a 4TB HDD inside of my old gaming PC (now a Proxmox server) and a TrueNAS VM to provide my network storage needs. However, as my media collection grew and I started to worry about the reliability due to the age of the drive, which was 5 years old at this point, I decided to build a dedicated NAS server.

Why

The main requirements for the new NAS server were: - Power Efficiency: Living in the UK we’re charged quite high rates for electricity, so having a power-hungry server running 24/7 was not ideal. - Storage Capacity: I want breadth of storage to grow my media collection and to be able to run backups of my homelab servers and host MinIO object storage. - Reliability: I wanted a solution that would provide data redundancy and protection against drive failures. - Performance: While not needing enterprise level performance, I wanted to be able to maximise my gigabit network speeds for file transfers and media streaming.

I planned to do more with my monitoring stack this year so I wanted to ensure that there was enough storage to capture long-term logs and metrics. I had been working a lot this year professionally on improving the efficiency of log retention and metric cardinality, so I wanted to ensure my home lab practiced what I preached. There’s also performance considerations with tin that you worry more about then in the cloud where you can just scale up resources.

How

I settled on the following:

I settled on Ryzen 3 4300G as it offered a good balance of performance and power efficiency as it only drew around 65W TDP. The integrated graphics also meant I didn’t need a dedicated GPU, further reducing power consumption and cost. The 64GB of RAM was chosen to ensure that ZFS had enough memory for caching and to support future expansion. ZFS is known to benefit from ample RAM, especially when dealing with large datasets and multiple concurrent accesses. The 4 x 12TB Seagate IronWolf Pro HDDs were selected for their reliability and performance. Using RAIDZ2 provided a good balance between storage efficiency and data protection, allowing for two drive failures without data loss.

Major Change! - Homelab APM Setup

What

Like you’d expect from a workplace environment, monitoring is key for getting insight on how systems are performing, their availability, and how they’re being used. However, I don’t have tens of thousands to spare on commercial APM solutions like Datadog, New Relic or Dynatrace. Now many out there probably already run Prometheus and Grafana on their homelabs and for a few hundred metrics and a handful of hosts a simple Prometheus on bare metal, VM or Kubernetes setup is perfectly fine. But, as my home lab is much more then a few development projects now, it actually captures measurements as small as biometrics from my smart watch to the power consumption of my entire house.

So I needed something more scalable, reliable and flexible. After researching a few options I settled on the following stack:

This setup was more focused on covering the big three pillars: metrics, logs, and traces.

Why

Mainly “because I can”, as I wanted to do more deep diving into observability and monitoring. I’ve always engaged with this area of work and even my initial blog platform I use to use a self hosted analytics platform (Matomo) to track usage. I wanted a setup that went beyond just simple metrics of user visits. I wanted a system that could give me insight into my own life.

As we wander about with our smartphones and watches, living in our smart homes with IoT devices and driving our Google-powered cars, we generate a lot of data. All of which we’re handing off to big tech companies to monetise. I wanted to take back control of my own data and use it give me insight into my own life. For example, I now track:

How

In the years gone by I’ve had the habit of wandering between different technologies and platforms. One year I’ll do everything in VMs in a hypervisor, I will then change the hypervisor then decided to containerise everything then move to Kubernetes. I would then flip-flop between which technology Im using: ansible, terraform, helm thats even before deciding on which application stack to use.

This year I decided to all-in on Kubernetes (K3S) as my main platform for everything. Making only minor changes to the language and framework based on which is best suited for the task at hand.

Once I’d locked in on the platform technologies, the rest wrote itself in a few months. I started with the creation of a new Helm chart called monitoring that would deploy all the components needed for the monitoring stack. This included:

I expanded the existing prometheus-operator helm chart (for note, it does have thanos support however it missed some key features I needed) to include thanos sidecars, store gateway and querier components.

The following diagram shows the architecture of my monitoring stack:

graph TD
    subgraph "TrueNAS (External)"
        Minio[MinIO S3]
        Minio -- "Bucket: prometheus-data" --> ThanosData[(Thanos Data)]
        Minio -- "Bucket: loki-chunks" --> LokiData[(Loki Chunks)]
        Minio -- "Bucket: loki-ruler" --> LokiRulerData[(Loki Rules)]
    end

    subgraph K3S Cluster
        Endpoint[K3s External Endpoint] <--> Minio

        subgraph "Namespace: monitoring"
            Grafana(Grafana UI)
            Alertmanager(Alertmanager)

            subgraph "Metrics Stack (Thanos/Prometheus)"
                PromOp(Prometheus Operator) -.-> Prom
                Prom(Prometheus + Thanos Sidecar)
                TQuery(Thanos Query)
                TStore(Thanos Store Gateway)
                TCompact(Thanos Compactor)
                TRuler(Thanos Ruler)

                Prom -- "Uploads Blocks" --> Endpoint
                TStore -- "Reads History" --> Endpoint
                TCompact -- "Compacts & Downsamples" --> Endpoint
                TRuler -- "Stores Rule Results" --> Endpoint

                TQuery -- "Queries Live" --> Prom
                TQuery -- "Queries History" --> TStore
                TQuery -- "Queries Rules" --> TRuler
            end

            subgraph "Logs Stack (Loki)"
                LokiLB[MetalLB Gateway\n192.168.55.10]
                LDistributor(Loki Distributor)
                LIngester(Loki Ingester)
                LQuery(Loki Querier)
                LQueryFE(Loki Query Frontend)
                LIndexGW(Loki Index Gateway)
                LCompactor(Loki Compactor)
                LRuler(Loki Ruler)
                LChunkCache[Chunks Cache]

                LokiLB --> LDistributor
                LDistributor --> LIngester
                LIngester -- "Flushes Chunks" --> Endpoint

                LQuery --> LQueryFE
                LQueryFE --> LIndexGW
                LQueryFE --> LChunkCache
                LIndexGW -- "Reads Indices" --> Endpoint
                LChunkCache -- "Caches Chunks" --> Endpoint

                LCompactor -- "Retention & Compaction" --> Endpoint
                LRuler -- "Reads Logs" --> LQuery
                LRuler -- "Remote Write Metrics" --> Prom
            end

            Alloy(Alloy Collector)

            Prom -- "Scrapes Metrics" --> Alloy
            Alloy -- "Pushes Logs" --> LokiLB

            Grafana -- "Data Source: Metrics" --> TQuery
            Grafana -- "Data Source: Logs" --> LQuery

            LRuler -- "Sends Alerts" --> Alertmanager
            Prom -- "Sends Alerts" --> Alertmanager
        end

        K3sNodes(K3s Nodes & Apps)
        ExternalSystems(External Systems\nHome Assistant VM)
        Alloy -- "Collects Telemetry" --> K3sNodes
        ExternalSystems -- "Pushes Logs" --> LokiLB
    end

    %% Retro Terminal Color Scheme
    %% Storage - Magenta/Pink accent
    style Minio fill:#2a2a2a,stroke:#ff6b9d,stroke-width:2px,color:#e0e0e0
    style ThanosData fill:#1a1a1a,stroke:#ff6b9d,stroke-width:1px,color:#e0e0e0
    style LokiData fill:#1a1a1a,stroke:#ff6b9d,stroke-width:1px,color:#e0e0e0
    style LokiRulerData fill:#1a1a1a,stroke:#ff6b9d,stroke-width:1px,color:#e0e0e0

    %% Grafana - Amber/Orange (brand color)
    style Grafana fill:#2a2a2a,stroke:#ffcc00,stroke-width:3px,color:#e0e0e0

    %% Alertmanager - Red accent
    style Alertmanager fill:#2a2a2a,stroke:#ff6b6b,stroke-width:2px,color:#e0e0e0

    %% Prometheus/Thanos Stack - Cyan
    style PromOp fill:#1a1a1a,stroke:#61dafb,stroke-width:1px,color:#e0e0e0
    style Prom fill:#2a2a2a,stroke:#61dafb,stroke-width:2px,color:#e0e0e0
    style TQuery fill:#2a2a2a,stroke:#61dafb,stroke-width:2px,color:#e0e0e0
    style TStore fill:#1a1a1a,stroke:#61dafb,stroke-width:1px,color:#e0e0e0
    style TCompact fill:#1a1a1a,stroke:#61dafb,stroke-width:1px,color:#e0e0e0
    style TRuler fill:#1a1a1a,stroke:#61dafb,stroke-width:1px,color:#e0e0e0

    %% Loki Stack - Green
    style LokiLB fill:#2a2a2a,stroke:#00ff88,stroke-width:2px,color:#e0e0e0
    style LDistributor fill:#1a1a1a,stroke:#00ff88,stroke-width:1px,color:#e0e0e0
    style LIngester fill:#1a1a1a,stroke:#00ff88,stroke-width:1px,color:#e0e0e0
    style LQuery fill:#2a2a2a,stroke:#00ff88,stroke-width:2px,color:#e0e0e0
    style LQueryFE fill:#1a1a1a,stroke:#00ff88,stroke-width:1px,color:#e0e0e0
    style LIndexGW fill:#1a1a1a,stroke:#00ff88,stroke-width:1px,color:#e0e0e0
    style LCompactor fill:#1a1a1a,stroke:#00ff88,stroke-width:1px,color:#e0e0e0
    style LRuler fill:#1a1a1a,stroke:#00ff88,stroke-width:1px,color:#e0e0e0
    style LChunkCache fill:#1a1a1a,stroke:#00ff88,stroke-width:1px,color:#e0e0e0

    %% Alloy - Magenta (collector/agent)
    style Alloy fill:#2a2a2a,stroke:#ff6b9d,stroke-width:2px,color:#e0e0e0

    %% Infrastructure
    style Endpoint fill:#1a1a1a,stroke:#444444,stroke-width:1px,color:#a0a0a0
    style K3sNodes fill:#1a1a1a,stroke:#444444,stroke-width:1px,color:#a0a0a0
    style ExternalSystems fill:#1a1a1a,stroke:#ffcc00,stroke-width:1px,color:#e0e0e0

Move to Solar & Battery Power

What

In mid-2025 I finally took the plunge and installed a solar panel system with battery storage at my home. After months contemplating the decision and researching the different options and the costs, I settled on a 4kW solar panel system with a 10kWh battery storage solution.

Why

The main reasons for the move to solar and battery power were:

The solution needed to be capable of the following:

Implementation

After researching various solar panel and battery storage options, I settled with Octopus Energy for the setup.

DeviceModel/SpecificationNumber of UnitsWarranty (Years)
Solar Panels455W JA Solar 430-4551530
InverterEnphase IQ8AC-72-M-INT1525
Battery StorageEnphase IQBATTERY-5P-1P-INT215

It’s only been a few months since the installation; however, I can report that even in the autumn and winter months, the system has been performing well and has reduced my electricity bills by 37%, mostly driven from the time obfuscation.

Conclusion

2025 has been a year of significant changes and improvements to my home lab and personal projects. From upgrading my networking equipment to Ubiquiti Unifi, building a robust ZFS NAS, implementing a comprehensive monitoring stack with Thanos and Loki, to transitioning to solar and battery power, each project has brought new challenges and learning opportunities. As for 2026, I plan to do more with AI and machine learning, as I write this article with the assistance of an AI language model. I’m excited to see what the new year brings and look forward to sharing more updates on my development journey.