summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-12-05 20:08:44 +0200
committerPaul Buetow <paul@buetow.org>2025-12-05 20:08:44 +0200
commit29acdda547254c0f96f62723be6300ebb1e2ca53 (patch)
treef5346f06a31b336fdf9fd9bbc40d12691c7cadef
parent54d3d740eb82bc62e4c56976ba18f5d0609e0195 (diff)
Add keybr.com typing tutor deployment
Amp-Thread-ID: https://ampcode.com/threads/T-ccf9cd44-5adf-4633-9f3d-d822f733af4d Co-authored-by: Amp <amp@ampcode.com>
-rw-r--r--f3s/keybr/Justfile16
-rw-r--r--f3s/keybr/README.md68
-rw-r--r--f3s/keybr/helm-chart/Chart.yaml5
-rw-r--r--f3s/keybr/helm-chart/templates/deployment.yaml46
-rw-r--r--f3s/keybr/helm-chart/templates/ingress.yaml20
-rw-r--r--f3s/keybr/helm-chart/templates/persistent-volume.yaml27
-rw-r--r--f3s/keybr/helm-chart/templates/service.yaml15
7 files changed, 197 insertions, 0 deletions
diff --git a/f3s/keybr/Justfile b/f3s/keybr/Justfile
new file mode 100644
index 0000000..f34f44f
--- /dev/null
+++ b/f3s/keybr/Justfile
@@ -0,0 +1,16 @@
+NAMESPACE := "services"
+RELEASE_NAME := "keybr"
+CHART_PATH := "./helm-chart"
+
+install:
+ helm install {{RELEASE_NAME}} {{CHART_PATH}} --namespace {{NAMESPACE}} --create-namespace
+
+upgrade:
+ helm upgrade {{RELEASE_NAME}} {{CHART_PATH}} --namespace {{NAMESPACE}}
+
+delete:
+ helm uninstall {{RELEASE_NAME}} --namespace {{NAMESPACE}}
+ kubectl delete pvc keybr-data-pvc -n {{NAMESPACE}} --ignore-not-found
+ kubectl delete pv keybr-data-pv --ignore-not-found
+
+deinstall: delete
diff --git a/f3s/keybr/README.md b/f3s/keybr/README.md
new file mode 100644
index 0000000..18492f9
--- /dev/null
+++ b/f3s/keybr/README.md
@@ -0,0 +1,68 @@
+# keybr.com
+
+Self-hosted deployment of [keybr.com](https://github.com/aradzie/keybr.com) - a typing tutor.
+
+## Prerequisites
+
+Before deploying, create the persistent volume directory on the k3s node:
+
+```bash
+mkdir -p /data/nfs/k3svolumes/keybr/data
+```
+
+## Deploy
+
+```bash
+just install
+```
+
+## Upgrade
+
+```bash
+just upgrade
+```
+
+## Remove
+
+```bash
+just delete
+```
+
+## Access
+
+http://keybr.f3s.buetow.org
+
+## Backup Progress (Anonymous Mode)
+
+In anonymous mode, keybr stores your progress in the browser's IndexedDB.
+
+### Option 1: Built-in Export
+
+1. Go to the **Profile** page on keybr
+2. Click the **Download** button to export your stats as a file
+
+### Option 2: Manual IndexedDB Export (Firefox)
+
+1. Open keybr in Firefox
+2. Press `F12` to open Developer Tools
+3. Go to **Storage** tab → **Indexed DB** → expand the site URL
+4. Find the `history` database with your results
+
+To export via Console (`F12` → Console):
+
+```javascript
+let request = indexedDB.open('history');
+request.onsuccess = () => {
+ let db = request.result;
+ let tx = db.transaction('results', 'readonly');
+ let store = tx.objectStore('results');
+ let getAll = store.getAll();
+ getAll.onsuccess = () => {
+ let blob = new Blob([JSON.stringify(getAll.result)], {type: 'application/json'});
+ let a = document.createElement('a');
+ a.href = URL.createObjectURL(blob);
+ a.download = 'keybr-backup.json';
+ a.click();
+ };
+};
+```
diff --git a/f3s/keybr/helm-chart/Chart.yaml b/f3s/keybr/helm-chart/Chart.yaml
new file mode 100644
index 0000000..7d6285d
--- /dev/null
+++ b/f3s/keybr/helm-chart/Chart.yaml
@@ -0,0 +1,5 @@
+apiVersion: v2
+name: keybr
+description: A Helm chart for deploying keybr.com typing tutor.
+version: 0.1.0
+appVersion: "latest"
diff --git a/f3s/keybr/helm-chart/templates/deployment.yaml b/f3s/keybr/helm-chart/templates/deployment.yaml
new file mode 100644
index 0000000..be29aeb
--- /dev/null
+++ b/f3s/keybr/helm-chart/templates/deployment.yaml
@@ -0,0 +1,46 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: keybr
+ namespace: services
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: keybr
+ template:
+ metadata:
+ labels:
+ app: keybr
+ spec:
+ securityContext:
+ runAsUser: 1000
+ runAsGroup: 1000
+ fsGroup: 1000
+ containers:
+ - name: keybr
+ image: ryanrhymes/keybr:latest
+ securityContext:
+ allowPrivilegeEscalation: false
+ ports:
+ - containerPort: 3000
+ env:
+ - name: APP_URL
+ value: "http://keybr.f3s.buetow.org/"
+ - name: COOKIE_DOMAIN
+ value: "keybr.f3s.buetow.org"
+ - name: COOKIE_SECURE
+ value: "false"
+ - name: DATA_DIR
+ value: "/data"
+ - name: DATABASE_CLIENT
+ value: "sqlite"
+ - name: DATABASE_FILENAME
+ value: "/data/database.sqlite"
+ volumeMounts:
+ - name: keybr-data
+ mountPath: /data
+ volumes:
+ - name: keybr-data
+ persistentVolumeClaim:
+ claimName: keybr-data-pvc
diff --git a/f3s/keybr/helm-chart/templates/ingress.yaml b/f3s/keybr/helm-chart/templates/ingress.yaml
new file mode 100644
index 0000000..05cfe16
--- /dev/null
+++ b/f3s/keybr/helm-chart/templates/ingress.yaml
@@ -0,0 +1,20 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: keybr-ingress
+ namespace: services
+ annotations:
+ spec.ingressClassName: traefik
+ traefik.ingress.kubernetes.io/router.entrypoints: web
+spec:
+ rules:
+ - host: keybr.f3s.buetow.org
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: keybr-service
+ port:
+ number: 3000
diff --git a/f3s/keybr/helm-chart/templates/persistent-volume.yaml b/f3s/keybr/helm-chart/templates/persistent-volume.yaml
new file mode 100644
index 0000000..c3960a2
--- /dev/null
+++ b/f3s/keybr/helm-chart/templates/persistent-volume.yaml
@@ -0,0 +1,27 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: keybr-data-pv
+spec:
+ capacity:
+ storage: 1Gi
+ volumeMode: Filesystem
+ accessModes:
+ - ReadWriteOnce
+ persistentVolumeReclaimPolicy: Retain
+ hostPath:
+ path: /data/nfs/k3svolumes/keybr/data
+ type: Directory
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: keybr-data-pvc
+ namespace: services
+spec:
+ storageClassName: ""
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
diff --git a/f3s/keybr/helm-chart/templates/service.yaml b/f3s/keybr/helm-chart/templates/service.yaml
new file mode 100644
index 0000000..021dd6f
--- /dev/null
+++ b/f3s/keybr/helm-chart/templates/service.yaml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ app: keybr
+ name: keybr-service
+ namespace: services
+spec:
+ ports:
+ - name: web
+ port: 3000
+ protocol: TCP
+ targetPort: 3000
+ selector:
+ app: keybr