Decision. autoSync on
Alternative. Manual sync
Why. Dashboard config is pure YAML with no runtime state; auto-applying keeps the pane accurate after every Git change with zero risk.
One pane of glass for every service in the lab
Homepage renders a single dashboard linking every service, with live status widgets where a service exposes them. Its configuration is declarative YAML in Git, which is why it is one of the few auto-synced entries.
Excerpt from argocd-apps/values.yaml in the argocd-apps chart,
with annotations added for this site:
homepage:
application: true
project: cluster-services
# true: dashboard YAML is declarative and risk-free to auto-apply
autoSync: true
The full homepage/values.yaml from the service's
own chart:
ports:
http: 3000
image:
name: registry.opi5cluster.co.uk/homepage:v2.0
volumeMounts:
mountPath: /app/config/
resources:
requests:
cpu: 15m
memory: 184M
config:
settings:
layout:
- Media:
style: row
columns: 3
- Home Lab:
style: row
columns: 3
- External Apps:
style: column
columns: 1
- Home Admin:
style: column
columns: 1
- Home Utilities:
style: column
columns: 1
bookmarks: []
services:
- Media:
- Seerr:
icon: seerr
href: https://seerr.opi5cluster.co.uk/
description: Media Discovery Service
- Jellyfin:
icon: jellyfin
href: https://jellyfin.opi5cluster.co.uk/
description: Media Centre
- qBittorrent:
icon: qbittorrent
href: https://qbittorrent.opi5cluster.co.uk/
description: Torrent Manager
- Sonarr:
icon: sonarr
href: https://sonarr.opi5cluster.co.uk/
description: Series Management
- Radarr:
icon: radarr
href: https://radarr.opi5cluster.co.uk/
description: Movie Management
- Prowlarr:
icon: prowlarr
href: https://prowlarr.opi5cluster.co.uk/
description: Series Management
- Bazarr:
icon: bazarr
href: https://bazarr.opi5cluster.co.uk/
description: Subtitles Management
- Tdarr:
icon: tdarr
href: https://tdarr.opi5cluster.co.uk/
description: Transcode Automation
- Home Lab:
- ArgoCD:
icon: /icons/argocd.svg
href: https://argocd.opi5cluster.co.uk
description: Declarative GitOps CD for Kubernetes
- Argo Workflows:
icon: /icons/argocd.svg
href: https://argo-workflows.opi5cluster.co.uk
description: Workflow Engine for Kubernetes
- Argo Rolleouts:
icon: /icons/argocd.svg
href: https://argo-rollouts.opi5cluster.co.uk
description: Progressive Delivery for Kubernetes
- Istio (Kiali):
icon: istio
href: https://kiali.opi5cluster.co.uk
description: Reverse Proxy
- Longhorn:
icon: /icons/longhorn.svg
href: https://longhorn.opi5cluster.co.uk
description: Distributed Block Storage
- RustFS:
icon: rustfs
href: https://rustfs.opi5cluster.co.uk
description: Object Storage
- RustFS Backup:
icon: rustfs
href: http://backup-raspi3.opi5cluster.co.uk:9001/
description: Object Storage - Backup
- AutoMQ:
icon: kafka-dark
href: https://automq.opi5cluster.co.uk
description: Kafka-Compatible Event Streaming
- Grafana:
icon: /icons/grafana.svg
href: https://grafana.opi5cluster.co.uk
description: Observability
- PG Admin:
icon: pgadmin
href: https://pgadmin.opi5cluster.co.uk/browser/
description: PostgreSQL Management Tool
- OpenWebUi:
icon: open-webui
href: https://open-webui.opi5cluster.co.uk
description: Self-hosted Generative AI Chatbot
- Vault:
icon: vault
href: https://vault.opi5cluster.co.uk
description: Secrets Management
- Zot:
icon: zot-registry
href: https://registry.opi5cluster.co.uk/explore
description: Container Registry
- Velero UI:
icon: velero
href: https://velero.opi5cluster.co.uk
description: K3s Backup Orchestration System
- External Apps:
- Gitlab:
icon: gitlab
href: https://gitlab.com/opi5-cluster
description: Source Control and CI
- Cloudflare:
icon: cloudflare
href: https://dash.cloudflare.com/
description: Connectivity and Content Cloud Provider
- Docker Hub:
icon: docker-moby
href: https://hub.docker.com/
description: Container Registry
- aKeyless:
icon: valkey
href: https://console.akeyless.io/items
description: Secrets Management
- ChatGPT:
icon: chatgpt
href: https://chatgpt.com/
description: Generative AI Chatbot
- Deepseek:
icon: deepseek
href: https://chat.deepseek.com/
description: Generative AI Chatbot
- Claude:
icon: claude-ai
href: https://claude.ai/chat
description: Generative AI Chatbot
- Perplexity:
icon: perplexity
href: https://www.perplexity.ai/
description: Generative AI Chatbot
- Home Admin:
- Glinet Router:
icon: /icons/glinet.svg
href: http://glinet-router.opi5cluster.co.uk
description: Router Glinet
- AdGuardHome(DNS01):
icon: adguard-home
href: http://dns01.opi5cluster.co.uk/
description: Ad blocking and privacy protection software
- AdGuardHome(DNS02):
icon: adguard-home
href: http://dns02.opi5cluster.co.uk/
description: Ad blocking and privacy protection software
- Beacon:
icon: /icons/beacon.svg
href: https://beacon.blocksensus.app
description: Discord Notifications and Events
- WoS-Assistant:
icon: /icons/wos-assistant.svg
href: https://wos-assistant.blocksensus.app
description: WoS Assistant
- Home Utilities:
- Bracknell Council:
icon: /icons/council.svg
href: https://www.bracknell-forest.gov.uk/
description: Bracknell Council
- Octopus Energy:
icon: /icons/octopus-energy.svg
href: https://octopus.energy/dashboard/new/accounts/A-9A8FCFB4/dashboard
description: Energy Provider
- Hyperoptic:
icon: /icons/hyperoptic-broadband.svg
href: https://hyperoptic.com/myaccount-login/
description: Broadband Provider
widgets:
- kubernetes:
cluster:
show: true
cpu: true
memory: true
showLabel: true
label: "cluster"
nodes:
show: true
cpu: true
memory: true
showLabel: true
kubernetes:
mode: cluster templates/configmap.yaml ConfigMap holding non-sensitive application configuration.
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Namespace }}-configmap
namespace: {{ .Release.Namespace }}
data:
bookmarks.yaml: {{- if .Values.config.bookmarks }} |
{{- .Values.config.bookmarks | toYaml | nindent 4}}
{{- else }} ""
{{- end }}
docker.yaml: {{- if .Values.config.docker }} |
{{- .Values.config.docker | toYaml | nindent 4 }}
{{- else }} ""
{{- end }}
kubernetes.yaml: {{- if .Values.config.kubernetes }} |
{{- .Values.config.kubernetes | toYaml | nindent 4 }}
{{- else }} ""
{{- end }}
services.yaml: {{- if .Values.config.services }} |
{{- .Values.config.services | toYaml | nindent 4 }}
{{- else }} ""
{{- end }}
settings.yaml: {{- if .Values.config.settings }} |
{{- .Values.config.settings | toYaml | nindent 4 }}
{{- else }} ""
{{- end }}
widgets.yaml: {{- if .Values.config.widgets }} |
{{- .Values.config.widgets | toYaml | nindent 4 }}
{{- else }} ""
{{- end }} templates/http-route.yaml Gateway API HTTPRoute exposing the service through the Istio gateway under opi5cluster.co.uk.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ .Release.Namespace }}-httproute
namespace: {{ .Release.Namespace }}
annotations:
link.argocd.argoproj.io/external-link: "https://{{ .Release.Namespace }}.opi5cluster.co.uk"
spec:
parentRefs:
- name: istio-gateway
namespace: istio
sectionName: websecure
hostnames:
- {{ .Release.Namespace }}.opi5cluster.co.uk
rules:
- backendRefs:
- name: {{ .Release.Namespace }}-service
port: {{ .Values.ports.http }} templates/rbac.yaml RBAC letting the Homepage service account read cluster state for its service widgets.
---
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: {{ .Release.Namespace }}-service-account-token
namespace: {{ .Release.Namespace }}
annotations:
kubernetes.io/service-account.name: {{ .Release.Namespace }}-service-account
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ .Release.Namespace }}-cluster-role
namespace: {{ .Release.Namespace }}
rules:
- apiGroups:
- ""
resources:
- namespaces
- pods
- nodes
verbs:
- get
- list
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- apiGroups:
- gateway.networking.k8s.io
resources:
- httproutes
verbs:
- get
- list
- apiGroups:
- metrics.k8s.io
resources:
- nodes
- pods
verbs:
- get
- list
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions/status
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ .Release.Namespace }}-cluster-binding
namespace: {{ .Release.Namespace }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ .Release.Namespace }}-cluster-role
subjects:
- kind: ServiceAccount
name: {{ .Release.Namespace }}-service-account
namespace: {{ .Release.Namespace }} templates/rollout.yaml Argo Rollout workload: container spec, probes, resources and rollout strategy.
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: {{ .Release.Namespace }}-rollout
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ .Release.Namespace }}
annotations:
gethomepage.dev/description: Dynamically Detected Homepage
gethomepage.dev/enabled: "true"
gethomepage.dev/group: Cluster Management
gethomepage.dev/icon: homepage.png
gethomepage.dev/name: Homepage
spec:
replicas: 1
strategy:
canary:
steps:
- setWeight: 25
- pause: {duration: 30s}
- setWeight: 50
- pause: {duration: 45s}
- setWeight: 100
selector:
matchLabels:
app: {{ .Release.Namespace }}
template:
metadata:
labels:
app: {{ .Release.Namespace }}
spec:
serviceAccount: {{ .Release.Namespace }}-service-account
serviceAccountName: {{ .Release.Namespace }}-service-account
automountServiceAccountToken: true
#imagePullSecrets:
# - name: {{ .Values.image.imagePullSecretsName }}
containers:
- name: {{ .Release.Namespace }}
image: {{ .Values.image.name }}
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 2000
runAsGroup: 2000
env:
- name: HOMEPAGE_ALLOWED_HOSTS
value: "{{ .Release.Namespace }}.opi5cluster.co.uk"
ports:
- name: {{ .Release.Namespace }}-http
containerPort: {{ .Values.ports.http }}
protocol: TCP
volumeMounts:
- name: {{ .Release.Namespace }}-config
mountPath: {{ .Values.volumeMounts.mountPath }}/settings.yaml
subPath: settings.yaml
- name: {{ .Release.Namespace }}-config
mountPath: {{ .Values.volumeMounts.mountPath }}/services.yaml
subPath: services.yaml
- name: {{ .Release.Namespace }}-config
mountPath: {{ .Values.volumeMounts.mountPath }}/widgets.yaml
subPath: widgets.yaml
- name: {{ .Release.Namespace }}-config
mountPath: {{ .Values.volumeMounts.mountPath }}/bookmarks.yaml
subPath: bookmarks.yaml
- name: {{ .Release.Namespace }}-config
mountPath: {{ .Values.volumeMounts.mountPath }}/kubernetes.yaml
subPath: kubernetes.yaml
- name: {{ .Release.Namespace }}-config
mountPath: {{ .Values.volumeMounts.mountPath }}/docker.yaml
subPath: docker.yaml
{{- with .Values.resources }}
resources:
{{- . | toYaml | nindent 10 }}
{{- end }}
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
volumes:
- name: {{ .Release.Namespace }}-config
configMap:
name: {{ .Release.Namespace }}-configmap templates/service-account.yaml ServiceAccount the workload runs as.
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ .Release.Namespace }}-service-account
namespace: {{ .Release.Namespace }} templates/service.yaml ClusterIP Service fronting the workload.
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Namespace }}-service
namespace: {{ .Release.Namespace }}
spec:
type: ClusterIP
selector:
app: {{ .Release.Namespace }}
ipFamilyPolicy: SingleStack
ports:
- name: {{ .Release.Namespace }}-http
protocol: TCP
port: {{ .Values.ports.http }}
targetPort: {{ .Values.ports.http }} Decision. autoSync on
Alternative. Manual sync
Why. Dashboard config is pure YAML with no runtime state; auto-applying keeps the pane accurate after every Git change with zero risk.