I’ve been using Smartthings as my smart home hub for a while. And I’d like to migrate to something that’s open source (or more importantly, self-hosted). There’s been a few horror stories out there that make me worry about the potential “hostage” situation. (e.g. manufacturers charging a monthly price for the service, or flat-out discontinuing the service).
Hardware


I bought a Dell Wyse N03D Thin Client off eBay at $35 each, complete with power supply, keyboard and mouse. The thin client is definitely not a powerhouse, but it’s dual core x86-64 processor and 4GB of RAM should be plenty sufficient for my use case. To let it connect to Z-Wave and ZigBee devices, I also paired it with a dongle.
Software
OS
The thin client came with Windows 7 Embedded pre-installed, which I absolutely don’t need. I replaced it with a fresh install of Ubuntu Server 20.04 LTS. As the thin client only has 16G of onboard storage, I modified the default partitioning scheme to get more space to the rootfs.
Kubernetes
I chose k3s for this project. It’s small size is a perfect fit. For the installation, running the following snippet is sufficient.
curl -sfL https://get.k3s.io | sh -
Running rancher is always a good idea. To have rancher installed on k3s, add the following manifest to /var/lib/rancher/k3s/server/manifests
---
apiVersion: v1
kind: Namespace
metadata:
name: cattle-system
---
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
name: rancher
namespace: kube-system
spec:
chart: https://releases.rancher.com/server-charts/stable/rancher-2.5.8.tgz
targetNamespace: cattle-system
valuesContent: |-
hostname: [REDACTED]
tls: external
replicas: 1
This works because k3s comes with a helm CRD.
Following that, apply the following manifest to get home-assistant and its friends installed.
---
apiVersion: v1
kind: Namespace
metadata:
name: home-assistant
---
apiVersion: v1
kind: Service
metadata:
namespace: home-assistant
name: home-assistant
spec:
selector:
app: home-assistant
ports:
- name: http
protocol: TCP
port: 80
targetPort: 8123
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: home-assistant
name: home-assistant
labels:
app: home-assistant
spec:
replicas: 1
selector:
matchLabels:
app: home-assistant
template:
metadata:
labels:
app: home-assistant
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- homelab-us-east-1-nano-1
containers:
- name: home-assistant
image: homeassistant/home-assistant:stable
ports:
- containerPort: 8123
volumeMounts:
- mountPath: /config
name: config
- mountPath: /dev/ttyUSB1
name: zigbee
securityContext:
privileged: true
volumes:
- name: config
hostPath:
path: /etc/home-assistant
type: DirectoryOrCreate
- name: zigbee
hostPath:
path: /dev/ttyUSB1
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: home-assistant
name: home-assistant
spec:
rules:
- host: [REDACTED]
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: home-assistant
port:
number: 80
---
apiVersion: v1
kind: Service
metadata:
namespace: home-assistant
name: zwavejs2mqtt
spec:
selector:
app: zwavejs2mqtt
type: NodePort
ports:
- name: http
protocol: TCP
port: 8091
targetPort: 8091
nodePort: 30091
- name: ws
protocol: TCP
port: 3000
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: home-assistant
name: zwavejs2mqtt
labels:
app: zwavejs2mqtt
spec:
replicas: 1
selector:
matchLabels:
app: zwavejs2mqtt
template:
metadata:
labels:
app: zwavejs2mqtt
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- homelab-us-east-1-nano-1
containers:
- name: zwavejs2mqtt
image: zwavejs/zwavejs2mqtt:4.5.1
ports:
- containerPort: 8091
- containerPort: 3000
volumeMounts:
- mountPath: /usr/src/app/store
name: config
- mountPath: /dev/ttyUSB0
name: zwave
securityContext:
privileged: true
volumes:
- name: config
hostPath:
path: /etc/zwavejs2mqtt
type: DirectoryOrCreate
- name: zwave
hostPath:
path: /dev/ttyUSB0
Done

I also used Cloudflare Argo tunnel to allow me to control my home automation outside of my house.