Files
homelab-manifests/web-system/web.yaml
Renovate Bot 386e764713
renovate/stability-days Updates have not met minimum release age requirement
Update filebrowser/filebrowser Docker tag to v2.63.13
2026-06-06 07:47:56 +00:00

515 lines
15 KiB
YAML

---
# FileBrowser - Web-based file manager
# https://filebrowser.org/
#
# Features:
# - Web-based file browser and manager
# - File upload/download via web UI
# - File preview (images, text, markdown, video)
# - Built-in text editor
# - Share links for files
# - Very lightweight (~15MB RAM)
# - Authentik SSO integration (proxy auth)
#
# Authentication: Via Authentik (no double login!)
# FileBrowser trusts the X-authentik-username header from the proxy.
#
# Authentik Setup:
# 1. Create a Proxy Provider in Authentik:
# - Name: FileBrowser
# - Authorization flow: default-provider-authorization-implicit-consent
# - Type: Forward auth (single application)
# - External host: https://webadmin.dooplex.hu
#
# 2. Create an Application:
# - Name: FileBrowser
# - Slug: filebrowser
# - Provider: FileBrowser (the one you just created)
#
# 3. Create an Outpost (or add to existing):
# - Name: filebrowser-outpost
# - Type: Proxy
# - Integration: Kubernetes (auth-system namespace)
# - Applications: FileBrowser
#
# 4. Authentik will auto-create:
# - Deployment: ak-outpost-filebrowser-outpost in auth-system
# - Service: ak-outpost-filebrowser-outpost in auth-system
# - Ingress for /outpost.goauthentik.io path on webadmin.dooplex.hu
#
# Note: The outpost service name in auth-url must match!
# If you name outpost differently, update the annotation:
# http://ak-outpost-<your-outpost-name>.auth-system.svc.cluster.local:9000/...
#
# Access:
# - Admin UI: https://webadmin.dooplex.hu (Authentik login)
# - Public files: https://web.dooplex.hu (direct file access, no auth)
#
# Usage for static HTML hosting:
# 1. Login to webadmin.dooplex.hu (via Authentik)
# 2. Upload HTML files and assets to /public folder
# 3. Access directly via web.dooplex.hu/filename or web.dooplex.hu/folder
#
# Clean URL examples:
# - /public/fizetes.html → web.dooplex.hu/fizetes
# - /public/fizetes/index.html → web.dooplex.hu/fizetes
# - /public/about/index.html → web.dooplex.hu/about
#
# Note: First user to login via Authentik becomes admin in FileBrowser.
# Additional users logging in will be created automatically.
#
apiVersion: v1
kind: Namespace
metadata:
name: web-system
labels:
app.kubernetes.io/name: web-system
---
# PVC for files
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: filebrowser-data
namespace: web-system
labels:
app.kubernetes.io/instance: filebrowser
app.kubernetes.io/name: filebrowser
recurring-job-group.longhorn.io/backup: enabled
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 5Gi
---
# PVC for database and config
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: filebrowser-config
namespace: web-system
labels:
app.kubernetes.io/instance: filebrowser
app.kubernetes.io/name: filebrowser
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 100Mi
---
# FileBrowser Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: filebrowser
namespace: web-system
labels:
app.kubernetes.io/instance: filebrowser
app.kubernetes.io/name: filebrowser
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/instance: filebrowser
app.kubernetes.io/name: filebrowser
template:
metadata:
labels:
app.kubernetes.io/instance: filebrowser
app.kubernetes.io/name: filebrowser
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
initContainers:
# Configure proxy auth in database before starting
- name: configure-auth
image: filebrowser/filebrowser:v2.63.13
command:
- sh
- -c
- |
# Create database if it doesn't exist and configure proxy auth
if [ ! -f /config/filebrowser.db ]; then
echo "Creating new database with proxy auth..."
filebrowser config init --database /config/filebrowser.db
fi
echo "Setting proxy authentication..."
filebrowser config set --database /config/filebrowser.db --auth.method=proxy --auth.header=X-authentik-username
echo "Configuration complete"
volumeMounts:
- name: config
mountPath: /config
securityContext:
runAsUser: 1000
runAsGroup: 1000
containers:
- name: filebrowser
image: filebrowser/filebrowser:v2.63.13
command:
- filebrowser
- --database=/config/filebrowser.db
- --root=/srv
- --port=80
- --address=0.0.0.0
ports:
- containerPort: 80
name: http
protocol: TCP
env:
- name: TZ
value: "Europe/Budapest"
volumeMounts:
- name: data
mountPath: /srv
- name: config
mountPath: /config
resources:
requests:
cpu: 10m
memory: 32Mi
limits:
cpu: 500m
memory: 256Mi
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 10
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
volumes:
- name: data
persistentVolumeClaim:
claimName: filebrowser-data
- name: config
persistentVolumeClaim:
claimName: filebrowser-config
---
# Service for FileBrowser
apiVersion: v1
kind: Service
metadata:
name: filebrowser
namespace: web-system
labels:
app.kubernetes.io/instance: filebrowser
app.kubernetes.io/name: filebrowser
spec:
type: ClusterIP
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/instance: filebrowser
app.kubernetes.io/name: filebrowser
---
# Ingress for FileBrowser admin UI (Authentik protected)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: filebrowser
namespace: web-system
labels:
app.kubernetes.io/instance: filebrowser
app.kubernetes.io/name: filebrowser
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
external-dns.alpha.kubernetes.io/hostname: webadmin.dooplex.hu
nginx.ingress.kubernetes.io/proxy-body-size: "1024m"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
# Authentik forward auth - update outpost name after creating in Authentik!
nginx.ingress.kubernetes.io/auth-url: http://ak-outpost-filebrowser-outpost.auth-system.svc.cluster.local:9000/outpost.goauthentik.io/auth/nginx
nginx.ingress.kubernetes.io/auth-signin: https://webadmin.dooplex.hu/outpost.goauthentik.io/start?rd=$escaped_request_uri
nginx.ingress.kubernetes.io/auth-response-headers: X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid
nginx.ingress.kubernetes.io/auth-snippet: |
proxy_set_header X-Forwarded-Host $http_host;
nginx.ingress.kubernetes.io/configuration-snippet: |
set $geo_allowed 0;
if ($remote_addr ~ "^192\.168\.") { set $geo_allowed 1; }
if ($remote_addr ~ "^10\.") { set $geo_allowed 1; }
if ($geoip2_country_code = "HU") { set $geo_allowed 1; }
if ($geo_allowed = 0) {
return 403 "Access restricted to Hungary";
}
spec:
ingressClassName: nginx-internal
tls:
- hosts:
- webadmin.dooplex.hu
secretName: filebrowser-tls
rules:
- host: webadmin.dooplex.hu
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: filebrowser
port:
name: http
- host: webadmin.home
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: filebrowser
port:
name: http
---
# ============================================
# NGINX Static File Server (Public Access)
# ============================================
# This serves files from /public folder without authentication
# Access: https://web.dooplex.hu/filename or https://web.dooplex.hu/folder
#
apiVersion: apps/v1
kind: Deployment
metadata:
name: static-server
namespace: web-system
labels:
app.kubernetes.io/instance: static-server
app.kubernetes.io/name: static-server
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/instance: static-server
app.kubernetes.io/name: static-server
template:
metadata:
labels:
app.kubernetes.io/instance: static-server
app.kubernetes.io/name: static-server
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
initContainers:
# Create public directory if it doesn't exist
- name: init-public-dir
image: busybox:1.38
command: ["sh", "-c", "mkdir -p /srv/public && chmod 755 /srv/public"]
volumeMounts:
- name: data
mountPath: /srv
securityContext:
runAsUser: 0
containers:
- name: nginx
image: nginx:1.31-alpine
ports:
- containerPort: 8080
name: http
protocol: TCP
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
subPath: public
readOnly: true
- name: nginx-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
resources:
requests:
cpu: 5m
memory: 16Mi
limits:
cpu: 100m
memory: 64Mi
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 3
periodSeconds: 10
volumes:
- name: data
persistentVolumeClaim:
claimName: filebrowser-data
- name: nginx-config
configMap:
name: static-server-config
---
# ConfigMap for nginx static server
apiVersion: v1
kind: ConfigMap
metadata:
name: static-server-config
namespace: web-system
labels:
app.kubernetes.io/instance: static-server
app.kubernetes.io/name: static-server
data:
nginx.conf: |
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /tmp/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
# Temp paths for non-root user
client_body_temp_path /tmp/client_temp;
proxy_temp_path /tmp/proxy_temp;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
server {
listen 8080;
server_name _;
root /usr/share/nginx/html;
index index.html index.htm;
# Fix redirects behind reverse proxy
absolute_redirect off;
# Health check endpoint
location /health {
access_log off;
return 200 "OK\n";
add_header Content-Type text/plain;
}
# Serve static files
location / {
try_files $uri $uri/ $uri.html =404;
# Prevent search engine indexing
add_header X-Robots-Tag "noindex, nofollow, noarchive" always;
# Directory listing disabled for security
# Uncomment below if you want to browse directories
# autoindex on;
# autoindex_exact_size off;
# autoindex_localtime on;
# Cache static assets
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2)$ {
expires 7d;
add_header Cache-Control "public, immutable";
}
}
# Security headers
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
}
}
---
# Service for static server
apiVersion: v1
kind: Service
metadata:
name: static-server
namespace: web-system
labels:
app.kubernetes.io/instance: static-server
app.kubernetes.io/name: static-server
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app.kubernetes.io/instance: static-server
app.kubernetes.io/name: static-server
---
# Ingress for public static files
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: static-server
namespace: web-system
labels:
app.kubernetes.io/instance: static-server
app.kubernetes.io/name: static-server
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
external-dns.alpha.kubernetes.io/hostname: web.dooplex.hu
nginx.ingress.kubernetes.io/configuration-snippet: |
set $geo_allowed 0;
if ($remote_addr ~ "^192\.168\.") { set $geo_allowed 1; }
if ($remote_addr ~ "^10\.") { set $geo_allowed 1; }
if ($geoip2_country_code = "HU") { set $geo_allowed 1; }
if ($geo_allowed = 0) {
return 403 "Access restricted to Hungary";
}
spec:
ingressClassName: nginx-internal
tls:
- hosts:
- web.dooplex.hu
secretName: static-server-tls
rules:
- host: web.dooplex.hu
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: static-server
port:
name: http
- host: web.home
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: static-server
port:
name: http