├── recipes ├── minio │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── palmr │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── wetty │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── actual │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── firefox │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── immich │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── jellyfin │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── mariadb │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── ollama │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── owntone │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── penpot │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── photoprism │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── rancher │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── reflector │ ├── README.md │ ├── recipe.yaml │ └── metadata.yaml ├── speedtest │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── syncthing │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── webdav │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── whoami │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── multus-dhcp │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── paperless-ngx │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── transmission │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── uptime-kuma │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── filebrowser-quantum │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── mariadb-operator │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── plex-media-server │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── open-webui │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── letsencrypt │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── shiori │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── pyload │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── forgejo │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── smokeping │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── piwigo │ ├── README.md │ ├── metadata.yaml │ └── recipe.yaml ├── acme-dns │ ├── metadata.yaml │ ├── README.md │ └── recipe.yaml ├── sabnzbd │ ├── metadata.yaml │ ├── README.md │ └── recipe.yaml ├── filebrowser │ ├── metadata.yaml │ ├── README.md │ └── recipe.yaml └── home-assistant │ ├── metadata.yaml │ ├── README.md │ └── recipe.yaml ├── .gitignore ├── .editorconfig ├── package.json ├── LICENSE └── README.md /recipes/minio/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/palmr/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/wetty/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/actual/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/firefox/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/immich/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/jellyfin/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/mariadb/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/ollama/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/owntone/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/penpot/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/photoprism/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/rancher/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/reflector/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/speedtest/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/syncthing/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/webdav/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/whoami/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | -------------------------------------------------------------------------------- /recipes/multus-dhcp/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/paperless-ngx/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/transmission/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/uptime-kuma/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/filebrowser-quantum/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/mariadb-operator/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/plex-media-server/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /recipes/open-webui/README.md: -------------------------------------------------------------------------------- 1 | > ℹ️ **Info:** This recipe requires the ollama recipe to be installed. 2 | -------------------------------------------------------------------------------- /recipes/letsencrypt/README.md: -------------------------------------------------------------------------------- 1 | > ℹ️ **Info:** This recipe requires the reflector recipe to be installed. 2 | -------------------------------------------------------------------------------- /recipes/shiori/README.md: -------------------------------------------------------------------------------- 1 | The default login is: 2 | 3 | **Username** - shiori 4 | **Password** - gopher 5 | -------------------------------------------------------------------------------- /recipes/pyload/README.md: -------------------------------------------------------------------------------- 1 | # pyLoad 2 | 3 | The default login is: 4 | 5 | **Username** - pyload 6 | **Password** - pyload 7 | 8 | Make sure to change in user settings. 9 | -------------------------------------------------------------------------------- /recipes/forgejo/README.md: -------------------------------------------------------------------------------- 1 | # Forgejo 2 | 3 | After starting the service, a configuration wizard is started that allows performing the initial configuration via the web interface. 4 | -------------------------------------------------------------------------------- /recipes/smokeping/README.md: -------------------------------------------------------------------------------- 1 | # Smokeping 2 | 3 | You can make custom changes to your smokeping config in the shared folder (see the `configSharedFolderName` variable in the recipe) that is configured for the configuration. 4 | 5 | Here you can also configure email alerts. 6 | -------------------------------------------------------------------------------- /recipes/piwigo/README.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | When the application is deployed, and you enter the UI the first time, then insert the following in the `MySQL-Host` form field to connect to the database: 3 | ``` 4 | mariadb 5 | ``` 6 | or 7 | ``` 8 | mariadb.piwigo-app.svc.cluster.local 9 | ``` 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | end_of_line = lf 11 | 12 | [*.md] 13 | max_line_length = off 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /recipes/minio/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: MinIO 2 | description: MinIO is a high-performance, S3 compatible object storage. 3 | section: net 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://min.io/ 8 | recipeVersion: "1.1.3" 9 | appVersion: latest 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://min.io/ 14 | - https://quay.io/repository/minio/minio 15 | -------------------------------------------------------------------------------- /recipes/reflector/recipe.yaml: -------------------------------------------------------------------------------- 1 | # !!! Only modify the following manifest if you need to make custom changes. !!! 2 | --- 3 | apiVersion: helm.cattle.io/v1 4 | kind: HelmChart 5 | metadata: 6 | name: reflector 7 | namespace: kube-system 8 | spec: 9 | repo: https://emberstack.github.io/helm-charts 10 | chart: reflector 11 | targetNamespace: kube-system 12 | valuesContent: |- 13 | fullnameOverride: reflector 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openmediavault-k8s-recipes", 3 | "version": "0.0.0", 4 | "description": "openmediavault Kubernetes recipes", 5 | "repository": "https://github.com/openmediavault/openmediavault-k8s-recipes", 6 | "author": "", 7 | "license": "MIT", 8 | "scripts": { 9 | "fix": "prettier --write recipes/**/*.yaml" 10 | }, 11 | "devDependencies": { 12 | "prettier": "^3.2.5" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /recipes/acme-dns/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: ACME DNS 2 | description: Run a simplified DNS server to automate ACME DNS challenges. 3 | section: net 4 | architecture: 5 | - amd64 6 | url: https://github.com/joohoi/acme-dns/ 7 | recipeVersion: "1.0.1" 8 | appVersion: latest 9 | maintainers: 10 | - Yuchen Shi 11 | sources: 12 | - https://github.com/joohoi/acme-dns/ 13 | - https://hub.docker.com/r/joohoi/acme-dns/ 14 | -------------------------------------------------------------------------------- /recipes/letsencrypt/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Let's Encrypt 2 | description: Acquire a TLS certificate from LetsEncrypt (or other ACME-compatible CAs). 3 | section: net 4 | architecture: 5 | - amd64 6 | depends: 7 | - reflector 8 | url: https://cert-manager.io/docs/configuration/acme/ 9 | recipeVersion: "1.0.0" 10 | appVersion: latest 11 | maintainers: 12 | - Yuchen Shi 13 | sources: 14 | - https://cert-manager.io/docs/configuration/acme/ 15 | -------------------------------------------------------------------------------- /recipes/transmission/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Transmission 2 | description: A fast, easy and free Bittorrent client. 3 | section: net 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://transmissionbt.com/ 8 | recipeVersion: "1.0.0" 9 | appVersion: latest 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://github.com/transmission/transmission/ 14 | - https://hub.docker.com/r/linuxserver/transmission/ 15 | -------------------------------------------------------------------------------- /recipes/wetty/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: WeTTY 2 | description: Terminal access in browser over http/https. 3 | section: net 4 | architecture: 5 | - amd64 6 | - armel 7 | - armhf 8 | - arm64 9 | url: https://butlerx.github.io/wetty/ 10 | recipeVersion: "1.2.3" 11 | appVersion: latest 12 | maintainers: 13 | - Volker Theile 14 | sources: 15 | - https://butlerx.github.io/wetty/ 16 | - https://hub.docker.com/r/wettyoss/wetty/ 17 | -------------------------------------------------------------------------------- /recipes/pyload/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: pyLoad 2 | description: Free and Open Source download manager written in Python 3 | section: net 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://pyload.net/ 8 | recipeVersion: "1.0.1" 9 | appVersion: latest 10 | maintainers: 11 | - Moritz Meintker 12 | - Volker Theile 13 | sources: 14 | - https://pyload.net/ 15 | - https://github.com/linuxserver/docker-pyload-ng/ 16 | -------------------------------------------------------------------------------- /recipes/sabnzbd/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: SABnzbd 2 | description: An automated Usenet download tool written in Python. 3 | section: net 4 | architecture: 5 | - amd64 6 | - arm64 7 | - riscv64 8 | url: https://sabnzbd.org/ 9 | recipeVersion: "1.0.0" 10 | appVersion: latest 11 | maintainers: 12 | - Jan Holthuis 13 | sources: 14 | - https://sabnzbd.org/ 15 | - https://github.com/sabnzbd/sabnzbd 16 | - https://hub.docker.com/r/linuxserver/sabnzbd/ 17 | -------------------------------------------------------------------------------- /recipes/uptime-kuma/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Uptime Kuma 2 | description: A self-hosted monitoring tool. 3 | section: net 4 | architecture: 5 | - amd64 6 | - arm64 7 | - armhf 8 | url: https://uptime.kuma.pet// 9 | recipeVersion: "1.0.1" 10 | appVersion: 11 | maintainers: 12 | - Volker Theile 13 | sources: 14 | - https://github.com/louislam/uptime-kuma/ 15 | - https://github.com/dirsigler/uptime-kuma-helm/ 16 | - https://hub.docker.com/r/louislam/uptime-kuma/ 17 | -------------------------------------------------------------------------------- /recipes/smokeping/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Smokeping 2 | description: Smokeping keeps track of your network latency. 3 | section: net 4 | architecture: 5 | - amd64 6 | - armhf 7 | url: https://oss.oetiker.ch/smokeping/ 8 | recipeVersion: "1.2.2" 9 | appVersion: latest 10 | maintainers: 11 | - Moritz Meintker 12 | - Volker Theile 13 | sources: 14 | - https://oss.oetiker.ch/smokeping/ 15 | - https://docs.linuxserver.io/images/docker-smokeping/ 16 | -------------------------------------------------------------------------------- /recipes/forgejo/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Forgejo 2 | description: A self-hosted software development platform, offering Git repository mangement, bug tracking and project management. It is a fork of Gitea. 3 | section: net 4 | architecture: 5 | - amd64 6 | url: https://forgejo.org/ 7 | recipeVersion: "1.0.0" 8 | appVersion: "12" 9 | maintainers: 10 | - Jan Holthuis 11 | sources: 12 | - https://forgejo.org/docs/latest/admin/installation/docker/ 13 | - https://codeberg.org/forgejo/forgejo 14 | -------------------------------------------------------------------------------- /recipes/filebrowser-quantum/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: FileBrowser Quantum 2 | description: Web file browser. 3 | section: net 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://filebrowserquantum.com/ 8 | recipeVersion: "1.0.2" 9 | appVersion: "stable" 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://github.com/gtsteffaniak/filebrowser/ 14 | - https://github.com/gtsteffaniak/filebrowser/pkgs/container/filebrowser/ 15 | - https://github.com/gtsteffaniak/filebrowser/wiki/ 16 | -------------------------------------------------------------------------------- /recipes/mariadb/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: MariaDB 2 | description: MariaDB Server is a high performing open source relational database, forked from MySQL. 3 | section: database 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://mariadb.org/ 8 | recipeVersion: "1.0.2" 9 | appVersion: latest 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://github.com/MariaDB/server/ 14 | - https://hub.docker.com/r/bitnami/mariadb/ 15 | - https://artifacthub.io/packages/helm/bitnami/mariadb/ 16 | -------------------------------------------------------------------------------- /recipes/plex-media-server/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Plex Media Server 2 | description: Plex Media Server is a software application that allows users to organize, stream, and share their media files, including movies, TV shows, music, and photos, across various devices. 3 | section: video 4 | architecture: 5 | - amd64 6 | url: https://www.plex.tv/ 7 | recipeVersion: "1.2.3" 8 | appVersion: 9 | maintainers: 10 | - Volker Theile 11 | sources: 12 | - https://www.plex.tv/ 13 | - https://github.com/plexinc/pms-docker/ 14 | -------------------------------------------------------------------------------- /recipes/whoami/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: whoami 2 | description: Troubleshooting/exploration tool for Traefik configuration. Demonstrates use of Traefik middleware. 3 | section: net 4 | architecture: 5 | - amd64 6 | url: https://hub.docker.com/r/traefik/whoami/ 7 | recipeVersion: "1.2.3" 8 | appVersion: latest 9 | maintainers: 10 | - Richard Cottrill 11 | - Volker Theile 12 | sources: 13 | - https://github.com/traefik/whoami 14 | - https://doc.traefik.io/traefik/middlewares/overview/ 15 | -------------------------------------------------------------------------------- /recipes/multus-dhcp/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Multus-DHCP 2 | description: A CNI meta-plugin for multi-homed pods in Kubernetes. The DHCP IPAM will be installed. 3 | section: kubernetes 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://docs.k3s.io/networking/multus-ipams/ 8 | recipeVersion: "1.0.2" 9 | appVersion: 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://github.com/rancher/rke2-charts/tree/main-source/packages/rke2-multus/ 14 | - https://github.com/k8snetworkplumbingwg/multus-cni/ 15 | -------------------------------------------------------------------------------- /recipes/palmr/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Palmr 2 | description: Palmr is a fast and secure platform for sharing files, built with performance and privacy in mind. 3 | section: utils 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://palmr.kyantech.com.br/ 8 | recipeVersion: "1.0.0" 9 | appVersion: "latest" 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://github.com/kyantech/Palmr/ 14 | - https://hub.docker.com/r/kyantech/palmr/ 15 | - https://palmr.kyantech.com.br/docs/3.2-beta/quick-start/ 16 | -------------------------------------------------------------------------------- /recipes/sabnzbd/README.md: -------------------------------------------------------------------------------- 1 | # SABnzbd 2 | 3 | Upon first start of the service, the config file `sabnzb.ini` in the shared folder is created. 4 | However, the web will be inaccessible and the following error message is shown: 5 | 6 | > Access denied - Hostname verification failed: https://sabnzbd.org/hostname-check 7 | 8 | You have to edit `sabnzb.ini`, set `host_whitelist = sabnzbd.` and then restart the pod. 9 | Afterwards, the web interface will be accessible and configuration wizard will be shown that allows performing the initial configuration. 10 | -------------------------------------------------------------------------------- /recipes/webdav/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: WebDAV 2 | description: Aims to enable a no-nonsense WebDAV docker system on the latest available nginx mainline. Magic included? 3 | section: net 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://github.com/dgraziotin/docker-nginx-webdav-nononsense/ 8 | recipeVersion: "1.0.0" 9 | appVersion: latest 10 | maintainers: 11 | - Yuchen Shi 12 | sources: 13 | - https://github.com/dgraziotin/docker-nginx-webdav-nononsense/ 14 | - https://hub.docker.com/r/dgraziotin/nginx-webdav-nononsense/ 15 | -------------------------------------------------------------------------------- /recipes/filebrowser/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: FileBrowser 2 | description: Web file browser. 3 | section: net 4 | architecture: 5 | - amd64 6 | - armel 7 | - armhf 8 | - arm64 9 | url: https://filebrowser.org/ 10 | recipeVersion: "1.2.9" 11 | appVersion: "v2.32.3" 12 | maintainers: 13 | - Volker Theile 14 | sources: 15 | - https://filebrowser.org/ 16 | - https://utkuozdemir.org/helm-charts/ 17 | - https://artifacthub.io/packages/helm/utkuozdemir/filebrowser/ 18 | - https://hub.docker.com/r/filebrowser/filebrowser/ 19 | -------------------------------------------------------------------------------- /recipes/piwigo/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Piwigo 2 | description: Piwigo is open source photo management software. Manage, organize and share your photo easily on the web. Designed for organisations, teams and individuals. 3 | section: graphics 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://www.piwigo.org/ 8 | recipeVersion: "1.0.4" 9 | appVersion: latest 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://docs.linuxserver.io/images/docker-piwigo/ 14 | - https://hub.docker.com/r/linuxserver/piwigo/ 15 | -------------------------------------------------------------------------------- /recipes/syncthing/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Syncthing 2 | description: Open source continuous file synchronization. 3 | section: utils 4 | architecture: 5 | - amd64 6 | - armhf 7 | - arm64 8 | url: https://syncthing.net/ 9 | recipeVersion: "1.0.0" 10 | appVersion: 11 | maintainers: 12 | - Volker Theile 13 | sources: 14 | - https://syncthing.net/ 15 | - https://github.com/syncthing/syncthing/ 16 | - https://hub.docker.com/r/syncthing/syncthing/ 17 | - https://artifacthub.io/packages/helm/brandan-schmitz-helm-charts/syncthing/ 18 | -------------------------------------------------------------------------------- /recipes/photoprism/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: PhotoPrism 2 | description: PhotoPrism® is an AI-Powered Photos App for the Decentralized Web. It makes use of the latest technologies to tag and find pictures automatically without getting in your way. 3 | section: graphics 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://www.photoprism.app/ 8 | recipeVersion: "1.2.5" 9 | appVersion: latest 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://dl.photoprism.app/docker/compose.yaml 14 | - https://hub.docker.com/r/photoprism/photoprism 15 | -------------------------------------------------------------------------------- /recipes/speedtest/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: SpeedTest 2 | description: Broadband Speed Test That Works on Any Web Browser. 3 | section: net 4 | architecture: 5 | - amd64 6 | - arm64 7 | - armhf 8 | - i386 9 | url: https://openspeedtest.com/ 10 | recipeVersion: "1.0.0" 11 | appVersion: 12 | maintainers: 13 | - Volker Theile 14 | sources: 15 | - https://github.com/openspeedtest/Speed-Test/ 16 | - https://artifacthub.io/packages/helm/speedtest/openspeedtest/ 17 | - https://hub.docker.com/r/openspeedtest/ 18 | - https://openspeedtest.github.io/Helm-chart/ 19 | -------------------------------------------------------------------------------- /recipes/paperless-ngx/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Paperless-ngx 2 | description: Paperless-ngx is a community-supported open-source document management system that transforms your physical documents into a searchable online archive so you can keep, well, less paper. 3 | section: net 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://docs.paperless-ngx.com/ 8 | recipeVersion: "1.0.3" 9 | appVersion: "2.12.1" 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://docs.paperless-ngx.com/setup/ 14 | - https://artifacthub.io/packages/helm/gabe565/paperless-ngx 15 | -------------------------------------------------------------------------------- /recipes/ollama/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Ollama 2 | description: Get up and running with large language models. 3 | section: science 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://ollama.com/ 8 | recipeVersion: "1.0.5" 9 | appVersion: 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://github.com/ollama/ollama/ 14 | - https://github.com/ollama/ollama/tree/main/docs 15 | - https://github.com/otwld/ollama-helm 16 | - https://hub.docker.com/r/ollama/ollama/ 17 | - https://artifacthub.io/packages/helm/ollama-helm/ollama/ 18 | - https://ollama.com/library 19 | -------------------------------------------------------------------------------- /recipes/jellyfin/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Jellyfin 2 | description: Jellyfin is the volunteer-built media solution that puts you in control of your media. Stream to any device from your own server, with no strings attached. Your media, your server, your way. 3 | section: net 4 | architecture: 5 | - amd64 6 | - armhf 7 | - arm64 8 | url: https://jellyfin.org/ 9 | recipeVersion: "1.2.2" 10 | appVersion: latest 11 | maintainers: 12 | - Volker Theile 13 | sources: 14 | - https://github.com/jellyfin/jellyfin 15 | - https://hub.docker.com/r/jellyfin/jellyfin 16 | - https://jellyfin.org/docs 17 | -------------------------------------------------------------------------------- /recipes/reflector/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Reflector 2 | description: Custom Kubernetes controller that can be used to replicate secrets, configmaps and certificates. 3 | section: kubernetes 4 | architecture: 5 | - amd64 6 | - arm64 7 | - armhf 8 | url: https://github.com/emberstack/kubernetes-reflector/ 9 | recipeVersion: "1.0.1" 10 | appVersion: 11 | maintainers: 12 | - Volker Theile 13 | sources: 14 | - https://github.com/emberstack/kubernetes-reflector/ 15 | - https://artifacthub.io/packages/helm/emberstack/reflector/ 16 | - https://hub.docker.com/r/emberstack/kubernetes-reflector/ 17 | -------------------------------------------------------------------------------- /recipes/mariadb-operator/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: MariaDB Operator 2 | description: Run and operate MariaDB in a cloud native way. 3 | section: database 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://github.com/mariadb-operator/mariadb-operator/ 8 | recipeVersion: "1.0.0" 9 | appVersion: latest 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://github.com/mariadb-operator/mariadb-operator/ 14 | - https://github.com/mariadb-operator/mariadb-operator-helm/ 15 | - https://operatorhub.io/operator/mariadb-operator/ 16 | - https://kubeadm.org/mariadb-operator-kubernetes/ 17 | -------------------------------------------------------------------------------- /recipes/immich/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Immich 2 | description: High performance self-hosted photo and video management solution. 3 | section: graphics 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://immich.app/ 8 | recipeVersion: "1.1.6" 9 | appVersion: "v1.119.0" 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://github.com/immich-app/immich/ 14 | - https://github.com/immich-app/immich-charts/ 15 | - https://immich.app/docs/overview/introduction/ 16 | - https://immich.app/docs/install/config-file/ 17 | - https://github.com/bjw-s/helm-charts/tree/main/charts/library/common/ 18 | -------------------------------------------------------------------------------- /recipes/open-webui/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Open WebUI 2 | description: Open WebUI is an extensible, self-hosted AI interface that adapts to your workflow, all while operating entirely offline. 3 | section: web 4 | architecture: 5 | - amd64 6 | - arm64 7 | depends: 8 | - ollama 9 | url: https://www.openwebui.com/ 10 | recipeVersion: "1.0.1" 11 | appVersion: 12 | maintainers: 13 | - Volker Theile 14 | sources: 15 | - https://github.com/open-webui/open-webui/ 16 | - https://github.com/open-webui/pipelines/ 17 | - https://github.com/open-webui/helm-charts/ 18 | - https://artifacthub.io/packages/helm/open-webui/open-webui/ 19 | -------------------------------------------------------------------------------- /recipes/actual/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Actual Budget 2 | description: > 3 | Actual Budget is a super fast and privacy-focused app for managing your 4 | finances. At its heart is the well proven and much loved Envelope Budgeting 5 | methodology. 6 | section: finance 7 | architecture: 8 | - amd64 9 | - armel 10 | - armhf 11 | - arm64 12 | url: https://actualbudget.org/ 13 | recipeVersion: "1.0.1" 14 | appVersion: "latest" 15 | maintainers: 16 | - Jan Holthuis 17 | sources: 18 | - https://github.com/actualbudget/actual 19 | - https://actualbudget.org/docs/install/docker 20 | - https://hub.docker.com/r/actualbudget/actual-server 21 | -------------------------------------------------------------------------------- /recipes/filebrowser/README.md: -------------------------------------------------------------------------------- 1 | > ⚠️ **Warning:** The `Filebrowser` project is on maintenance-only mode. Since the used Helm Chart has not been updated, newer images cannot be used. Therefore, this recipe only uses version v2.32.3. Alternatively, use the `Filebrowser Quantum` recipe. 2 | 3 | The default login is: 4 | 5 | **Username** - admin 6 | **Password** - RANDOM_GENERATED_PASSWORD 7 | 8 | To get the random password that is automatically generated on first startup of the pod, go to the `Services | Kubernetes | Resources | Pods` page after the recipe has been installed and check the logs of the filebrowser pod for the line that says: `Generated random admin password for quick setup`. 9 | -------------------------------------------------------------------------------- /recipes/owntone/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: OwnTone 2 | description: OwnTone is an open source (audio) media server. It allows sharing and streaming your media library to iTunes (DAAP1), Roku (RSP), AirPlay devices (multi-room), Chromecast and also supports local playback. 3 | section: sound 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://owntone.github.io/owntone-server/ 8 | recipeVersion: "1.0.3" 9 | appVersion: latest 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://github.com/owntone/owntone-server/ 14 | - https://owntone.github.io/owntone-server/configuration/ 15 | - https://github.com/owntone/owntone-container/ 16 | -------------------------------------------------------------------------------- /recipes/home-assistant/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Home Assistant 2 | description: Open source home automation that puts local control and privacy first. Powered by a worldwide community of tinkerers and DIY enthusiasts. 3 | section: net 4 | architecture: 5 | - i386 6 | - amd64 7 | - armel 8 | - armhf 9 | - arm64 10 | url: https://www.home-assistant.io/ 11 | recipeVersion: "1.0.0" 12 | appVersion: stable 13 | maintainers: 14 | - Volker Theile 15 | sources: 16 | - https://github.com/home-assistant/core/pkgs/container/home-assistant/ 17 | - https://www.home-assistant.io/installation/alternative/ 18 | - https://www.home-assistant.io/integrations/http/ 19 | -------------------------------------------------------------------------------- /recipes/firefox/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Firefox 2 | description: Firefox Browser, also known as Mozilla Firefox or simply Firefox, is a free and open-source web browser developed by the Mozilla Foundation and its subsidiary, the Mozilla Corporation. Firefox uses the Gecko layout engine to render web pages, which implements current and anticipated web standards. 3 | section: web 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://www.mozilla.org/firefox/ 8 | recipeVersion: "1.0.4" 9 | appVersion: latest 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://docs.linuxserver.io/images/docker-firefox/ 14 | - https://hub.docker.com/r/linuxserver/firefox/ 15 | -------------------------------------------------------------------------------- /recipes/penpot/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Penpot 2 | description: Penpot is the web-based open-source design tool that bridges the gap between designers and developers. 3 | section: devel 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://penpot.app/ 8 | recipeVersion: "1.0.0" 9 | appVersion: "2.9.0" 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://artifacthub.io/packages/helm/penpot/penpot/ 14 | - https://artifacthub.io/packages/helm/bitnami/postgresql/ 15 | - https://artifacthub.io/packages/helm/bitnami/valkey/ 16 | - https://hub.docker.com/u/penpotapp/ 17 | - https://help.penpot.app/technical-guide/getting-started/#install-with-kubernetes/ 18 | - https://github.com/penpot/penpot-helm/blob/main/charts/penpot/values.yaml 19 | -------------------------------------------------------------------------------- /recipes/rancher/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Rancher 2 | description: Rancher is a Kubernetes management tool to deploy and run clusters anywhere and on any provider. 3 | section: net 4 | architecture: 5 | - amd64 6 | - arm64 7 | url: https://www.rancher.com/ 8 | recipeVersion: "1.0.3" 9 | appVersion: stable 10 | maintainers: 11 | - Volker Theile 12 | sources: 13 | - https://www.rancher.com/ 14 | - https://github.com/rancher/rancher/ 15 | - https://www.suse.com/suse-rancher/support-matrix/all-supported-versions/ 16 | - https://ranchermanager.docs.rancher.com/getting-started/installation-and-upgrade/install-upgrade-on-a-kubernetes-cluster/ 17 | - https://ranchermanager.docs.rancher.com/getting-started/installation-and-upgrade/installation-references/helm-chart-options/ 18 | -------------------------------------------------------------------------------- /recipes/shiori/metadata.yaml: -------------------------------------------------------------------------------- 1 | name: Shiori 2 | description: Shiori is a simple bookmarks manager written in the Go language. Intended as a simple clone of Pocket. You can use it as a command line application or as a web application. This application is distributed as a single binary, which means it can be installed and used easily. 3 | section: web 4 | architecture: 5 | - amd64 6 | - armhf 7 | - arm64 8 | url: https://github.com/go-shiori/shiori 9 | recipeVersion: "1.0.2" 10 | appVersion: "latest" 11 | maintainers: 12 | - Ronnie Bathoorn 13 | - Volker Theile 14 | sources: 15 | - https://github.com/go-shiori/shiori 16 | - https://github.com/go-shiori/shiori/blob/master/docs/Configuration.md 17 | - https://github.com/go-shiori/shiori/blob/master/docs/Installation.md#using-kubernetes-manifests 18 | - https://github.com/go-shiori/shiori/blob/master/docs/Usage.md 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 openmediavault 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /recipes/mariadb-operator/recipe.yaml: -------------------------------------------------------------------------------- 1 | # !!! Only modify the following manifest if you need to make custom changes. !!! 2 | --- 3 | apiVersion: v1 4 | kind: Namespace 5 | metadata: 6 | name: mariadb-operator-app 7 | --- 8 | apiVersion: helm.cattle.io/v1 9 | kind: HelmChart 10 | metadata: 11 | name: mariadb-operator-crds 12 | namespace: mariadb-operator-app 13 | labels: 14 | app.kubernetes.io/instance: mariadb-operator-crds 15 | app.kubernetes.io/name: mariadb-operator-crds 16 | spec: 17 | repo: https://helm.mariadb.com/mariadb-operator/ 18 | chart: mariadb-operator-crds 19 | targetNamespace: mariadb-operator-app 20 | valuesContent: |- 21 | image: 22 | tag: latest 23 | --- 24 | apiVersion: helm.cattle.io/v1 25 | kind: HelmChart 26 | metadata: 27 | name: mariadb-operator 28 | namespace: mariadb-operator-app 29 | labels: 30 | app.kubernetes.io/instance: mariadb-operator 31 | app.kubernetes.io/name: mariadb-operator 32 | spec: 33 | repo: https://helm.mariadb.com/mariadb-operator/ 34 | chart: mariadb-operator 35 | targetNamespace: mariadb-operator-app 36 | valuesContent: |- 37 | image: 38 | tag: latest 39 | -------------------------------------------------------------------------------- /recipes/speedtest/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://speedtest.:8443 2 | # !!! Only modify the following manifest if you need to make custom changes. !!! 3 | --- 4 | apiVersion: v1 5 | kind: Namespace 6 | metadata: 7 | name: speedtest-app 8 | --- 9 | apiVersion: helm.cattle.io/v1 10 | kind: HelmChart 11 | metadata: 12 | name: speedtest 13 | namespace: speedtest-app 14 | labels: 15 | app.kubernetes.io/instance: speedtest 16 | app.kubernetes.io/name: speedtest 17 | spec: 18 | repo: https://openspeedtest.github.io/Helm-chart/ 19 | chart: openspeedtest 20 | targetNamespace: speedtest-app 21 | valuesContent: |- 22 | fullnameOverride: speedtest 23 | service: 24 | type: ClusterIP 25 | --- 26 | apiVersion: traefik.io/v1alpha1 27 | kind: IngressRoute 28 | metadata: 29 | name: speedtest-websecure 30 | namespace: speedtest-app 31 | labels: 32 | app.kubernetes.io/instance: speedtest 33 | app.kubernetes.io/name: speedtest 34 | spec: 35 | entryPoints: 36 | - websecure 37 | routes: 38 | - match: Host(`speedtest.{{ fqdn() }}`) 39 | kind: Rule 40 | services: 41 | - name: speedtest 42 | port: 3000 43 | tls: {} 44 | -------------------------------------------------------------------------------- /recipes/rancher/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://rancher.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set bootstrapPassword = 'rancher' %} 4 | # !!! Only modify the following manifest if you need to make custom changes. !!! 5 | --- 6 | apiVersion: v1 7 | kind: Namespace 8 | metadata: 9 | name: cattle-system 10 | --- 11 | apiVersion: helm.cattle.io/v1 12 | kind: HelmChart 13 | metadata: 14 | name: rancher 15 | namespace: cattle-system 16 | labels: 17 | app.kubernetes.io/instance: rancher 18 | app.kubernetes.io/name: rancher 19 | spec: 20 | repo: https://releases.rancher.com/server-charts/stable 21 | chart: rancher 22 | targetNamespace: cattle-system 23 | valuesContent: |- 24 | bootstrapPassword: "{{ bootstrapPassword }}" 25 | hostname: "rancher.{{ fqdn() }}" 26 | replicas: 1 27 | ingress: 28 | enabled: false 29 | --- 30 | apiVersion: traefik.io/v1alpha1 31 | kind: IngressRoute 32 | metadata: 33 | name: rancher-websecure 34 | namespace: cattle-system 35 | labels: 36 | app.kubernetes.io/instance: rancher 37 | app.kubernetes.io/name: rancher 38 | spec: 39 | entryPoints: 40 | - websecure 41 | routes: 42 | - match: Host(`rancher.{{ fqdn() }}`) 43 | kind: Rule 44 | services: 45 | - name: rancher 46 | port: 80 47 | tls: {} 48 | -------------------------------------------------------------------------------- /recipes/acme-dns/README.md: -------------------------------------------------------------------------------- 1 | The acme-dns HTTPS API is reverse-proxied through `https://acme-dns.:8443` . 2 | 3 | > ℹ️ **Info:** Unlike default acme-dns setup, the API is **not accessible** at `https://auth./` ! 4 | 5 | ---- 6 | 7 | To start, port forward UDP & TCP [your-public-ip]:53 to [k8s-machine]:30053 (DNS standards mandate the use of Port 53 but Kubernetes does not allow :53 as a NodePort by default). 8 | 9 | Then create the following records at your DNS provider: 10 | 11 | ``` 12 | auth.your-domain.test. NS auth-ns.your-domain.test. 13 | auth-ns.your-domain.test. A 0.0.0.0 # Replace 0.0.0.0 with your public IP. 14 | ``` 15 | 16 | If you're using a dynamic DNS service where `mybox.ddns-provider.test` points to your public address, you just need one `NS` record to point at it. 17 | 18 | Don't forget to update the `nsname` variable in the recipe to match. 19 | 20 | ``` 21 | auth.your-domain.test. NS mybox.ddns-provider.test. 22 | ``` 23 | 24 | You can then follow the official testing instructions (just remember to use the base URL mentioned above instead of `auth.example.org`): 25 | 26 | https://github.com/joohoi/acme-dns?tab=readme-ov-file#testing-it-out 27 | 28 | You may have to ignore certificate warnings if `` is not a public domain or if the default certificate is selfsigned, e.g. 29 | `curl --insecure -X POST https://acme-dns.:8443/register` 30 | -------------------------------------------------------------------------------- /recipes/open-webui/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://openwebui.:8443 2 | # Note, this recipe requires the Ollama recipe to be deployed and running. 3 | # Change the following variables to adapt the recipe to your needs. 4 | # !!! Only modify the following manifest if you need to make custom changes. !!! 5 | --- 6 | apiVersion: v1 7 | kind: Namespace 8 | metadata: 9 | name: openwebui-app 10 | --- 11 | apiVersion: helm.cattle.io/v1 12 | kind: HelmChart 13 | metadata: 14 | name: openwebui 15 | namespace: openwebui-app 16 | labels: 17 | app.kubernetes.io/instance: openwebui 18 | app.kubernetes.io/name: openwebui 19 | spec: 20 | repo: https://helm.openwebui.com/ 21 | chart: open-webui 22 | targetNamespace: openwebui-app 23 | valuesContent: |- 24 | ollama: 25 | enabled: false 26 | ollamaUrls: 27 | - http://ollama.ollama-app.svc.cluster.local:11434 28 | pipelines: 29 | enabled: false 30 | --- 31 | apiVersion: traefik.io/v1alpha1 32 | kind: IngressRoute 33 | metadata: 34 | name: openwebui-websecure 35 | namespace: openwebui-app 36 | labels: 37 | app.kubernetes.io/instance: openwebui 38 | app.kubernetes.io/name: openwebui 39 | spec: 40 | entryPoints: 41 | - websecure 42 | routes: 43 | - match: Host(`openwebui.{{ fqdn() }}`) 44 | kind: Rule 45 | services: 46 | - name: open-webui 47 | port: 80 48 | tls: {} 49 | -------------------------------------------------------------------------------- /recipes/multus-dhcp/recipe.yaml: -------------------------------------------------------------------------------- 1 | # Note, K3s >= v1.31.2+k3s1 is required to install Multus CNI. 2 | # 3 | # Use the `k8s.v1.cni.cncf.io/networks: default/multus-dhcp` annotation in 4 | # your pod spec to create an network interface managed by Multus CNI. 5 | # 6 | # Change the following variables to adapt the recipe to your needs. 7 | {% set ifaceName = 'ens6' %} 8 | # !!! Only modify the following manifest if you need to make custom changes. !!! 9 | --- 10 | apiVersion: helm.cattle.io/v1 11 | kind: HelmChart 12 | metadata: 13 | name: multus 14 | namespace: kube-system 15 | spec: 16 | repo: https://rke2-charts.rancher.io 17 | chart: rke2-multus 18 | targetNamespace: kube-system 19 | valuesContent: |- 20 | config: 21 | fullnameOverride: multus 22 | cni_conf: 23 | confDir: /var/lib/rancher/k3s/agent/etc/cni/net.d 24 | binDir: /var/lib/rancher/k3s/data/cni/ 25 | kubeconfig: /var/lib/rancher/k3s/agent/etc/cni/net.d/multus.d/multus.kubeconfig 26 | manifests: 27 | dhcpDaemonSet: true 28 | --- 29 | apiVersion: "k8s.cni.cncf.io/v1" 30 | kind: NetworkAttachmentDefinition 31 | metadata: 32 | name: multus-dhcp 33 | namespace: default 34 | spec: 35 | config: | 36 | { 37 | "cniVersion": "0.3.1", 38 | "type": "macvlan", 39 | "master": "{{ ifaceName }}", 40 | "mode": "bridge", 41 | "ipam": { 42 | "type": "dhcp" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /recipes/home-assistant/README.md: -------------------------------------------------------------------------------- 1 | # Post installation 2 | 3 | After installing the Home Assistant recipe, you need to modify the `configuration.yaml` file in the shared folder that is used to store the Home Assistant configuration. 4 | To get the required information try to access the Home Assistant web interface at `https://home-assistant.:8443`. This will generate an error message in the log files of the Home Assistant pod. 5 | 6 | Go to `Services | Kubernetes | Resources | Pods` in the openmediavault Workbench, find the Home Assistant pod, select it and click the `Logs` action button at the top of the datatable. 7 | 8 | Look out for the following error message: 9 | ```text 10 | [31m2025-07-30 17:16:06.218 ERROR (MainThread) [homeassistant.components.http.forwarded] 2025-07-30 17:16:06.218 ERROR (MainThread) [homeassistant.components.http.forwarded] A request from a reverse proxy was received from 10.42.0.13, but your HTTP integration is not set-up for reverse proxies 11 | ``` 12 | 13 | The `configuration.yaml` file needs to be modified by including the following lines at the bottom of the file: 14 | 15 | ```yaml 16 | http: 17 | use_x_forwarded_for: true 18 | trusted_proxies: 19 | - 10.42.0.13 20 | ``` 21 | 22 | Replace `10.42.0.13` with your IP address from the error message. Alternatively use `10.42.0.0/16` to allow all IP addresses from the Traefik reverse proxy. 23 | 24 | Finally restart the Home Assistant pod by going to `Services | Kubernetes | Resources | Pods`, select the pod and click the `Delete` action button at the top of the datatable. 25 | 26 | Now the Home Assistant web interface should be accessible via the reverse proxy of the openmediavault Kubernetes plugin. 27 | 28 | > ℹ️ **Info:** You might need to modify the `configuration.yaml` file after restoring a backup. 29 | -------------------------------------------------------------------------------- /recipes/uptime-kuma/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://uptime-kuma.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | # Insert the name of the shared folder you want to use. 4 | {% set dataSharedFolderName = '' %} 5 | # !!! Only modify the following manifest if you need to make custom changes. !!! 6 | --- 7 | apiVersion: v1 8 | kind: Namespace 9 | metadata: 10 | name: uptime-kuma-app 11 | --- 12 | apiVersion: helm.cattle.io/v1 13 | kind: HelmChart 14 | metadata: 15 | name: uptime-kuma 16 | namespace: uptime-kuma-app 17 | labels: 18 | app.kubernetes.io/instance: uptime-kuma 19 | app.kubernetes.io/name: uptime-kuma 20 | spec: 21 | repo: https://helm.irsigler.cloud 22 | chart: uptime-kuma 23 | targetNamespace: uptime-kuma-app 24 | valuesContent: |- 25 | fullnameOverride: uptime-kuma 26 | volume: 27 | storageClassName: shared-folder 28 | --- 29 | apiVersion: v1 30 | kind: PersistentVolume 31 | metadata: 32 | name: data-dir 33 | labels: 34 | app.kubernetes.io/instance: uptime-kuma 35 | app.kubernetes.io/name: uptime-kuma 36 | spec: 37 | storageClassName: shared-folder 38 | capacity: 39 | storage: 4Gi 40 | hostPath: 41 | # Insert the name of the shared folder you want to use. 42 | # Make sure the configured UID/GID the container is running 43 | # with has access to that directory. 44 | path: {{ sharedfolder_path(dataSharedFolderName) }} 45 | type: Directory 46 | accessModes: 47 | - ReadWriteOnce 48 | --- 49 | apiVersion: traefik.io/v1alpha1 50 | kind: IngressRoute 51 | metadata: 52 | name: uptime-kuma-websecure 53 | namespace: uptime-kuma-app 54 | labels: 55 | app.kubernetes.io/instance: uptime-kuma 56 | app.kubernetes.io/name: uptime-kuma 57 | spec: 58 | entryPoints: 59 | - websecure 60 | routes: 61 | - match: Host(`uptime-kuma.{{ fqdn() }}`) 62 | kind: Rule 63 | services: 64 | - name: uptime-kuma 65 | port: 3001 66 | tls: {} 67 | -------------------------------------------------------------------------------- /recipes/syncthing/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://syncthing.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | # Insert the name of the shared folder you want to use. Make sure the 6 | # configured UID/GID the container is running with has access to that 7 | # directory. 8 | {% set dataSharedFolderName = '' %} 9 | # !!! Only modify the following manifest if you need to make custom changes. !!! 10 | --- 11 | apiVersion: v1 12 | kind: Namespace 13 | metadata: 14 | name: syncthing-app 15 | --- 16 | apiVersion: helm.cattle.io/v1 17 | kind: HelmChart 18 | metadata: 19 | name: syncthing 20 | namespace: syncthing-app 21 | labels: 22 | app.kubernetes.io/instance: syncthing 23 | app.kubernetes.io/name: syncthing 24 | spec: 25 | repo: http://brandan-schmitz.github.io/helm-charts 26 | chart: syncthing 27 | targetNamespace: syncthing-app 28 | valuesContent: |- 29 | controllers: 30 | main: 31 | pod: 32 | securityContext: 33 | runAsNonRoot: true 34 | # Specifies the UID for the process running in the container. 35 | runAsUser: {{ uid(runAsUser) }} 36 | # Specifies the GID for the process running in the container. 37 | runAsGroup: {{ gid(runAsGroup) }} 38 | fsGroup: {{ gid(runAsGroup) }} 39 | persistence: 40 | config: 41 | type: hostPath 42 | hostPath: {{ sharedfolder_path(dataSharedFolderName) }} 43 | hostPathType: Directory 44 | --- 45 | apiVersion: traefik.io/v1alpha1 46 | kind: IngressRoute 47 | metadata: 48 | name: syncthing-websecure 49 | namespace: syncthing-app 50 | labels: 51 | app.kubernetes.io/instance: syncthing 52 | app.kubernetes.io/name: syncthing 53 | spec: 54 | entryPoints: 55 | - websecure 56 | routes: 57 | - match: Host(`syncthing.{{ fqdn() }}`) 58 | kind: Rule 59 | services: 60 | - name: syncthing 61 | port: 8384 62 | tls: {} 63 | -------------------------------------------------------------------------------- /recipes/filebrowser/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://filebrowser.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | # Insert the name of the shared folder you want to use. Make sure the 6 | # configured UID/GID the container is running with has access to that 7 | # directory. 8 | {% set rootSharedFolderName = '' %} 9 | # !!! Only modify the following manifest if you need to make custom changes. !!! 10 | --- 11 | apiVersion: v1 12 | kind: Namespace 13 | metadata: 14 | name: filebrowser-app 15 | --- 16 | apiVersion: helm.cattle.io/v1 17 | kind: HelmChart 18 | metadata: 19 | name: filebrowser 20 | namespace: filebrowser-app 21 | labels: 22 | app.kubernetes.io/instance: filebrowser 23 | app.kubernetes.io/name: filebrowser 24 | spec: 25 | repo: https://utkuozdemir.org/helm-charts 26 | chart: filebrowser 27 | version: "1.0.0" 28 | targetNamespace: filebrowser-app 29 | valuesContent: |- 30 | image: 31 | tag: "v2.32.3" 32 | securityContext: 33 | runAsNonRoot: true 34 | # Specifies the UID for the process running in the container. 35 | runAsUser: {{ uid(runAsUser) }} 36 | # Specifies the GID for the process running in the container. 37 | runAsGroup: {{ gid(runAsGroup) }} 38 | rootDir: 39 | type: hostPath 40 | hostPath: 41 | # Insert the name of the shared folder you want to use. 42 | # Make sure the configured UID/GID the container is running 43 | # with has access to that directory. 44 | path: {{ sharedfolder_path(rootSharedFolderName) }} 45 | config: 46 | baseURL: / 47 | --- 48 | apiVersion: traefik.io/v1alpha1 49 | kind: IngressRoute 50 | metadata: 51 | name: filebrowser-websecure 52 | namespace: filebrowser-app 53 | labels: 54 | app.kubernetes.io/instance: filebrowser 55 | app.kubernetes.io/name: filebrowser 56 | spec: 57 | entryPoints: 58 | - websecure 59 | routes: 60 | - match: Host(`filebrowser.{{ fqdn() }}`) 61 | kind: Rule 62 | services: 63 | - name: filebrowser 64 | port: 80 65 | tls: {} 66 | -------------------------------------------------------------------------------- /recipes/wetty/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://wetty.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'nogroup' %} 5 | # !!! Only modify the following manifest if you need to make custom changes. !!! 6 | --- 7 | apiVersion: v1 8 | kind: Namespace 9 | metadata: 10 | name: wetty-app 11 | --- 12 | apiVersion: apps/v1 13 | kind: Deployment 14 | metadata: 15 | labels: 16 | app.kubernetes.io/instance: wetty 17 | app.kubernetes.io/name: wetty 18 | name: wetty 19 | namespace: wetty-app 20 | spec: 21 | replicas: 1 22 | selector: 23 | matchLabels: 24 | app.kubernetes.io/instance: wetty 25 | app.kubernetes.io/name: wetty 26 | strategy: 27 | type: Recreate 28 | template: 29 | metadata: 30 | labels: 31 | app.kubernetes.io/instance: wetty 32 | app.kubernetes.io/name: wetty 33 | spec: 34 | containers: 35 | - image: docker.io/wettyoss/wetty:latest 36 | imagePullPolicy: IfNotPresent 37 | name: wetty 38 | ports: 39 | - containerPort: 3000 40 | securityContext: 41 | runAsNonRoot: true 42 | runAsUser: {{ uid(runAsUser) }} 43 | runAsGroup: {{ gid(runAsGroup) }} 44 | args: 45 | - "--port=3000" 46 | - "--base=/" 47 | - "--force-ssh" 48 | - "--ssh-port={{ conf_get('conf.service.ssh') | get('port') }}" 49 | - "--ssh-host={{ hostname() }}" 50 | restartPolicy: Always 51 | --- 52 | apiVersion: v1 53 | kind: Service 54 | metadata: 55 | name: wetty 56 | namespace: wetty-app 57 | labels: 58 | app.kubernetes.io/instance: wetty 59 | app.kubernetes.io/name: wetty 60 | spec: 61 | type: ClusterIP 62 | ports: 63 | - port: 3000 64 | protocol: TCP 65 | targetPort: 3000 66 | selector: 67 | app.kubernetes.io/instance: wetty 68 | app.kubernetes.io/name: wetty 69 | --- 70 | apiVersion: traefik.io/v1alpha1 71 | kind: IngressRoute 72 | metadata: 73 | name: wetty-websecure 74 | namespace: wetty-app 75 | labels: 76 | app.kubernetes.io/instance: wetty 77 | app.kubernetes.io/name: wetty 78 | spec: 79 | entryPoints: 80 | - websecure 81 | routes: 82 | - match: Host(`wetty.{{ fqdn() }}`) 83 | kind: Rule 84 | services: 85 | - name: wetty 86 | port: 3000 87 | tls: {} 88 | -------------------------------------------------------------------------------- /recipes/mariadb/recipe.yaml: -------------------------------------------------------------------------------- 1 | # Change the following variables to adapt the recipe to your needs. 2 | {% set runAsUser = 'nobody' %} 3 | {% set runAsGroup = 'users' %} 4 | {% set rootPassword = 'mypassword' %} 5 | {% set databaseName = 'mydatabase' %} 6 | {% set userName = 'myuser' %} 7 | {% set userPassword = 'myuserpassword' %} 8 | # Insert the name of the shared folder you want to use. Make sure the 9 | # configured UID/GID the container is running with has access to that 10 | # directory. 11 | {% set dataSharedFolderName = '' %} 12 | # !!! Only modify the following manifest if you need to make custom changes. !!! 13 | --- 14 | apiVersion: v1 15 | kind: Namespace 16 | metadata: 17 | name: mariadb-app 18 | --- 19 | apiVersion: helm.cattle.io/v1 20 | kind: HelmChart 21 | metadata: 22 | name: mariadb 23 | namespace: mariadb-app 24 | labels: 25 | app.kubernetes.io/instance: mariadb 26 | app.kubernetes.io/name: mariadb 27 | spec: 28 | repo: https://charts.bitnami.com/bitnami/ 29 | chart: mariadb 30 | targetNamespace: mariadb-app 31 | # Check https://artifacthub.io/packages/helm/bitnami/mariadb?modal=values for more information. 32 | valuesContent: |- 33 | image: 34 | tag: latest 35 | auth: 36 | rootPassword: "{{ rootPassword }}" 37 | database: "{{ databaseName }}" 38 | username: "{{ userName }}" 39 | password: "{{ userPassword }}" 40 | primary: 41 | name: "mariadb-primary" 42 | resourcesPreset: "nano" 43 | podSecurityContext: 44 | fsGroup: {{ gid(runAsGroup) }} 45 | containerSecurityContext: 46 | # Specifies the UID for the process running in the container. 47 | runAsUser: {{ uid(runAsUser) }} 48 | # Specifies the GID for the process running in the container. 49 | runAsGroup: {{ gid(runAsGroup) }} 50 | persistence: 51 | storageClass: "shared-folder" 52 | selector: 53 | matchLabels: 54 | app.kubernetes.io/instance: mariadb 55 | app.kubernetes.io/name: mariadb 56 | extraEnvVars: 57 | - name: TZ 58 | value: "{{ tz() }}" 59 | --- 60 | apiVersion: v1 61 | kind: PersistentVolume 62 | metadata: 63 | name: mariadb-data 64 | labels: 65 | app.kubernetes.io/instance: mariadb 66 | app.kubernetes.io/name: mariadb 67 | spec: 68 | storageClassName: "shared-folder" 69 | capacity: 70 | storage: 8Gi 71 | hostPath: 72 | path: {{ sharedfolder_path(dataSharedFolderName) }} 73 | type: Directory 74 | accessModes: 75 | - ReadWriteOnce 76 | -------------------------------------------------------------------------------- /recipes/ollama/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://ollama.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | # Insert the name of the shared folder you want to use. Make sure the 4 | # configured UID/GID the container is running with has access to that 5 | # directory. 6 | {% set dataSharedFolderName = '' %} 7 | # !!! Only modify the following manifest if you need to make custom changes. !!! 8 | --- 9 | apiVersion: v1 10 | kind: Namespace 11 | metadata: 12 | name: ollama-app 13 | --- 14 | apiVersion: helm.cattle.io/v1 15 | kind: HelmChart 16 | metadata: 17 | name: ollama 18 | namespace: ollama-app 19 | labels: 20 | app.kubernetes.io/instance: ollama 21 | app.kubernetes.io/name: ollama 22 | spec: 23 | repo: https://otwld.github.io/ollama-helm/ 24 | chart: ollama 25 | targetNamespace: ollama-app 26 | valuesContent: |- 27 | deployment: 28 | labels: 29 | app.kubernetes.io/instance: ollama 30 | app.kubernetes.io/name: ollama 31 | podLabels: 32 | app.kubernetes.io/instance: ollama 33 | app.kubernetes.io/name: ollama 34 | persistentVolume: 35 | enabled: true 36 | storageClass: shared-folder 37 | volumeName: data-dir 38 | ollama: 39 | selectorLabels: 40 | app.kubernetes.io/instance: ollama 41 | app.kubernetes.io/name: ollama 42 | # The available model names can be found at https://ollama.com/library. 43 | # Keep in mind that the models require a lot of disk storage and RAM. 44 | models: 45 | pull: 46 | - gemma3:1b 47 | run: 48 | - gemma3:1b 49 | --- 50 | apiVersion: v1 51 | kind: PersistentVolume 52 | metadata: 53 | name: data-dir 54 | labels: 55 | app.kubernetes.io/instance: ollama 56 | app.kubernetes.io/name: ollama 57 | spec: 58 | storageClassName: shared-folder 59 | capacity: 60 | storage: 30Gi 61 | hostPath: 62 | # Insert the name of the shared folder you want to use. 63 | # Make sure the configured UID/GID the container is running 64 | # with has access to that directory. 65 | path: {{ sharedfolder_path(dataSharedFolderName) }} 66 | type: Directory 67 | accessModes: 68 | - ReadWriteOnce 69 | --- 70 | # apiVersion: traefik.io/v1alpha1 71 | # kind: IngressRoute 72 | # metadata: 73 | # name: ollama-websecure 74 | # namespace: ollama-app 75 | # labels: 76 | # app.kubernetes.io/instance: ollama 77 | # app.kubernetes.io/name: ollama 78 | # spec: 79 | # entryPoints: 80 | # - websecure 81 | # routes: 82 | # - match: Host(`ollama.{{ fqdn() }}`) 83 | # kind: Rule 84 | # services: 85 | # - name: ollama 86 | # port: 11434 87 | # tls: {} 88 | -------------------------------------------------------------------------------- /recipes/actual/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://actual.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | # Insert the name of the shared folder you want to use. Make sure the 6 | # configured UID/GID the container is running with has access to that 7 | # directory. 8 | {% set dataSharedFolderName = '' %} 9 | # !!! Only modify the following manifest if you need to make custom changes. !!! 10 | --- 11 | apiVersion: v1 12 | kind: Namespace 13 | metadata: 14 | name: actual-app 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | labels: 20 | app.kubernetes.io/instance: actual 21 | app.kubernetes.io/name: actual 22 | name: actual 23 | namespace: actual-app 24 | spec: 25 | replicas: 1 26 | selector: 27 | matchLabels: 28 | app.kubernetes.io/instance: actual 29 | app.kubernetes.io/name: actual 30 | strategy: 31 | type: Recreate 32 | template: 33 | metadata: 34 | labels: 35 | app.kubernetes.io/instance: actual 36 | app.kubernetes.io/name: actual 37 | spec: 38 | containers: 39 | - name: actual 40 | image: actualbudget/actual-server:latest 41 | imagePullPolicy: Always 42 | securityContext: 43 | runAsNonRoot: true 44 | # Specifies the UID for the process running in the container. 45 | runAsUser: {{ uid(runAsUser) }} 46 | # Specifies the GID for the process running in the container. 47 | runAsGroup: {{ gid(runAsGroup) }} 48 | env: 49 | - name: ACTUAL_PORT 50 | value: "5006" 51 | ports: 52 | - containerPort: 5006 53 | protocol: TCP 54 | volumeMounts: 55 | - name: data 56 | mountPath: /data 57 | restartPolicy: Always 58 | volumes: 59 | - name: data 60 | hostPath: 61 | type: Directory 62 | path: {{ sharedfolder_path(dataSharedFolderName) }} 63 | --- 64 | apiVersion: v1 65 | kind: Service 66 | metadata: 67 | name: actual 68 | namespace: actual-app 69 | labels: 70 | app.kubernetes.io/instance: actual 71 | app.kubernetes.io/name: actual 72 | spec: 73 | type: ClusterIP 74 | selector: 75 | app.kubernetes.io/instance: actual 76 | app.kubernetes.io/name: actual 77 | ports: 78 | - protocol: TCP 79 | port: 5006 80 | targetPort: 5006 81 | --- 82 | apiVersion: traefik.io/v1alpha1 83 | kind: IngressRoute 84 | metadata: 85 | name: actual-websecure 86 | namespace: actual-app 87 | spec: 88 | entryPoints: 89 | - websecure 90 | routes: 91 | - match: Host(`actual.{{ fqdn() }}`) 92 | kind: Rule 93 | services: 94 | - name: actual 95 | port: 5006 96 | tls: {} 97 | -------------------------------------------------------------------------------- /recipes/whoami/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://whoami.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'nogroup' %} 5 | # !!! Only modify the following manifest if you need to make custom changes. !!! 6 | --- 7 | apiVersion: v1 8 | kind: Namespace 9 | metadata: 10 | name: whoami-app 11 | --- 12 | apiVersion: v1 13 | kind: Service 14 | metadata: 15 | name: whoami 16 | namespace: whoami-app 17 | labels: 18 | app.kubernetes.io/instance: whoami 19 | app.kubernetes.io/name: whoami 20 | spec: 21 | ports: 22 | - port: 80 23 | protocol: TCP 24 | targetPort: 8080 25 | selector: 26 | app.kubernetes.io/instance: whoami 27 | app.kubernetes.io/name: whoami 28 | --- 29 | apiVersion: apps/v1 30 | kind: Deployment 31 | metadata: 32 | namespace: whoami-app 33 | name: whoami 34 | labels: 35 | app.kubernetes.io/instance: whoami 36 | app.kubernetes.io/name: whoami 37 | spec: 38 | replicas: 1 39 | selector: 40 | matchLabels: 41 | app.kubernetes.io/instance: whoami 42 | app.kubernetes.io/name: whoami 43 | strategy: 44 | type: Recreate 45 | template: 46 | metadata: 47 | labels: 48 | app.kubernetes.io/instance: whoami 49 | app.kubernetes.io/name: whoami 50 | spec: 51 | containers: 52 | - name: whoami 53 | image: traefik/whoami 54 | imagePullPolicy: Always 55 | # Listen on port 8080 to run as non-root user 56 | args: 57 | - --port 58 | - '8080' 59 | securityContext: 60 | readOnlyRootFilesystem: true 61 | runAsNonRoot: true 62 | runAsUser: {{ uid(runAsUser) }} 63 | runAsGroup: {{ gid(runAsGroup) }} 64 | capabilities: 65 | drop: 66 | - ALL 67 | livenessProbe: 68 | failureThreshold: 3 69 | httpGet: 70 | path: /health 71 | port: 8080 72 | scheme: HTTP 73 | initialDelaySeconds: 5 74 | periodSeconds: 10 75 | timeoutSeconds: 3 76 | resources: 77 | limits: 78 | memory: '50Mi' 79 | cpu: '500m' # 50% 80 | ports: 81 | - containerPort: 8080 82 | --- 83 | apiVersion: traefik.io/v1alpha1 84 | kind: IngressRoute 85 | metadata: 86 | name: whoami-websecure 87 | namespace: whoami-app 88 | labels: 89 | app.kubernetes.io/instance: whoami 90 | app.kubernetes.io/name: whoami 91 | spec: 92 | entryPoints: 93 | - websecure 94 | routes: 95 | - match: Host(`whoami.{{ fqdn() }}`) 96 | kind: Rule 97 | services: 98 | - name: whoami 99 | port: 80 100 | tls: {} 101 | -------------------------------------------------------------------------------- /recipes/plex-media-server/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://plex.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | # Insert the name of the shared folder you want to use. Make sure the 6 | # configured UID/GID the container is running with has access to that 7 | # directory. 8 | {% set configSharedFolderName = '' %} 9 | # !!! Only modify the following manifest if you need to make custom changes. !!! 10 | --- 11 | apiVersion: v1 12 | kind: Namespace 13 | metadata: 14 | name: plex-app 15 | --- 16 | apiVersion: v1 17 | kind: PersistentVolume 18 | metadata: 19 | name: config-dir 20 | labels: 21 | app.kubernetes.io/instance: plex-media-server 22 | app.kubernetes.io/name: plex-media-server 23 | spec: 24 | storageClassName: shared-folder 25 | capacity: 26 | storage: 2Gi 27 | hostPath: 28 | # Insert the name of the shared folder you want to use. 29 | # Make sure the configured UID/GID the container is running 30 | # with has access to that directory. 31 | path: {{ sharedfolder_path(configSharedFolderName) }} 32 | type: Directory 33 | accessModes: 34 | - ReadWriteMany 35 | --- 36 | apiVersion: "v1" 37 | kind: "PersistentVolumeClaim" 38 | metadata: 39 | name: config-dir 40 | namespace: plex-app 41 | labels: 42 | app.kubernetes.io/instance: plex-media-server 43 | app.kubernetes.io/name: plex-media-server 44 | spec: 45 | storageClassName: shared-folder 46 | accessModes: 47 | - "ReadWriteMany" 48 | resources: 49 | requests: 50 | storage: "2Gi" 51 | volumeName: config-dir 52 | --- 53 | apiVersion: helm.cattle.io/v1 54 | kind: HelmChart 55 | metadata: 56 | name: plex-media-server 57 | namespace: plex-app 58 | labels: 59 | app.kubernetes.io/instance: plex-media-server 60 | app.kubernetes.io/name: plex-media-server 61 | spec: 62 | repo: https://raw.githubusercontent.com/plexinc/pms-docker/gh-pages 63 | chart: plex-media-server 64 | targetNamespace: plex-app 65 | valuesContent: |- 66 | pms: 67 | configExistingClaim: config-dir 68 | ingress: 69 | enabled: false 70 | rclone: 71 | enabled: false 72 | service: 73 | type: ClusterIP 74 | extraEnv: 75 | # Specifies the UID for the process running in the container. 76 | PLEX_UID: "{{ uid(runAsUser) }}" 77 | # Specifies the GID for the process running in the container. 78 | PLEX_GID: "{{ gid(runAsGroup) }}" 79 | --- 80 | apiVersion: traefik.io/v1alpha1 81 | kind: IngressRoute 82 | metadata: 83 | name: plex-media-server-websecure 84 | namespace: plex-app 85 | labels: 86 | app.kubernetes.io/instance: plex-media-server 87 | app.kubernetes.io/name: plex-media-server 88 | spec: 89 | entryPoints: 90 | - websecure 91 | routes: 92 | - match: Host(`plex.{{ fqdn() }}`) 93 | kind: Rule 94 | services: 95 | - name: plex-media-server 96 | port: 32400 97 | tls: {} 98 | -------------------------------------------------------------------------------- /recipes/shiori/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://shiori.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | # Insert the name of the shared folder you want to use. Make sure the 6 | # configured UID/GID the container is running with has access to that 7 | # directory. 8 | {% set dataSharedFolderName = '' %} 9 | # !!! Only modify the following manifest if you need to make custom changes. !!! 10 | --- 11 | apiVersion: v1 12 | kind: Namespace 13 | metadata: 14 | name: shiori-app 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | name: shiori 20 | namespace: shiori-app 21 | labels: 22 | app.kubernetes.io/instance: shiori 23 | app.kubernetes.io/name: shiori 24 | spec: 25 | replicas: 1 26 | selector: 27 | matchLabels: 28 | app.kubernetes.io/instance: shiori 29 | app.kubernetes.io/name: shiori 30 | strategy: 31 | type: Recreate 32 | template: 33 | metadata: 34 | labels: 35 | app.kubernetes.io/instance: shiori 36 | app.kubernetes.io/name: shiori 37 | spec: 38 | volumes: 39 | - name: app 40 | hostPath: 41 | type: Directory 42 | path: {{ sharedfolder_path(dataSharedFolderName) }} 43 | - name: tmp 44 | emptyDir: 45 | medium: Memory 46 | containers: 47 | - name: shiori 48 | image: ghcr.io/go-shiori/shiori:latest 49 | command: ["/usr/bin/shiori", "server"] 50 | imagePullPolicy: Always 51 | securityContext: 52 | runAsNonRoot: true 53 | # Specifies the UID for the process running in the container. 54 | runAsUser: {{ uid(runAsUser) }} 55 | # Specifies the GID for the process running in the container. 56 | runAsGroup: {{ gid(runAsGroup) }} 57 | ports: 58 | - containerPort: 8080 59 | env: 60 | - name: SHIORI_DIR 61 | value: /srv/shiori 62 | volumeMounts: 63 | - mountPath: /srv/shiori 64 | name: app 65 | - mountPath: /tmp 66 | name: tmp 67 | --- 68 | apiVersion: v1 69 | kind: Service 70 | metadata: 71 | name: shiori 72 | namespace: shiori-app 73 | labels: 74 | app.kubernetes.io/instance: shiori 75 | app.kubernetes.io/name: shiori 76 | spec: 77 | type: ClusterIP 78 | ports: 79 | - port: 8080 80 | protocol: TCP 81 | targetPort: 8080 82 | selector: 83 | app.kubernetes.io/instance: shiori 84 | app.kubernetes.io/name: shiori 85 | --- 86 | apiVersion: traefik.io/v1alpha1 87 | kind: IngressRoute 88 | metadata: 89 | name: shiori-websecure 90 | namespace: shiori-app 91 | labels: 92 | app.kubernetes.io/instance: shiori 93 | app.kubernetes.io/name: shiori 94 | spec: 95 | entryPoints: 96 | - websecure 97 | routes: 98 | - match: Host(`shiori.{{ fqdn() }}`) 99 | kind: Rule 100 | services: 101 | - name: shiori 102 | port: 8080 103 | tls: {} 104 | -------------------------------------------------------------------------------- /recipes/home-assistant/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://home-assistant.:8443 2 | # Insert the name of the shared folder you want to use. Make sure the 3 | # configured UID/GID the container is running with has access to that 4 | # directory. 5 | {% set configSharedFolderName = '' %} 6 | # !!! Only modify the following manifest if you need to make custom changes. !!! 7 | --- 8 | apiVersion: v1 9 | kind: Namespace 10 | metadata: 11 | name: home-assistant-app 12 | --- 13 | apiVersion: apps/v1 14 | kind: Deployment 15 | metadata: 16 | labels: 17 | app.kubernetes.io/instance: home-assistant 18 | app.kubernetes.io/name: home-assistant 19 | name: home-assistant 20 | namespace: home-assistant-app 21 | spec: 22 | replicas: 1 23 | selector: 24 | matchLabels: 25 | app.kubernetes.io/instance: home-assistant 26 | app.kubernetes.io/name: home-assistant 27 | strategy: 28 | type: Recreate 29 | template: 30 | metadata: 31 | labels: 32 | app.kubernetes.io/instance: home-assistant 33 | app.kubernetes.io/name: home-assistant 34 | spec: 35 | containers: 36 | - image: ghcr.io/home-assistant/home-assistant:stable 37 | imagePullPolicy: IfNotPresent 38 | name: home-assistant 39 | ports: 40 | - containerPort: 8123 41 | protocol: TCP 42 | securityContext: 43 | privileged: true 44 | volumeMounts: 45 | - name: config 46 | mountPath: /config 47 | - name: d-bus 48 | mountPath: /run/dbus 49 | - name: localtime 50 | mountPath: /etc/localtime 51 | - name: zigbee 52 | mountPath: /dev/ttyUSB0 53 | hostNetwork: true 54 | restartPolicy: Always 55 | volumes: 56 | - name: config 57 | hostPath: 58 | type: Directory 59 | path: {{ sharedfolder_path(configSharedFolderName) }} 60 | - name: d-bus 61 | hostPath: 62 | path: /run/dbus 63 | - name: localtime 64 | hostPath: 65 | path: /etc/localtime 66 | - name: zigbee 67 | hostPath: 68 | path: /dev/ttyUSB0 69 | --- 70 | apiVersion: v1 71 | kind: Service 72 | metadata: 73 | name: home-assistant 74 | namespace: home-assistant-app 75 | labels: 76 | app.kubernetes.io/instance: home-assistant 77 | app.kubernetes.io/name: home-assistant 78 | spec: 79 | type: ClusterIP 80 | selector: 81 | app.kubernetes.io/instance: home-assistant 82 | app.kubernetes.io/name: home-assistant 83 | ports: 84 | - protocol: TCP 85 | port: 8123 86 | targetPort: 8123 87 | --- 88 | apiVersion: traefik.io/v1alpha1 89 | kind: IngressRoute 90 | metadata: 91 | name: home-assistant-websecure 92 | namespace: home-assistant-app 93 | spec: 94 | entryPoints: 95 | - websecure 96 | routes: 97 | - match: Host(`home-assistant.{{ fqdn() }}`) 98 | kind: Rule 99 | services: 100 | - name: home-assistant 101 | port: 8123 102 | tls: {} 103 | -------------------------------------------------------------------------------- /recipes/sabnzbd/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://sabnzbd.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | # Insert the name of the shared folder you want to use. Make sure the 6 | # configured UID/GID the container is running with has access to that 7 | # directory. 8 | {% set configSharedFolderName = '' %} 9 | {% set downloadsSharedFolderName = '' %} 10 | {% set incompleteDownloadsSharedFolderName = '' %} 11 | # !!! Only modify the following manifest if you need to make custom changes. !!! 12 | --- 13 | apiVersion: v1 14 | kind: Namespace 15 | metadata: 16 | name: sabnzbd-app 17 | --- 18 | apiVersion: apps/v1 19 | kind: Deployment 20 | metadata: 21 | labels: 22 | app.kubernetes.io/instance: sabnzbd 23 | app.kubernetes.io/name: sabnzbd 24 | name: sabnzbd 25 | namespace: sabnzbd-app 26 | spec: 27 | replicas: 1 28 | selector: 29 | matchLabels: 30 | app.kubernetes.io/instance: sabnzbd 31 | app.kubernetes.io/name: sabnzbd 32 | strategy: 33 | type: Recreate 34 | template: 35 | metadata: 36 | labels: 37 | app.kubernetes.io/instance: sabnzbd 38 | app.kubernetes.io/name: sabnzbd 39 | spec: 40 | containers: 41 | - name: sabnzbd 42 | image: linuxserver/sabnzbd:latest 43 | imagePullPolicy: Always 44 | securityContext: 45 | runAsNonRoot: true 46 | # Specifies the UID for the process running in the container. 47 | runAsUser: {{ uid(runAsUser) }} 48 | # Specifies the GID for the process running in the container. 49 | runAsGroup: {{ gid(runAsGroup) }} 50 | ports: 51 | - containerPort: 8080 52 | protocol: TCP 53 | volumeMounts: 54 | - name: config 55 | mountPath: /config 56 | - name: downloads 57 | mountPath: /downloads 58 | - name: incomplete-downloads 59 | mountPath: /incomplete-downloads 60 | restartPolicy: Always 61 | volumes: 62 | - name: config 63 | hostPath: 64 | type: Directory 65 | path: {{ sharedfolder_path(configSharedFolderName) }} 66 | - name: downloads 67 | hostPath: 68 | type: Directory 69 | path: {{ sharedfolder_path(downloadsSharedFolderName) }} 70 | - name: incomplete-downloads 71 | hostPath: 72 | type: Directory 73 | path: {{ sharedfolder_path(incompleteDownloadsSharedFolderName) }} 74 | --- 75 | apiVersion: v1 76 | kind: Service 77 | metadata: 78 | name: sabnzbd 79 | namespace: sabnzbd-app 80 | labels: 81 | app.kubernetes.io/instance: sabnzbd 82 | app.kubernetes.io/name: sabnzbd 83 | spec: 84 | type: ClusterIP 85 | selector: 86 | app.kubernetes.io/instance: sabnzbd 87 | app.kubernetes.io/name: sabnzbd 88 | ports: 89 | - protocol: TCP 90 | port: 8080 91 | targetPort: 8080 92 | --- 93 | apiVersion: traefik.io/v1alpha1 94 | kind: IngressRoute 95 | metadata: 96 | name: sabnzbd-websecure 97 | namespace: sabnzbd-app 98 | spec: 99 | entryPoints: 100 | - web 101 | - websecure 102 | routes: 103 | - match: Host(`sabnzbd.{{ fqdn() }}`) 104 | kind: Rule 105 | services: 106 | - name: sabnzbd 107 | port: 8080 108 | tls: {} 109 | -------------------------------------------------------------------------------- /recipes/firefox/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://firefox.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set user = 'admin' %} 4 | {% set password = 'firefox' %} 5 | {% set runAsUser = 'nobody' %} 6 | {% set runAsGroup = 'users' %} 7 | # Insert the name of the shared folder you want to use. Make sure the 8 | # configured UID/GID the container is running with has access to that 9 | # directory. 10 | {% set configSharedFolderName = '' %} 11 | # !!! Only modify the following manifest if you need to make custom changes. !!! 12 | --- 13 | apiVersion: v1 14 | kind: Namespace 15 | metadata: 16 | name: firefox-app 17 | --- 18 | apiVersion: v1 19 | kind: Secret 20 | metadata: 21 | name: firefox 22 | namespace: firefox-app 23 | labels: 24 | app.kubernetes.io/instance: firefox 25 | app.kubernetes.io/name: firefox 26 | stringData: 27 | PASSWORD: "{{ password }}" 28 | --- 29 | apiVersion: v1 30 | kind: ConfigMap 31 | metadata: 32 | name: firefox-env 33 | namespace: firefox-app 34 | data: 35 | CUSTOM_USER: "{{ user }}" 36 | PUID: "{{ uid(runAsUser) }}" 37 | PGID: "{{ gid(runAsGroup) }}" 38 | TZ: "{{ tz() }}" 39 | FIREFOX_CLI: "https://www.openmediavault.org" 40 | LC_ALL: "en_US.UTF-8" 41 | NO_DECOR: "1" 42 | DOCKER_MODS: "linuxserver/mods:universal-package-install" 43 | INSTALL_PACKAGES: "fonts-noto-cjk" 44 | --- 45 | apiVersion: apps/v1 46 | kind: Deployment 47 | metadata: 48 | labels: 49 | app.kubernetes.io/instance: firefox 50 | app.kubernetes.io/name: firefox 51 | name: firefox 52 | namespace: firefox-app 53 | spec: 54 | replicas: 1 55 | selector: 56 | matchLabels: 57 | app.kubernetes.io/instance: firefox 58 | app.kubernetes.io/name: firefox 59 | strategy: 60 | type: Recreate 61 | template: 62 | metadata: 63 | labels: 64 | app.kubernetes.io/instance: firefox 65 | app.kubernetes.io/name: firefox 66 | spec: 67 | containers: 68 | - name: firefox 69 | image: lscr.io/linuxserver/firefox:latest 70 | imagePullPolicy: IfNotPresent 71 | ports: 72 | - containerPort: 3000 73 | protocol: TCP 74 | envFrom: 75 | - secretRef: 76 | name: firefox 77 | - configMapRef: 78 | name: firefox-env 79 | volumeMounts: 80 | - name: "config" 81 | mountPath: "/config" 82 | restartPolicy: Always 83 | volumes: 84 | - name: "config" 85 | hostPath: 86 | type: "Directory" 87 | # Insert the name of the shared folder you want to use. 88 | # Make sure the configured UID/GID the container is running 89 | # with has access to that directory. 90 | path: "{{ sharedfolder_path(configSharedFolderName) }}" 91 | --- 92 | apiVersion: v1 93 | kind: Service 94 | metadata: 95 | name: firefox 96 | namespace: firefox-app 97 | labels: 98 | app.kubernetes.io/instance: firefox 99 | app.kubernetes.io/name: firefox 100 | spec: 101 | type: ClusterIP 102 | ports: 103 | - port: 3000 104 | protocol: TCP 105 | targetPort: 3000 106 | selector: 107 | app.kubernetes.io/instance: firefox 108 | app.kubernetes.io/name: firefox 109 | --- 110 | apiVersion: traefik.io/v1alpha1 111 | kind: IngressRoute 112 | metadata: 113 | name: firefox-websecure 114 | namespace: firefox-app 115 | labels: 116 | app.kubernetes.io/instance: firefox 117 | app.kubernetes.io/name: firefox 118 | spec: 119 | entryPoints: 120 | - websecure 121 | routes: 122 | - match: Host(`firefox.{{ fqdn() }}`) 123 | kind: Rule 124 | services: 125 | - name: firefox 126 | port: 3000 127 | tls: {} 128 | -------------------------------------------------------------------------------- /recipes/minio/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://minio-console.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | # Insert the name of the shared folder you want to use. Make sure the 6 | # configured UID/GID the container is running with has access to that 7 | # directory. 8 | {% set dataSharedFolderName = '' %} 9 | # !!! Only modify the following manifest if you need to make custom changes. !!! 10 | --- 11 | apiVersion: v1 12 | kind: Namespace 13 | metadata: 14 | name: minio-app 15 | --- 16 | apiVersion: apps/v1 17 | kind: Deployment 18 | metadata: 19 | labels: 20 | app.kubernetes.io/instance: minio 21 | app.kubernetes.io/name: minio 22 | name: minio 23 | namespace: minio-app 24 | spec: 25 | selector: 26 | matchLabels: 27 | app.kubernetes.io/instance: minio 28 | app.kubernetes.io/name: minio 29 | replicas: 1 30 | strategy: 31 | type: Recreate 32 | template: 33 | metadata: 34 | labels: 35 | app.kubernetes.io/instance: minio 36 | app.kubernetes.io/name: minio 37 | spec: 38 | containers: 39 | - name: minio 40 | image: quay.io/minio/minio:latest 41 | imagePullPolicy: IfNotPresent 42 | securityContext: 43 | runAsNonRoot: true 44 | # Specifies the UID for the process running in the container. 45 | runAsUser: {{ uid(runAsUser) }} 46 | # Specifies the GID for the process running in the container. 47 | runAsGroup: {{ gid(runAsGroup) }} 48 | args: 49 | - "server" 50 | - "/data/" 51 | env: 52 | - name: "MINIO_ADDRESS" 53 | value: ":9000" 54 | - name: "MINIO_CONSOLE_ADDRESS" 55 | value: ":9001" 56 | - name: "MINIO_ROOT_USER" 57 | value: "admin" 58 | - name: "MINIO_ROOT_PASSWORD" 59 | value: "openmediavault" 60 | ports: 61 | - containerPort: 9000 62 | name: api 63 | protocol: TCP 64 | - containerPort: 9001 65 | name: console 66 | protocol: TCP 67 | volumeMounts: 68 | - name: data 69 | mountPath: "/data/" 70 | restartPolicy: Always 71 | volumes: 72 | - name: data 73 | hostPath: 74 | type: Directory 75 | # Insert the name of the shared folder you want to use. 76 | # Make sure the configured UID/GID the container is running 77 | # with has access to that directory. 78 | path: {{ sharedfolder_path(dataSharedFolderName) }} 79 | --- 80 | apiVersion: v1 81 | kind: Service 82 | metadata: 83 | name: minio-api 84 | namespace: minio-app 85 | spec: 86 | selector: 87 | app.kubernetes.io/instance: minio 88 | app.kubernetes.io/name: minio 89 | type: ClusterIP 90 | ports: 91 | - port: 9000 92 | protocol: TCP 93 | targetPort: 9000 94 | --- 95 | apiVersion: v1 96 | kind: Service 97 | metadata: 98 | name: minio-console 99 | namespace: minio-app 100 | labels: 101 | app.kubernetes.io/instance: minio 102 | app.kubernetes.io/name: minio 103 | spec: 104 | selector: 105 | app.kubernetes.io/instance: minio 106 | app.kubernetes.io/name: minio 107 | type: ClusterIP 108 | ports: 109 | - port: 9001 110 | protocol: TCP 111 | targetPort: 9001 112 | --- 113 | apiVersion: traefik.io/v1alpha1 114 | kind: IngressRoute 115 | metadata: 116 | name: minio-console-websecure 117 | namespace: minio-app 118 | labels: 119 | app.kubernetes.io/instance: minio 120 | app.kubernetes.io/name: minio 121 | spec: 122 | entryPoints: 123 | - websecure 124 | routes: 125 | - match: Host(`minio-console.{{ fqdn() }}`) 126 | kind: Rule 127 | services: 128 | - name: minio-console 129 | port: 9001 130 | tls: {} 131 | -------------------------------------------------------------------------------- /recipes/paperless-ngx/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://paperless.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | {% set adminUser = 'admin' %} 6 | {% set adminPassword = 'admin' %} 7 | {% set dbPassword = 'paperless-ngx' %} 8 | {% set dbRootPassword = 'paperless-ngx' %} 9 | # https://tesseract-ocr.github.io/tessdoc/Data-Files-in-different-versions.html 10 | {% set ocrLanguage = 'eng' %} 11 | # Insert the name of the shared folder you want to use. Make sure the 12 | # configured UID/GID the container is running with has access to that 13 | # directory. 14 | {% set dataSharedFolderName = '' %} 15 | {% set mediaSharedFolderName = '' %} 16 | {% set exportSharedFolderName = '' %} 17 | {% set consumeSharedFolderName = '' %} 18 | # !!! Only modify the following manifest if you need to make custom changes. !!! 19 | --- 20 | apiVersion: v1 21 | kind: Namespace 22 | metadata: 23 | name: paperless-app 24 | --- 25 | apiVersion: v1 26 | kind: ConfigMap 27 | metadata: 28 | name: paperless 29 | namespace: paperless-app 30 | data: 31 | # https://docs.paperless-ngx.com/configuration/ 32 | USERMAP_UID: "{{ uid(runAsUser) }}" 33 | USERMAP_GID: "{{ gid(runAsGroup) }}" 34 | PAPERLESS_ADMIN_USER: "{{ adminUser }}" 35 | PAPERLESS_FILENAME_DATE_ORDER: "YMD" 36 | PAPERLESS_DATE_ORDER: "DMY" 37 | PAPERLESS_URL: "https://paperless.{{ fqdn() }}:{{ conf_get('conf.service.k8s') | get('websecureport') }}" 38 | PAPERLESS_CSRF_TRUSTED_ORIGINS: "https://*.{{ fqdn() }}" 39 | PAPERLESS_ALLOWED_HOSTS: "paperless.{{ fqdn() }}:{{ conf_get('conf.service.k8s') | get('websecureport') }}" 40 | PAPERLESS_OCR_LANGUAGE: "{{ ocrLanguage }}" 41 | --- 42 | apiVersion: v1 43 | kind: Secret 44 | metadata: 45 | name: paperless 46 | namespace: paperless-app 47 | labels: 48 | app.kubernetes.io/instance: paperless 49 | app.kubernetes.io/name: paperless 50 | stringData: 51 | PAPERLESS_ADMIN_PASSWORD: "{{ adminPassword }}" 52 | --- 53 | apiVersion: helm.cattle.io/v1 54 | kind: HelmChart 55 | metadata: 56 | name: paperless 57 | namespace: paperless-app 58 | labels: 59 | app.kubernetes.io/instance: paperless 60 | app.kubernetes.io/name: paperless 61 | spec: 62 | repo: https://charts.gabe565.com 63 | chart: paperless-ngx 64 | targetNamespace: paperless-app 65 | valuesContent: |- 66 | image: 67 | tag: 2.12.1 68 | env: 69 | TZ: {{ tz() }} 70 | envFrom: 71 | - secretRef: 72 | name: paperless 73 | - configMapRef: 74 | name: paperless 75 | mariadb: 76 | enabled: true 77 | auth: 78 | password: {{ dbPassword }} 79 | rootPassword: {{ dbRootPassword }} 80 | persistence: 81 | data: 82 | enabled: true 83 | type: hostPath 84 | hostPath: {{ sharedfolder_path(dataSharedFolderName) }} 85 | hostPathType: Directory 86 | media: 87 | enabled: true 88 | type: hostPath 89 | hostPath: {{ sharedfolder_path(mediaSharedFolderName) }} 90 | hostPathType: Directory 91 | export: 92 | enabled: true 93 | type: hostPath 94 | hostPath: {{ sharedfolder_path(exportSharedFolderName) }} 95 | hostPathType: Directory 96 | consume: 97 | enabled: true 98 | type: hostPath 99 | hostPath: {{ sharedfolder_path(consumeSharedFolderName) }} 100 | hostPathType: Directory 101 | --- 102 | apiVersion: traefik.io/v1alpha1 103 | kind: IngressRoute 104 | metadata: 105 | name: paperless-websecure 106 | namespace: paperless-app 107 | labels: 108 | app.kubernetes.io/instance: paperless 109 | app.kubernetes.io/name: paperless 110 | spec: 111 | entryPoints: 112 | - websecure 113 | routes: 114 | - match: Host(`paperless.{{ fqdn() }}`) 115 | kind: Rule 116 | services: 117 | - name: paperless-paperless-ngx 118 | port: 8000 119 | tls: {} 120 | -------------------------------------------------------------------------------- /recipes/jellyfin/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://jellyfin.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | # Insert the name of the shared folder you want to use. Make sure the 6 | # configured UID/GID the container is running with has access to that 7 | # directory. 8 | {% set cacheSharedFolderName = '' %} 9 | {% set configSharedFolderName = '' %} 10 | {% set mediaSharedFolderName = '' %} 11 | # !!! Only modify the following manifest if you need to make custom changes. !!! 12 | --- 13 | apiVersion: v1 14 | kind: Namespace 15 | metadata: 16 | name: jellyfin-app 17 | --- 18 | apiVersion: apps/v1 19 | kind: Deployment 20 | metadata: 21 | labels: 22 | app.kubernetes.io/instance: jellyfin 23 | app.kubernetes.io/name: jellyfin 24 | name: jellyfin 25 | namespace: jellyfin-app 26 | spec: 27 | replicas: 1 28 | selector: 29 | matchLabels: 30 | app.kubernetes.io/instance: jellyfin 31 | app.kubernetes.io/name: jellyfin 32 | strategy: 33 | type: Recreate 34 | template: 35 | metadata: 36 | labels: 37 | app.kubernetes.io/instance: jellyfin 38 | app.kubernetes.io/name: jellyfin 39 | spec: 40 | containers: 41 | - image: docker.io/jellyfin/jellyfin:latest 42 | imagePullPolicy: IfNotPresent 43 | name: jellyfin 44 | ports: 45 | - containerPort: 8096 46 | name: http 47 | protocol: TCP 48 | securityContext: 49 | runAsNonRoot: true 50 | # Specifies the UID for the process running in the container. 51 | runAsUser: {{ uid(runAsUser) }} 52 | # Specifies the GID for the process running in the container. 53 | runAsGroup: {{ gid(runAsGroup) }} 54 | volumeMounts: 55 | - name: cache 56 | mountPath: /cache 57 | - name: config 58 | mountPath: /config 59 | - name: media 60 | mountPath: /media 61 | restartPolicy: Always 62 | volumes: 63 | - name: cache 64 | hostPath: 65 | type: Directory 66 | # Insert the name of the shared folder you want to use. 67 | # Make sure the configured UID/GID the container is running 68 | # with has access to that directory. 69 | path: {{ sharedfolder_path(cacheSharedFolderName) }} 70 | - name: config 71 | hostPath: 72 | type: Directory 73 | # Insert the name of the shared folder you want to use. 74 | # Make sure the configured UID/GID the container is running 75 | # with has access to that directory. 76 | path: {{ sharedfolder_path(configSharedFolderName) }} 77 | - name: media 78 | hostPath: 79 | type: Directory 80 | # Insert the name of the shared folder you want to use. 81 | # Make sure the configured UID/GID the container is running 82 | # with has access to that directory. 83 | path: {{ sharedfolder_path(mediaSharedFolderName) }} 84 | --- 85 | apiVersion: v1 86 | kind: Service 87 | metadata: 88 | name: jellyfin 89 | namespace: jellyfin-app 90 | labels: 91 | app.kubernetes.io/instance: jellyfin 92 | app.kubernetes.io/name: jellyfin 93 | spec: 94 | type: ClusterIP 95 | ports: 96 | - port: 8096 97 | protocol: TCP 98 | targetPort: 8096 99 | selector: 100 | app.kubernetes.io/instance: jellyfin 101 | app.kubernetes.io/name: jellyfin 102 | --- 103 | apiVersion: traefik.io/v1alpha1 104 | kind: IngressRoute 105 | metadata: 106 | name: jellyfin-websecure 107 | namespace: jellyfin-app 108 | spec: 109 | entryPoints: 110 | - websecure 111 | routes: 112 | - match: Host(`jellyfin.{{ fqdn() }}`) 113 | kind: Rule 114 | services: 115 | - name: jellyfin 116 | port: 8096 117 | tls: {} 118 | -------------------------------------------------------------------------------- /recipes/webdav/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://webdav.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set userName = 'admin' %} 4 | {% set userPassword = 'admin' %} 5 | {% set runAsUser = 'nobody' %} 6 | {% set runAsGroup = 'users' %} 7 | # Insert the name of the shared folder you want to use. Make sure the 8 | # configured UID/GID the container is running with has access to that 9 | # directory. 10 | {% set dataSharedFolderName = '' %} 11 | # !!! Only modify the following manifest if you need to make custom changes. !!! 12 | --- 13 | apiVersion: v1 14 | kind: Namespace 15 | metadata: 16 | name: webdav-app 17 | --- 18 | apiVersion: v1 19 | kind: Service 20 | metadata: 21 | name: webdav 22 | namespace: webdav-app 23 | labels: 24 | app.kubernetes.io/instance: webdav 25 | app.kubernetes.io/name: webdav 26 | spec: 27 | type: ClusterIP 28 | selector: 29 | app.kubernetes.io/instance: webdav 30 | app.kubernetes.io/name: webdav 31 | ports: 32 | - name: webdav 33 | port: 80 34 | --- 35 | apiVersion: v1 36 | kind: Secret 37 | metadata: 38 | name: webdav 39 | namespace: webdav-app 40 | labels: 41 | app.kubernetes.io/instance: webdav 42 | app.kubernetes.io/name: webdav 43 | stringData: 44 | WEBDAV_PASSWORD: "{{ userPassword }}" 45 | --- 46 | apiVersion: v1 47 | kind: ConfigMap 48 | metadata: 49 | name: webdav-env 50 | namespace: webdav-app 51 | data: 52 | WEBDAV_USERNAME: "{{ userName }}" 53 | PUID: "{{ uid(runAsUser) }}" 54 | PGID: "{{ gid(runAsGroup) }}" 55 | TZ: "{{ tz() }}" 56 | SERVER_NAMES: "webdav.{{ fqdn() }}:{{ conf_get('conf.service.k8s') | get('websecureport') }}" 57 | CLIENT_MAX_BODY_SIZE: "120M" # must end with M(egabytes) or G(igabytes) 58 | TIMEOUTS_S: "1200" # these are seconds 59 | --- 60 | apiVersion: apps/v1 61 | kind: StatefulSet 62 | metadata: 63 | labels: 64 | app.kubernetes.io/instance: webdav 65 | app.kubernetes.io/name: webdav 66 | name: webdav 67 | namespace: webdav-app 68 | spec: 69 | replicas: 1 70 | selector: 71 | matchLabels: 72 | app.kubernetes.io/instance: webdav 73 | app.kubernetes.io/name: webdav 74 | serviceName: webdav 75 | template: 76 | metadata: 77 | labels: 78 | app.kubernetes.io/instance: webdav 79 | app.kubernetes.io/name: webdav 80 | spec: 81 | containers: 82 | - envFrom: 83 | - secretRef: 84 | name: webdav 85 | - configMapRef: 86 | name: webdav-env 87 | image: dgraziotin/nginx-webdav-nononsense:latest 88 | name: webdav 89 | ports: 90 | - containerPort: 80 91 | protocol: TCP 92 | volumeMounts: 93 | - name: webdav-config 94 | mountPath: /config 95 | - name: data 96 | mountPath: /data 97 | restartPolicy: Always 98 | volumes: 99 | - name: data 100 | hostPath: 101 | type: Directory 102 | # Insert the name of the shared folder you want to use. 103 | # Make sure the configured UID/GID the container is running 104 | # with has access to that directory. 105 | path: "{{ sharedfolder_path(dataSharedFolderName) }}" 106 | volumeClaimTemplates: 107 | - metadata: 108 | labels: 109 | app.kubernetes.io/instance: webdav 110 | app.kubernetes.io/name: webdav 111 | name: webdav-config 112 | namespace: webdav-app 113 | spec: 114 | accessModes: 115 | - ReadWriteOnce 116 | resources: 117 | requests: 118 | storage: 100Mi 119 | --- 120 | apiVersion: traefik.io/v1alpha1 121 | kind: IngressRoute 122 | metadata: 123 | name: webdav-websecure 124 | namespace: webdav-app 125 | labels: 126 | app.kubernetes.io/instance: webdav 127 | app.kubernetes.io/name: webdav 128 | spec: 129 | entryPoints: 130 | - websecure 131 | routes: 132 | - match: Host(`webdav.{{ fqdn() }}`) 133 | kind: Rule 134 | services: 135 | - name: webdav 136 | port: 80 137 | tls: {} 138 | -------------------------------------------------------------------------------- /recipes/smokeping/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at http://:8080/smokeping 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set emailPass = '' %} 4 | {% set emailUser = '' %} 5 | {% set emailHost = '' %} 6 | # Insert the name of the shared folder you want to use. Make sure the 7 | # configured UID/GID the container is running with has access to that 8 | # directory. 9 | {% set configSharedFolderName = '' %} 10 | {% set dataSharedFolderName = '' %} 11 | # !!! Only modify the following manifest if you need to make custom changes. !!! 12 | --- 13 | apiVersion: v1 14 | kind: Namespace 15 | metadata: 16 | name: smokeping-app 17 | --- 18 | apiVersion: v1 19 | kind: ConfigMap 20 | metadata: 21 | name: smokeping-ssmtp 22 | namespace: smokeping-app 23 | data: 24 | ssmtp.conf: | 25 | root={{ emailUser }} 26 | mailhub={{ emailHost }} 27 | AuthUser={{ emailUser }} 28 | AuthPass={{ emailPass }} 29 | UseTLS=YES 30 | UseSTARTTLS=YES 31 | FromLineOverride=YES 32 | hostname=smokeping.kubernetes.default.svc 33 | --- 34 | apiVersion: traefik.io/v1alpha1 35 | kind: IngressRoute 36 | metadata: 37 | name: smokeping-web 38 | namespace: smokeping-app 39 | labels: 40 | app.kubernetes.io/instance: smokeping 41 | app.kubernetes.io/name: smokeping 42 | spec: 43 | entryPoints: 44 | - web 45 | routes: 46 | - match: PathPrefix(`/smokeping`) 47 | kind: Rule 48 | services: 49 | - name: smokeping 50 | port: 80 51 | --- 52 | apiVersion: v1 53 | kind: Service 54 | metadata: 55 | name: smokeping 56 | namespace: smokeping-app 57 | labels: 58 | app.kubernetes.io/instance: smokeping 59 | app.kubernetes.io/name: smokeping 60 | spec: 61 | ports: 62 | - port: 80 63 | targetPort: 80 64 | protocol: TCP 65 | name: http 66 | selector: 67 | app.kubernetes.io/instance: smokeping 68 | app.kubernetes.io/name: smokeping 69 | type: ClusterIP 70 | --- 71 | apiVersion: apps/v1 72 | kind: Deployment 73 | metadata: 74 | name: smokeping 75 | namespace: smokeping-app 76 | labels: 77 | app.kubernetes.io/instance: smokeping 78 | app.kubernetes.io/name: smokeping 79 | spec: 80 | strategy: 81 | type: Recreate 82 | replicas: 1 83 | selector: 84 | matchLabels: 85 | app.kubernetes.io/instance: smokeping 86 | app.kubernetes.io/name: smokeping 87 | template: 88 | metadata: 89 | labels: 90 | app.kubernetes.io/instance: smokeping 91 | app.kubernetes.io/name: smokeping 92 | spec: 93 | containers: 94 | - name: smokeping 95 | image: linuxserver/smokeping:latest 96 | imagePullPolicy: Always 97 | ports: 98 | - containerPort: 80 99 | name: http 100 | protocol: TCP 101 | volumeMounts: 102 | - mountPath: "/config" 103 | name: config 104 | - mountPath: "/data" 105 | name: data 106 | - mountPath: "/etc/ssmtp/ssmtp.conf" 107 | name: ssmtp-config 108 | subPath: ssmtp.conf 109 | readOnly: true 110 | env: 111 | - name: PUID 112 | value: "1000" 113 | - name: PGID 114 | value: "1000" 115 | - name: TZ 116 | value: {{ tz() }} 117 | volumes: 118 | - name: config 119 | hostPath: 120 | type: Directory 121 | # Insert the name of the shared folder you want to use. 122 | # Make sure the configured UID/GID the container is running 123 | # with has access to that directory. 124 | path: {{ sharedfolder_path(configSharedFolderName) }} 125 | - name: data 126 | hostPath: 127 | type: Directory 128 | # Insert the name of the shared folder you want to use. 129 | # Make sure the configured UID/GID the container is running 130 | # with has access to that directory. 131 | path: {{ sharedfolder_path(dataSharedFolderName) }} 132 | - name: ssmtp-config 133 | configMap: 134 | name: smokeping-ssmtp 135 | -------------------------------------------------------------------------------- /recipes/immich/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://immich.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | # Insert the name of the shared folder you want to use. Make sure the 6 | # configured UID/GID the container is running with has access to that 7 | # directory. 8 | {% set librarySharedFolderName = '' %} 9 | {% set importSharedFolderName = '' %} 10 | # !!! Only modify the following manifest if you need to make custom changes. !!! 11 | --- 12 | apiVersion: v1 13 | kind: Namespace 14 | metadata: 15 | name: immich-app 16 | --- 17 | apiVersion: v1 18 | kind: PersistentVolume 19 | metadata: 20 | name: immich-library 21 | labels: 22 | app.kubernetes.io/instance: immich 23 | app.kubernetes.io/name: immich 24 | spec: 25 | storageClassName: shared-folder 26 | capacity: 27 | storage: 2Gi 28 | hostPath: 29 | # This is the path where the immich library will be stored. 30 | # Insert the name of the shared folder you want to use. 31 | path: {{ sharedfolder_path(librarySharedFolderName) }} 32 | type: Directory 33 | accessModes: 34 | - "ReadWriteOnce" 35 | --- 36 | apiVersion: "v1" 37 | kind: "PersistentVolumeClaim" 38 | metadata: 39 | name: immich-library 40 | namespace: immich-app 41 | labels: 42 | app.kubernetes.io/instance: immich 43 | app.kubernetes.io/name: immich 44 | spec: 45 | storageClassName: shared-folder 46 | accessModes: 47 | - "ReadWriteOnce" 48 | resources: 49 | requests: 50 | storage: "2Gi" 51 | volumeName: immich-library 52 | --- 53 | apiVersion: helm.cattle.io/v1 54 | kind: HelmChart 55 | metadata: 56 | name: immich 57 | namespace: immich-app 58 | labels: 59 | app.kubernetes.io/instance: immich 60 | app.kubernetes.io/name: immich 61 | spec: 62 | repo: https://immich-app.github.io/immich-charts 63 | chart: immich 64 | version: 0.9.0 65 | targetNamespace: immich-app 66 | valuesContent: |- 67 | securityContext: 68 | runAsNonRoot: true 69 | # Specifies the UID for the process running in the container. 70 | runAsUser: {{ uid(runAsUser) }} 71 | # Specifies the GID for the process running in the container. 72 | runAsGroup: {{ gid(runAsGroup) }} 73 | image: 74 | tag: v1.119.0 75 | immich: 76 | persistence: 77 | library: 78 | existingClaim: immich-library 79 | useDeprecatedPostgresChart: true 80 | postgresql: 81 | enabled: true 82 | primary: 83 | # This fixes startup issues for a fresh install. See this issue 84 | # for details: 85 | # https://github.com/immich-app/immich-charts/issues/130#issuecomment-2410351150 86 | resourcesPreset: large 87 | server: 88 | probes: 89 | startup: 90 | spec: 91 | # This fixes startup issues for a fresh install. See this issue 92 | # for details: 93 | # https://github.com/immich-app/immich-charts/issues/130#issuecomment-2414043494 94 | failureThreshold: 360 95 | redis: 96 | enabled: true 97 | persistence: 98 | # This is the shared folder that is used to import existing files to the immich library. 99 | # See https://immich.app/docs/guides/external-library/ for more information. 100 | import: 101 | enabled: true # Set to false if you do not want to have an external library. 102 | type: hostPath 103 | readOnly: true 104 | mountPath: /srv/import # Use this path in the `Add Import Path` dialog. 105 | hostPath: {{ sharedfolder_path(importSharedFolderName) }} 106 | hostPathType: Directory 107 | --- 108 | apiVersion: traefik.io/v1alpha1 109 | kind: IngressRoute 110 | metadata: 111 | name: immich-websecure 112 | namespace: immich-app 113 | labels: 114 | app.kubernetes.io/instance: immich 115 | app.kubernetes.io/name: immich 116 | spec: 117 | entryPoints: 118 | - websecure 119 | routes: 120 | - match: Host(`immich.{{ fqdn() }}`) 121 | kind: Rule 122 | services: 123 | - name: immich-server 124 | port: 2283 125 | tls: {} 126 | -------------------------------------------------------------------------------- /recipes/palmr/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at http://palmr.:8080 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | # Insert the name of the shared folder you want to use. Make sure the 6 | # configured UID/GID the container is running with has access to that 7 | # directory. 8 | {% set dataSharedFolderName = '' %} 9 | # !!! Only modify the following manifest if you need to make custom changes. !!! 10 | --- 11 | apiVersion: v1 12 | kind: Namespace 13 | metadata: 14 | name: palmr-app 15 | --- 16 | apiVersion: v1 17 | kind: ConfigMap 18 | metadata: 19 | name: palmr-env 20 | namespace: palmr-app 21 | data: 22 | # Optional: Uncomment and configure as needed (if you don`t use, you can remove) 23 | # ENABLE_S3: true # Set to true to enable S3-compatible storage 24 | # DISABLE_FILESYSTEM_ENCRYPTION: false # Set to false to enable file encryption 25 | # ENCRYPTION_KEY: your-secure-key-min-32-chars # Required only if encryption is enabled 26 | PALMR_UID: "{{ uid(runAsUser) }}" # UID for the container processes (default is 1000) 27 | PALMR_GID: "{{ gid(runAsGroup) }}" # GID for the container processes (default is 1000) 28 | SECURE_SITE: "true" # Set to true if you are using a reverse proxy 29 | # DEFAULT_LANGUAGE: en-US # Default language for the application (optional, defaults to en-US) 30 | # PRESIGNED_URL_EXPIRATION: 3600 # Duration in seconds for presigned URL expiration (optional, defaults to 3600 seconds / 1 hour) 31 | # DOWNLOAD_MAX_CONCURRENT: 5 # Maximum simultaneous downloads (auto-scales if not set) 32 | # DOWNLOAD_MEMORY_THRESHOLD_MB: 2048 # Memory threshold in MB before throttling (auto-scales if not set) 33 | # DOWNLOAD_QUEUE_SIZE: 25 # Maximum queue size for pending downloads (auto-scales if not set) 34 | # DOWNLOAD_MIN_FILE_SIZE_GB: 3.0 # Minimum file size in GB to activate memory management (default: 3.0) 35 | # DOWNLOAD_AUTO_SCALE: true # Enable auto-scaling based on system memory (default: true) 36 | # NODE_OPTIONS: --expose-gc # Enable garbage collection for large downloads (recommended for production) 37 | --- 38 | apiVersion: traefik.io/v1alpha1 39 | kind: IngressRoute 40 | metadata: 41 | name: palmr-websecure 42 | namespace: palmr-app 43 | labels: 44 | app.kubernetes.io/instance: palmr 45 | app.kubernetes.io/name: palmr 46 | spec: 47 | entryPoints: 48 | - websecure 49 | routes: 50 | - match: Host(`palmr.{{ fqdn() }}`) 51 | kind: Rule 52 | services: 53 | - name: palmr 54 | port: 5487 55 | tls: {} 56 | --- 57 | apiVersion: v1 58 | kind: Service 59 | metadata: 60 | name: palmr 61 | namespace: palmr-app 62 | labels: 63 | app.kubernetes.io/instance: palmr 64 | app.kubernetes.io/name: palmr 65 | spec: 66 | ports: 67 | - port: 5487 68 | targetPort: 5487 69 | protocol: TCP 70 | name: http 71 | selector: 72 | app.kubernetes.io/instance: palmr 73 | app.kubernetes.io/name: palmr 74 | type: ClusterIP 75 | --- 76 | apiVersion: apps/v1 77 | kind: Deployment 78 | metadata: 79 | name: palmr 80 | namespace: palmr-app 81 | labels: 82 | app.kubernetes.io/instance: palmr 83 | app.kubernetes.io/name: palmr 84 | spec: 85 | strategy: 86 | type: Recreate 87 | replicas: 1 88 | selector: 89 | matchLabels: 90 | app.kubernetes.io/instance: palmr 91 | app.kubernetes.io/name: palmr 92 | template: 93 | metadata: 94 | labels: 95 | app.kubernetes.io/instance: palmr 96 | app.kubernetes.io/name: palmr 97 | spec: 98 | containers: 99 | - name: palmr 100 | image: kyantech/palmr:latest 101 | imagePullPolicy: Always 102 | ports: 103 | - containerPort: 5487 104 | name: http 105 | protocol: TCP 106 | volumeMounts: 107 | - mountPath: "/app/server" 108 | name: data 109 | envFrom: 110 | - configMapRef: 111 | name: palmr-env 112 | volumes: 113 | - name: data 114 | hostPath: 115 | type: Directory 116 | path: {{ sharedfolder_path(dataSharedFolderName) }} 117 | -------------------------------------------------------------------------------- /recipes/pyload/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at http://pyload.:8080 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | # Insert the name of the shared folder you want to use. Make sure the 6 | # configured UID/GID the container is running with has access to that 7 | # directory. 8 | {% set configSharedFolderName = '' %} 9 | {% set dataSharedFolderName = '' %} 10 | # !!! Only modify the following manifest if you need to make custom changes. !!! 11 | --- 12 | apiVersion: v1 13 | kind: Namespace 14 | metadata: 15 | name: pyload-app 16 | --- 17 | apiVersion: traefik.io/v1alpha1 18 | kind: Middleware 19 | metadata: 20 | name: pyload-headers 21 | namespace: pyload-app 22 | labels: 23 | app.kubernetes.io/instance: pyload 24 | app.kubernetes.io/name: pyload 25 | spec: 26 | headers: 27 | customResponseHeaders: 28 | X-Frame-Options: "SAMEORIGIN" 29 | --- 30 | apiVersion: traefik.io/v1alpha1 31 | kind: IngressRoute 32 | metadata: 33 | name: pyload-web 34 | namespace: pyload-app 35 | labels: 36 | app.kubernetes.io/instance: pyload 37 | app.kubernetes.io/name: pyload 38 | spec: 39 | entryPoints: 40 | - web 41 | routes: 42 | - match: Host(`pyload.{{ fqdn() }}`) 43 | kind: Rule 44 | services: 45 | - name: pyload 46 | port: 8000 47 | middlewares: 48 | - name: pyload-headers 49 | --- 50 | apiVersion: v1 51 | kind: Service 52 | metadata: 53 | name: pyload 54 | namespace: pyload-app 55 | labels: 56 | app.kubernetes.io/instance: pyload 57 | app.kubernetes.io/name: pyload 58 | spec: 59 | ports: 60 | - port: 8000 61 | targetPort: 8000 62 | protocol: TCP 63 | name: http 64 | selector: 65 | app.kubernetes.io/instance: pyload 66 | app.kubernetes.io/name: pyload 67 | type: ClusterIP 68 | --- 69 | apiVersion: apps/v1 70 | kind: Deployment 71 | metadata: 72 | name: pyload 73 | namespace: pyload-app 74 | labels: 75 | app.kubernetes.io/instance: pyload 76 | app.kubernetes.io/name: pyload 77 | spec: 78 | strategy: 79 | type: Recreate 80 | replicas: 1 81 | selector: 82 | matchLabels: 83 | app.kubernetes.io/instance: pyload 84 | app.kubernetes.io/name: pyload 85 | template: 86 | metadata: 87 | labels: 88 | app.kubernetes.io/instance: pyload 89 | app.kubernetes.io/name: pyload 90 | spec: 91 | containers: 92 | - name: pyload 93 | image: lscr.io/linuxserver/pyload-ng:latest 94 | imagePullPolicy: Always 95 | securityContext: 96 | runAsNonRoot: true 97 | # Specifies the UID for the process running in the container. 98 | runAsUser: {{ uid(runAsUser) }} 99 | # Specifies the GID for the process running in the container. 100 | runAsGroup: {{ gid(runAsGroup) }} 101 | ports: 102 | - containerPort: 8000 103 | name: http 104 | protocol: TCP 105 | - containerPort: 9666 106 | name: clicknload 107 | protocol: TCP 108 | hostPort: 9666 109 | volumeMounts: 110 | - mountPath: "/config" 111 | name: config 112 | - mountPath: "/downloads" 113 | name: data 114 | env: 115 | - name: PUID 116 | value: "1000" 117 | - name: PGID 118 | value: "1000" 119 | - name: TZ 120 | value: {{ tz() }} 121 | volumes: 122 | - name: config 123 | hostPath: 124 | type: Directory 125 | # Insert the name of the shared folder you want to use. 126 | # Make sure the configured UID/GID the container is running 127 | # with has access to that directory. 128 | path: {{ sharedfolder_path(configSharedFolderName) }} 129 | - name: data 130 | hostPath: 131 | type: Directory 132 | # Insert the name of the shared folder you want to use. 133 | # Make sure the configured UID/GID the container is running 134 | # with has access to that directory. 135 | path: {{ sharedfolder_path(dataSharedFolderName) }} 136 | -------------------------------------------------------------------------------- /recipes/forgejo/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://forgejo.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | # Insert the name of the shared folder you want to use. Make sure the 6 | # configured UID/GID the container is running with has access to that 7 | # directory. 8 | {% set homeSharedFolderName = '' %} 9 | {% set configSharedFolderName = '' %} 10 | # !!! Only modify the following manifest if you need to make custom changes. !!! 11 | --- 12 | apiVersion: v1 13 | kind: Namespace 14 | metadata: 15 | name: forgejo-app 16 | --- 17 | apiVersion: apps/v1 18 | kind: Deployment 19 | metadata: 20 | labels: 21 | app.kubernetes.io/instance: forgejo 22 | app.kubernetes.io/name: forgejo 23 | name: forgejo 24 | namespace: forgejo-app 25 | spec: 26 | replicas: 1 27 | selector: 28 | matchLabels: 29 | app.kubernetes.io/instance: forgejo 30 | app.kubernetes.io/name: forgejo 31 | strategy: 32 | type: Recreate 33 | template: 34 | metadata: 35 | labels: 36 | app.kubernetes.io/instance: forgejo 37 | app.kubernetes.io/name: forgejo 38 | spec: 39 | containers: 40 | - name: forgejo 41 | image: codeberg.org/forgejo/forgejo:12-rootless 42 | imagePullPolicy: Always 43 | env: 44 | - name: USER_UID 45 | value: "{{ uid(runAsUser) }}" 46 | - name: USER_GID 47 | value: "{{ gid(runAsGroup) }}" 48 | - name: FORGEJO__server__DOMAIN 49 | value: "forgejo.{{ fqdn() }}" 50 | - name: FORGEJO__server__ROOT_URL 51 | value: "https://forgejo.{{ fqdn() }}:{{ conf_get('conf.service.k8s') | get('websecureport') }}/" 52 | - name: FORGEJO__server__SSH_DOMAIN 53 | value: "{{ fqdn() }}" 54 | - name: FORGEJO__server__SSH_PORT 55 | value: "2222" 56 | - name: FORGEJO__server__SSH_LISTEN_PORT 57 | value: "2222" 58 | securityContext: 59 | runAsNonRoot: true 60 | # Specifies the UID for the process running in the container. 61 | runAsUser: {{ uid(runAsUser) }} 62 | # Specifies the GID for the process running in the container. 63 | runAsGroup: {{ gid(runAsGroup) }} 64 | ports: 65 | - name: http 66 | protocol: TCP 67 | containerPort: 3000 68 | - name: 69 | protocol: TCP 70 | containerPort: 2222 71 | hostPort: 2222 72 | volumeMounts: 73 | - name: home 74 | mountPath: /var/lib/gitea 75 | - name: config 76 | mountPath: /etc/gitea 77 | - name: timezone 78 | mountPath: /timezone 79 | readOnly: true 80 | - name: localtime 81 | mountPath: /etc/localtime 82 | readOnly: true 83 | restartPolicy: Always 84 | volumes: 85 | - name: home 86 | hostPath: 87 | type: Directory 88 | path: {{ sharedfolder_path(homeSharedFolderName) }} 89 | - name: config 90 | hostPath: 91 | type: Directory 92 | path: {{ sharedfolder_path(configSharedFolderName) }} 93 | - name: timezone 94 | hostPath: 95 | type: File 96 | path: /etc/timezone 97 | - name: localtime 98 | hostPath: 99 | type: File 100 | path: /etc/localtime 101 | --- 102 | apiVersion: v1 103 | kind: Service 104 | metadata: 105 | name: forgejo 106 | namespace: forgejo-app 107 | labels: 108 | app.kubernetes.io/instance: forgejo 109 | app.kubernetes.io/name: forgejo 110 | spec: 111 | type: ClusterIP 112 | selector: 113 | app.kubernetes.io/instance: forgejo 114 | app.kubernetes.io/name: forgejo 115 | ports: 116 | - protocol: TCP 117 | port: 3000 118 | targetPort: 3000 119 | --- 120 | apiVersion: traefik.io/v1alpha1 121 | kind: IngressRoute 122 | metadata: 123 | name: forgejo-websecure 124 | namespace: forgejo-app 125 | spec: 126 | entryPoints: 127 | - websecure 128 | routes: 129 | - match: Host(`forgejo.{{ fqdn() }}`) 130 | kind: Rule 131 | services: 132 | - name: forgejo 133 | port: 3000 134 | tls: {} 135 | -------------------------------------------------------------------------------- /recipes/penpot/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://penpot.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | {% set sizeDataAssets = '20Gi' %} 6 | {% set sizeDataPostgresql = '8Gi' %} 7 | # Insert the name of the shared folder you want to use. Make sure the 8 | # configured UID/GID the container is running with has access to that 9 | # directory. 10 | {% set assetsSharedFolderName = '' %} 11 | {% set postgresqlSharedFolderName = '' %} 12 | # !!! Only modify the following manifest if you need to make custom changes. !!! 13 | --- 14 | apiVersion: v1 15 | kind: Namespace 16 | metadata: 17 | name: penpot-app 18 | --- 19 | apiVersion: v1 20 | kind: PersistentVolume 21 | metadata: 22 | name: penpot-data-assets 23 | labels: 24 | app.kubernetes.io/instance: penpot 25 | app.kubernetes.io/name: penpot 26 | spec: 27 | storageClassName: shared-folder 28 | capacity: 29 | storage: "{{ sizeDataAssets }}" 30 | hostPath: 31 | path: {{ sharedfolder_path(assetsSharedFolderName) }} 32 | type: Directory 33 | accessModes: 34 | - "ReadWriteOnce" 35 | --- 36 | apiVersion: "v1" 37 | kind: "PersistentVolumeClaim" 38 | metadata: 39 | name: penpot-data-assets 40 | namespace: penpot-app 41 | labels: 42 | app.kubernetes.io/instance: penpot 43 | app.kubernetes.io/name: penpot 44 | spec: 45 | storageClassName: shared-folder 46 | accessModes: 47 | - "ReadWriteOnce" 48 | resources: 49 | requests: 50 | storage: "{{ sizeDataAssets }}" 51 | volumeName: penpot-data-assets 52 | --- 53 | apiVersion: v1 54 | kind: PersistentVolume 55 | metadata: 56 | name: penpot-data-postgresql 57 | labels: 58 | app.kubernetes.io/instance: penpot 59 | app.kubernetes.io/name: penpot 60 | spec: 61 | storageClassName: shared-folder 62 | capacity: 63 | storage: "{{ sizeDataPostgresql }}" 64 | hostPath: 65 | path: {{ sharedfolder_path(postgresqlSharedFolderName) }} 66 | type: Directory 67 | accessModes: 68 | - "ReadWriteOnce" 69 | --- 70 | apiVersion: "v1" 71 | kind: "PersistentVolumeClaim" 72 | metadata: 73 | name: penpot-data-postgresql 74 | namespace: penpot-app 75 | labels: 76 | app.kubernetes.io/instance: penpot 77 | app.kubernetes.io/name: penpot 78 | spec: 79 | storageClassName: shared-folder 80 | accessModes: 81 | - "ReadWriteOnce" 82 | resources: 83 | requests: 84 | storage: "{{ sizeDataPostgresql }}" 85 | volumeName: penpot-data-postgresql 86 | --- 87 | apiVersion: helm.cattle.io/v1 88 | kind: HelmChart 89 | metadata: 90 | name: penpot 91 | namespace: penpot-app 92 | labels: 93 | app.kubernetes.io/instance: penpot 94 | app.kubernetes.io/name: penpot 95 | spec: 96 | repo: http://helm.penpot.app 97 | chart: penpot 98 | version: "0.26.0" 99 | targetNamespace: penpot-app 100 | valuesContent: |- 101 | global: 102 | postgresqlEnabled: true 103 | valkeyEnabled: true 104 | config: 105 | publicUri: "https://penpot.{{ fqdn() }}" 106 | backend: 107 | podSecurityContext: 108 | fsGroup: {{ gid(runAsGroup) }} 109 | containerSecurityContext: 110 | runAsUser: {{ uid(runAsUser) }} 111 | exporter: 112 | podSecurityContext: 113 | fsGroup: {{ gid(runAsGroup) }} 114 | containerSecurityContext: 115 | runAsUser: {{ uid(runAsUser) }} 116 | persistence: 117 | assets: 118 | enabled: true 119 | existingClaim: "penpot-data-assets" 120 | size: "{{ sizeDataAssets }}" 121 | accessModes: 122 | - "ReadWriteOnce" 123 | postgresql: 124 | primary: 125 | containerSecurityContext: 126 | runAsUser: {{ uid(runAsUser) }} 127 | runAsGroup: {{ gid(runAsGroup) }} 128 | persistence: 129 | enabled: true 130 | volumeName: "penpot-data-postgresql" 131 | existingClaim: "penpot-data-postgresql" 132 | size: "{{ sizeDataPostgresql }}" 133 | accessModes: 134 | - "ReadWriteOnce" 135 | valkey: 136 | primary: 137 | persistence: 138 | enabled: false 139 | --- 140 | apiVersion: traefik.io/v1alpha1 141 | kind: IngressRoute 142 | metadata: 143 | name: penpot-websecure 144 | namespace: penpot-app 145 | labels: 146 | app.kubernetes.io/instance: penpot 147 | app.kubernetes.io/name: penpot 148 | spec: 149 | entryPoints: 150 | - websecure 151 | routes: 152 | - match: Host(`penpot.{{ fqdn() }}`) 153 | kind: Rule 154 | services: 155 | - name: penpot 156 | port: 8080 157 | tls: {} 158 | -------------------------------------------------------------------------------- /recipes/transmission/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://transmission.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set user = 'admin' %} 4 | {% set password = 'transmission' %} 5 | {% set runAsUser = 'nobody' %} 6 | {% set runAsGroup = 'users' %} 7 | # Insert the name of the shared folder you want to use. Make sure the 8 | # configured UID/GID the container is running with has access to that 9 | # directory. 10 | {% set configSharedFolderName = '' %} 11 | {% set downloadsSharedFolderName = '' %} 12 | {% set watchSharedFolderName = '' %} 13 | # !!! Only modify the following manifest if you need to make custom changes. !!! 14 | --- 15 | apiVersion: v1 16 | kind: Namespace 17 | metadata: 18 | name: transmission-app 19 | --- 20 | apiVersion: apps/v1 21 | kind: Deployment 22 | metadata: 23 | labels: 24 | app.kubernetes.io/instance: transmission 25 | app.kubernetes.io/name: transmission 26 | name: transmission 27 | namespace: transmission-app 28 | spec: 29 | replicas: 1 30 | selector: 31 | matchLabels: 32 | app.kubernetes.io/instance: transmission 33 | app.kubernetes.io/name: transmission 34 | strategy: 35 | type: Recreate 36 | template: 37 | metadata: 38 | labels: 39 | app.kubernetes.io/instance: transmission 40 | app.kubernetes.io/name: transmission 41 | spec: 42 | containers: 43 | - image: docker.io/linuxserver/transmission:latest 44 | imagePullPolicy: IfNotPresent 45 | name: transmission 46 | ports: 47 | - containerPort: 9091 48 | protocol: TCP 49 | - containerPort: 51413 50 | protocol: TCP 51 | - containerPort: 51413 52 | protocol: UDP 53 | securityContext: 54 | runAsNonRoot: true 55 | # Specifies the UID for the process running in the container. 56 | runAsUser: {{ uid(runAsUser) }} 57 | # Specifies the GID for the process running in the container. 58 | runAsGroup: {{ gid(runAsGroup) }} 59 | env: 60 | - name: PUID 61 | value: "1000" 62 | - name: PGID 63 | value: "1000" 64 | - name: TZ 65 | value: {{ tz() }} 66 | - name: USER 67 | value: {{ user }} 68 | envFrom: 69 | - secretRef: 70 | name: transmission 71 | volumeMounts: 72 | - name: config 73 | mountPath: /config 74 | - name: downloads 75 | mountPath: /downloads 76 | - name: watch 77 | mountPath: /watch 78 | restartPolicy: Always 79 | volumes: 80 | - name: config 81 | hostPath: 82 | type: Directory 83 | # Insert the name of the shared folder you want to use. 84 | # Make sure the configured UID/GID the container is running 85 | # with has access to that directory. 86 | path: {{ sharedfolder_path(configSharedFolderName) }} 87 | - name: downloads 88 | hostPath: 89 | type: Directory 90 | # Insert the name of the shared folder you want to use. 91 | # Make sure the configured UID/GID the container is running 92 | # with has access to that directory. 93 | path: {{ sharedfolder_path(downloadsSharedFolderName) }} 94 | - name: watch 95 | hostPath: 96 | type: Directory 97 | # Insert the name of the shared folder you want to use. 98 | # Make sure the configured UID/GID the container is running 99 | # with has access to that directory. 100 | path: {{ sharedfolder_path(watchSharedFolderName) }} 101 | --- 102 | apiVersion: v1 103 | kind: Secret 104 | metadata: 105 | name: transmission 106 | namespace: transmission-app 107 | labels: 108 | app.kubernetes.io/instance: transmission 109 | app.kubernetes.io/name: transmission 110 | stringData: 111 | PASS: {{ password }} 112 | --- 113 | apiVersion: v1 114 | kind: Service 115 | metadata: 116 | name: transmission 117 | namespace: transmission-app 118 | labels: 119 | app.kubernetes.io/instance: transmission 120 | app.kubernetes.io/name: transmission 121 | spec: 122 | type: ClusterIP 123 | ports: 124 | - protocol: TCP 125 | name: web-interface 126 | port: 9091 127 | - protocol: TCP 128 | name: torrent-tcp 129 | port: 51413 130 | - protocol: UDP 131 | name: torrents-udp 132 | port: 51413 133 | selector: 134 | app.kubernetes.io/instance: transmission 135 | app.kubernetes.io/name: transmission 136 | --- 137 | apiVersion: traefik.io/v1alpha1 138 | kind: IngressRoute 139 | metadata: 140 | name: transmission-websecure 141 | namespace: transmission-app 142 | spec: 143 | entryPoints: 144 | - websecure 145 | routes: 146 | - match: Host(`transmission.{{ fqdn() }}`) 147 | kind: Rule 148 | services: 149 | - name: transmission 150 | port: 9091 151 | tls: {} 152 | -------------------------------------------------------------------------------- /recipes/letsencrypt/recipe.yaml: -------------------------------------------------------------------------------- 1 | # This recipe acquires TLS certs for your domain. There's no web page / API. 2 | # Note, this recipe requires the reflector recipe to be deployed and running. 3 | # Change the following variables and solvers to adapt the recipe to your needs. 4 | # 5 | # This must be a public domain name that you own (resolvable via global DNS). 6 | # If fqdn() is private / internal, use a different domain like this: 7 | # {% set domain = 'optional-nested-domain.my-domain.tld' %} 8 | {% set domain = fqdn() %} 9 | # It is highly recommended to try staging first to avoid rate limiting. 10 | # Once it works, flip this to false to get a new cert trusted by the browsers. 11 | {% set staging = true %} 12 | # 13 | # To use the certificate(s), recipes must be modified in the following ways: 14 | # 1. Each routes[*].match statement in IngressRoute must reference the same 15 | # domain name as specified above. (The certificate will not be used if there 16 | # is no `Host` in match or the domain is not covered by the certificate. By 17 | # default a wildcard cert is requested, but note that it only covers one 18 | # level below like `sub.{{ domain }}`, not `nested.sub.{{ domain }}`.) 19 | # 2. The tls section of each IngressRoute must explicitly reference the secret. 20 | # (This recipe will take care of copying the TLS secret to all namespaces.) 21 | # 22 | # Example (only showing relevant parts): 23 | # --- 24 | # kind: IngressRoute 25 | # spec: 26 | # routes: 27 | # # 1. If you picked a different domain than fqdn() then remember to change 28 | # # all match statements that contain `someapp.{{ fqdn() }}`. Make sure: 29 | # # This string vvvvvvvvvvvvvvv must be {{ domain }} or a direct subdomain. 30 | # - match: Host(`sub.example.com`) 31 | # kind: Rule 32 | # ... 33 | # # 2. Change every occurrence of `tls: {}` to these two lines instead. 34 | # tls: 35 | # secretName: letsencrypt-cert 36 | # # ... (other fields can be left untouched.) 37 | # ... 38 | --- 39 | apiVersion: v1 40 | kind: Namespace 41 | metadata: 42 | name: letsencrypt-app 43 | --- 44 | apiVersion: cert-manager.io/v1 45 | kind: ClusterIssuer 46 | metadata: 47 | name: letsencrypt{{ staging ? '-staging' }} 48 | namespace: letsencrypt-app 49 | labels: 50 | app.kubernetes.io/instance: letsencrypt{{ staging ? '-staging' }} 51 | app.kubernetes.io/name: letsencrypt 52 | spec: 53 | acme: 54 | server: https://acme{{ staging ? '-staging' }}-v02.api.letsencrypt.org/directory 55 | privateKeySecretRef: 56 | name: letsencrypt{{ staging ? '-staging' }} 57 | solvers: 58 | # dns01 must be used instead of http if you want wildcard certs. 59 | - dns01: 60 | # TODO: Configure your own solver, such as acmeDNS, webhook, etc. 61 | # https://cert-manager.io/docs/configuration/acme/ 62 | # The sample config below works with the acme-dns recipe. 63 | acmeDNS: 64 | host: http://acme-dns.acme-dns-app 65 | accountSecretRef: 66 | name: acme-dns 67 | key: acmedns.json 68 | --- 69 | # This sample secret works with the acme-dns recipe -- just fill in the JSON. 70 | # If you use another solver, you may need a different secret structure, e.g. 71 | # username + password / API key from your DNS provider. See: 72 | # https://cert-manager.io/docs/configuration/acme/ 73 | apiVersion: v1 74 | kind: Secret 75 | metadata: 76 | name: acme-dns 77 | namespace: cert-manager # This has to be in the "cluster resource namespace". 78 | type: Opaque 79 | stringData: 80 | acmedns.json: | 81 | { 82 | "{{ domain }}": { 83 | "username":"", 84 | "password":"", 85 | "fulldomain":"", 86 | "subdomain":"", 87 | "allowfrom":[] 88 | } 89 | } 90 | # !!! Only modify the following manifest if you need to make custom changes. !!! 91 | --- 92 | apiVersion: cert-manager.io/v1 93 | kind: Certificate 94 | metadata: 95 | name: letsencrypt-cert 96 | namespace: letsencrypt-app 97 | spec: 98 | commonName: '{{ domain }}' 99 | dnsNames: 100 | # Recommended setting: a single cert for base domain + wildcard subdomains. 101 | # If dns01 challenge is not viable, remove the wildcard entry and add one 102 | # Certificate covering each subdomain.{{ domain }}. 103 | # WARNING: Beware of the (rather tight) rate limits! You may not hit it on 104 | # staging, but you'll very likely hit it on prod with one-cert-for-each. 105 | # https://letsencrypt.org/docs/rate-limits/ 106 | - '{{ domain }}' 107 | - '*.{{ domain }}' 108 | issuerRef: 109 | name: letsencrypt{{ staging ? '-staging' }} 110 | kind: ClusterIssuer 111 | secretName: letsencrypt-cert 112 | secretTemplate: 113 | annotations: 114 | reflector.v1.k8s.emberstack.com/reflection-allowed: "true" 115 | reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: "^(?!(?:cert-manager|kube-system|kube-node-lease|kube-public)$).*" 116 | reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true" 117 | reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "" # all namespaces, filtered by allowed namespaces 118 | -------------------------------------------------------------------------------- /recipes/acme-dns/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The acme-dns API can be reached at https://acme-dns.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | # Change this to the domain (zone) that ACME DNS should manage. 4 | {% set domain = 'auth.' ~ fqdn() %} 5 | # At your DNS provider, create the following record: 6 | # {{ domain }}. NS {{ nsname }}. 7 | # Example: 8 | # auth.example.org. NS auth-ns.example.org. 9 | # Change this to a domain that has an A/AAAA record with your public IP. 10 | # It may be a DDNS domain or dynamically updated as the IP changes. 11 | # It must not be the same or a subdomain of the above. 12 | {% set nsname = 'auth-ns.' ~ fqdn() %} 13 | # See README.md for required port forwarding and DNS records setup. 14 | # !!! Only modify the following manifest if you need to make custom changes. !!! 15 | --- 16 | apiVersion: v1 17 | kind: Namespace 18 | metadata: 19 | name: acme-dns-app 20 | --- 21 | apiVersion: v1 22 | kind: Service 23 | metadata: 24 | name: acme-dns 25 | namespace: acme-dns-app 26 | labels: 27 | app.kubernetes.io/instance: acme-dns 28 | app.kubernetes.io/name: acme-dns 29 | spec: 30 | type: NodePort 31 | selector: 32 | app.kubernetes.io/instance: acme-dns 33 | app.kubernetes.io/name: acme-dns 34 | ports: 35 | - name: dns-tcp 36 | port: 53 37 | nodePort: 30053 38 | protocol: TCP 39 | - name: dns-udp 40 | port: 53 41 | nodePort: 30053 42 | protocol: UDP 43 | - name: http 44 | port: 80 45 | --- 46 | apiVersion: v1 47 | kind: ConfigMap 48 | metadata: 49 | name: acme-dns-config 50 | namespace: acme-dns-app 51 | labels: 52 | app.kubernetes.io/instance: acme-dns 53 | app.kubernetes.io/name: acme-dns 54 | data: 55 | config.cfg: | 56 | [general] 57 | listen = ":53" 58 | protocol = "both" 59 | # domain name to serve the requests off of 60 | domain = "{{ domain }}" 61 | # zone name server 62 | nsname = "{{ nsname }}" 63 | # admin email address, where @ is substituted with . 64 | nsadmin = "ns-admin.{{ nsname }}" 65 | # predefined records served in addition to the TXT 66 | records = [ 67 | # specify that {{ nsname }} will resolve any *.{{ domain }} records 68 | "{{ domain }}. NS {{ nsname }}.", 69 | # Note: We intentionally don't add an A record for either domain to 70 | # avoid hard-coding IP addresses that may change on a home network. 71 | # To access the API server, use acme-dns.{{ fqdn() }} instead (route below). 72 | ] 73 | # debug messages from CORS etc 74 | debug = false 75 | 76 | [database] 77 | # Database engine to use, sqlite3 or postgres 78 | engine = "sqlite3" 79 | # Connection string, filename for sqlite3 and postgres://$username:$password@$host/$db_name for postgres 80 | connection = "/var/lib/acme-dns/acme-dns.db" 81 | # connection = "postgres://user:password@localhost/acmedns_db" 82 | 83 | [api] 84 | ip = "0.0.0.0" 85 | # disable registration endpoint 86 | disable_registration = false 87 | port = "80" 88 | tls = "none" 89 | # CORS AllowOrigins, wildcards can be used 90 | corsorigins = [ 91 | "*" 92 | ] 93 | # use HTTP header to get the client ip 94 | use_header = false 95 | # header name to pull the ip address / list of ip addresses from 96 | header_name = "X-Forwarded-For" 97 | 98 | [logconfig] 99 | # logging level: "error", "warning", "info" or "debug" 100 | loglevel = "debug" 101 | logtype = "stdout" 102 | # format, either "json" or "text" 103 | logformat = "text" 104 | --- 105 | apiVersion: apps/v1 106 | kind: StatefulSet 107 | metadata: 108 | namespace: acme-dns-app 109 | name: acme-dns 110 | labels: 111 | app.kubernetes.io/instance: acme-dns 112 | app.kubernetes.io/name: acme-dns 113 | spec: 114 | selector: 115 | matchLabels: 116 | app.kubernetes.io/instance: acme-dns 117 | app.kubernetes.io/name: acme-dns 118 | serviceName: acme-dns-service 119 | replicas: 1 120 | template: 121 | metadata: 122 | labels: 123 | app.kubernetes.io/instance: acme-dns 124 | app.kubernetes.io/name: acme-dns 125 | spec: 126 | containers: 127 | - name: acme-dns 128 | image: joohoi/acme-dns:latest 129 | imagePullPolicy: Always 130 | securityContext: 131 | readOnlyRootFilesystem: true 132 | livenessProbe: 133 | failureThreshold: 3 134 | httpGet: 135 | path: /health 136 | port: 80 137 | scheme: HTTP 138 | initialDelaySeconds: 5 139 | periodSeconds: 10 140 | timeoutSeconds: 3 141 | resources: 142 | limits: 143 | memory: '50Mi' 144 | cpu: '500m' # 50% 145 | volumeMounts: 146 | - name: acme-dns-data 147 | mountPath: /var/lib/acme-dns 148 | - name: acme-dns-config 149 | mountPath: /etc/acme-dns 150 | volumes: 151 | - name: acme-dns-config 152 | configMap: 153 | name: acme-dns-config 154 | volumeClaimTemplates: 155 | - metadata: 156 | name: acme-dns-data 157 | spec: 158 | accessModes: [ "ReadWriteOnce" ] 159 | resources: 160 | requests: 161 | storage: 200Mi 162 | --- 163 | apiVersion: traefik.io/v1alpha1 164 | kind: IngressRoute 165 | metadata: 166 | name: acme-dns-websecure 167 | namespace: acme-dns-app 168 | labels: 169 | app.kubernetes.io/instance: acme-dns 170 | app.kubernetes.io/name: acme-dns 171 | spec: 172 | entryPoints: 173 | - websecure 174 | routes: 175 | - match: Host(`acme-dns.{{ fqdn() }}`) 176 | kind: Rule 177 | services: 178 | - name: acme-dns 179 | port: 80 180 | tls: {} 181 | -------------------------------------------------------------------------------- /recipes/filebrowser-quantum/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://filebrowser.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | {% set adminUsername = 'admin' %} 6 | {% set adminPassword = 'admin' %} 7 | # Insert the name of the shared folder you want to use. Make sure the 8 | # configured UID/GID the container is running with has access to that 9 | # directory. 10 | {% set dataSharedFolderName = '' %} 11 | {% set rootSharedFolderName = '' %} 12 | # !!! Only modify the following manifest if you need to make custom changes. !!! 13 | --- 14 | apiVersion: v1 15 | kind: Namespace 16 | metadata: 17 | name: filebrowser-quantum-app 18 | --- 19 | apiVersion: v1 20 | kind: ConfigMap 21 | metadata: 22 | name: filebrowser-quantum-config 23 | namespace: filebrowser-quantum-app 24 | data: 25 | config.yaml: | 26 | # https://github.com/gtsteffaniak/filebrowser/wiki/Full-Config-Example 27 | server: 28 | disableUpdateCheck: true 29 | port: 80 30 | baseURL: "/" 31 | logging: 32 | - levels: "info|warning|error" 33 | cacheDir: "/data/tmp" 34 | database: "/data/database.db" 35 | sources: 36 | - path: "/srv" 37 | config: 38 | defaultEnabled: true 39 | auth: 40 | adminUsername: "{{ adminUsername }}" 41 | userDefaults: 42 | preview: 43 | image: true 44 | popup: true 45 | video: false 46 | office: false 47 | highQuality: false 48 | darkMode: true 49 | disableSettings: false 50 | singleClick: false 51 | permissions: 52 | admin: false 53 | modify: false 54 | share: false 55 | api: false 56 | --- 57 | apiVersion: apps/v1 58 | kind: Deployment 59 | metadata: 60 | labels: 61 | app.kubernetes.io/instance: filebrowser-quantum 62 | app.kubernetes.io/name: filebrowser-quantum 63 | name: filebrowser-quantum 64 | namespace: filebrowser-quantum-app 65 | spec: 66 | selector: 67 | matchLabels: 68 | app.kubernetes.io/instance: filebrowser-quantum 69 | app.kubernetes.io/name: filebrowser-quantum 70 | replicas: 1 71 | strategy: 72 | type: Recreate 73 | template: 74 | metadata: 75 | labels: 76 | app.kubernetes.io/instance: filebrowser-quantum 77 | app.kubernetes.io/name: filebrowser-quantum 78 | spec: 79 | containers: 80 | - name: filebrowser-quantum 81 | image: ghcr.io/gtsteffaniak/filebrowser:stable 82 | imagePullPolicy: IfNotPresent 83 | securityContext: 84 | runAsNonRoot: true 85 | # Specifies the UID for the process running in the container. 86 | runAsUser: {{ uid(runAsUser) }} 87 | # Specifies the GID for the process running in the container. 88 | runAsGroup: {{ gid(runAsGroup) }} 89 | ports: 90 | - containerPort: 80 91 | protocol: TCP 92 | # https://github.com/gtsteffaniak/filebrowser/wiki/Environment-Variables 93 | env: 94 | - name: FILEBROWSER_CONFIG 95 | value: /data/config.yaml 96 | - name: FILEBROWSER_DATABASE 97 | value: /data/database.db 98 | envFrom: 99 | - secretRef: 100 | name: filebrowser-quantum 101 | volumeMounts: 102 | - name: data 103 | mountPath: "/data" 104 | - name: config 105 | mountPath: "/data/config.yaml" 106 | readOnly: true 107 | subPath: config.yaml 108 | - name: srv 109 | mountPath: "/srv" 110 | restartPolicy: Always 111 | volumes: 112 | - name: data 113 | hostPath: 114 | type: Directory 115 | # Insert the name of the shared folder you want to use. 116 | # Make sure the configured UID/GID the container is running 117 | # with has access to that directory. 118 | path: {{ sharedfolder_path(dataSharedFolderName) }} 119 | - name: config 120 | configMap: 121 | name: filebrowser-quantum-config 122 | - name: srv 123 | hostPath: 124 | type: Directory 125 | # Insert the name of the shared folder you want to use. 126 | # Make sure the configured UID/GID the container is running 127 | # with has access to that directory. 128 | path: {{ sharedfolder_path(rootSharedFolderName) }} 129 | --- 130 | apiVersion: v1 131 | kind: Secret 132 | metadata: 133 | name: filebrowser-quantum 134 | namespace: filebrowser-quantum-app 135 | labels: 136 | app.kubernetes.io/instance: filebrowser-quantum 137 | app.kubernetes.io/name: filebrowser-quantum 138 | stringData: 139 | FILEBROWSER_ADMIN_PASSWORD: {{ adminPassword }} 140 | --- 141 | apiVersion: v1 142 | kind: Service 143 | metadata: 144 | name: filebrowser-quantum 145 | namespace: filebrowser-quantum-app 146 | labels: 147 | app.kubernetes.io/instance: filebrowser-quantum 148 | app.kubernetes.io/name: filebrowser-quantum 149 | spec: 150 | type: ClusterIP 151 | ports: 152 | - protocol: TCP 153 | port: 80 154 | selector: 155 | app.kubernetes.io/instance: filebrowser-quantum 156 | app.kubernetes.io/name: filebrowser-quantum 157 | --- 158 | apiVersion: traefik.io/v1alpha1 159 | kind: IngressRoute 160 | metadata: 161 | name: filebrowser-quantum-websecure 162 | namespace: filebrowser-quantum-app 163 | labels: 164 | app.kubernetes.io/instance: filebrowser-quantum 165 | app.kubernetes.io/name: filebrowser-quantum 166 | spec: 167 | entryPoints: 168 | - websecure 169 | routes: 170 | - match: Host(`filebrowser.{{ fqdn() }}`) 171 | kind: Rule 172 | services: 173 | - name: filebrowser-quantum 174 | port: 80 175 | tls: {} 176 | -------------------------------------------------------------------------------- /recipes/piwigo/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://piwigo.:8443 2 | # Use `mariadb` in the `MySQL-Host` form field. 3 | # Change the following variables to adapt the recipe to your needs. 4 | {% set dbName = 'piwigo' %} 5 | {% set dbUser = 'piwigo' %} 6 | {% set dbPassword = 'piwigo' %} 7 | {% set dbRootPassword = 'piwigo' %} 8 | {% set runAsUser = 'nobody' %} 9 | {% set runAsGroup = 'users' %} 10 | # Insert the name of the shared folder you want to use. Make sure the 11 | # configured UID/GID the container is running with has access to that 12 | # directory. 13 | {% set configSharedFolderName = '' %} 14 | {% set gallerySharedFolderName = '' %} 15 | {% set dbSharedFolderName = '' %} 16 | # !!! Only modify the following manifest if you need to make custom changes. !!! 17 | --- 18 | apiVersion: v1 19 | kind: Namespace 20 | metadata: 21 | name: piwigo-app 22 | --- 23 | apiVersion: v1 24 | kind: ConfigMap 25 | metadata: 26 | name: piwigo-env 27 | namespace: piwigo-app 28 | data: 29 | PUID: "{{ uid(runAsUser) }}" 30 | PGID: "{{ gid(runAsGroup) }}" 31 | TZ: "{{ tz() }}" 32 | --- 33 | apiVersion: v1 34 | kind: ConfigMap 35 | metadata: 36 | name: mariadb-env 37 | namespace: piwigo-app 38 | labels: 39 | app.kubernetes.io/instance: piwigo 40 | app.kubernetes.io/name: piwigo 41 | data: 42 | MARIADB_DATABASE: "{{ dbName }}" 43 | MARIADB_USER: "{{ dbUser }}" 44 | --- 45 | apiVersion: v1 46 | kind: Secret 47 | metadata: 48 | name: mariadb 49 | namespace: piwigo-app 50 | labels: 51 | app.kubernetes.io/instance: piwigo 52 | app.kubernetes.io/name: piwigo 53 | stringData: 54 | MARIADB_PASSWORD: "{{ dbPassword }}" 55 | MARIADB_ROOT_PASSWORD: "{{ dbRootPassword }}" 56 | --- 57 | apiVersion: apps/v1 58 | kind: Deployment 59 | metadata: 60 | labels: 61 | app.kubernetes.io/instance: piwigo 62 | app.kubernetes.io/name: piwigo 63 | name: piwigo 64 | namespace: piwigo-app 65 | spec: 66 | replicas: 1 67 | selector: 68 | matchLabels: 69 | app.kubernetes.io/instance: piwigo 70 | app.kubernetes.io/name: piwigo 71 | strategy: 72 | type: Recreate 73 | template: 74 | metadata: 75 | labels: 76 | app.kubernetes.io/instance: piwigo 77 | app.kubernetes.io/name: piwigo 78 | spec: 79 | containers: 80 | - name: piwigo 81 | image: lscr.io/linuxserver/piwigo:latest 82 | imagePullPolicy: IfNotPresent 83 | ports: 84 | - containerPort: 80 85 | protocol: TCP 86 | envFrom: 87 | - configMapRef: 88 | name: piwigo-env 89 | volumeMounts: 90 | - name: "config" 91 | mountPath: "/config" 92 | - name: "gallery" 93 | mountPath: "/gallery" 94 | - name: mariadb 95 | image: docker.io/mariadb:11 96 | imagePullPolicy: IfNotPresent 97 | ports: 98 | - containerPort: 3306 99 | securityContext: 100 | runAsNonRoot: true 101 | # Specifies the UID for the process running in the container. 102 | runAsUser: {{ uid(runAsUser) }} 103 | # Specifies the GID for the process running in the container. 104 | runAsGroup: {{ gid(runAsGroup) }} 105 | envFrom: 106 | - secretRef: 107 | name: mariadb 108 | - configMapRef: 109 | name: mariadb-env 110 | volumeMounts: 111 | - name: "db" 112 | mountPath: /var/lib/mysql 113 | restartPolicy: Always 114 | volumes: 115 | - name: "config" 116 | hostPath: 117 | type: "Directory" 118 | # Insert the name of the shared folder you want to use. 119 | # Make sure the configured UID/GID the container is running 120 | # with has access to that directory. 121 | path: "{{ sharedfolder_path(configSharedFolderName) }}" 122 | - name: "gallery" 123 | hostPath: 124 | type: "Directory" 125 | # Insert the name of the shared folder you want to use. 126 | # Make sure the configured UID/GID the container is running 127 | # with has access to that directory. 128 | path: "{{ sharedfolder_path(gallerySharedFolderName) }}" 129 | - name: "db" 130 | hostPath: 131 | type: Directory 132 | # Insert the name of the shared folder you want to use. 133 | # Make sure the configured UID/GID the container is running 134 | # with has access to that directory. 135 | path: {{ sharedfolder_path(dbSharedFolderName) }} 136 | --- 137 | apiVersion: v1 138 | kind: Service 139 | metadata: 140 | name: piwigo 141 | namespace: piwigo-app 142 | labels: 143 | app.kubernetes.io/instance: piwigo 144 | app.kubernetes.io/name: piwigo 145 | spec: 146 | type: ClusterIP 147 | ports: 148 | - port: 80 149 | protocol: TCP 150 | targetPort: 80 151 | selector: 152 | app.kubernetes.io/instance: piwigo 153 | app.kubernetes.io/name: piwigo 154 | --- 155 | apiVersion: v1 156 | kind: Service 157 | metadata: 158 | name: mariadb 159 | namespace: piwigo-app 160 | labels: 161 | app.kubernetes.io/instance: piwigo 162 | app.kubernetes.io/name: piwigo 163 | spec: 164 | type: ClusterIP 165 | ports: 166 | - port: 3306 167 | protocol: TCP 168 | targetPort: 3306 169 | selector: 170 | app.kubernetes.io/instance: piwigo 171 | app.kubernetes.io/name: piwigo 172 | --- 173 | apiVersion: traefik.io/v1alpha1 174 | kind: IngressRoute 175 | metadata: 176 | name: piwigo-websecure 177 | namespace: piwigo-app 178 | labels: 179 | app.kubernetes.io/instance: piwigo 180 | app.kubernetes.io/name: piwigo 181 | spec: 182 | entryPoints: 183 | - websecure 184 | routes: 185 | - match: Host(`piwigo.{{ fqdn() }}`) 186 | kind: Rule 187 | services: 188 | - name: piwigo 189 | port: 80 190 | tls: {} 191 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository contains a recipe collection for easy deployment of container-based applications with the 2 | `openmediavault-k8s` Kubernetes plugin. 3 | 4 | # Table of contents 5 | 6 | - [General information](#general-information) 7 | - [metadata.yaml](#metadatayaml) 8 | - [Domain Specific Language](#domain-specific-language) 9 | - [FAQ](#faq) 10 | 11 | # General information 12 | 13 | The following rules should be observed in the recipes: 14 | 15 | - Create a namespace for each application according the schema: `-app` 16 | - Traefik is used by the `openmediavault-k8s` plugin. So use `IngressRoute` over `Ingress`. 17 | - For HTTPS ingresses apply `tls: {}` to make use of the default TLS certificate. 18 | - The default entry points for `IngressRoute` are `web` (HTTP) and `websecure` (HTTPS). 19 | - Make use of a `NodePort` service only if the application does not work behind a reverse proxy. 20 | - Make use of the `HelmChart` resource if the application can be installed via Helm. 21 | 22 | # metadata.yaml 23 | 24 | ## Depends 25 | 26 | The `depends` field is used to declare a dependency relationship by one recipe on another. 27 | 28 | Please note that the recipes do not have a package management-like function to automatically install dependent recipes. This would go beyond the scope of the recipe collection and is therefore up to the user. 29 | 30 | ## Architecture 31 | 32 | Use this translation table for the `architecture` field in the `metadata.yaml` file: 33 | 34 | | Architecture | Also known as | 35 | |---------------|-----------------------------| 36 | | `i386` | `i386` | 37 | | `amd64` | `x86_64` | 38 | | `armel` | `armv6l`, `linux/arm/v6` | 39 | | `armhf` | `armv7l`, `linux/arm/v7` | 40 | | `arm64` | `aarch64`, `linux/arm64/v8` | 41 | 42 | The [architecture names](https://wiki.debian.org/SupportedArchitectures) are taken from the Debian project. 43 | 44 | ## Section 45 | 46 | The `section` field in the `metadata.yaml` file is inspired by those that are used in Debian, e.g. `graphics`, `net` or `utils`. Get a full list [here](https://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections). 47 | 48 | Additionally, you can use: 49 | 50 | - `kubernetes` 51 | 52 | # Domain Specific Language 53 | 54 | The recipe editor of the `openmediavault-k8s` plugin has a DSL (Domain Specific Language) 55 | that supports the user in getting specific information from their openmediavault 56 | host system in Kubernetes manifests. 57 | 58 | The following functions are currently available: 59 | 60 | - **hostname()** – Get the hostname of the host. 61 | - **domain()** – Get the domain name of the host. 62 | - **fqdn()** – Get the FQDN of the host. 63 | - **ipaddr(name=NULL)** – Get the IPv4 address of the specified network interface. If not set, the IPv4 address of the interface of the first default route is used. 64 | - **ipaddr6(name=NULL)** – Get the IPv6 address of the specified network interface. If not set, the IPv6 address of the interface of the first default route is used. 65 | - **uid(name)** – Get the UID of the specified user. 66 | - **gid(name)** – Get the GID of the specified group. 67 | - **sharedfolder_path(name)** – Get the full path of the specified shared folder. 68 | - **conf_get(id, uuid=NULL)** – Get the specified database configuration object. 69 | - **tz()** – Get the time zone of the host. 70 | 71 | The following filters are currently available: 72 | 73 | - **get(key, default=NULL)** – Get the specified key, e.g. `foo.bar.baz` from a dictionary. 74 | 75 | For the built-in features of the used template engine please have a look here: 76 | 77 | - [Basic knowledge](https://twig.symfony.com/doc/3.x/templates.html) 78 | - [Filters](https://twig.symfony.com/doc/3.x/filters/index.html) and [functions](https://twig.symfony.com/doc/3.x/functions/index.html) 79 | 80 | ## Examples: 81 | ```yaml 82 | apiVersion: apps/v1 83 | kind: Deployment 84 | ... 85 | spec: 86 | ... 87 | template: 88 | metadata: 89 | ... 90 | spec: 91 | containers: 92 | - securityContext: 93 | runAsNonRoot: true 94 | runAsUser: {{ uid('nobody') }} 95 | runAsGroup: {{ gid('nogroup') }} 96 | args: 97 | - "--port 3000" 98 | - "--base /wetty" 99 | - "--force-ssh" 100 | - "--ssh-port {{ conf_get('conf.service.ssh') | get('port') }}" 101 | - "--ssh-host {{ hostname() }}" 102 | ... 103 | ``` 104 | ```yaml 105 | apiVersion: apps/v1 106 | kind: Deployment 107 | ... 108 | spec: 109 | ... 110 | template: 111 | metadata: 112 | ... 113 | spec: 114 | containers: 115 | ... 116 | volumes: 117 | - name: originals-volume 118 | hostPath: 119 | type: Directory 120 | path: {{ sharedfolder_path('images') }} 121 | ... 122 | ``` 123 | ```yaml 124 | apiVersion: traefik.containo.us/v1alpha1 125 | kind: IngressRoute 126 | metadata: 127 | name: immich-websecure 128 | namespace: immich-app 129 | ... 130 | spec: 131 | entryPoints: 132 | - websecure 133 | routes: 134 | - match: Host(`immich.{{ ipaddr() }}.sslip.io`) 135 | kind: Rule 136 | services: 137 | - name: immich-server 138 | port: 3001 139 | ``` 140 | 141 | # FAQ 142 | 143 | ## Why do recipes use subdomains instead of URL path prefixes? 144 | 145 | Using subdomains (e.g., app.mynas.internal) is preferred over path prefixes (e.g., mynas.internal/app) for accessing apps via the Traefik reverse proxy in the openmediavault Kubernetes plugin because: 146 | - Cleaner and simpler routing – Subdomains keep Ingress rules modular and avoid complex path rewrites. 147 | - Fewer compatibility issues – Many apps assume they run at / and break when served under a path prefix due to issues with relative URLs, static assets, or routing. 148 | - Avoids URL rewriting problems – With path prefixes, you often need to rewrite URLs or modify the app, which can cause subtle bugs or failures. 149 | - Better isolation and security – Subdomains help enforce security boundaries between apps. 150 | - Easier scaling and maintenance – Apps on subdomains are more portable, scalable, and microservice-friendly. 151 | -------------------------------------------------------------------------------- /recipes/photoprism/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://photoprism.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | # Insert the name of the shared folder you want to use. Make sure the 6 | # configured UID/GID the container is running with has access to that 7 | # directory. 8 | {% set originalsSharedFolderName = '' %} 9 | {% set storageSharedFolderName = '' %} 10 | {% set importSharedFolderName = '' %} 11 | {% set mariaDbSharedFolderName = '' %} 12 | # !!! Only modify the following manifest if you need to make custom changes. !!! 13 | --- 14 | apiVersion: v1 15 | kind: Namespace 16 | metadata: 17 | name: photoprism-app 18 | --- 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | labels: 23 | app.kubernetes.io/instance: photoprism 24 | app.kubernetes.io/name: photoprism 25 | name: photoprism 26 | namespace: photoprism-app 27 | spec: 28 | replicas: 1 29 | selector: 30 | matchLabels: 31 | app.kubernetes.io/instance: photoprism 32 | app.kubernetes.io/name: photoprism 33 | strategy: 34 | type: Recreate 35 | template: 36 | metadata: 37 | labels: 38 | app.kubernetes.io/instance: photoprism 39 | app.kubernetes.io/name: photoprism 40 | spec: 41 | containers: 42 | - image: docker.io/photoprism/photoprism:latest 43 | imagePullPolicy: IfNotPresent 44 | name: photoprism 45 | ports: 46 | - containerPort: 2342 47 | securityContext: 48 | runAsNonRoot: true 49 | # Specifies the UID for the process running in the container. 50 | runAsUser: {{ uid(runAsUser) }} 51 | # Specifies the GID for the process running in the container. 52 | runAsGroup: {{ gid(runAsGroup) }} 53 | env: 54 | - name: PHOTOPRISM_HTTP_PORT 55 | value: "2342" 56 | - name: PHOTOPRISM_SITE_URL 57 | value: "https://photoprism.{{ fqdn() }}:{{ conf_get('conf.service.k8s') | get('websecureport') }}" 58 | - name: PHOTOPRISM_DISABLE_TLS 59 | value: "true" 60 | envFrom: 61 | - secretRef: 62 | name: photoprism 63 | - configMapRef: 64 | name: photoprism 65 | - configMapRef: 66 | name: photoprism-db 67 | volumeMounts: 68 | - name: originals-volume 69 | mountPath: /photoprism/originals 70 | - name: storage-volume 71 | mountPath: /photoprism/storage 72 | # - name: import-volume 73 | # mountPath: /photoprism/import 74 | restartPolicy: Always 75 | volumes: 76 | # Folder to store original media files (DO NOT REMOVE). 77 | - name: originals-volume 78 | hostPath: 79 | type: Directory 80 | # Insert the name of the shared folder you want to use. 81 | # Make sure the configured UID/GID the container is running 82 | # with has access to that directory. 83 | path: {{ sharedfolder_path(originalsSharedFolderName) }} 84 | # Folder for cache, database, and sidecar files (DO NOT REMOVE). 85 | - name: storage-volume 86 | hostPath: 87 | type: Directory 88 | # Insert the name of the shared folder you want to use. 89 | # Make sure the configured UID/GID the container is running 90 | # with has access to that directory. 91 | path: {{ sharedfolder_path(storageSharedFolderName) }} 92 | # Folder from which files can be imported to originals. 93 | # - name: import-volume 94 | # hostPath: 95 | # type: Directory 96 | # # Insert the name of the shared folder you want to use. 97 | # # Make sure the configured UID/GID the container is running 98 | # # with has access to that directory. 99 | # path: {{ sharedfolder_path(importSharedFolderName) }} 100 | --- 101 | apiVersion: apps/v1 102 | kind: Deployment 103 | metadata: 104 | labels: 105 | app.kubernetes.io/instance: mariadb 106 | app.kubernetes.io/name: mariadb 107 | name: mariadb 108 | namespace: photoprism-app 109 | spec: 110 | replicas: 1 111 | selector: 112 | matchLabels: 113 | app.kubernetes.io/instance: mariadb 114 | app.kubernetes.io/name: mariadb 115 | strategy: 116 | type: Recreate 117 | template: 118 | metadata: 119 | labels: 120 | app.kubernetes.io/instance: mariadb 121 | app.kubernetes.io/name: mariadb 122 | spec: 123 | containers: 124 | - image: docker.io/mariadb:11 125 | imagePullPolicy: IfNotPresent 126 | name: mariadb 127 | ports: 128 | - containerPort: 3306 129 | securityContext: 130 | runAsNonRoot: true 131 | # Specifies the UID for the process running in the container. 132 | runAsUser: {{ uid(runAsUser) }} 133 | # Specifies the GID for the process running in the container. 134 | runAsGroup: {{ gid(runAsGroup) }} 135 | args: 136 | - --innodb-buffer-pool-size=512M 137 | - --transaction-isolation=READ-COMMITTED 138 | - --character-set-server=utf8mb4 139 | - --collation-server=utf8mb4_unicode_ci 140 | - --max-connections=512 141 | - --innodb-rollback-on-timeout=OFF 142 | - --innodb-lock-wait-timeout=120 143 | envFrom: 144 | - secretRef: 145 | name: mariadb 146 | - configMapRef: 147 | name: mariadb 148 | volumeMounts: 149 | - name: db-volume 150 | mountPath: /var/lib/mysql 151 | restartPolicy: Always 152 | volumes: 153 | - name: db-volume 154 | hostPath: 155 | type: Directory 156 | # Insert the name of the shared folder you want to use. 157 | # Make sure the configured UID/GID the container is running 158 | # with has access to that directory. 159 | path: {{ sharedfolder_path(mariadbSharedFolderName) }} 160 | --- 161 | apiVersion: v1 162 | kind: Secret 163 | metadata: 164 | name: photoprism 165 | namespace: photoprism-app 166 | labels: 167 | app.kubernetes.io/instance: photoprism 168 | app.kubernetes.io/name: photoprism 169 | stringData: 170 | PHOTOPRISM_ADMIN_PASSWORD: "admin" 171 | PHOTOPRISM_DATABASE_PASSWORD: "photoprism" 172 | --- 173 | apiVersion: v1 174 | kind: Secret 175 | metadata: 176 | name: mariadb 177 | namespace: photoprism-app 178 | labels: 179 | app.kubernetes.io/instance: photoprism 180 | app.kubernetes.io/name: photoprism 181 | stringData: 182 | MARIADB_PASSWORD: "photoprism" 183 | MARIADB_ROOT_PASSWORD: "photoprism" 184 | --- 185 | apiVersion: v1 186 | kind: ConfigMap 187 | metadata: 188 | name: photoprism 189 | namespace: photoprism-app 190 | data: 191 | # https://docs.photoprism.app/getting-started/config-options/ 192 | PHOTOPRISM_READONLY: "false" 193 | PHOTOPRISM_PUBLIC: "false" 194 | --- 195 | apiVersion: v1 196 | kind: ConfigMap 197 | metadata: 198 | name: photoprism-db 199 | namespace: photoprism-app 200 | labels: 201 | app.kubernetes.io/instance: photoprism 202 | app.kubernetes.io/name: photoprism 203 | data: 204 | PHOTOPRISM_DATABASE_DRIVER: "mysql" 205 | PHOTOPRISM_DATABASE_SERVER: "mariadb:3306" 206 | PHOTOPRISM_DATABASE_NAME: "photoprism" 207 | PHOTOPRISM_DATABASE_USER: "photoprism" 208 | --- 209 | apiVersion: v1 210 | kind: ConfigMap 211 | metadata: 212 | name: mariadb 213 | namespace: photoprism-app 214 | labels: 215 | app.kubernetes.io/instance: photoprism 216 | app.kubernetes.io/name: photoprism 217 | data: 218 | MARIADB_AUTO_UPGRADE: "1" 219 | MARIADB_INITDB_SKIP_TZINFO: "1" 220 | MARIADB_DATABASE: "photoprism" 221 | MARIADB_USER: "photoprism" 222 | --- 223 | apiVersion: v1 224 | kind: Service 225 | metadata: 226 | name: photoprism 227 | namespace: photoprism-app 228 | labels: 229 | app.kubernetes.io/instance: photoprism 230 | app.kubernetes.io/name: photoprism 231 | spec: 232 | type: ClusterIP 233 | ports: 234 | - port: 2342 235 | protocol: TCP 236 | targetPort: 2342 237 | selector: 238 | app.kubernetes.io/instance: photoprism 239 | app.kubernetes.io/name: photoprism 240 | --- 241 | apiVersion: v1 242 | kind: Service 243 | metadata: 244 | name: mariadb 245 | namespace: photoprism-app 246 | labels: 247 | app.kubernetes.io/instance: mariadb 248 | app.kubernetes.io/name: mariadb 249 | spec: 250 | type: ClusterIP 251 | ports: 252 | - port: 3306 253 | protocol: TCP 254 | targetPort: 3306 255 | selector: 256 | app.kubernetes.io/instance: mariadb 257 | app.kubernetes.io/name: mariadb 258 | --- 259 | apiVersion: traefik.io/v1alpha1 260 | kind: IngressRoute 261 | metadata: 262 | name: photoprism-websecure 263 | namespace: photoprism-app 264 | labels: 265 | app.kubernetes.io/instance: photoprism 266 | app.kubernetes.io/name: photoprism 267 | spec: 268 | entryPoints: 269 | - websecure 270 | routes: 271 | - match: Host(`photoprism.{{ fqdn() }}`) 272 | kind: Rule 273 | services: 274 | - name: photoprism 275 | port: 2342 276 | tls: {} 277 | -------------------------------------------------------------------------------- /recipes/owntone/recipe.yaml: -------------------------------------------------------------------------------- 1 | # The app can be reached at https://owntone.:8443 2 | # Change the following variables to adapt the recipe to your needs. 3 | {% set runAsUser = 'nobody' %} 4 | {% set runAsGroup = 'users' %} 5 | # Insert the name of the shared folder you want to use. Make sure the 6 | # configured UID/GID the container is running with has access to that 7 | # directory. 8 | {% set mediaSharedFolderName = '' %} 9 | # !!! Only modify the following manifest if you need to make custom changes. !!! 10 | --- 11 | apiVersion: v1 12 | kind: Namespace 13 | metadata: 14 | name: owntone-app 15 | --- 16 | apiVersion: v1 17 | kind: ConfigMap 18 | metadata: 19 | name: owntone 20 | namespace: owntone-app 21 | labels: 22 | app.kubernetes.io/instance: owntone 23 | app.kubernetes.io/name: owntone 24 | data: 25 | owntone.conf: | 26 | # See https://owntone.github.io/owntone-server/configuration/ 27 | general { 28 | # Username 29 | # Make sure the user has read access to the library directories you set 30 | # below, and full access to the databases, log and local audio 31 | uid = "owntone" 32 | 33 | # Database location 34 | db_path = "/var/cache/owntone/database.db" 35 | 36 | # Database backup location 37 | # Uncomment and specify a full path to enable abilty to use REST endpoint 38 | # to initiate backup of songs3.db 39 | db_backup_path = "/var/cache/owntone/database.bak" 40 | 41 | # Log file and level 42 | # Available levels: fatal, log, warning, info, debug, spam 43 | logfile = "/dev/stderr" 44 | loglevel = log 45 | 46 | # Admin password for the web interface 47 | # Note that access to the web interface from computers in 48 | # "trusted_network" (see below) does not require password 49 | # admin_password = "" 50 | 51 | # Websocket port for the web interface. 52 | # websocket_port = 3688 53 | 54 | # Websocket interface to bind listener to (e.g. "eth0"). Default is 55 | # disabled, which means listen on all interfaces. 56 | # websocket_interface = "" 57 | 58 | # Sets who is allowed to connect without authorisation. This applies to 59 | # client types like Remotes, DAAP clients (iTunes) and to the web 60 | # interface. Options are "any", "lan", "localhost", "none" or the prefix 61 | # to one or more ipv4/6 networks. The default is { "lan" } 62 | trusted_networks = { "any" } 63 | 64 | # Enable/disable IPv6 65 | # ipv6 = no 66 | 67 | # Set this if you want the server to bind to a specific IP address. Can 68 | # be ipv6 or ipv4. Default (commented out or "::") is to listen on all 69 | # IP addresses. 70 | # bind_address = "::" 71 | 72 | # Directory where the server keeps cached data 73 | # cache_dir = "/var/cache/owntone" 74 | 75 | # DAAP requests that take longer than this threshold (in msec) get their 76 | # replies cached for next time. Set to 0 to disable caching. 77 | # cache_daap_threshold = 1000 78 | 79 | # When starting playback, autoselect speaker (if none of the previously 80 | # selected speakers/outputs are available) 81 | # speaker_autoselect = no 82 | 83 | # Most modern systems have a high-resolution clock, but if you are on an 84 | # unusual platform and experience audio drop-outs, you can try changing 85 | # this option 86 | # high_resolution_clock = yes 87 | } 88 | 89 | # Library configuration 90 | library { 91 | # Name of the library as displayed by the clients (%h: hostname). If you 92 | # change the name after pairing with Remote you may have to re-pair. 93 | name = "My Music on %h" 94 | 95 | # TCP port to listen on. Default port is 3689 (daap) 96 | port = 3689 97 | 98 | # Password for the library. Optional. 99 | # password = "" 100 | 101 | # Directories to index 102 | directories = { "/srv/media" } 103 | 104 | # Follow symlinks. Default: true. 105 | # follow_symlinks = true 106 | 107 | # Directories containing podcasts 108 | # For each directory that is indexed the path is matched against these 109 | # names. If there is a match all items in the directory are marked as 110 | # podcasts. Eg. if you index /srv/music, and your podcasts are in 111 | # /srv/music/Podcasts, you can set this to "/Podcasts". 112 | # (changing this setting only takes effect after rescan, see the README) 113 | podcasts = { "/Podcasts" } 114 | 115 | # Directories containing audiobooks 116 | # For each directory that is indexed the path is matched against these 117 | # names. If there is a match all items in the directory are marked as 118 | # audiobooks. 119 | # (changing this setting only takes effect after rescan, see the README) 120 | audiobooks = { "/Audiobooks" } 121 | 122 | # Directories containing compilations (eg soundtracks) 123 | # For each directory that is indexed the path is matched against these 124 | # names. If there is a match all items in the directory are marked as 125 | # compilations. 126 | # (changing this setting only takes effect after rescan, see the README) 127 | compilations = { "/Compilations" } 128 | 129 | # Compilations usually have many artists, and sometimes no album artist. 130 | # If you don't want every artist to be listed in artist views, you can 131 | # set a single name which will be used for all compilation tracks 132 | # without an album artist, and for all tracks in the compilation 133 | # directories. 134 | # (changing this setting only takes effect after rescan, see the README) 135 | compilation_artist = "Various Artists" 136 | 137 | # If your album and artist lists are cluttered, you can choose to hide 138 | # albums and artists with only one track. The tracks will still be 139 | # visible in other lists, e.g. songs and playlists. This setting 140 | # currently only works in some remotes. 141 | # hide_singles = false 142 | 143 | # Internet streams in your playlists will by default be shown in the 144 | # "Radio" library, like iTunes does. However, some clients (like 145 | # TunesRemote+) won't show the "Radio" library. If you would also like 146 | # to have them shown like normal playlists, you can enable this option. 147 | # radio_playlists = false 148 | 149 | # These are the default playlists. If you want them to have other names, 150 | # you can set it here. 151 | # name_library = "Library" 152 | # name_music = "Music" 153 | # name_movies = "Movies" 154 | # name_tvshows = "TV Shows" 155 | # name_podcasts = "Podcasts" 156 | # name_audiobooks = "Audiobooks" 157 | # name_radio = "Radio" 158 | 159 | # Artwork file names (without file type extension) 160 | # OwnTone will look for jpg and png files with these base names 161 | # artwork_basenames = { "artwork", "cover", "Folder" } 162 | 163 | # Enable searching for artwork corresponding to each individual media 164 | # file instead of only looking for album artwork. This is disabled by 165 | # default to reduce cache size. 166 | # artwork_individual = false 167 | 168 | # File types the scanner should ignore 169 | # Non-audio files will never be added to the database, but here you 170 | # can prevent the scanner from even probing them. This might improve 171 | # scan time. By default .db, .ini, .db-journal, .pdf and .metadata are 172 | # ignored. 173 | # filetypes_ignore = { ".db", ".ini", ".db-journal", ".pdf", ".metadata" } 174 | 175 | # File paths the scanner should ignore 176 | # If you want to exclude files on a more advanced basis you can enter 177 | # one or more POSIX regular expressions, and any file with a matching 178 | # path will be ignored. 179 | # filepath_ignore = { "myregex" } 180 | 181 | # Disable startup file scanning 182 | # When OwnTone starts it will do an initial file scan of your 183 | # library (and then watch it for changes). If you are sure your library 184 | # never changes while OwnTone is not running, you can disable the 185 | # initial file scan and save some system ressources. Disabling this scan 186 | # may lead to OwnTone's database coming out of sync with the 187 | # library. If that happens read the instructions in the README on how 188 | # to trigger a rescan. 189 | # filescan_disable = false 190 | 191 | # Only use the first genre found in metadata 192 | # Some tracks have multiple genres semicolon-separated in the same tag, 193 | # e.g. 'Pop;Rock'. If you don't want them listed like this, you can 194 | # enable this option and only the first genre will be used (i.e. 'Pop'). 195 | # only_first_genre = false 196 | 197 | # Should metadata from m3u playlists, e.g. artist and title in EXTINF, 198 | # override the metadata we get from radio streams? 199 | # m3u_overrides = false 200 | 201 | # Should iTunes metadata override ours? 202 | # itunes_overrides = false 203 | 204 | # Should we import the content of iTunes smart playlists? 205 | # itunes_smartpl = false 206 | 207 | # Transcoding options for DAAP and RSP clients 208 | # Since iTunes has native support for mpeg, mp4a, mp4v, alac and wav, 209 | # such files will be sent as they are. Any other formats will be 210 | # transcoded. Some other clients, including Roku/RSP, announce what 211 | # formats they support, and the server will transcode to one of those if 212 | # necessary. Clients that don't announce supported formats are assumed 213 | # to support mpeg (mp3), wav and alac. 214 | # Here you can change when and how to transcode. The settings *only* 215 | # affect serving audio to DAAP and RSP clients, they have no effect on 216 | # direct AirPlay, Chromecast and local audio playback. 217 | # Formats: mp4a, mp4v, mpeg, alac, flac, mpc, ogg, wma, wmal, wmav, aif, wav 218 | # Formats that should never be transcoded 219 | # no_decode = { "format", "format" } 220 | # Formats that should always be transcoded 221 | # force_decode = { "format", "format" } 222 | # Prefer transcode to wav (default), alac or mpeg (mp3 with the bit rate 223 | # configured below in the streaming section). Note that alac requires 224 | # precomputing and caching mp4 headers, which takes both cpu and disk. 225 | # prefer_format = "format" 226 | 227 | # Set ffmpeg filters (similar to 'ffmpeg -af xxx') that you want the 228 | # server to use when decoding files from your library. Examples: 229 | # { 'volume=replaygain=track' } -> use REPLAYGAIN_TRACK_GAIN metadata 230 | # { 'loudnorm=I=-16:LRA=11:TP=-1.5' } -> normalize volume 231 | # decode_audio_filters = { } 232 | 233 | # Watch named pipes in the library for data and autostart playback when 234 | # there is data to be read. To exclude specific pipes from watching, 235 | # consider using the above _ignore options. 236 | # pipe_autostart = true 237 | 238 | # Enable automatic rating updates 239 | # If enabled, rating is automatically updated after a song has either been 240 | # played or skipped (only skipping to the next song is taken into account). 241 | # The calculation is taken from the beets plugin "mpdstats" (see 242 | # https://beets.readthedocs.io/en/latest/plugins/mpdstats.html). 243 | # It consist of calculating a stable rating based only on the play- and 244 | # skipcount and a rolling rating based on the current rating and the action 245 | # (played or skipped). Both results are combined with a mix-factor of 0.75: 246 | # new rating = 0.75 * stable rating + 0.25 * rolling rating) 247 | # rating_updates = false 248 | 249 | # By default, ratings are only saved in the server's database. Enable 250 | # the below to make the server also read ratings from file metadata and 251 | # write on update (requires write access). To avoid excessive writing to 252 | # the library, automatic rating updates are not written, even with the 253 | # write_rating option enabled. 254 | # read_rating = false 255 | # write_rating = false 256 | # The scale used when reading/writing ratings to files 257 | # max_rating = 100 258 | 259 | # Allows creating, deleting and modifying m3u playlists in the library directories. 260 | # Only supported by the player web interface and some mpd clients 261 | # Defaults to being disabled. 262 | # allow_modifying_stored_playlists = false 263 | 264 | # A directory in one of the library directories that will be used as the default 265 | # playlist directory. OwnTone creates new playlists in this directory if only 266 | # a playlist name is provided (requires "allow_modify_stored_playlists" set to true). 267 | # default_playlist_directory = "" 268 | 269 | # By default OwnTone will - like iTunes - clear the playqueue if 270 | # playback stops. Setting clear_queue_on_stop_disable to true will keep 271 | # the playlist like MPD does. Note that some dacp clients do not show 272 | # the playqueue if playback is stopped. 273 | # clear_queue_on_stop_disable = false 274 | } 275 | 276 | # Local audio output 277 | audio { 278 | # Name - used in the speaker list in Remote 279 | nickname = "Computer" 280 | 281 | # Type of the output (alsa, pulseaudio, dummy or disabled) 282 | # type = "alsa" 283 | 284 | # For pulseaudio output, an optional server hostname or IP can be 285 | # specified (e.g. "localhost"). If not set, connection is made via local 286 | # socket. 287 | # server = "" 288 | 289 | # Audio PCM device name for local audio output - ALSA only 290 | # card = "default" 291 | 292 | # Mixer channel to use for volume control - ALSA only 293 | # If not set, PCM will be used if available, otherwise Master. 294 | # mixer = "" 295 | 296 | # Mixer device to use for volume control - ALSA only 297 | # If not set, the value for "card" will be used. 298 | # mixer_device = "" 299 | 300 | # Enable or disable audio resampling to keep local audio in sync with 301 | # e.g. Airplay. This feature relies on accurate ALSA measurements of 302 | # delay, and some devices don't provide that. If that is the case you 303 | # are better off disabling the feature. 304 | # sync_disable = false 305 | 306 | # Here you can adjust when local audio is started relative to other 307 | # speakers, e.g. Airplay. Negative values correspond to moving local 308 | # audio ahead, positive correspond to delaying it. The unit is 309 | # milliseconds. The offset must be between -1000 and 1000 (+/- 1 sec). 310 | # offset_ms = 0 311 | 312 | # To calculate what and if resampling is required, local audio delay is 313 | # measured each second. After a period the collected measurements are 314 | # used to estimate drift and latency, which determines if corrections 315 | # are required. This setting sets the length of that period in seconds. 316 | # adjust_period_seconds = 100 317 | } 318 | 319 | # ALSA device settings 320 | # If you have multiple ALSA devices you can configure them individually via 321 | # sections like the below. Make sure to set the "card name" correctly. See the 322 | # README about ALSA for details. Note that these settings will override the ALSA 323 | # settings in the "audio" section above. 324 | #alsa "card name" { 325 | # Name used in the speaker list. If not set, the card name will be used. 326 | # nickname = "Computer" 327 | 328 | # Mixer channel to use for volume control 329 | # If not set, PCM will be used if available, otherwise Master 330 | # mixer = "" 331 | 332 | # Mixer device to use for volume control 333 | # If not set, the card name will be used 334 | # mixer_device = "" 335 | #} 336 | 337 | # Pipe output 338 | # Allows OwnTone to output audio data to a named pipe 339 | #fifo { 340 | # nickname = "fifo" 341 | # path = "/path/to/fifo" 342 | #} 343 | 344 | # AirPlay settings common to all devices 345 | #airplay_shared { 346 | # UDP ports used when airplay devices make connections back to 347 | # OwnTone (choosing specific ports may be helpful when running 348 | # OwnTone behind a firewall) 349 | # control_port = 0 350 | # timing_port = 0 351 | 352 | # Switch Airplay 1 streams to uncompressed ALAC (as opposed to regular, 353 | # compressed ALAC). Reduces CPU use at the cost of network bandwidth. 354 | # uncompressed_alac = false 355 | #} 356 | 357 | # AirPlay per device settings 358 | # (make sure you get the capitalization of the device name right) 359 | #airplay "My AirPlay device" { 360 | # OwnTone's volume goes to 11! If that's more than you can handle 361 | # you can set a lower value here 362 | # max_volume = 11 363 | 364 | # Enable this option to exclude a particular AirPlay device from the 365 | # speaker list 366 | # exclude = false 367 | 368 | # Enable this option to keep a particular AirPlay device in the speaker 369 | # list and thus ignore mdns notifications about it no longer being 370 | # present. The speaker will remain until restart of OwnTone. 371 | # permanent = false 372 | 373 | # Some devices spuriously disconnect during playback, and based on the 374 | # device type OwnTone may attempt to reconnect. Setting this option 375 | # overrides this so reconnecting is either always enabled or disabled. 376 | # reconnect = false 377 | 378 | # AirPlay password 379 | # password = "s1kr3t" 380 | 381 | # Disable AirPlay 1 (RAOP) 382 | # raop_disable = false 383 | 384 | # Name used in the speaker list, overrides name from the device 385 | # nickname = "My speaker name" 386 | #} 387 | 388 | # Chromecast settings 389 | # (make sure you get the capitalization of the device name right) 390 | #chromecast "My Chromecast device" { 391 | # OwnTone's volume goes to 11! If that's more than you can handle 392 | # you can set a lower value here 393 | # max_volume = 11 394 | 395 | # Enable this option to exclude a particular device from the speaker 396 | # list 397 | # exclude = false 398 | 399 | # Name used in the speaker list, overrides name from the device 400 | # nickname = "My speaker name" 401 | #} 402 | 403 | # Spotify settings (only have effect if Spotify enabled - see README/INSTALL) 404 | spotify { 405 | # Set preferred bitrate for music streaming 406 | # 0: No preference (default), 1: 96kbps, 2: 160kbps, 3: 320kbps 407 | # bitrate = 0 408 | 409 | # Your Spotify playlists will by default be put in a "Spotify" playlist 410 | # folder. If you would rather have them together with your other 411 | # playlists you can set this option to true. 412 | # base_playlist_disable = false 413 | 414 | # Spotify playlists usually have many artist, and if you don't want 415 | # every artist to be listed when artist browsing in Remote, you can set 416 | # the artist_override flag to true. This will use the compilation_artist 417 | # as album artist for Spotify items. 418 | # artist_override = false 419 | 420 | # Similar to the different artists in Spotify playlists, the playlist 421 | # items belong to different albums, and if you do not want every album 422 | # to be listed when browsing in Remote, you can set the album_override 423 | # flag to true. This will use the playlist name as album name for 424 | # Spotify items. Notice that if an item is in more than one playlist, 425 | # it will only appear in one album when browsing (in which album is 426 | # random). 427 | # album_override = false 428 | } 429 | 430 | # RCP/Roku Soundbridge output settings 431 | # (make sure you get the capitalization of the device name right) 432 | #rcp "My SoundBridge device" { 433 | # Enable this option to exclude a particular device from the speaker 434 | # list 435 | # exclude = false 436 | 437 | # A Roku/SoundBridge can power up in 2 modes: (default) reconnect to the 438 | # previously used library (ie OwnTone) or in a 'cleared library' mode. 439 | # The Roku power up behaviour is affected by how OwnTone disconnects 440 | # from the Roku device. 441 | # 442 | # Set to false to maintain default Roku power on behaviour 443 | # clear_on_close = false 444 | #} 445 | 446 | 447 | # MPD configuration (only have effect if MPD enabled - see README/INSTALL) 448 | mpd { 449 | # TCP port to listen on for MPD client requests. 450 | # Default port is 6600, set to 0 to disable MPD support. 451 | # port = 6600 452 | 453 | # HTTP port to listen for artwork requests (only supported by some MPD 454 | # clients and will need additional configuration in the MPD client to 455 | # work). Set to 0 to disable serving artwork over http. 456 | # http_port = 0 457 | 458 | # Whether to emit an output with plugin type "httpd" to tell clients 459 | # that a stream is available for local playback. 460 | # enable_httpd_plugin = false 461 | } 462 | 463 | # SQLite configuration (allows to modify the operation of the SQLite databases) 464 | # Make sure to read the SQLite documentation for the corresponding PRAGMA 465 | # statements as changing them from the defaults may increase the possibility of 466 | # database corruptions! By default the SQLite default values are used. 467 | sqlite { 468 | # Cache size in number of db pages for the library database 469 | # (SQLite default page size is 1024 bytes and cache size is 2000 pages) 470 | # pragma_cache_size_library = 2000 471 | 472 | # Cache size in number of db pages for the daap cache database 473 | # (SQLite default page size is 1024 bytes and cache size is 2000 pages) 474 | # pragma_cache_size_cache = 2000 475 | 476 | # Sets the journal mode for the database 477 | # DELETE (default), TRUNCATE, PERSIST, MEMORY, WAL, OFF 478 | # pragma_journal_mode = DELETE 479 | 480 | # Change the setting of the "synchronous" flag 481 | # 0: OFF, 1: NORMAL, 2: FULL (default) 482 | # pragma_synchronous = 2 483 | 484 | # Number of bytes set aside for memory-mapped I/O for the library database 485 | # (requires sqlite 3.7.17 or later) 486 | # 0: disables mmap (default), any other value > 0: number of bytes for mmap 487 | # pragma_mmap_size_library = 0 488 | 489 | # Number of bytes set aside for memory-mapped I/O for the cache database 490 | # (requires sqlite 3.7.17 or later) 491 | # 0: disables mmap (default), any other value > 0: number of bytes for mmap 492 | # pragma_mmap_size_cache = 0 493 | 494 | # Should the database be vacuumed on startup? (increases startup time, 495 | # but may reduce database size). Default is yes. 496 | # vacuum = yes 497 | } 498 | 499 | # Streaming audio settings for remote connections (ie stream.mp3) 500 | streaming { 501 | # Sample rate, typically 44100 or 48000 502 | # sample_rate = 44100 503 | 504 | # Set the MP3 streaming bit rate (in kbps), valid options: 64 / 96 / 128 / 192 / 320 505 | # bit_rate = 192 506 | } 507 | --- 508 | apiVersion: apps/v1 509 | kind: Deployment 510 | metadata: 511 | labels: 512 | app.kubernetes.io/instance: owntone 513 | app.kubernetes.io/name: owntone 514 | name: owntone 515 | namespace: owntone-app 516 | spec: 517 | replicas: 1 518 | selector: 519 | matchLabels: 520 | app.kubernetes.io/instance: owntone 521 | app.kubernetes.io/name: owntone 522 | strategy: 523 | type: Recreate 524 | template: 525 | metadata: 526 | labels: 527 | app.kubernetes.io/instance: owntone 528 | app.kubernetes.io/name: owntone 529 | spec: 530 | # Share the network stack with the underlying host node to be able 531 | # to advertise the service via Avahi (mDNS/Zeroconf). 532 | hostNetwork: true 533 | containers: 534 | - image: docker.io/owntone/owntone:latest 535 | imagePullPolicy: IfNotPresent 536 | name: owntone 537 | env: 538 | # Specifies the UID for the process running in the container. 539 | # This user must be able to access the media files. 540 | - name: "UID" 541 | value: "{{ uid(runAsUser) }}" 542 | # Specifies the GID for the process running in the container. 543 | - name: "GID" 544 | value: "{{ gid(runAsGroup) }}" 545 | ports: 546 | - containerPort: 3688 547 | hostPort: 3688 548 | protocol: TCP 549 | - containerPort: 3689 550 | hostPort: 3689 551 | protocol: TCP 552 | volumeMounts: 553 | - name: config 554 | mountPath: /etc/owntone/owntone.conf 555 | subPath: owntone.conf 556 | - name: database 557 | mountPath: /var/cache/owntone/ 558 | - name: media 559 | mountPath: /srv/media/ 560 | restartPolicy: Always 561 | volumes: 562 | - name: config 563 | configMap: 564 | name: owntone 565 | # Please note that the database directory is not persistent and is 566 | # therefore re-indexed each time the container is restarted. 567 | - name: database 568 | emptyDir: {} 569 | - name: media 570 | hostPath: 571 | type: Directory 572 | # Insert the name of the shared folder you want to use. 573 | # Make sure the configured UID/GID the container is running 574 | # with has access to that directory. 575 | path: {{ sharedfolder_path(mediaSharedFolderName) }} 576 | --- 577 | apiVersion: v1 578 | kind: Service 579 | metadata: 580 | name: owntone 581 | namespace: owntone-app 582 | labels: 583 | app.kubernetes.io/instance: owntone 584 | app.kubernetes.io/name: owntone 585 | spec: 586 | type: ClusterIP 587 | ports: 588 | - port: 3689 589 | protocol: TCP 590 | targetPort: 3689 591 | selector: 592 | app.kubernetes.io/instance: owntone 593 | app.kubernetes.io/name: owntone 594 | --- 595 | apiVersion: traefik.io/v1alpha1 596 | kind: IngressRoute 597 | metadata: 598 | name: owntone-websecure 599 | namespace: owntone-app 600 | spec: 601 | entryPoints: 602 | - websecure 603 | routes: 604 | - match: Host(`owntone.{{ fqdn() }}`) 605 | kind: Rule 606 | services: 607 | - name: owntone 608 | port: 3689 609 | tls: {} 610 | --------------------------------------------------------------------------------