Documentation Index Fetch the complete documentation index at: https://mintlify.com/homarr-labs/homarr/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Deploying Homarr on Kubernetes provides high availability, automatic scaling, and robust orchestration capabilities. This guide covers various deployment strategies from simple single-instance setups to production-grade highly available configurations.
Homarr supports Kubernetes deployments with features like external Redis and database support for distributed caching and data persistence.
Prerequisites
Kubernetes cluster 1.20+ (Minikube, k3s, EKS, GKE, AKS, etc.)
kubectl configured to access your cluster
Basic understanding of Kubernetes concepts (Pods, Services, Deployments)
Optional: Helm 3+ for easier deployment
Architecture
A typical Homarr Kubernetes deployment consists of:
Basic Deployment
Simple Single Pod Deployment
Create homarr-deployment.yaml:
apiVersion : v1
kind : Namespace
metadata :
name : homarr
---
apiVersion : v1
kind : Secret
metadata :
name : homarr-secrets
namespace : homarr
type : Opaque
stringData :
secret-encryption-key : "0000000000000000000000000000000000000000000000000000000000000000"
---
apiVersion : v1
kind : PersistentVolumeClaim
metadata :
name : homarr-data
namespace : homarr
spec :
accessModes :
- ReadWriteOnce
resources :
requests :
storage : 5Gi
---
apiVersion : apps/v1
kind : Deployment
metadata :
name : homarr
namespace : homarr
labels :
app : homarr
spec :
replicas : 1
selector :
matchLabels :
app : homarr
template :
metadata :
labels :
app : homarr
spec :
containers :
- name : homarr
image : ghcr.io/homarr-labs/homarr:latest
ports :
- containerPort : 7575
name : http
env :
- name : SECRET_ENCRYPTION_KEY
valueFrom :
secretKeyRef :
name : homarr-secrets
key : secret-encryption-key
- name : LOG_LEVEL
value : "info"
- name : DB_DRIVER
value : "better-sqlite3"
- name : DB_URL
value : "/appdata/db/db.sqlite"
volumeMounts :
- name : data
mountPath : /appdata
resources :
requests :
memory : "512Mi"
cpu : "250m"
limits :
memory : "1Gi"
cpu : "1000m"
livenessProbe :
httpGet :
path : /
port : 7575
initialDelaySeconds : 60
periodSeconds : 10
readinessProbe :
httpGet :
path : /
port : 7575
initialDelaySeconds : 30
periodSeconds : 5
volumes :
- name : data
persistentVolumeClaim :
claimName : homarr-data
---
apiVersion : v1
kind : Service
metadata :
name : homarr
namespace : homarr
labels :
app : homarr
spec :
type : ClusterIP
ports :
- port : 7575
targetPort : 7575
protocol : TCP
name : http
selector :
app : homarr
Deploy:
kubectl apply -f homarr-deployment.yaml
Replace the secret-encryption-key with a real 64-character hex string generated by openssl rand -hex 32.
Expose with Ingress
Create homarr-ingress.yaml:
apiVersion : networking.k8s.io/v1
kind : Ingress
metadata :
name : homarr
namespace : homarr
annotations :
cert-manager.io/cluster-issuer : "letsencrypt-prod"
nginx.ingress.kubernetes.io/proxy-body-size : "32m"
nginx.ingress.kubernetes.io/websocket-services : "homarr"
nginx.ingress.kubernetes.io/proxy-read-timeout : "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout : "3600"
spec :
ingressClassName : nginx
tls :
- hosts :
- homarr.example.com
secretName : homarr-tls
rules :
- host : homarr.example.com
http :
paths :
- path : /
pathType : Prefix
backend :
service :
name : homarr
port :
number : 7575
Apply:
kubectl apply -f homarr-ingress.yaml
Production Deployment with PostgreSQL
For production, use an external database like PostgreSQL:
apiVersion : v1
kind : Namespace
metadata :
name : homarr
---
apiVersion : v1
kind : Secret
metadata :
name : homarr-secrets
namespace : homarr
type : Opaque
stringData :
secret-encryption-key : "your-64-character-hex-string"
db-password : "secure-database-password"
---
apiVersion : v1
kind : ConfigMap
metadata :
name : homarr-config
namespace : homarr
data :
LOG_LEVEL : "info"
DB_DRIVER : "node-postgres"
REDIS_IS_EXTERNAL : "true"
REDIS_HOST : "redis"
REDIS_PORT : "6379"
---
apiVersion : apps/v1
kind : StatefulSet
metadata :
name : postgres
namespace : homarr
spec :
serviceName : postgres
replicas : 1
selector :
matchLabels :
app : postgres
template :
metadata :
labels :
app : postgres
spec :
containers :
- name : postgres
image : postgres:16-alpine
ports :
- containerPort : 5432
name : postgres
env :
- name : POSTGRES_USER
value : homarr
- name : POSTGRES_PASSWORD
valueFrom :
secretKeyRef :
name : homarr-secrets
key : db-password
- name : POSTGRES_DB
value : homarrdb
- name : PGDATA
value : /var/lib/postgresql/data/pgdata
volumeMounts :
- name : postgres-data
mountPath : /var/lib/postgresql/data
resources :
requests :
memory : "256Mi"
cpu : "250m"
limits :
memory : "1Gi"
cpu : "1000m"
volumeClaimTemplates :
- metadata :
name : postgres-data
spec :
accessModes : [ "ReadWriteOnce" ]
resources :
requests :
storage : 10Gi
---
apiVersion : v1
kind : Service
metadata :
name : postgres
namespace : homarr
spec :
clusterIP : None
ports :
- port : 5432
targetPort : 5432
selector :
app : postgres
---
apiVersion : apps/v1
kind : StatefulSet
metadata :
name : redis
namespace : homarr
spec :
serviceName : redis
replicas : 1
selector :
matchLabels :
app : redis
template :
metadata :
labels :
app : redis
spec :
containers :
- name : redis
image : redis:7-alpine
command : [ "redis-server" , "--appendonly" , "yes" ]
ports :
- containerPort : 6379
name : redis
volumeMounts :
- name : redis-data
mountPath : /data
resources :
requests :
memory : "128Mi"
cpu : "100m"
limits :
memory : "512Mi"
cpu : "500m"
volumeClaimTemplates :
- metadata :
name : redis-data
spec :
accessModes : [ "ReadWriteOnce" ]
resources :
requests :
storage : 1Gi
---
apiVersion : v1
kind : Service
metadata :
name : redis
namespace : homarr
spec :
clusterIP : None
ports :
- port : 6379
targetPort : 6379
selector :
app : redis
---
apiVersion : v1
kind : PersistentVolumeClaim
metadata :
name : homarr-data
namespace : homarr
spec :
accessModes :
- ReadWriteMany # Use ReadWriteMany for multiple replicas
resources :
requests :
storage : 5Gi
---
apiVersion : apps/v1
kind : Deployment
metadata :
name : homarr
namespace : homarr
labels :
app : homarr
spec :
replicas : 2
strategy :
type : RollingUpdate
rollingUpdate :
maxSurge : 1
maxUnavailable : 0
selector :
matchLabels :
app : homarr
template :
metadata :
labels :
app : homarr
spec :
containers :
- name : homarr
image : ghcr.io/homarr-labs/homarr:latest
ports :
- containerPort : 7575
name : http
env :
- name : SECRET_ENCRYPTION_KEY
valueFrom :
secretKeyRef :
name : homarr-secrets
key : secret-encryption-key
- name : DB_URL
value : "postgres://homarr:$(DB_PASSWORD)@postgres:5432/homarrdb"
- name : DB_PASSWORD
valueFrom :
secretKeyRef :
name : homarr-secrets
key : db-password
envFrom :
- configMapRef :
name : homarr-config
volumeMounts :
- name : data
mountPath : /appdata
resources :
requests :
memory : "512Mi"
cpu : "250m"
limits :
memory : "2Gi"
cpu : "2000m"
livenessProbe :
httpGet :
path : /
port : 7575
initialDelaySeconds : 60
periodSeconds : 10
timeoutSeconds : 5
failureThreshold : 3
readinessProbe :
httpGet :
path : /
port : 7575
initialDelaySeconds : 30
periodSeconds : 5
timeoutSeconds : 3
failureThreshold : 3
volumes :
- name : data
persistentVolumeClaim :
claimName : homarr-data
---
apiVersion : v1
kind : Service
metadata :
name : homarr
namespace : homarr
labels :
app : homarr
spec :
type : ClusterIP
ports :
- port : 7575
targetPort : 7575
protocol : TCP
name : http
selector :
app : homarr
Kubernetes Features
Horizontal Pod Autoscaling
Create homarr-hpa.yaml:
apiVersion : autoscaling/v2
kind : HorizontalPodAutoscaler
metadata :
name : homarr
namespace : homarr
spec :
scaleTargetRef :
apiVersion : apps/v1
kind : Deployment
name : homarr
minReplicas : 2
maxReplicas : 10
metrics :
- type : Resource
resource :
name : cpu
target :
type : Utilization
averageUtilization : 70
- type : Resource
resource :
name : memory
target :
type : Utilization
averageUtilization : 80
Pod Disruption Budget
Ensure availability during maintenance:
apiVersion : policy/v1
kind : PodDisruptionBudget
metadata :
name : homarr
namespace : homarr
spec :
minAvailable : 1
selector :
matchLabels :
app : homarr
Network Policies
Restrict network access:
homarr-networkpolicy.yaml
apiVersion : networking.k8s.io/v1
kind : NetworkPolicy
metadata :
name : homarr
namespace : homarr
spec :
podSelector :
matchLabels :
app : homarr
policyTypes :
- Ingress
- Egress
ingress :
- from :
- namespaceSelector :
matchLabels :
name : ingress-nginx
ports :
- protocol : TCP
port : 7575
egress :
- to :
- podSelector :
matchLabels :
app : postgres
ports :
- protocol : TCP
port : 5432
- to :
- podSelector :
matchLabels :
app : redis
ports :
- protocol : TCP
port : 6379
- to :
- namespaceSelector : {}
ports :
- protocol : TCP
port : 53
- protocol : UDP
port : 53
Monitoring and Observability
Add Prometheus Annotations
metadata :
annotations :
prometheus.io/scrape : "true"
prometheus.io/port : "7575"
prometheus.io/path : "/metrics"
Create ServiceMonitor (for Prometheus Operator)
homarr-servicemonitor.yaml
apiVersion : monitoring.coreos.com/v1
kind : ServiceMonitor
metadata :
name : homarr
namespace : homarr
spec :
selector :
matchLabels :
app : homarr
endpoints :
- port : http
interval : 30s
Management Commands
View Resources
# List all resources in homarr namespace
kubectl get all -n homarr
# Get pod details
kubectl describe pod -n homarr -l app=homarr
# View logs
kubectl logs -n homarr -l app=homarr -f
Scale Deployment
# Scale to 3 replicas
kubectl scale deployment homarr -n homarr --replicas=3
# View scaling status
kubectl get pods -n homarr -w
Update Configuration
# Edit ConfigMap
kubectl edit configmap homarr-config -n homarr
# Restart pods to pick up changes
kubectl rollout restart deployment homarr -n homarr
Access Homarr CLI
# Get pod name
POD = $( kubectl get pod -n homarr -l app=homarr -o jsonpath="{.items[0].metadata.name}" )
# Run CLI command
kubectl exec -n homarr $POD -- homarr --help
# Reset password
kubectl exec -n homarr $POD -- homarr reset-password admin
Backup and Restore
Backup Strategy
Create a CronJob for automated backups:
homarr-backup-cronjob.yaml
apiVersion : batch/v1
kind : CronJob
metadata :
name : homarr-backup
namespace : homarr
spec :
schedule : "0 2 * * *" # Daily at 2 AM
jobTemplate :
spec :
template :
spec :
containers :
- name : backup
image : postgres:16-alpine
command :
- /bin/sh
- -c
- |
pg_dump -h postgres -U homarr homarrdb | \
gzip > /backup/homarr-$(date +%Y%m%d-%H%M%S).sql.gz
env :
- name : PGPASSWORD
valueFrom :
secretKeyRef :
name : homarr-secrets
key : db-password
volumeMounts :
- name : backup
mountPath : /backup
restartPolicy : OnFailure
volumes :
- name : backup
persistentVolumeClaim :
claimName : homarr-backup
Manual Backup
# Backup PostgreSQL database
kubectl exec -n homarr postgres-0 -- \
pg_dump -U homarr homarrdb | \
gzip > homarr-backup- $( date +%Y%m%d ) .sql.gz
# Backup PVC data
kubectl cp homarr/ < pod-nam e > :/appdata ./homarr-data-backup
Restore from Backup
# Restore PostgreSQL database
gunzip -c homarr-backup-20240101.sql.gz | \
kubectl exec -i -n homarr postgres-0 -- \
psql -U homarr homarrdb
# Restore PVC data
kubectl cp ./homarr-data-backup homarr/ < pod-nam e > :/appdata
Troubleshooting
Pods Not Starting
# Check pod status
kubectl get pods -n homarr
# Describe pod for events
kubectl describe pod -n homarr < pod-nam e >
# Check logs
kubectl logs -n homarr < pod-nam e >
Database Connection Issues
# Test database connectivity
kubectl run -it --rm debug --image=postgres:16-alpine --restart=Never -n homarr -- \
psql -h postgres -U homarr -d homarrdb
# Check service endpoints
kubectl get endpoints -n homarr postgres
PVC Not Mounting
# Check PVC status
kubectl get pvc -n homarr
# Describe PVC
kubectl describe pvc -n homarr homarr-data
# Check storage class
kubectl get storageclass
Best Practices
Use external databases - Don’t run SQLite with multiple replicas
Enable external Redis - Required for distributed caching across pods
Set resource limits - Prevent resource exhaustion
Use ReadWriteMany PVCs - When running multiple replicas with shared storage
Implement health checks - Ensure automatic recovery from failures
Use ConfigMaps and Secrets - Separate configuration from code
Enable autoscaling - Handle varying load automatically
Implement PodDisruptionBudgets - Maintain availability during updates
Regular backups - Automate database and volume backups
Monitor metrics - Use Prometheus and Grafana for observability
Next Steps
Environment Variables Configure environment variables
Authentication Set up authentication providers
Backup & Restore Backup your Kubernetes deployment
Troubleshooting Common Kubernetes issues