diff options
| author | Paul Buetow <paul@buetow.org> | 2025-11-21 18:27:06 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-11-21 18:27:06 +0200 |
| commit | a8695edcd9c36fff8452948834e819af4e965d21 (patch) | |
| tree | 8b56d39f5ce9021c1af9d20cc259a72bf0c4d7ff | |
| parent | 254bbeb7990df9d5c55cac3ce8eca1c33e7420fe (diff) | |
initial filerise
| -rw-r--r-- | f3s/filerise/Justfile | 14 | ||||
| -rw-r--r-- | f3s/filerise/README.md | 69 | ||||
| -rw-r--r-- | f3s/filerise/helm-chart/Chart.yaml | 5 | ||||
| -rw-r--r-- | f3s/filerise/helm-chart/templates/configmap.yaml | 199 | ||||
| -rw-r--r-- | f3s/filerise/helm-chart/templates/deployment.yaml | 110 | ||||
| -rw-r--r-- | f3s/filerise/helm-chart/templates/ingress.yaml | 20 | ||||
| -rw-r--r-- | f3s/filerise/helm-chart/templates/persistent-volume.yaml | 111 | ||||
| -rw-r--r-- | f3s/filerise/helm-chart/templates/service.yaml | 15 | ||||
| -rw-r--r-- | frontends/Rexfile | 2 |
9 files changed, 544 insertions, 1 deletions
diff --git a/f3s/filerise/Justfile b/f3s/filerise/Justfile new file mode 100644 index 0000000..3a3a41b --- /dev/null +++ b/f3s/filerise/Justfile @@ -0,0 +1,14 @@ +NAMESPACE := "services" +RELEASE_NAME := "filerise" +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}} + +deinstall: delete diff --git a/f3s/filerise/README.md b/f3s/filerise/README.md new file mode 100644 index 0000000..c48a53a --- /dev/null +++ b/f3s/filerise/README.md @@ -0,0 +1,69 @@ + +# FileRise Kubernetes Deployment + +This directory contains the Kubernetes configuration for deploying FileRise to a k3s cluster. + +## Deployment + +To deploy FileRise, use the Justfile commands: + +```bash +just install +``` + +## Prerequisites + +Before deploying, ensure the following are set up: + +### 1. Create Persistent Volume Directories + +The deployment requires three persistent volumes. Create the directories on the k3s node: + +```bash +mkdir -p /data/nfs/k3svolumes/filerise/uploads +mkdir -p /data/nfs/k3svolumes/filerise/users +mkdir -p /data/nfs/k3svolumes/filerise/metadata +mkdir -p /data/nfs/k3svolumes/filerise/config +chown -R 1000:1000 /data/nfs/k3svolumes/filerise/ +chmod -R 775 /data/nfs/k3svolumes/filerise/ +``` + +### 2. Create the Secret + +FileRise uses a Kubernetes secret to manage the `PERSISTENT_TOKENS_KEY` environment variable. This secret is not included in the repository for security reasons. You must create it manually in the `services` namespace. + +Create the secret with the following command: + +```bash +kubectl create secret generic filerise-secret --from-literal=PERSISTENT_TOKENS_KEY='your_random_secure_key_here' -n services +``` + +Replace `your_random_secure_key_here` with a strong random string. + +### Updating the Secret + +To update the secret, you can delete and recreate it, or use `kubectl edit`: + +```bash +kubectl edit secret filerise-secret -n services +``` + +## Configuration + +FileRise will be accessible at: `http://filerise.f3s.buetow.org` + +On first launch, you'll be guided through creating the initial admin user. + +## Storage + +The deployment uses four persistent volumes: +- **uploads** (50Gi): Stores uploaded files +- **users** (1Gi): Stores user data and configurations +- **metadata** (5Gi): Stores file metadata and database +- **config** (1Gi): Stores application configuration files + +## Justfile Commands + +- `just install` - Install FileRise using Helm +- `just upgrade` - Upgrade the FileRise deployment +- `just delete` - Uninstall FileRise from the cluster diff --git a/f3s/filerise/helm-chart/Chart.yaml b/f3s/filerise/helm-chart/Chart.yaml new file mode 100644 index 0000000..17863c9 --- /dev/null +++ b/f3s/filerise/helm-chart/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: filerise +description: A Helm chart for deploying FileRise file manager. +version: 0.1.0 +appVersion: "latest" diff --git a/f3s/filerise/helm-chart/templates/configmap.yaml b/f3s/filerise/helm-chart/templates/configmap.yaml new file mode 100644 index 0000000..bd901cb --- /dev/null +++ b/f3s/filerise/helm-chart/templates/configmap.yaml @@ -0,0 +1,199 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: filerise-start-script + namespace: services +data: + start.sh: | + #!/bin/bash + set -euo pipefail + umask 002 + echo "π Running start.sh..." + + # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ + # 0) If NOT root, we can't remap/chown. Log a hint and skip those parts. + # If root, remap www-data to PUID/PGID and (optionally) chown data dirs. + if [ "$(id -u)" -ne 0 ]; then + echo "[startup] Running as non-root. Skipping PUID/PGID remap and chown." + echo "[startup] Tip: remove '--user' and set PUID/PGID env vars instead." + else + # Remap www-data to match provided PUID/PGID (e.g., Unraid 99:100 or 1000:1000) + if [ -n "${PGID:-}" ]; then + current_gid="$(getent group www-data | cut -d: -f3 || true)" + if [ "${current_gid}" != "${PGID}" ]; then + groupmod -o -g "${PGID}" www-data || true + fi + fi + if [ -n "${PUID:-}" ]; then + current_uid="$(id -u www-data 2>/dev/null || echo '')" + target_gid="${PGID:-$(getent group www-data | cut -d: -f3)}" + if [ "${current_uid}" != "${PUID}" ]; then + usermod -o -u "${PUID}" -g "${target_gid}" www-data || true + fi + fi + + # Optional: normalize ownership on data dirs (good for first run on existing shares) + if [ "${CHOWN_ON_START:-true}" = "true" ]; then + echo "[startup] Normalizing ownership on uploads/metadata..." + chown -R www-data:www-data /var/www/metadata /var/www/uploads || echo "[startup] chown failed (continuing)" + chmod -R u+rwX /var/www/metadata /var/www/uploads || echo "[startup] chmod failed (continuing)" + fi + fi + + # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ + # 1) Tokenβkey warning (guarded for -u) + if [ "${PERSISTENT_TOKENS_KEY:-}" = "default_please_change_this_key" ] || [ -z "${PERSISTENT_TOKENS_KEY:-}" ]; then + echo "β οΈ WARNING: Using default/empty persistent tokens keyβoverride for production." + fi + + # 2) Update config.php based on environment variables + CONFIG_FILE="/var/www/config/config.php" + if [ -f "${CONFIG_FILE}" ]; then + echo "π Updating config.php from env vars..." + [ -n "${TIMEZONE:-}" ] && sed -i "s|define('TIMEZONE',[[:space:]]*'[^']*');|define('TIMEZONE', '${TIMEZONE}');|" "${CONFIG_FILE}" + [ -n "${DATE_TIME_FORMAT:-}" ] && sed -i "s|define('DATE_TIME_FORMAT',[[:space:]]*'[^']*');|define('DATE_TIME_FORMAT', '${DATE_TIME_FORMAT}');|" "${CONFIG_FILE}" + if [ -n "${TOTAL_UPLOAD_SIZE:-}" ]; then + sed -i "s|define('TOTAL_UPLOAD_SIZE',[[:space:]]*'[^']*');|define('TOTAL_UPLOAD_SIZE', '${TOTAL_UPLOAD_SIZE}');|" "${CONFIG_FILE}" + fi + [ -n "${SECURE:-}" ] && sed -i "s|\$envSecure = getenv('SECURE');|\$envSecure = '${SECURE}';|" "${CONFIG_FILE}" + # NOTE: SHARE_URL is read from getenv in PHP; no sed needed. + fi + + # 2.1) Prepare metadata/log & sessions (skip chown if non-root) + mkdir -p /var/www/metadata/log + if [ "$(id -u)" -eq 0 ]; then + chown www-data:www-data /var/www/metadata/log || true + chmod 775 /var/www/metadata/log || true + fi + : > /var/www/metadata/log/error.log || true + : > /var/www/metadata/log/access.log || true + if [ "$(id -u)" -eq 0 ]; then + chown www-data:www-data /var/www/metadata/log/*.log || true + fi + + mkdir -p /var/www/sessions + if [ "$(id -u)" -eq 0 ]; then + chown www-data:www-data /var/www/sessions || true + chmod 700 /var/www/sessions || true + else + chmod 700 /var/www/sessions || true + fi + + # 2.2) Prepare dynamic dirs (uploads/users/metadata) + for d in uploads users metadata; do + tgt="/var/www/${d}" + mkdir -p "${tgt}" + if [ "$(id -u)" -eq 0 ]; then + chown www-data:www-data "${tgt}" || true + chmod 775 "${tgt}" || true + else + chmod 775 "${tgt}" || true + fi + done + + # 3) Ensure PHP conf dir & set upload limits + mkdir -p /etc/php/8.3/apache2/conf.d + if [ -n "${TOTAL_UPLOAD_SIZE:-}" ]; then + echo "π Setting PHP upload limits to ${TOTAL_UPLOAD_SIZE}" + cat > /etc/php/8.3/apache2/conf.d/99-custom.ini <<EOF + upload_max_filesize = ${TOTAL_UPLOAD_SIZE} + post_max_size = ${TOTAL_UPLOAD_SIZE} + EOF + fi + + # 4) Adjust Apache LimitRequestBody + if [ -n "${TOTAL_UPLOAD_SIZE:-}" ]; then + size_str="$(echo "${TOTAL_UPLOAD_SIZE}" | tr '[:upper:]' '[:lower:]')" + case "${size_str: -1}" in + g) factor=$((1024*1024*1024)); num=${size_str%g} ;; + m) factor=$((1024*1024)); num=${size_str%m} ;; + k) factor=1024; num=${size_str%k} ;; + *) factor=1; num=${size_str} ;; + esac + LIMIT_REQUEST_BODY=$(( num * factor )) + echo "π Setting Apache LimitRequestBody to ${LIMIT_REQUEST_BODY} bytes" + cat > /etc/apache2/conf-enabled/limit_request_body.conf <<EOF + <Directory "/var/www/public"> + LimitRequestBody ${LIMIT_REQUEST_BODY} + </Directory> + EOF + fi + + # 5) Configure Apache timeout (600s) + cat > /etc/apache2/conf-enabled/timeout.conf <<EOF + Timeout 600 + EOF + + # 6) Override ports if provided + if [ -n "${HTTP_PORT:-}" ]; then + sed -i "s/^Listen 80$/Listen ${HTTP_PORT}/" /etc/apache2/ports.conf || true + sed -i "s/<VirtualHost \*:80>/<VirtualHost *:${HTTP_PORT}>/" /etc/apache2/sites-available/000-default.conf || true + fi + if [ -n "${HTTPS_PORT:-}" ]; then + sed -i "s/^Listen 443$/Listen ${HTTPS_PORT}/" /etc/apache2/ports.conf || true + fi + + # 7) Set ServerName (idempotent) + SN="${SERVER_NAME:-FileRise}" + if grep -qE '^ServerName\s' /etc/apache2/apache2.conf; then + sed -i "s|^ServerName .*|ServerName ${SN}|" /etc/apache2/apache2.conf + else + echo "ServerName ${SN}" >> /etc/apache2/apache2.conf + fi + + # 8) Initialize persistent files if absent + if [ ! -f /var/www/users/users.txt ]; then + echo "" > /var/www/users/users.txt + if [ "$(id -u)" -eq 0 ]; then + chown www-data:www-data /var/www/users/users.txt || true + chmod 664 /var/www/users/users.txt || true + else + chmod 664 /var/www/users/users.txt || true + fi + fi + + if [ ! -f /var/www/metadata/createdTags.json ]; then + echo "[]" > /var/www/metadata/createdTags.json + if [ "$(id -u)" -eq 0 ]; then + chown www-data:www-data /var/www/metadata/createdTags.json || true + chmod 664 /var/www/metadata/createdTags.json || true + else + chmod 664 /var/www/metadata/createdTags.json || true + fi + fi + + # 8.5) Harden scan script perms (only if root) + if [ -f /var/www/scripts/scan_uploads.php ] && [ "$(id -u)" -eq 0 ]; then + chown root:root /var/www/scripts/scan_uploads.php + chmod 0644 /var/www/scripts/scan_uploads.php + fi + + # 9) One-shot scan when the container starts (opt-in via SCAN_ON_START) + if [ "${SCAN_ON_START:-}" = "true" ]; then + echo "[startup] Scanning uploads directory to build metadata..." + if [ "$(id -u)" -eq 0 ]; then + if command -v runuser >/dev/null 2>&1; then + runuser -u www-data -- /usr/bin/php /var/www/scripts/scan_uploads.php || echo "[startup] Scan failed (continuing)" + else + su -s /bin/sh -c "/usr/bin/php /var/www/scripts/scan_uploads.php" www-data || echo "[startup] Scan failed (continuing)" + fi + else + # Non-root fallback: run as current user (permissions may limit writes) + /usr/bin/php /var/www/scripts/scan_uploads.php || echo "[startup] Scan failed (continuing)" + fi + fi + + # 9.6) Stream Apache logs to the container console (optional toggle) + LOG_STREAM="${LOG_STREAM:-error}" + case "${LOG_STREAM,,}" in + none) STREAM_ERR=false; STREAM_ACC=false ;; + access) STREAM_ERR=false; STREAM_ACC=true ;; + both) STREAM_ERR=true; STREAM_ACC=true ;; + error|*)STREAM_ERR=true; STREAM_ACC=false ;; + esac + + echo "π₯ Starting Apache..." + # Stream only the chosen logs; -n0 = don't dump history, -F = follow across rotations/creation + [ "${STREAM_ERR}" = "true" ] && tail -n0 -F /var/www/metadata/log/error.log 2>/dev/null & + [ "${STREAM_ACC}" = "true" ] && tail -n0 -F /var/www/metadata/log/access.log 2>/dev/null & + exec apachectl -D FOREGROUND diff --git a/f3s/filerise/helm-chart/templates/deployment.yaml b/f3s/filerise/helm-chart/templates/deployment.yaml new file mode 100644 index 0000000..db0990b --- /dev/null +++ b/f3s/filerise/helm-chart/templates/deployment.yaml @@ -0,0 +1,110 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: filerise + namespace: services +spec: + replicas: 1 + selector: + matchLabels: + app: filerise + template: + metadata: + labels: + app: filerise + spec: + securityContext: + fsGroup: 1000 + initContainers: + - name: setup-directories + image: busybox:latest + command: + - sh + - -c + - | + mkdir -p /var/www/metadata/log + mkdir -p /var/www/uploads + mkdir -p /var/www/users + mkdir -p /var/www/config + mkdir -p /var/www/sessions + touch /var/www/metadata/log/error.log + touch /var/www/metadata/log/access.log + touch /var/www/users/users.txt + echo "[]" > /var/www/metadata/createdTags.json + chown -R 1000:1000 /var/www/metadata /var/www/uploads /var/www/users /var/www/config /var/www/sessions + chmod -R 775 /var/www/metadata /var/www/uploads /var/www/users /var/www/config + chmod 700 /var/www/sessions + chmod 664 /var/www/users/users.txt + chmod 664 /var/www/metadata/createdTags.json + volumeMounts: + - name: filerise-uploads + mountPath: /var/www/uploads + - name: filerise-users + mountPath: /var/www/users + - name: filerise-metadata + mountPath: /var/www/metadata + - name: filerise-config + mountPath: /var/www/config + - name: filerise-sessions + mountPath: /var/www/sessions + containers: + - name: filerise + image: error311/filerise-docker:latest + command: ["/bin/bash", "/usr/local/bin/start-override.sh"] + ports: + - containerPort: 80 + env: + - name: TIMEZONE + value: "UTC" + - name: DATE_TIME_FORMAT + value: "m/d/y h:iA" + - name: TOTAL_UPLOAD_SIZE + value: "5G" + - name: SECURE + value: "false" + - name: PERSISTENT_TOKENS_KEY + valueFrom: + secretKeyRef: + name: filerise-secret + key: PERSISTENT_TOKENS_KEY + - name: PUID + value: "1000" + - name: PGID + value: "1000" + - name: CHOWN_ON_START + value: "false" + - name: SCAN_ON_START + value: "true" + volumeMounts: + - name: filerise-uploads + mountPath: /var/www/uploads + - name: filerise-users + mountPath: /var/www/users + - name: filerise-metadata + mountPath: /var/www/metadata + - name: filerise-config + mountPath: /var/www/config + - name: filerise-sessions + mountPath: /var/www/sessions + - name: start-script + mountPath: /usr/local/bin/start-override.sh + subPath: start.sh + volumes: + - name: filerise-uploads + persistentVolumeClaim: + claimName: filerise-uploads-pvc + - name: filerise-users + persistentVolumeClaim: + claimName: filerise-users-pvc + - name: filerise-metadata + persistentVolumeClaim: + claimName: filerise-metadata-pvc + - name: filerise-config + persistentVolumeClaim: + claimName: filerise-config-pvc + - name: start-script + configMap: + name: filerise-start-script + defaultMode: 0755 + - name: filerise-sessions + emptyDir: {} diff --git a/f3s/filerise/helm-chart/templates/ingress.yaml b/f3s/filerise/helm-chart/templates/ingress.yaml new file mode 100644 index 0000000..5c31db1 --- /dev/null +++ b/f3s/filerise/helm-chart/templates/ingress.yaml @@ -0,0 +1,20 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: filerise-ingress + namespace: services + annotations: + spec.ingressClassName: traefik + traefik.ingress.kubernetes.io/router.entrypoints: web +spec: + rules: + - host: filerise.f3s.buetow.org + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: filerise-service + port: + number: 80 diff --git a/f3s/filerise/helm-chart/templates/persistent-volume.yaml b/f3s/filerise/helm-chart/templates/persistent-volume.yaml new file mode 100644 index 0000000..22cd75e --- /dev/null +++ b/f3s/filerise/helm-chart/templates/persistent-volume.yaml @@ -0,0 +1,111 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: filerise-uploads-pv +spec: + capacity: + storage: 50Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + hostPath: + path: /data/nfs/k3svolumes/filerise/uploads + type: Directory +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: filerise-users-pv +spec: + capacity: + storage: 1Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + hostPath: + path: /data/nfs/k3svolumes/filerise/users + type: Directory +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: filerise-metadata-pv +spec: + capacity: + storage: 5Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + hostPath: + path: /data/nfs/k3svolumes/filerise/metadata + type: Directory +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: filerise-config-pv +spec: + capacity: + storage: 1Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + hostPath: + path: /data/nfs/k3svolumes/filerise/config + type: Directory +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: filerise-uploads-pvc + namespace: services +spec: + storageClassName: "" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: filerise-users-pvc + namespace: services +spec: + storageClassName: "" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: filerise-metadata-pvc + namespace: services +spec: + storageClassName: "" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: filerise-config-pvc + namespace: services +spec: + storageClassName: "" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi diff --git a/f3s/filerise/helm-chart/templates/service.yaml b/f3s/filerise/helm-chart/templates/service.yaml new file mode 100644 index 0000000..cbae845 --- /dev/null +++ b/f3s/filerise/helm-chart/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: filerise + name: filerise-service + namespace: services +spec: + ports: + - name: web + port: 80 + protocol: TCP + targetPort: 80 + selector: + app: filerise diff --git a/frontends/Rexfile b/frontends/Rexfile index e023aaa..6cc91d3 100644 --- a/frontends/Rexfile +++ b/frontends/Rexfile @@ -77,7 +77,7 @@ our @dns_zones_remove = qw//; # k3s cluster running on FreeBSD in my LAN our @f3s_hosts = - qw/f3s.buetow.org anki.f3s.buetow.org bag.f3s.buetow.org flux.f3s.buetow.org audiobookshelf.f3s.buetow.org grafana.f3s.buetow.org radicale.f3s.buetow.org vault.f3s.buetow.org syncthing.f3s.buetow.org uprecords.f3s.buetow.org koreader.f3s.buetow.org/; + qw/f3s.buetow.org anki.f3s.buetow.org bag.f3s.buetow.org flux.f3s.buetow.org audiobookshelf.f3s.buetow.org grafana.f3s.buetow.org radicale.f3s.buetow.org vault.f3s.buetow.org syncthing.f3s.buetow.org uprecords.f3s.buetow.org koreader.f3s.buetow.org filerise.f3s.buetow.org/; # optionally, only enable manually for temp time, as no password protection yet # push @f3s_hosts, 'registry.f3s.buetow.org'; |
