Plenty of memory. Plenty of CPU. Elastic infrastructure behind the scenes.

This one is not.

This cluster runs on a Raspberry Pi 3, inside a normal household network, behind an ISP router that cannot be replaced. It shares that network with personal devices, guest devices, and the usual mix of consumer hardware.

The goal was not to build a "homelab".

The goal was to design a small, portable, security-focused platform using the same principles I would apply in a professional environment.

The constraints were real. And they shaped every decision.

Constraints That Shaped the Design

Before choosing tools, I defined the boundaries:

  • Consumer ISP router with limited configurability
  • A separate guest network that must remain functional
  • Limited RAM and CPU
  • No appetite for breaking household connectivity
  • Future physical relocation to a different property

The Raspberry Pi 3 provides 1GB of RAM. Kubernetes does not treat that as generous.

The router cannot be replaced, and guest network behaviour is largely opaque.

These were not inconveniences to be engineered around later. They were design inputs from the start.

If a solution required ideal networking hardware or exposed services to the internet, it was rejected immediately.

This environment had to be:

  • Self-contained
  • Portable
  • Recoverable from scratch

Why Kubernetes Here, Despite the Overhead

Running Kubernetes on a Raspberry Pi is often described as overkill.

In many cases, that criticism is valid.

This cluster is not about scale. It is not about handling traffic spikes. It is not about demonstrating high availability.

It is about discipline.

Using k3s enforces:

  • Declarative configuration
  • Explicit resource management
  • Containerised workloads
  • Repeatable deployments
  • Clear separation between services

The overhead is significant on constrained hardware. Default components alone can overwhelm a Pi 3.

But the payoff is structural.

If the hardware changes, if a new node is added, or if the cluster must be rebuilt after relocation, the deployment model remains identical.

The trade-off is complexity in exchange for long-term flexibility.

In this context, that trade-off is intentional.

Architecture Overview

The current cluster is single-node.

The Raspberry Pi 3 runs both control plane components and workloads. There is no high availability and no redundancy. This is a known and accepted limitation.

Core services include:

  • Pi-hole for network-wide DNS control
  • Tailscale for secure remote access
  • Linkding as a stateful user workload

All services are deployed using raw Kubernetes manifests. There are no Helm charts and no abstraction layers beyond Kubernetes itself.

Stateful workloads use PersistentVolumeClaims backed by local storage. This is a compromise driven by hardware limitations.

Traffic flow is simple:

Internal devices -> Router DHCP -> DNS requests to Pi-hole -> Upstream resolver Remote access -> Encrypted overlay via Tailscale -> Internal services

Nothing is exposed publicly.

The architecture prioritises clarity over cleverness.

Networking and DNS: Where Theory Met Reality

Networking proved to be the first real constraint.

The household network includes:

  • Trusted devices
  • IoT devices
  • A separate guest network

The initial plan was to move DHCP to Pi-hole and centralise both DNS and address management.

This broke the guest network.

The ISP router did not allow sufficient configuration to support that model cleanly. The guest network relied on router-controlled DHCP behaviour that could not be replicated externally.

The solution was not complex.

The router retained DHCP responsibilities. Pi-hole became the sole DNS server configured on the router.

This preserved:

  • Guest network functionality
  • DNS-level visibility and filtering
  • Simplicity

The compromise was correct because it respected the environment.

Good infrastructure adapts to its constraints instead of fighting them.

Security Model and Attack Surface

Security in this cluster is based on reduction rather than exposure.

No services are publicly accessible.

There is no port forwarding. There are no open inbound firewall rules. There is no public ingress controller.

Remote access is handled exclusively through Tailscale, providing:

  • Encrypted connectivity
  • Identity-based access control
  • No reliance on IP trust

The threat model is pragmatic.

It assumes:

  • The local network may contain untrusted devices
  • The public internet should not have visibility into internal services

It does not attempt to defend against nation-state actors.

The security posture is proportional to the context.

What Broke, and What Changed Because of It

Several assumptions failed early.

The first mistake was starting from an outdated Raspberry Pi OS image. Package updates were unreliable, and the system required a complete reinstallation using a current release.

Next, default k3s components proved too heavy for the hardware.

Traefik, ServiceLB, metrics-server, and local storage were initially enabled. Performance was inconsistent, and memory pressure was significant.

Removing non-essential components stabilised the node.

Later, deploying Linkding introduced new constraints. Django migrations were slow, and default uWSGI settings triggered out-of-memory conditions.

Mitigations included:

  • Reducing worker and thread counts
  • Setting explicit resource limits
  • Re-enabling local storage carefully

Each adjustment followed the same pattern:

Assumption -> failure -> simplification.

The system improved not through expansion, but through restraint.

Future Evolution Without Re-Architecture

The design intentionally supports gradual evolution.

Planned changes include:

  • Adding a Raspberry Pi 5 as a second node
  • Moving stateful workloads to SSD-backed storage
  • Labelling nodes for clearer workload separation

The existing manifests will not require structural redesign.

The deployment model remains consistent whether running on one node or two.

High availability is not currently implemented. It may be considered later, but only if justified by actual requirements rather than theoretical completeness.

The cluster is allowed to grow, but not at the expense of clarity.

What This Project Actually Demonstrates

This cluster is small.

It is not enterprise scale. It is not highly available. It is not complex for its own sake.

What it represents is:

  • Decision-making under constraint
  • Security-first design in consumer environments
  • Comfort with trade-offs
  • Operational tuning on limited hardware
  • Discipline in documentation and reproducibility

The most valuable lessons did not come from adding components.

They came from removing them.

For full manifests, diagrams, and documentation, the complete repository is available here:

https://github.com/Razeen-Abdal-Rahman/portable-k3s-homelab