homepage: init with dashboard contract
This commit is contained in:
parent
77869300ee
commit
f485cc60fe
50 changed files with 3072 additions and 411 deletions
|
|
@ -37,13 +37,17 @@ Provided contracts are:
|
||||||
- [SSL generator contract](contracts-ssl.html) to generate SSL certificates.
|
- [SSL generator contract](contracts-ssl.html) to generate SSL certificates.
|
||||||
Two providers are implemented: self-signed and Let's Encrypt.
|
Two providers are implemented: self-signed and Let's Encrypt.
|
||||||
- [Backup contract][] to backup directories.
|
- [Backup contract][] to backup directories.
|
||||||
One provider is implemented: [Restic][].
|
Two providers are implemented: [BorgBackup][] and [Restic][].
|
||||||
- [Database Backup contract](contracts-databasebackup.html) to backup database dumps.
|
- [Database Backup contract](contracts-databasebackup.html) to backup database dumps.
|
||||||
One provider is implemented: [Restic][].
|
One provider is implemented: [BorgBackup][] and [Restic][].
|
||||||
- [Secret contract](contracts-secret.html) to provide secrets that are deployed outside of the Nix store.
|
- [Contract for Secrets](contracts-secret.html) to provide secrets that are deployed outside of the Nix store.
|
||||||
One provider is implemented: [SOPS][].
|
One provider is implemented: [SOPS][].
|
||||||
|
- [Dashboard contract](contracts-dashboard.html) to show services in a nice user-facing dashboard.
|
||||||
|
One provider is implemented: [Homepage][].
|
||||||
|
|
||||||
[backup contract]: contracts-backup.html
|
[backup contract]: contracts-backup.html
|
||||||
|
[borgbackup]: blocks-borgbackup.html
|
||||||
|
[homepage]: services-homepage.html
|
||||||
[restic]: blocks-restic.html
|
[restic]: blocks-restic.html
|
||||||
[sops]: blocks-sops.html
|
[sops]: blocks-sops.html
|
||||||
|
|
||||||
|
|
@ -63,6 +67,10 @@ modules/contracts/databasebackup/docs/default.md
|
||||||
modules/contracts/secret/docs/default.md
|
modules/contracts/secret/docs/default.md
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```{=include=} chapters html:into-file=//contracts-dashboard.html
|
||||||
|
modules/contracts/dashboard/docs/default.md
|
||||||
|
```
|
||||||
|
|
||||||
## Problem Statement {#contracts-why}
|
## Problem Statement {#contracts-why}
|
||||||
|
|
||||||
Currently in nixpkgs, every module accessing a shared resource
|
Currently in nixpkgs, every module accessing a shared resource
|
||||||
|
|
|
||||||
|
|
@ -128,3 +128,29 @@ shb.sops.secret."awesome" = {
|
||||||
request = config.shb.restic.instances.awesome.settings.passphrase.request;
|
request = config.shb.restic.instances.awesome.settings.passphrase.request;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Impermanence {#recipes-exposeService-impermanence}
|
||||||
|
|
||||||
|
To save the data folder in an impermanence setup, add:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.zfs.datasets."safe/awesome".path = config.services.awesome.dataDir;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Application Dashboard {#recipes-exposeService-applicationdashboard}
|
||||||
|
|
||||||
|
For example using the [Homepage](services-homepage.html) service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.MyServices.services.Awesome = {
|
||||||
|
sortOrder = 1;
|
||||||
|
dashboard.request = {
|
||||||
|
externalUrl = "https://${fqdn}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString listenPort}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,6 @@
|
||||||
"blocks-authelia-forward-auth": [
|
"blocks-authelia-forward-auth": [
|
||||||
"blocks-authelia.html#blocks-authelia-forward-auth"
|
"blocks-authelia.html#blocks-authelia-forward-auth"
|
||||||
],
|
],
|
||||||
"blocks-authelia-global-setup": [
|
|
||||||
"blocks-authelia.html#blocks-authelia-global-setup"
|
|
||||||
],
|
|
||||||
"blocks-authelia-oidc": [
|
"blocks-authelia-oidc": [
|
||||||
"blocks-authelia.html#blocks-authelia-oidc"
|
"blocks-authelia.html#blocks-authelia-oidc"
|
||||||
],
|
],
|
||||||
|
|
@ -65,6 +62,21 @@
|
||||||
"blocks-authelia-options-shb.authelia.autheliaUser": [
|
"blocks-authelia-options-shb.authelia.autheliaUser": [
|
||||||
"blocks-authelia.html#blocks-authelia-options-shb.authelia.autheliaUser"
|
"blocks-authelia.html#blocks-authelia-options-shb.authelia.autheliaUser"
|
||||||
],
|
],
|
||||||
|
"blocks-authelia-options-shb.authelia.dashboard": [
|
||||||
|
"blocks-authelia.html#blocks-authelia-options-shb.authelia.dashboard"
|
||||||
|
],
|
||||||
|
"blocks-authelia-options-shb.authelia.dashboard.request": [
|
||||||
|
"blocks-authelia.html#blocks-authelia-options-shb.authelia.dashboard.request"
|
||||||
|
],
|
||||||
|
"blocks-authelia-options-shb.authelia.dashboard.request.externalUrl": [
|
||||||
|
"blocks-authelia.html#blocks-authelia-options-shb.authelia.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"blocks-authelia-options-shb.authelia.dashboard.request.internalUrl": [
|
||||||
|
"blocks-authelia.html#blocks-authelia-options-shb.authelia.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"blocks-authelia-options-shb.authelia.dashboard.result": [
|
||||||
|
"blocks-authelia.html#blocks-authelia-options-shb.authelia.dashboard.result"
|
||||||
|
],
|
||||||
"blocks-authelia-options-shb.authelia.dcdomain": [
|
"blocks-authelia-options-shb.authelia.dcdomain": [
|
||||||
"blocks-authelia.html#blocks-authelia-options-shb.authelia.dcdomain"
|
"blocks-authelia.html#blocks-authelia-options-shb.authelia.dcdomain"
|
||||||
],
|
],
|
||||||
|
|
@ -323,6 +335,9 @@
|
||||||
"blocks-authelia-troubleshooting": [
|
"blocks-authelia-troubleshooting": [
|
||||||
"blocks-authelia.html#blocks-authelia-troubleshooting"
|
"blocks-authelia.html#blocks-authelia-troubleshooting"
|
||||||
],
|
],
|
||||||
|
"blocks-authelia-usage-configuration": [
|
||||||
|
"blocks-authelia.html#blocks-authelia-usage-configuration"
|
||||||
|
],
|
||||||
"blocks-borgbackup": [
|
"blocks-borgbackup": [
|
||||||
"blocks-borgbackup.html#blocks-borgbackup"
|
"blocks-borgbackup.html#blocks-borgbackup"
|
||||||
],
|
],
|
||||||
|
|
@ -578,8 +593,8 @@
|
||||||
"blocks-lldap": [
|
"blocks-lldap": [
|
||||||
"blocks-lldap.html#blocks-lldap"
|
"blocks-lldap.html#blocks-lldap"
|
||||||
],
|
],
|
||||||
"blocks-lldap-global-setup": [
|
"blocks-lldap-features": [
|
||||||
"blocks-lldap.html#blocks-lldap-global-setup"
|
"blocks-lldap.html#blocks-lldap-features"
|
||||||
],
|
],
|
||||||
"blocks-lldap-manage-groups": [
|
"blocks-lldap-manage-groups": [
|
||||||
"blocks-lldap.html#blocks-lldap-manage-groups"
|
"blocks-lldap.html#blocks-lldap-manage-groups"
|
||||||
|
|
@ -623,6 +638,21 @@
|
||||||
"blocks-lldap-options-shb.lldap.backup.result.restoreScript": [
|
"blocks-lldap-options-shb.lldap.backup.result.restoreScript": [
|
||||||
"blocks-lldap.html#blocks-lldap-options-shb.lldap.backup.result.restoreScript"
|
"blocks-lldap.html#blocks-lldap-options-shb.lldap.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"blocks-lldap-options-shb.lldap.dashboard": [
|
||||||
|
"blocks-lldap.html#blocks-lldap-options-shb.lldap.dashboard"
|
||||||
|
],
|
||||||
|
"blocks-lldap-options-shb.lldap.dashboard.request": [
|
||||||
|
"blocks-lldap.html#blocks-lldap-options-shb.lldap.dashboard.request"
|
||||||
|
],
|
||||||
|
"blocks-lldap-options-shb.lldap.dashboard.request.externalUrl": [
|
||||||
|
"blocks-lldap.html#blocks-lldap-options-shb.lldap.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"blocks-lldap-options-shb.lldap.dashboard.request.internalUrl": [
|
||||||
|
"blocks-lldap.html#blocks-lldap-options-shb.lldap.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"blocks-lldap-options-shb.lldap.dashboard.result": [
|
||||||
|
"blocks-lldap.html#blocks-lldap-options-shb.lldap.dashboard.result"
|
||||||
|
],
|
||||||
"blocks-lldap-options-shb.lldap.dcdomain": [
|
"blocks-lldap-options-shb.lldap.dcdomain": [
|
||||||
"blocks-lldap.html#blocks-lldap-options-shb.lldap.dcdomain"
|
"blocks-lldap.html#blocks-lldap-options-shb.lldap.dcdomain"
|
||||||
],
|
],
|
||||||
|
|
@ -824,18 +854,27 @@
|
||||||
"blocks-lldap-options-shb.lldap.webUIListenPort": [
|
"blocks-lldap-options-shb.lldap.webUIListenPort": [
|
||||||
"blocks-lldap.html#blocks-lldap-options-shb.lldap.webUIListenPort"
|
"blocks-lldap.html#blocks-lldap-options-shb.lldap.webUIListenPort"
|
||||||
],
|
],
|
||||||
"blocks-lldap-restrict-access-by-ip": [
|
|
||||||
"blocks-lldap.html#blocks-lldap-restrict-access-by-ip"
|
|
||||||
],
|
|
||||||
"blocks-lldap-ssl": [
|
|
||||||
"blocks-lldap.html#blocks-lldap-ssl"
|
|
||||||
],
|
|
||||||
"blocks-lldap-tests": [
|
"blocks-lldap-tests": [
|
||||||
"blocks-lldap.html#blocks-lldap-tests"
|
"blocks-lldap.html#blocks-lldap-tests"
|
||||||
],
|
],
|
||||||
"blocks-lldap-troubleshooting": [
|
"blocks-lldap-troubleshooting": [
|
||||||
"blocks-lldap.html#blocks-lldap-troubleshooting"
|
"blocks-lldap.html#blocks-lldap-troubleshooting"
|
||||||
],
|
],
|
||||||
|
"blocks-lldap-usage": [
|
||||||
|
"blocks-lldap.html#blocks-lldap-usage"
|
||||||
|
],
|
||||||
|
"blocks-lldap-usage-applicationdashboard": [
|
||||||
|
"blocks-lldap.html#blocks-lldap-usage-applicationdashboard"
|
||||||
|
],
|
||||||
|
"blocks-lldap-usage-configuration": [
|
||||||
|
"blocks-lldap.html#blocks-lldap-usage-configuration"
|
||||||
|
],
|
||||||
|
"blocks-lldap-usage-restrict-access-by-ip": [
|
||||||
|
"blocks-lldap.html#blocks-lldap-usage-restrict-access-by-ip"
|
||||||
|
],
|
||||||
|
"blocks-lldap-usage-ssl": [
|
||||||
|
"blocks-lldap.html#blocks-lldap-usage-ssl"
|
||||||
|
],
|
||||||
"blocks-mitmdump": [
|
"blocks-mitmdump": [
|
||||||
"blocks-mitmdump.html#blocks-mitmdump"
|
"blocks-mitmdump.html#blocks-mitmdump"
|
||||||
],
|
],
|
||||||
|
|
@ -953,6 +992,21 @@
|
||||||
"blocks-monitoring-options-shb.monitoring.contactPoints": [
|
"blocks-monitoring-options-shb.monitoring.contactPoints": [
|
||||||
"blocks-monitoring.html#blocks-monitoring-options-shb.monitoring.contactPoints"
|
"blocks-monitoring.html#blocks-monitoring-options-shb.monitoring.contactPoints"
|
||||||
],
|
],
|
||||||
|
"blocks-monitoring-options-shb.monitoring.dashboard": [
|
||||||
|
"blocks-monitoring.html#blocks-monitoring-options-shb.monitoring.dashboard"
|
||||||
|
],
|
||||||
|
"blocks-monitoring-options-shb.monitoring.dashboard.request": [
|
||||||
|
"blocks-monitoring.html#blocks-monitoring-options-shb.monitoring.dashboard.request"
|
||||||
|
],
|
||||||
|
"blocks-monitoring-options-shb.monitoring.dashboard.request.externalUrl": [
|
||||||
|
"blocks-monitoring.html#blocks-monitoring-options-shb.monitoring.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"blocks-monitoring-options-shb.monitoring.dashboard.request.internalUrl": [
|
||||||
|
"blocks-monitoring.html#blocks-monitoring-options-shb.monitoring.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"blocks-monitoring-options-shb.monitoring.dashboard.result": [
|
||||||
|
"blocks-monitoring.html#blocks-monitoring-options-shb.monitoring.dashboard.result"
|
||||||
|
],
|
||||||
"blocks-monitoring-options-shb.monitoring.dashboards": [
|
"blocks-monitoring-options-shb.monitoring.dashboards": [
|
||||||
"blocks-monitoring.html#blocks-monitoring-options-shb.monitoring.dashboards"
|
"blocks-monitoring.html#blocks-monitoring-options-shb.monitoring.dashboards"
|
||||||
],
|
],
|
||||||
|
|
@ -1133,6 +1187,12 @@
|
||||||
"blocks-monitoring-usage": [
|
"blocks-monitoring-usage": [
|
||||||
"blocks-monitoring.html#blocks-monitoring-usage"
|
"blocks-monitoring.html#blocks-monitoring-usage"
|
||||||
],
|
],
|
||||||
|
"blocks-monitoring-usage-applicationdashboard": [
|
||||||
|
"blocks-monitoring.html#blocks-monitoring-usage-applicationdashboard"
|
||||||
|
],
|
||||||
|
"blocks-monitoring-usage-configuration": [
|
||||||
|
"blocks-monitoring.html#blocks-monitoring-usage-configuration"
|
||||||
|
],
|
||||||
"blocks-monitoring-usage-log-optimization": [
|
"blocks-monitoring-usage-log-optimization": [
|
||||||
"blocks-monitoring.html#blocks-monitoring-usage-log-optimization"
|
"blocks-monitoring.html#blocks-monitoring-usage-log-optimization"
|
||||||
],
|
],
|
||||||
|
|
@ -1712,6 +1772,15 @@
|
||||||
"contract-backup-usage": [
|
"contract-backup-usage": [
|
||||||
"contracts-backup.html#contract-backup-usage"
|
"contracts-backup.html#contract-backup-usage"
|
||||||
],
|
],
|
||||||
|
"contract-dashboard": [
|
||||||
|
"contracts-dashboard.html#contract-dashboard"
|
||||||
|
],
|
||||||
|
"contract-dashboard-options": [
|
||||||
|
"contracts-dashboard.html#contract-dashboard-options"
|
||||||
|
],
|
||||||
|
"contract-dashboard-providers": [
|
||||||
|
"contracts-dashboard.html#contract-dashboard-providers"
|
||||||
|
],
|
||||||
"contract-databasebackup": [
|
"contract-databasebackup": [
|
||||||
"contracts-databasebackup.html#contract-databasebackup"
|
"contracts-databasebackup.html#contract-databasebackup"
|
||||||
],
|
],
|
||||||
|
|
@ -1805,6 +1874,27 @@
|
||||||
"contracts-concept": [
|
"contracts-concept": [
|
||||||
"contracts.html#contracts-concept"
|
"contracts.html#contracts-concept"
|
||||||
],
|
],
|
||||||
|
"contracts-dashboard-options-shb.contracts.dashboard": [
|
||||||
|
"contracts-dashboard.html#contracts-dashboard-options-shb.contracts.dashboard"
|
||||||
|
],
|
||||||
|
"contracts-dashboard-options-shb.contracts.dashboard.request": [
|
||||||
|
"contracts-dashboard.html#contracts-dashboard-options-shb.contracts.dashboard.request"
|
||||||
|
],
|
||||||
|
"contracts-dashboard-options-shb.contracts.dashboard.request.externalUrl": [
|
||||||
|
"contracts-dashboard.html#contracts-dashboard-options-shb.contracts.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"contracts-dashboard-options-shb.contracts.dashboard.request.internalUrl": [
|
||||||
|
"contracts-dashboard.html#contracts-dashboard-options-shb.contracts.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"contracts-dashboard-options-shb.contracts.dashboard.result": [
|
||||||
|
"contracts-dashboard.html#contracts-dashboard-options-shb.contracts.dashboard.result"
|
||||||
|
],
|
||||||
|
"contracts-dashboard-options-shb.contracts.dashboard.settings": [
|
||||||
|
"contracts-dashboard.html#contracts-dashboard-options-shb.contracts.dashboard.settings"
|
||||||
|
],
|
||||||
|
"contracts-dashboard-usage": [
|
||||||
|
"contracts-dashboard.html#contracts-dashboard-usage"
|
||||||
|
],
|
||||||
"contracts-databasebackup-options-shb.contracts.databasebackup": [
|
"contracts-databasebackup-options-shb.contracts.databasebackup": [
|
||||||
"contracts-databasebackup.html#contracts-databasebackup-options-shb.contracts.databasebackup"
|
"contracts-databasebackup.html#contracts-databasebackup-options-shb.contracts.databasebackup"
|
||||||
],
|
],
|
||||||
|
|
@ -2156,12 +2246,18 @@
|
||||||
"recipes-exposeService": [
|
"recipes-exposeService": [
|
||||||
"recipes-exposeService.html#recipes-exposeService"
|
"recipes-exposeService.html#recipes-exposeService"
|
||||||
],
|
],
|
||||||
|
"recipes-exposeService-applicationdashboard": [
|
||||||
|
"recipes-exposeService.html#recipes-exposeService-applicationdashboard"
|
||||||
|
],
|
||||||
"recipes-exposeService-backup": [
|
"recipes-exposeService-backup": [
|
||||||
"recipes-exposeService.html#recipes-exposeService-backup"
|
"recipes-exposeService.html#recipes-exposeService-backup"
|
||||||
],
|
],
|
||||||
"recipes-exposeService-debug": [
|
"recipes-exposeService-debug": [
|
||||||
"recipes-exposeService.html#recipes-exposeService-debug"
|
"recipes-exposeService.html#recipes-exposeService-debug"
|
||||||
],
|
],
|
||||||
|
"recipes-exposeService-impermanence": [
|
||||||
|
"recipes-exposeService.html#recipes-exposeService-impermanence"
|
||||||
|
],
|
||||||
"recipes-exposeService-ldap": [
|
"recipes-exposeService-ldap": [
|
||||||
"recipes-exposeService.html#recipes-exposeService-ldap"
|
"recipes-exposeService.html#recipes-exposeService-ldap"
|
||||||
],
|
],
|
||||||
|
|
@ -2216,6 +2312,9 @@
|
||||||
"services-arr": [
|
"services-arr": [
|
||||||
"services-arr.html#services-arr"
|
"services-arr.html#services-arr"
|
||||||
],
|
],
|
||||||
|
"services-arr-features": [
|
||||||
|
"services-arr.html#services-arr-features"
|
||||||
|
],
|
||||||
"services-arr-options": [
|
"services-arr-options": [
|
||||||
"services-arr.html#services-arr-options"
|
"services-arr.html#services-arr-options"
|
||||||
],
|
],
|
||||||
|
|
@ -2258,6 +2357,21 @@
|
||||||
"services-arr-options-shb.arr.bazarr.backup.result.restoreScript": [
|
"services-arr-options-shb.arr.bazarr.backup.result.restoreScript": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.bazarr.backup.result.restoreScript"
|
"services-arr.html#services-arr-options-shb.arr.bazarr.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"services-arr-options-shb.arr.bazarr.dashboard": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.bazarr.dashboard"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.bazarr.dashboard.request": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.bazarr.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.bazarr.dashboard.request.externalUrl": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.bazarr.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.bazarr.dashboard.request.internalUrl": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.bazarr.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.bazarr.dashboard.result": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.bazarr.dashboard.result"
|
||||||
|
],
|
||||||
"services-arr-options-shb.arr.bazarr.dataDir": [
|
"services-arr-options-shb.arr.bazarr.dataDir": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.bazarr.dataDir"
|
"services-arr.html#services-arr-options-shb.arr.bazarr.dataDir"
|
||||||
],
|
],
|
||||||
|
|
@ -2273,6 +2387,15 @@
|
||||||
"services-arr-options-shb.arr.bazarr.settings": [
|
"services-arr-options-shb.arr.bazarr.settings": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.bazarr.settings"
|
"services-arr.html#services-arr-options-shb.arr.bazarr.settings"
|
||||||
],
|
],
|
||||||
|
"services-arr-options-shb.arr.bazarr.settings.ApiKey": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.bazarr.settings.ApiKey"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.bazarr.settings.ApiKey.source": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.bazarr.settings.ApiKey.source"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.bazarr.settings.ApiKey.transform": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.bazarr.settings.ApiKey.transform"
|
||||||
|
],
|
||||||
"services-arr-options-shb.arr.bazarr.settings.LogLevel": [
|
"services-arr-options-shb.arr.bazarr.settings.LogLevel": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.bazarr.settings.LogLevel"
|
"services-arr.html#services-arr-options-shb.arr.bazarr.settings.LogLevel"
|
||||||
],
|
],
|
||||||
|
|
@ -2336,6 +2459,21 @@
|
||||||
"services-arr-options-shb.arr.jackett.backup.result.restoreScript": [
|
"services-arr-options-shb.arr.jackett.backup.result.restoreScript": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.jackett.backup.result.restoreScript"
|
"services-arr.html#services-arr-options-shb.arr.jackett.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"services-arr-options-shb.arr.jackett.dashboard": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.jackett.dashboard"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.jackett.dashboard.request": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.jackett.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.jackett.dashboard.request.externalUrl": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.jackett.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.jackett.dashboard.request.internalUrl": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.jackett.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.jackett.dashboard.result": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.jackett.dashboard.result"
|
||||||
|
],
|
||||||
"services-arr-options-shb.arr.jackett.dataDir": [
|
"services-arr-options-shb.arr.jackett.dataDir": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.jackett.dataDir"
|
"services-arr.html#services-arr-options-shb.arr.jackett.dataDir"
|
||||||
],
|
],
|
||||||
|
|
@ -2441,6 +2579,21 @@
|
||||||
"services-arr-options-shb.arr.lidarr.backup.result.restoreScript": [
|
"services-arr-options-shb.arr.lidarr.backup.result.restoreScript": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.lidarr.backup.result.restoreScript"
|
"services-arr.html#services-arr-options-shb.arr.lidarr.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"services-arr-options-shb.arr.lidarr.dashboard": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.lidarr.dashboard"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.lidarr.dashboard.request": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.lidarr.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.lidarr.dashboard.request.externalUrl": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.lidarr.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.lidarr.dashboard.request.internalUrl": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.lidarr.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.lidarr.dashboard.result": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.lidarr.dashboard.result"
|
||||||
|
],
|
||||||
"services-arr-options-shb.arr.lidarr.dataDir": [
|
"services-arr-options-shb.arr.lidarr.dataDir": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.lidarr.dataDir"
|
"services-arr.html#services-arr-options-shb.arr.lidarr.dataDir"
|
||||||
],
|
],
|
||||||
|
|
@ -2456,6 +2609,15 @@
|
||||||
"services-arr-options-shb.arr.lidarr.settings": [
|
"services-arr-options-shb.arr.lidarr.settings": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.lidarr.settings"
|
"services-arr.html#services-arr-options-shb.arr.lidarr.settings"
|
||||||
],
|
],
|
||||||
|
"services-arr-options-shb.arr.lidarr.settings.ApiKey": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.lidarr.settings.ApiKey"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.lidarr.settings.ApiKey.source": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.lidarr.settings.ApiKey.source"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.lidarr.settings.ApiKey.transform": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.lidarr.settings.ApiKey.transform"
|
||||||
|
],
|
||||||
"services-arr-options-shb.arr.lidarr.settings.LogLevel": [
|
"services-arr-options-shb.arr.lidarr.settings.LogLevel": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.lidarr.settings.LogLevel"
|
"services-arr.html#services-arr-options-shb.arr.lidarr.settings.LogLevel"
|
||||||
],
|
],
|
||||||
|
|
@ -2519,6 +2681,21 @@
|
||||||
"services-arr-options-shb.arr.radarr.backup.result.restoreScript": [
|
"services-arr-options-shb.arr.radarr.backup.result.restoreScript": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.radarr.backup.result.restoreScript"
|
"services-arr.html#services-arr-options-shb.arr.radarr.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"services-arr-options-shb.arr.radarr.dashboard": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.radarr.dashboard"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.radarr.dashboard.request": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.radarr.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.radarr.dashboard.request.externalUrl": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.radarr.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.radarr.dashboard.request.internalUrl": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.radarr.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.radarr.dashboard.result": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.radarr.dashboard.result"
|
||||||
|
],
|
||||||
"services-arr-options-shb.arr.radarr.dataDir": [
|
"services-arr-options-shb.arr.radarr.dataDir": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.radarr.dataDir"
|
"services-arr.html#services-arr-options-shb.arr.radarr.dataDir"
|
||||||
],
|
],
|
||||||
|
|
@ -2609,6 +2786,21 @@
|
||||||
"services-arr-options-shb.arr.readarr.backup.result.restoreScript": [
|
"services-arr-options-shb.arr.readarr.backup.result.restoreScript": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.readarr.backup.result.restoreScript"
|
"services-arr.html#services-arr-options-shb.arr.readarr.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"services-arr-options-shb.arr.readarr.dashboard": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.readarr.dashboard"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.readarr.dashboard.request": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.readarr.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.readarr.dashboard.request.externalUrl": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.readarr.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.readarr.dashboard.request.internalUrl": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.readarr.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.readarr.dashboard.result": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.readarr.dashboard.result"
|
||||||
|
],
|
||||||
"services-arr-options-shb.arr.readarr.dataDir": [
|
"services-arr-options-shb.arr.readarr.dataDir": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.readarr.dataDir"
|
"services-arr.html#services-arr-options-shb.arr.readarr.dataDir"
|
||||||
],
|
],
|
||||||
|
|
@ -2624,6 +2816,15 @@
|
||||||
"services-arr-options-shb.arr.readarr.settings": [
|
"services-arr-options-shb.arr.readarr.settings": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.readarr.settings"
|
"services-arr.html#services-arr-options-shb.arr.readarr.settings"
|
||||||
],
|
],
|
||||||
|
"services-arr-options-shb.arr.readarr.settings.ApiKey": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.readarr.settings.ApiKey"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.readarr.settings.ApiKey.source": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.readarr.settings.ApiKey.source"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.readarr.settings.ApiKey.transform": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.readarr.settings.ApiKey.transform"
|
||||||
|
],
|
||||||
"services-arr-options-shb.arr.readarr.settings.LogLevel": [
|
"services-arr-options-shb.arr.readarr.settings.LogLevel": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.readarr.settings.LogLevel"
|
"services-arr.html#services-arr-options-shb.arr.readarr.settings.LogLevel"
|
||||||
],
|
],
|
||||||
|
|
@ -2687,6 +2888,21 @@
|
||||||
"services-arr-options-shb.arr.sonarr.backup.result.restoreScript": [
|
"services-arr-options-shb.arr.sonarr.backup.result.restoreScript": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.sonarr.backup.result.restoreScript"
|
"services-arr.html#services-arr-options-shb.arr.sonarr.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"services-arr-options-shb.arr.sonarr.dashboard": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.sonarr.dashboard"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.sonarr.dashboard.request": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.sonarr.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.sonarr.dashboard.request.externalUrl": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.sonarr.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.sonarr.dashboard.request.internalUrl": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.sonarr.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-arr-options-shb.arr.sonarr.dashboard.result": [
|
||||||
|
"services-arr.html#services-arr-options-shb.arr.sonarr.dashboard.result"
|
||||||
|
],
|
||||||
"services-arr-options-shb.arr.sonarr.dataDir": [
|
"services-arr-options-shb.arr.sonarr.dataDir": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.sonarr.dataDir"
|
"services-arr.html#services-arr-options-shb.arr.sonarr.dataDir"
|
||||||
],
|
],
|
||||||
|
|
@ -2735,6 +2951,30 @@
|
||||||
"services-arr-options-shb.arr.sonarr.subdomain": [
|
"services-arr-options-shb.arr.sonarr.subdomain": [
|
||||||
"services-arr.html#services-arr-options-shb.arr.sonarr.subdomain"
|
"services-arr.html#services-arr-options-shb.arr.sonarr.subdomain"
|
||||||
],
|
],
|
||||||
|
"services-arr-usage": [
|
||||||
|
"services-arr.html#services-arr-usage"
|
||||||
|
],
|
||||||
|
"services-arr-usage-apikeys": [
|
||||||
|
"services-arr.html#services-arr-usage-apikeys"
|
||||||
|
],
|
||||||
|
"services-arr-usage-applicationdashboard": [
|
||||||
|
"services-arr.html#services-arr-usage-applicationdashboard"
|
||||||
|
],
|
||||||
|
"services-arr-usage-configuration": [
|
||||||
|
"services-arr.html#services-arr-usage-configuration"
|
||||||
|
],
|
||||||
|
"services-arr-usage-jackett-proxy": [
|
||||||
|
"services-arr.html#services-arr-usage-jackett-proxy"
|
||||||
|
],
|
||||||
|
"services-authelia-features": [
|
||||||
|
"blocks-authelia.html#services-authelia-features"
|
||||||
|
],
|
||||||
|
"services-authelia-usage": [
|
||||||
|
"blocks-authelia.html#services-authelia-usage"
|
||||||
|
],
|
||||||
|
"services-authelia-usage-applicationdashboard": [
|
||||||
|
"blocks-authelia.html#services-authelia-usage-applicationdashboard"
|
||||||
|
],
|
||||||
"services-category-ai": [
|
"services-category-ai": [
|
||||||
"services.html#services-category-ai"
|
"services.html#services-category-ai"
|
||||||
],
|
],
|
||||||
|
|
@ -2744,6 +2984,9 @@
|
||||||
"services-category-code": [
|
"services-category-code": [
|
||||||
"services.html#services-category-code"
|
"services.html#services-category-code"
|
||||||
],
|
],
|
||||||
|
"services-category-dashboard": [
|
||||||
|
"services.html#services-category-dashboard"
|
||||||
|
],
|
||||||
"services-category-documents": [
|
"services-category-documents": [
|
||||||
"services.html#services-category-documents"
|
"services.html#services-category-documents"
|
||||||
],
|
],
|
||||||
|
|
@ -2771,6 +3014,9 @@
|
||||||
"services-firefly-iii-declarative-ldap": [
|
"services-firefly-iii-declarative-ldap": [
|
||||||
"services-firefly-iii.html#services-firefly-iii-declarative-ldap"
|
"services-firefly-iii.html#services-firefly-iii-declarative-ldap"
|
||||||
],
|
],
|
||||||
|
"services-firefly-iii-features": [
|
||||||
|
"services-firefly-iii.html#services-firefly-iii-features"
|
||||||
|
],
|
||||||
"services-firefly-iii-impermanence": [
|
"services-firefly-iii-impermanence": [
|
||||||
"services-firefly-iii.html#services-firefly-iii-impermanence"
|
"services-firefly-iii.html#services-firefly-iii-impermanence"
|
||||||
],
|
],
|
||||||
|
|
@ -2837,6 +3083,21 @@
|
||||||
"services-firefly-iii-options-shb.firefly-iii.backup.result.restoreScript": [
|
"services-firefly-iii-options-shb.firefly-iii.backup.result.restoreScript": [
|
||||||
"services-firefly-iii.html#services-firefly-iii-options-shb.firefly-iii.backup.result.restoreScript"
|
"services-firefly-iii.html#services-firefly-iii-options-shb.firefly-iii.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"services-firefly-iii-options-shb.firefly-iii.dashboard": [
|
||||||
|
"services-firefly-iii.html#services-firefly-iii-options-shb.firefly-iii.dashboard"
|
||||||
|
],
|
||||||
|
"services-firefly-iii-options-shb.firefly-iii.dashboard.request": [
|
||||||
|
"services-firefly-iii.html#services-firefly-iii-options-shb.firefly-iii.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-firefly-iii-options-shb.firefly-iii.dashboard.request.externalUrl": [
|
||||||
|
"services-firefly-iii.html#services-firefly-iii-options-shb.firefly-iii.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-firefly-iii-options-shb.firefly-iii.dashboard.request.internalUrl": [
|
||||||
|
"services-firefly-iii.html#services-firefly-iii-options-shb.firefly-iii.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-firefly-iii-options-shb.firefly-iii.dashboard.result": [
|
||||||
|
"services-firefly-iii.html#services-firefly-iii-options-shb.firefly-iii.dashboard.result"
|
||||||
|
],
|
||||||
"services-firefly-iii-options-shb.firefly-iii.dbPassword": [
|
"services-firefly-iii-options-shb.firefly-iii.dbPassword": [
|
||||||
"services-firefly-iii.html#services-firefly-iii-options-shb.firefly-iii.dbPassword"
|
"services-firefly-iii.html#services-firefly-iii-options-shb.firefly-iii.dbPassword"
|
||||||
],
|
],
|
||||||
|
|
@ -3050,9 +3311,15 @@
|
||||||
"services-firefly-iii-usage": [
|
"services-firefly-iii-usage": [
|
||||||
"services-firefly-iii.html#services-firefly-iii-usage"
|
"services-firefly-iii.html#services-firefly-iii-usage"
|
||||||
],
|
],
|
||||||
|
"services-firefly-iii-usage-applicationdashboard": [
|
||||||
|
"services-firefly-iii.html#services-firefly-iii-usage-applicationdashboard"
|
||||||
|
],
|
||||||
"services-firefly-iii-usage-backup": [
|
"services-firefly-iii-usage-backup": [
|
||||||
"services-firefly-iii.html#services-firefly-iii-usage-backup"
|
"services-firefly-iii.html#services-firefly-iii-usage-backup"
|
||||||
],
|
],
|
||||||
|
"services-firefly-iii-usage-configuration": [
|
||||||
|
"services-firefly-iii.html#services-firefly-iii-usage-configuration"
|
||||||
|
],
|
||||||
"services-forgejo": [
|
"services-forgejo": [
|
||||||
"services-forgejo.html#services-forgejo"
|
"services-forgejo.html#services-forgejo"
|
||||||
],
|
],
|
||||||
|
|
@ -3098,6 +3365,21 @@
|
||||||
"services-forgejo-options-shb.forgejo.backup.result.restoreScript": [
|
"services-forgejo-options-shb.forgejo.backup.result.restoreScript": [
|
||||||
"services-forgejo.html#services-forgejo-options-shb.forgejo.backup.result.restoreScript"
|
"services-forgejo.html#services-forgejo-options-shb.forgejo.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"services-forgejo-options-shb.forgejo.dashboard": [
|
||||||
|
"services-forgejo.html#services-forgejo-options-shb.forgejo.dashboard"
|
||||||
|
],
|
||||||
|
"services-forgejo-options-shb.forgejo.dashboard.request": [
|
||||||
|
"services-forgejo.html#services-forgejo-options-shb.forgejo.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-forgejo-options-shb.forgejo.dashboard.request.externalUrl": [
|
||||||
|
"services-forgejo.html#services-forgejo-options-shb.forgejo.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-forgejo-options-shb.forgejo.dashboard.request.internalUrl": [
|
||||||
|
"services-forgejo.html#services-forgejo-options-shb.forgejo.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-forgejo-options-shb.forgejo.dashboard.result": [
|
||||||
|
"services-forgejo.html#services-forgejo-options-shb.forgejo.dashboard.result"
|
||||||
|
],
|
||||||
"services-forgejo-options-shb.forgejo.databasePassword": [
|
"services-forgejo-options-shb.forgejo.databasePassword": [
|
||||||
"services-forgejo.html#services-forgejo-options-shb.forgejo.databasePassword"
|
"services-forgejo.html#services-forgejo-options-shb.forgejo.databasePassword"
|
||||||
],
|
],
|
||||||
|
|
@ -3359,6 +3641,9 @@
|
||||||
"services-forgejo-usage": [
|
"services-forgejo-usage": [
|
||||||
"services-forgejo.html#services-forgejo-usage"
|
"services-forgejo.html#services-forgejo-usage"
|
||||||
],
|
],
|
||||||
|
"services-forgejo-usage-applicationdashboard": [
|
||||||
|
"services-forgejo.html#services-forgejo-usage-applicationdashboard"
|
||||||
|
],
|
||||||
"services-forgejo-usage-backup": [
|
"services-forgejo-usage-backup": [
|
||||||
"services-forgejo.html#services-forgejo-usage-backup"
|
"services-forgejo.html#services-forgejo-usage-backup"
|
||||||
],
|
],
|
||||||
|
|
@ -3446,6 +3731,21 @@
|
||||||
"services-home-assistant-options-shb.home-assistant.config.unit_system": [
|
"services-home-assistant-options-shb.home-assistant.config.unit_system": [
|
||||||
"services-home-assistant.html#services-home-assistant-options-shb.home-assistant.config.unit_system"
|
"services-home-assistant.html#services-home-assistant-options-shb.home-assistant.config.unit_system"
|
||||||
],
|
],
|
||||||
|
"services-home-assistant-options-shb.home-assistant.dashboard": [
|
||||||
|
"services-home-assistant.html#services-home-assistant-options-shb.home-assistant.dashboard"
|
||||||
|
],
|
||||||
|
"services-home-assistant-options-shb.home-assistant.dashboard.request": [
|
||||||
|
"services-home-assistant.html#services-home-assistant-options-shb.home-assistant.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-home-assistant-options-shb.home-assistant.dashboard.request.externalUrl": [
|
||||||
|
"services-home-assistant.html#services-home-assistant-options-shb.home-assistant.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-home-assistant-options-shb.home-assistant.dashboard.request.internalUrl": [
|
||||||
|
"services-home-assistant.html#services-home-assistant-options-shb.home-assistant.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-home-assistant-options-shb.home-assistant.dashboard.result": [
|
||||||
|
"services-home-assistant.html#services-home-assistant-options-shb.home-assistant.dashboard.result"
|
||||||
|
],
|
||||||
"services-home-assistant-options-shb.home-assistant.domain": [
|
"services-home-assistant-options-shb.home-assistant.domain": [
|
||||||
"services-home-assistant.html#services-home-assistant-options-shb.home-assistant.domain"
|
"services-home-assistant.html#services-home-assistant-options-shb.home-assistant.domain"
|
||||||
],
|
],
|
||||||
|
|
@ -3503,6 +3803,9 @@
|
||||||
"services-home-assistant-usage": [
|
"services-home-assistant-usage": [
|
||||||
"services-home-assistant.html#services-home-assistant-usage"
|
"services-home-assistant.html#services-home-assistant-usage"
|
||||||
],
|
],
|
||||||
|
"services-home-assistant-usage-applicationdashboard": [
|
||||||
|
"services-home-assistant.html#services-home-assistant-usage-applicationdashboard"
|
||||||
|
],
|
||||||
"services-home-assistant-usage-backup": [
|
"services-home-assistant-usage-backup": [
|
||||||
"services-home-assistant.html#services-home-assistant-usage-backup"
|
"services-home-assistant.html#services-home-assistant-usage-backup"
|
||||||
],
|
],
|
||||||
|
|
@ -3539,6 +3842,132 @@
|
||||||
"services-home-assistant-usage-voice": [
|
"services-home-assistant-usage-voice": [
|
||||||
"services-home-assistant.html#services-home-assistant-usage-voice"
|
"services-home-assistant.html#services-home-assistant-usage-voice"
|
||||||
],
|
],
|
||||||
|
"services-homepage": [
|
||||||
|
"services-homepage.html#services-homepage"
|
||||||
|
],
|
||||||
|
"services-homepage-features": [
|
||||||
|
"services-homepage.html#services-homepage-features"
|
||||||
|
],
|
||||||
|
"services-homepage-options": [
|
||||||
|
"services-homepage.html#services-homepage-options"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.domain": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.domain"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.enable": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.enable"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.ldap": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.ldap"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.ldap.userGroup": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.ldap.userGroup"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.name": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.name"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey.request": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey.request"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey.request.group": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey.request.group"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey.request.mode": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey.request.mode"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey.request.owner": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey.request.owner"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey.request.restartUnits": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey.request.restartUnits"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey.result": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey.result"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey.result.path": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.apiKey.result.path"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.dashboard": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.dashboard"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.dashboard.request": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.dashboard.request.externalUrl": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.dashboard.request.internalUrl": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.dashboard.result": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.dashboard.result"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.name": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.name"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.settings": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.settings"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.sortOrder": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.sortOrder"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.servicesGroups._name_.sortOrder": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.servicesGroups._name_.sortOrder"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.ssl": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.ssl"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.ssl.paths": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.ssl.paths"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.ssl.paths.cert": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.ssl.paths.cert"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.ssl.paths.key": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.ssl.paths.key"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.ssl.systemdService": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.ssl.systemdService"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.sso": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.sso"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.sso.authEndpoint": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.sso.authEndpoint"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.sso.authorization_policy": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.sso.authorization_policy"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.sso.enable": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.sso.enable"
|
||||||
|
],
|
||||||
|
"services-homepage-options-shb.homepage.subdomain": [
|
||||||
|
"services-homepage.html#services-homepage-options-shb.homepage.subdomain"
|
||||||
|
],
|
||||||
|
"services-homepage-usage": [
|
||||||
|
"services-homepage.html#services-homepage-usage"
|
||||||
|
],
|
||||||
|
"services-homepage-usage-custom": [
|
||||||
|
"services-homepage.html#services-homepage-usage-custom"
|
||||||
|
],
|
||||||
|
"services-homepage-usage-main": [
|
||||||
|
"services-homepage.html#services-homepage-usage-main"
|
||||||
|
],
|
||||||
|
"services-homepage-usage-service": [
|
||||||
|
"services-homepage.html#services-homepage-usage-service"
|
||||||
|
],
|
||||||
|
"services-homepage-usage-widget": [
|
||||||
|
"services-homepage.html#services-homepage-usage-widget"
|
||||||
|
],
|
||||||
"services-jellyfin": [
|
"services-jellyfin": [
|
||||||
"services-jellyfin.html#services-jellyfin"
|
"services-jellyfin.html#services-jellyfin"
|
||||||
],
|
],
|
||||||
|
|
@ -3623,6 +4052,21 @@
|
||||||
"services-jellyfin-options-shb.jellyfin.backup.result.restoreScript": [
|
"services-jellyfin-options-shb.jellyfin.backup.result.restoreScript": [
|
||||||
"services-jellyfin.html#services-jellyfin-options-shb.jellyfin.backup.result.restoreScript"
|
"services-jellyfin.html#services-jellyfin-options-shb.jellyfin.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"services-jellyfin-options-shb.jellyfin.dashboard": [
|
||||||
|
"services-jellyfin.html#services-jellyfin-options-shb.jellyfin.dashboard"
|
||||||
|
],
|
||||||
|
"services-jellyfin-options-shb.jellyfin.dashboard.request": [
|
||||||
|
"services-jellyfin.html#services-jellyfin-options-shb.jellyfin.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-jellyfin-options-shb.jellyfin.dashboard.request.externalUrl": [
|
||||||
|
"services-jellyfin.html#services-jellyfin-options-shb.jellyfin.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-jellyfin-options-shb.jellyfin.dashboard.request.internalUrl": [
|
||||||
|
"services-jellyfin.html#services-jellyfin-options-shb.jellyfin.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-jellyfin-options-shb.jellyfin.dashboard.result": [
|
||||||
|
"services-jellyfin.html#services-jellyfin-options-shb.jellyfin.dashboard.result"
|
||||||
|
],
|
||||||
"services-jellyfin-options-shb.jellyfin.debug": [
|
"services-jellyfin-options-shb.jellyfin.debug": [
|
||||||
"services-jellyfin.html#services-jellyfin-options-shb.jellyfin.debug"
|
"services-jellyfin.html#services-jellyfin-options-shb.jellyfin.debug"
|
||||||
],
|
],
|
||||||
|
|
@ -3776,9 +4220,15 @@
|
||||||
"services-jellyfin-usage": [
|
"services-jellyfin-usage": [
|
||||||
"services-jellyfin.html#services-jellyfin-usage"
|
"services-jellyfin.html#services-jellyfin-usage"
|
||||||
],
|
],
|
||||||
|
"services-jellyfin-usage-applicationdashboard": [
|
||||||
|
"services-jellyfin.html#services-jellyfin-usage-applicationdashboard"
|
||||||
|
],
|
||||||
"services-jellyfin-usage-backup": [
|
"services-jellyfin-usage-backup": [
|
||||||
"services-jellyfin.html#services-jellyfin-usage-backup"
|
"services-jellyfin.html#services-jellyfin-usage-backup"
|
||||||
],
|
],
|
||||||
|
"services-jellyfin-usage-configuration": [
|
||||||
|
"services-jellyfin.html#services-jellyfin-usage-configuration"
|
||||||
|
],
|
||||||
"services-karakeep": [
|
"services-karakeep": [
|
||||||
"services-karakeep.html#services-karakeep"
|
"services-karakeep.html#services-karakeep"
|
||||||
],
|
],
|
||||||
|
|
@ -3824,6 +4274,21 @@
|
||||||
"services-karakeep-options-shb.karakeep.backup.result.restoreScript": [
|
"services-karakeep-options-shb.karakeep.backup.result.restoreScript": [
|
||||||
"services-karakeep.html#services-karakeep-options-shb.karakeep.backup.result.restoreScript"
|
"services-karakeep.html#services-karakeep-options-shb.karakeep.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"services-karakeep-options-shb.karakeep.dashboard": [
|
||||||
|
"services-karakeep.html#services-karakeep-options-shb.karakeep.dashboard"
|
||||||
|
],
|
||||||
|
"services-karakeep-options-shb.karakeep.dashboard.request": [
|
||||||
|
"services-karakeep.html#services-karakeep-options-shb.karakeep.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-karakeep-options-shb.karakeep.dashboard.request.externalUrl": [
|
||||||
|
"services-karakeep.html#services-karakeep-options-shb.karakeep.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-karakeep-options-shb.karakeep.dashboard.request.internalUrl": [
|
||||||
|
"services-karakeep.html#services-karakeep-options-shb.karakeep.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-karakeep-options-shb.karakeep.dashboard.result": [
|
||||||
|
"services-karakeep.html#services-karakeep-options-shb.karakeep.dashboard.result"
|
||||||
|
],
|
||||||
"services-karakeep-options-shb.karakeep.domain": [
|
"services-karakeep-options-shb.karakeep.domain": [
|
||||||
"services-karakeep.html#services-karakeep-options-shb.karakeep.domain"
|
"services-karakeep.html#services-karakeep-options-shb.karakeep.domain"
|
||||||
],
|
],
|
||||||
|
|
@ -3974,6 +4439,12 @@
|
||||||
"services-karakeep-usage": [
|
"services-karakeep-usage": [
|
||||||
"services-karakeep.html#services-karakeep-usage"
|
"services-karakeep.html#services-karakeep-usage"
|
||||||
],
|
],
|
||||||
|
"services-karakeep-usage-applicationdashboard": [
|
||||||
|
"services-karakeep.html#services-karakeep-usage-applicationdashboard"
|
||||||
|
],
|
||||||
|
"services-karakeep-usage-configuration": [
|
||||||
|
"services-karakeep.html#services-karakeep-usage-configuration"
|
||||||
|
],
|
||||||
"services-mailserver": [
|
"services-mailserver": [
|
||||||
"services-mailserver.html#services-mailserver"
|
"services-mailserver.html#services-mailserver"
|
||||||
],
|
],
|
||||||
|
|
@ -4583,6 +5054,21 @@
|
||||||
"services-nextcloudserver-options-shb.nextcloud.backup.result.restoreScript": [
|
"services-nextcloudserver-options-shb.nextcloud.backup.result.restoreScript": [
|
||||||
"services-nextcloud.html#services-nextcloudserver-options-shb.nextcloud.backup.result.restoreScript"
|
"services-nextcloud.html#services-nextcloudserver-options-shb.nextcloud.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"services-nextcloudserver-options-shb.nextcloud.dashboard": [
|
||||||
|
"services-nextcloud.html#services-nextcloudserver-options-shb.nextcloud.dashboard"
|
||||||
|
],
|
||||||
|
"services-nextcloudserver-options-shb.nextcloud.dashboard.request": [
|
||||||
|
"services-nextcloud.html#services-nextcloudserver-options-shb.nextcloud.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-nextcloudserver-options-shb.nextcloud.dashboard.request.externalUrl": [
|
||||||
|
"services-nextcloud.html#services-nextcloudserver-options-shb.nextcloud.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-nextcloudserver-options-shb.nextcloud.dashboard.request.internalUrl": [
|
||||||
|
"services-nextcloud.html#services-nextcloudserver-options-shb.nextcloud.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-nextcloudserver-options-shb.nextcloud.dashboard.result": [
|
||||||
|
"services-nextcloud.html#services-nextcloudserver-options-shb.nextcloud.dashboard.result"
|
||||||
|
],
|
||||||
"services-nextcloudserver-options-shb.nextcloud.dataDir": [
|
"services-nextcloudserver-options-shb.nextcloud.dataDir": [
|
||||||
"services-nextcloud.html#services-nextcloudserver-options-shb.nextcloud.dataDir"
|
"services-nextcloud.html#services-nextcloudserver-options-shb.nextcloud.dataDir"
|
||||||
],
|
],
|
||||||
|
|
@ -4667,6 +5153,9 @@
|
||||||
"services-nextcloudserver-usage": [
|
"services-nextcloudserver-usage": [
|
||||||
"services-nextcloud.html#services-nextcloudserver-usage"
|
"services-nextcloud.html#services-nextcloudserver-usage"
|
||||||
],
|
],
|
||||||
|
"services-nextcloudserver-usage-applicationdashboard": [
|
||||||
|
"services-nextcloud.html#services-nextcloudserver-usage-applicationdashboard"
|
||||||
|
],
|
||||||
"services-nextcloudserver-usage-backup": [
|
"services-nextcloudserver-usage-backup": [
|
||||||
"services-nextcloud.html#services-nextcloudserver-usage-backup"
|
"services-nextcloud.html#services-nextcloudserver-usage-backup"
|
||||||
],
|
],
|
||||||
|
|
@ -4754,6 +5243,21 @@
|
||||||
"services-open-webui-options-shb.open-webui.backup.result.restoreScript": [
|
"services-open-webui-options-shb.open-webui.backup.result.restoreScript": [
|
||||||
"services-open-webui.html#services-open-webui-options-shb.open-webui.backup.result.restoreScript"
|
"services-open-webui.html#services-open-webui-options-shb.open-webui.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"services-open-webui-options-shb.open-webui.dashboard": [
|
||||||
|
"services-open-webui.html#services-open-webui-options-shb.open-webui.dashboard"
|
||||||
|
],
|
||||||
|
"services-open-webui-options-shb.open-webui.dashboard.request": [
|
||||||
|
"services-open-webui.html#services-open-webui-options-shb.open-webui.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-open-webui-options-shb.open-webui.dashboard.request.externalUrl": [
|
||||||
|
"services-open-webui.html#services-open-webui-options-shb.open-webui.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-open-webui-options-shb.open-webui.dashboard.request.internalUrl": [
|
||||||
|
"services-open-webui.html#services-open-webui-options-shb.open-webui.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-open-webui-options-shb.open-webui.dashboard.result": [
|
||||||
|
"services-open-webui.html#services-open-webui-options-shb.open-webui.dashboard.result"
|
||||||
|
],
|
||||||
"services-open-webui-options-shb.open-webui.domain": [
|
"services-open-webui-options-shb.open-webui.domain": [
|
||||||
"services-open-webui.html#services-open-webui-options-shb.open-webui.domain"
|
"services-open-webui.html#services-open-webui-options-shb.open-webui.domain"
|
||||||
],
|
],
|
||||||
|
|
@ -4859,12 +5363,21 @@
|
||||||
"services-open-webui-usage": [
|
"services-open-webui-usage": [
|
||||||
"services-open-webui.html#services-open-webui-usage"
|
"services-open-webui.html#services-open-webui-usage"
|
||||||
],
|
],
|
||||||
|
"services-open-webui-usage-applicationdashboard": [
|
||||||
|
"services-open-webui.html#services-open-webui-usage-applicationdashboard"
|
||||||
|
],
|
||||||
"services-open-webui-usage-backup": [
|
"services-open-webui-usage-backup": [
|
||||||
"services-open-webui.html#services-open-webui-usage-backup"
|
"services-open-webui.html#services-open-webui-usage-backup"
|
||||||
],
|
],
|
||||||
|
"services-open-webui-usage-configuration": [
|
||||||
|
"services-open-webui.html#services-open-webui-usage-configuration"
|
||||||
|
],
|
||||||
"services-pinchflat": [
|
"services-pinchflat": [
|
||||||
"services-pinchflat.html#services-pinchflat"
|
"services-pinchflat.html#services-pinchflat"
|
||||||
],
|
],
|
||||||
|
"services-pinchflat-features": [
|
||||||
|
"services-pinchflat.html#services-pinchflat-features"
|
||||||
|
],
|
||||||
"services-pinchflat-options": [
|
"services-pinchflat-options": [
|
||||||
"services-pinchflat.html#services-pinchflat-options"
|
"services-pinchflat.html#services-pinchflat-options"
|
||||||
],
|
],
|
||||||
|
|
@ -4901,6 +5414,21 @@
|
||||||
"services-pinchflat-options-shb.pinchflat.backup.result.restoreScript": [
|
"services-pinchflat-options-shb.pinchflat.backup.result.restoreScript": [
|
||||||
"services-pinchflat.html#services-pinchflat-options-shb.pinchflat.backup.result.restoreScript"
|
"services-pinchflat.html#services-pinchflat-options-shb.pinchflat.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"services-pinchflat-options-shb.pinchflat.dashboard": [
|
||||||
|
"services-pinchflat.html#services-pinchflat-options-shb.pinchflat.dashboard"
|
||||||
|
],
|
||||||
|
"services-pinchflat-options-shb.pinchflat.dashboard.request": [
|
||||||
|
"services-pinchflat.html#services-pinchflat-options-shb.pinchflat.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-pinchflat-options-shb.pinchflat.dashboard.request.externalUrl": [
|
||||||
|
"services-pinchflat.html#services-pinchflat-options-shb.pinchflat.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-pinchflat-options-shb.pinchflat.dashboard.request.internalUrl": [
|
||||||
|
"services-pinchflat.html#services-pinchflat-options-shb.pinchflat.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-pinchflat-options-shb.pinchflat.dashboard.result": [
|
||||||
|
"services-pinchflat.html#services-pinchflat-options-shb.pinchflat.dashboard.result"
|
||||||
|
],
|
||||||
"services-pinchflat-options-shb.pinchflat.domain": [
|
"services-pinchflat-options-shb.pinchflat.domain": [
|
||||||
"services-pinchflat.html#services-pinchflat-options-shb.pinchflat.domain"
|
"services-pinchflat.html#services-pinchflat-options-shb.pinchflat.domain"
|
||||||
],
|
],
|
||||||
|
|
@ -4982,9 +5510,15 @@
|
||||||
"services-pinchflat-usage": [
|
"services-pinchflat-usage": [
|
||||||
"services-pinchflat.html#services-pinchflat-usage"
|
"services-pinchflat.html#services-pinchflat-usage"
|
||||||
],
|
],
|
||||||
|
"services-pinchflat-usage-applicationdashboard": [
|
||||||
|
"services-pinchflat.html#services-pinchflat-usage-applicationdashboard"
|
||||||
|
],
|
||||||
"services-pinchflat-usage-backup": [
|
"services-pinchflat-usage-backup": [
|
||||||
"services-pinchflat.html#services-pinchflat-usage-backup"
|
"services-pinchflat.html#services-pinchflat-usage-backup"
|
||||||
],
|
],
|
||||||
|
"services-pinchflat-usage-configuration": [
|
||||||
|
"services-pinchflat.html#services-pinchflat-usage-configuration"
|
||||||
|
],
|
||||||
"services-vaultwarden": [
|
"services-vaultwarden": [
|
||||||
"services-vaultwarden.html#services-vaultwarden"
|
"services-vaultwarden.html#services-vaultwarden"
|
||||||
],
|
],
|
||||||
|
|
@ -5039,6 +5573,21 @@
|
||||||
"services-vaultwarden-options-shb.vaultwarden.backup.result.restoreScript": [
|
"services-vaultwarden-options-shb.vaultwarden.backup.result.restoreScript": [
|
||||||
"services-vaultwarden.html#services-vaultwarden-options-shb.vaultwarden.backup.result.restoreScript"
|
"services-vaultwarden.html#services-vaultwarden-options-shb.vaultwarden.backup.result.restoreScript"
|
||||||
],
|
],
|
||||||
|
"services-vaultwarden-options-shb.vaultwarden.dashboard": [
|
||||||
|
"services-vaultwarden.html#services-vaultwarden-options-shb.vaultwarden.dashboard"
|
||||||
|
],
|
||||||
|
"services-vaultwarden-options-shb.vaultwarden.dashboard.request": [
|
||||||
|
"services-vaultwarden.html#services-vaultwarden-options-shb.vaultwarden.dashboard.request"
|
||||||
|
],
|
||||||
|
"services-vaultwarden-options-shb.vaultwarden.dashboard.request.externalUrl": [
|
||||||
|
"services-vaultwarden.html#services-vaultwarden-options-shb.vaultwarden.dashboard.request.externalUrl"
|
||||||
|
],
|
||||||
|
"services-vaultwarden-options-shb.vaultwarden.dashboard.request.internalUrl": [
|
||||||
|
"services-vaultwarden.html#services-vaultwarden-options-shb.vaultwarden.dashboard.request.internalUrl"
|
||||||
|
],
|
||||||
|
"services-vaultwarden-options-shb.vaultwarden.dashboard.result": [
|
||||||
|
"services-vaultwarden.html#services-vaultwarden-options-shb.vaultwarden.dashboard.result"
|
||||||
|
],
|
||||||
"services-vaultwarden-options-shb.vaultwarden.databasePassword": [
|
"services-vaultwarden-options-shb.vaultwarden.databasePassword": [
|
||||||
"services-vaultwarden.html#services-vaultwarden-options-shb.vaultwarden.databasePassword"
|
"services-vaultwarden.html#services-vaultwarden-options-shb.vaultwarden.databasePassword"
|
||||||
],
|
],
|
||||||
|
|
@ -5150,6 +5699,9 @@
|
||||||
"services-vaultwarden-usage": [
|
"services-vaultwarden-usage": [
|
||||||
"services-vaultwarden.html#services-vaultwarden-usage"
|
"services-vaultwarden.html#services-vaultwarden-usage"
|
||||||
],
|
],
|
||||||
|
"services-vaultwarden-usage-applicationdashboard": [
|
||||||
|
"services-vaultwarden.html#services-vaultwarden-usage-applicationdashboard"
|
||||||
|
],
|
||||||
"services-vaultwarden-usage-configuration": [
|
"services-vaultwarden-usage-configuration": [
|
||||||
"services-vaultwarden.html#services-vaultwarden-usage-configuration"
|
"services-vaultwarden.html#services-vaultwarden-usage-configuration"
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
<!-- Read these docs at https://shb.skarabox.com -->
|
<!-- Read these docs at https://shb.skarabox.com -->
|
||||||
# Services {#services}
|
# Services {#services}
|
||||||
|
|
||||||
Services are usually web applications that SHB help you self-host.
|
Services are usually web applications that SHB help you self-host some of your data.
|
||||||
Configuration of those is purposely made more opinionated than the upstream nixpkgs modules
|
Configuration of those is purposely made more opinionated than the upstream nixpkgs modules
|
||||||
in exchange for requiring less options to define.
|
in exchange for an uniformized configuration experience.
|
||||||
That is possible thanks to the extensive use of blocks provided by SHB.
|
That is possible thanks to the extensive use of blocks provided by SHB.
|
||||||
|
|
||||||
::: {.note}
|
::: {.note}
|
||||||
|
|
@ -19,6 +19,7 @@ information is provided in the respective manual sections.
|
||||||
| [Firefly-iii][] | Y (1) | Y | Y | Y | Y (2) | N |
|
| [Firefly-iii][] | Y (1) | Y | Y | Y | Y (2) | N |
|
||||||
| [Forgejo][] | Y (1) | Y | Y | Y | Y (2) | N |
|
| [Forgejo][] | Y (1) | Y | Y | Y | Y (2) | N |
|
||||||
| [Home-Assistant][] | Y (1) | Y | N | Y | Y (2) | N |
|
| [Home-Assistant][] | Y (1) | Y | N | Y | Y (2) | N |
|
||||||
|
| [Homepage][] | Y (1) | Y | N | Y | Y (2) | N |
|
||||||
| [Jellyfin][] | Y (1) | Y | Y | Y | Y (2) | N |
|
| [Jellyfin][] | Y (1) | Y | Y | Y | Y (2) | N |
|
||||||
| [Karakeep][] | Y (1) | Y | Y | Y | Y (2) | N |
|
| [Karakeep][] | Y (1) | Y | Y | Y | Y (2) | N |
|
||||||
| [Nextcloud Server][] | Y (1) | Y | Y | Y | Y (2) | P (3) |
|
| [Nextcloud Server][] | Y (1) | Y | Y | Y | Y (2) | P (3) |
|
||||||
|
|
@ -40,6 +41,7 @@ Legend: **N**: no but WIP; **P**: partial; **Y**: yes
|
||||||
[Firefly-iii]: services-firefly-iii.html
|
[Firefly-iii]: services-firefly-iii.html
|
||||||
[Forgejo]: services-forgejo.html
|
[Forgejo]: services-forgejo.html
|
||||||
[Home-Assistant]: services-home-assistant.html
|
[Home-Assistant]: services-home-assistant.html
|
||||||
|
[Homepage]: services-homepage.html
|
||||||
[Jellyfin]: services-jellyfin.html
|
[Jellyfin]: services-jellyfin.html
|
||||||
[Karakeep]: services-karakeep.html
|
[Karakeep]: services-karakeep.html
|
||||||
[Nextcloud Server]: services-nextcloud.html
|
[Nextcloud Server]: services-nextcloud.html
|
||||||
|
|
@ -48,6 +50,12 @@ Legend: **N**: no but WIP; **P**: partial; **Y**: yes
|
||||||
[Simple NixOS Mailserver]: services-mailserver.html
|
[Simple NixOS Mailserver]: services-mailserver.html
|
||||||
[Vaultwarden]: services-vaultwarden.html
|
[Vaultwarden]: services-vaultwarden.html
|
||||||
|
|
||||||
|
## Dashboard {#services-category-dashboard}
|
||||||
|
|
||||||
|
```{=include=} chapters html:into-file=//services-homepage.html
|
||||||
|
modules/services/homepage/docs/default.md
|
||||||
|
```
|
||||||
|
|
||||||
## Documents {#services-category-documents}
|
## Documents {#services-category-documents}
|
||||||
|
|
||||||
```{=include=} chapters html:into-file=//services-nextcloud.html
|
```{=include=} chapters html:into-file=//services-nextcloud.html
|
||||||
|
|
|
||||||
15
flake.nix
15
flake.nix
|
|
@ -66,6 +66,9 @@
|
||||||
# The contract dummies are used to show options for contracts.
|
# The contract dummies are used to show options for contracts.
|
||||||
contractDummyModules = [
|
contractDummyModules = [
|
||||||
modules/contracts/backup/dummyModule.nix
|
modules/contracts/backup/dummyModule.nix
|
||||||
|
modules/contracts/dashboard/dummyModule.nix
|
||||||
|
modules/contracts/databasebackup/dummyModule.nix
|
||||||
|
modules/contracts/secret/dummyModule.nix
|
||||||
modules/contracts/ssl/dummyModule.nix
|
modules/contracts/ssl/dummyModule.nix
|
||||||
];
|
];
|
||||||
in
|
in
|
||||||
|
|
@ -110,6 +113,7 @@
|
||||||
(pkgs.path + "/nixos/modules/services/misc/forgejo.nix")
|
(pkgs.path + "/nixos/modules/services/misc/forgejo.nix")
|
||||||
];
|
];
|
||||||
"services/home-assistant" = ./modules/services/home-assistant.nix;
|
"services/home-assistant" = ./modules/services/home-assistant.nix;
|
||||||
|
"services/homepage" = ./modules/services/homepage.nix;
|
||||||
"services/jellyfin" = ./modules/services/jellyfin.nix;
|
"services/jellyfin" = ./modules/services/jellyfin.nix;
|
||||||
"services/karakeep" = ./modules/services/karakeep.nix;
|
"services/karakeep" = ./modules/services/karakeep.nix;
|
||||||
"services/mailserver" = ./modules/services/mailserver.nix;
|
"services/mailserver" = ./modules/services/mailserver.nix;
|
||||||
|
|
@ -131,6 +135,14 @@
|
||||||
"backup"
|
"backup"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
"contracts/dashboard" = {
|
||||||
|
module = ./modules/contracts/dashboard/dummyModule.nix;
|
||||||
|
optionRoot = [
|
||||||
|
"shb"
|
||||||
|
"contracts"
|
||||||
|
"dashboard"
|
||||||
|
];
|
||||||
|
};
|
||||||
"contracts/databasebackup" = {
|
"contracts/databasebackup" = {
|
||||||
module = ./modules/contracts/databasebackup/dummyModule.nix;
|
module = ./modules/contracts/databasebackup/dummyModule.nix;
|
||||||
optionRoot = [
|
optionRoot = [
|
||||||
|
|
@ -298,6 +310,7 @@
|
||||||
// (vm_test "hledger" ./test/services/hledger.nix)
|
// (vm_test "hledger" ./test/services/hledger.nix)
|
||||||
// (vm_test "immich" ./test/services/immich.nix)
|
// (vm_test "immich" ./test/services/immich.nix)
|
||||||
// (vm_test "homeassistant" ./test/services/home-assistant.nix)
|
// (vm_test "homeassistant" ./test/services/home-assistant.nix)
|
||||||
|
// (vm_test "homepage" ./test/services/homepage.nix)
|
||||||
// (vm_test "jellyfin" ./test/services/jellyfin.nix)
|
// (vm_test "jellyfin" ./test/services/jellyfin.nix)
|
||||||
// (vm_test "karakeep" ./test/services/karakeep.nix)
|
// (vm_test "karakeep" ./test/services/karakeep.nix)
|
||||||
// (vm_test "nextcloud" ./test/services/nextcloud.nix)
|
// (vm_test "nextcloud" ./test/services/nextcloud.nix)
|
||||||
|
|
@ -407,6 +420,7 @@
|
||||||
self.nixosModules.hledger
|
self.nixosModules.hledger
|
||||||
self.nixosModules.immich
|
self.nixosModules.immich
|
||||||
self.nixosModules.home-assistant
|
self.nixosModules.home-assistant
|
||||||
|
self.nixosModules.homepage
|
||||||
self.nixosModules.jellyfin
|
self.nixosModules.jellyfin
|
||||||
self.nixosModules.karakeep
|
self.nixosModules.karakeep
|
||||||
self.nixosModules.mailserver
|
self.nixosModules.mailserver
|
||||||
|
|
@ -445,6 +459,7 @@
|
||||||
nixosModules.hledger = modules/services/hledger.nix;
|
nixosModules.hledger = modules/services/hledger.nix;
|
||||||
nixosModules.immich = modules/services/immich.nix;
|
nixosModules.immich = modules/services/immich.nix;
|
||||||
nixosModules.home-assistant = modules/services/home-assistant.nix;
|
nixosModules.home-assistant = modules/services/home-assistant.nix;
|
||||||
|
nixosModules.homepage = modules/services/homepage.nix;
|
||||||
nixosModules.jellyfin = modules/services/jellyfin.nix;
|
nixosModules.jellyfin = modules/services/jellyfin.nix;
|
||||||
nixosModules.karakeep = modules/services/karakeep.nix;
|
nixosModules.karakeep = modules/services/karakeep.nix;
|
||||||
nixosModules.mailserver = modules/services/mailserver.nix;
|
nixosModules.mailserver = modules/services/mailserver.nix;
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@
|
||||||
let
|
let
|
||||||
inherit (builtins) isAttrs hasAttr;
|
inherit (builtins) isAttrs hasAttr;
|
||||||
inherit (lib) any concatMapStringsSep concatStringsSep;
|
inherit (lib) any concatMapStringsSep concatStringsSep;
|
||||||
in
|
shb = rec {
|
||||||
rec {
|
|
||||||
# Replace secrets in a file.
|
# Replace secrets in a file.
|
||||||
# - userConfig is an attrset that will produce a config file.
|
# - userConfig is an attrset that will produce a config file.
|
||||||
# - resultPath is the location the config file should have on the filesystem.
|
# - resultPath is the location the config file should have on the filesystem.
|
||||||
|
|
@ -409,4 +408,14 @@ rec {
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
) { };
|
) { };
|
||||||
|
|
||||||
|
update =
|
||||||
|
attr: fn: attrset:
|
||||||
|
attrset // { ${attr} = fn attrset.${attr}; };
|
||||||
|
|
||||||
|
};
|
||||||
|
in
|
||||||
|
shb
|
||||||
|
// {
|
||||||
|
homepage = pkgs.callPackage ./homepage.nix { inherit shb; };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
92
lib/homepage.nix
Normal file
92
lib/homepage.nix
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
{ lib, shb }:
|
||||||
|
let
|
||||||
|
sort =
|
||||||
|
attr: vs:
|
||||||
|
map (v: { ${v.name} = v.${attr}; }) (
|
||||||
|
lib.sortOn (v: v.sortOrder) (lib.mapAttrsToList (n: v: v // { name = n; }) vs)
|
||||||
|
);
|
||||||
|
|
||||||
|
slufigy = builtins.replaceStrings [ "-" ] [ "_" ];
|
||||||
|
|
||||||
|
mkService =
|
||||||
|
groupName: serviceName:
|
||||||
|
{
|
||||||
|
request,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
apiKey: settings:
|
||||||
|
lib.recursiveUpdate (
|
||||||
|
{
|
||||||
|
href = request.externalUrl;
|
||||||
|
siteMonitor = if (request.internalUrl == null) then null else request.internalUrl;
|
||||||
|
icon = "sh-${lib.toLower serviceName}";
|
||||||
|
}
|
||||||
|
// lib.optionalAttrs (apiKey != null) {
|
||||||
|
widget = {
|
||||||
|
# Duplicating because widgets call the api key various names
|
||||||
|
# and duplicating is a hacky but easy solution.
|
||||||
|
key = "{{HOMEPAGE_FILE_${slufigy groupName}_${slufigy serviceName}}}";
|
||||||
|
password = "{{HOMEPAGE_FILE_${slufigy groupName}_${slufigy serviceName}}}";
|
||||||
|
type = lib.toLower serviceName;
|
||||||
|
url = if (request.internalUrl != null) then request.internalUrl else request.externalUrl;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
) settings;
|
||||||
|
|
||||||
|
asServiceGroup =
|
||||||
|
cfg:
|
||||||
|
sort "services" (
|
||||||
|
lib.mapAttrs (
|
||||||
|
groupName: groupCfg:
|
||||||
|
shb.update "services" (
|
||||||
|
services:
|
||||||
|
sort "dashboard" (
|
||||||
|
lib.mapAttrs (
|
||||||
|
serviceName: serviceCfg:
|
||||||
|
shb.update "dashboard" (
|
||||||
|
dashboard:
|
||||||
|
(mkService groupName serviceName) dashboard serviceCfg.apiKey (serviceCfg.settings or { })
|
||||||
|
) serviceCfg
|
||||||
|
) services
|
||||||
|
)
|
||||||
|
) groupCfg
|
||||||
|
) cfg
|
||||||
|
);
|
||||||
|
|
||||||
|
allKeys =
|
||||||
|
cfg:
|
||||||
|
let
|
||||||
|
flat = lib.flatten (
|
||||||
|
lib.mapAttrsToList (
|
||||||
|
groupName: groupCfg:
|
||||||
|
lib.mapAttrsToList (
|
||||||
|
serviceName: serviceCfg:
|
||||||
|
lib.optionalAttrs (serviceCfg.apiKey != null) {
|
||||||
|
inherit serviceName groupName;
|
||||||
|
inherit (serviceCfg.apiKey.result) path;
|
||||||
|
}
|
||||||
|
) groupCfg.services
|
||||||
|
) cfg
|
||||||
|
);
|
||||||
|
|
||||||
|
flatWithApiKey = builtins.filter (v: v != { }) flat;
|
||||||
|
in
|
||||||
|
builtins.listToAttrs (
|
||||||
|
map (
|
||||||
|
{
|
||||||
|
groupName,
|
||||||
|
serviceName,
|
||||||
|
path,
|
||||||
|
}:
|
||||||
|
lib.nameValuePair "${slufigy groupName}_${slufigy serviceName}" path
|
||||||
|
) flatWithApiKey
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit
|
||||||
|
allKeys
|
||||||
|
asServiceGroup
|
||||||
|
mkService
|
||||||
|
sort
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
@ -390,6 +390,20 @@ in
|
||||||
to see exactly what Authelia receives and sends back.
|
to see exactly what Authelia receives and sends back.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.authelia.subdomain}.\${config.shb.authelia.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString listenPort}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,13 @@ as well as some extensive [troubleshooting](#blocks-authelia-troubleshooting) fe
|
||||||
|
|
||||||
Note that forward authentication is configured with the [nginx block](blocks-nginx.html#blocks-nginx-usage-shbforwardauth).
|
Note that forward authentication is configured with the [nginx block](blocks-nginx.html#blocks-nginx-usage-shbforwardauth).
|
||||||
|
|
||||||
## Global Setup {#blocks-authelia-global-setup}
|
## Features {#services-authelia-features}
|
||||||
|
|
||||||
|
- Integration with the [dashboard contract](contracts-dashboard.html) for displaying user facing application in a dashboard. [Manual](#services-authelia-usage-applicationdashboard)
|
||||||
|
|
||||||
|
## Usage {#services-authelia-usage}
|
||||||
|
|
||||||
|
### Initial Configuration {#blocks-authelia-usage-configuration}
|
||||||
|
|
||||||
Authelia cannot work without SSL and LDAP.
|
Authelia cannot work without SSL and LDAP.
|
||||||
So setting up the Authelia block requires to setup the [SSL block][] first
|
So setting up the Authelia block requires to setup the [SSL block][] first
|
||||||
|
|
@ -80,6 +86,22 @@ Crucially, the `shb.authelia.secrets.ldapAdminPasswordFile` must be the same
|
||||||
as the `shb.lldap.ldapUserPassword` defined for the [LLDAP block][].
|
as the `shb.lldap.ldapUserPassword` defined for the [LLDAP block][].
|
||||||
This is done using Sops' `key` option.
|
This is done using Sops' `key` option.
|
||||||
|
|
||||||
|
### Application Dashboard {#services-authelia-usage-applicationdashboard}
|
||||||
|
|
||||||
|
Integration with the [dashboard contract](contracts-dashboard.html) is provided
|
||||||
|
by the [dashboard option](#blocks-authelia-options-shb.authelia.dashboard).
|
||||||
|
|
||||||
|
For example using the [Homepage](services-homepage.html) service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Admin.services.Authelia = {
|
||||||
|
sortOrder = 2;
|
||||||
|
dashboard.request = config.shb.authelia.dashboard.request;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## SHB OIDC integration {#blocks-authelia-shb-oidc}
|
## SHB OIDC integration {#blocks-authelia-shb-oidc}
|
||||||
|
|
||||||
For services [provided by SelfHostBlocks][services] that handle [OIDC integration][OIDC],
|
For services [provided by SelfHostBlocks][services] that handle [OIDC integration][OIDC],
|
||||||
|
|
|
||||||
|
|
@ -333,6 +333,20 @@ in
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.lldap.subdomain}.\${config.shb.lldap.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString cfg.webUIListenPort}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,13 @@ across services.
|
||||||
|
|
||||||
[LLDAP]: https://github.com/lldap/lldap
|
[LLDAP]: https://github.com/lldap/lldap
|
||||||
|
|
||||||
## Global Setup {#blocks-lldap-global-setup}
|
## Features {#blocks-lldap-features}
|
||||||
|
|
||||||
|
- Integration with the [dashboard contract](contracts-dashboard.html) for displaying user facing application in a dashboard. [Manual](#blocks-lldap-usage-applicationdashboard)
|
||||||
|
|
||||||
|
## Usage {#blocks-lldap-usage}
|
||||||
|
|
||||||
|
### Initial Configuration {#blocks-lldap-usage-configuration}
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
shb.lldap = {
|
shb.lldap = {
|
||||||
|
|
@ -29,7 +35,7 @@ shb.sops.secret."lldap/user_password".request = config.shb.lldap.ldapUserPasswor
|
||||||
This assumes secrets are setup with SOPS
|
This assumes secrets are setup with SOPS
|
||||||
as mentioned in [the secrets setup section](usage.html#usage-secrets) of the manual.
|
as mentioned in [the secrets setup section](usage.html#usage-secrets) of the manual.
|
||||||
|
|
||||||
## SSL {#blocks-lldap-ssl}
|
### SSL {#blocks-lldap-usage-ssl}
|
||||||
|
|
||||||
Using SSL is an important security practice, like always.
|
Using SSL is an important security practice, like always.
|
||||||
Using the [SSL block][], the configuration to add to the one above is:
|
Using the [SSL block][], the configuration to add to the one above is:
|
||||||
|
|
@ -44,7 +50,7 @@ shb.certs.certs.letsencrypt.${domain}.extraDomains = [
|
||||||
shb.lldap.ssl = config.shb.certs.certs.letsencrypt.${config.shb.lldap.domain};
|
shb.lldap.ssl = config.shb.certs.certs.letsencrypt.${config.shb.lldap.domain};
|
||||||
```
|
```
|
||||||
|
|
||||||
## Restrict Access By IP {#blocks-lldap-restrict-access-by-ip}
|
### Restrict Access By IP {#blocks-lldap-usage-restrict-access-by-ip}
|
||||||
|
|
||||||
For added security, you can restrict access to the LLDAP UI
|
For added security, you can restrict access to the LLDAP UI
|
||||||
by adding the following line:
|
by adding the following line:
|
||||||
|
|
@ -53,6 +59,22 @@ by adding the following line:
|
||||||
shb.lldap.restrictAccessIPRange = "192.168.50.0/24";
|
shb.lldap.restrictAccessIPRange = "192.168.50.0/24";
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Application Dashboard {#blocks-lldap-usage-applicationdashboard}
|
||||||
|
|
||||||
|
Integration with the [dashboard contract](contracts-dashboard.html) is provided
|
||||||
|
by the [dashboard option](#blocks-lldap-options-shb.lldap.dashboard).
|
||||||
|
|
||||||
|
For example using the [Homepage](services-homepage.html) service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Admin.services.LLDAP = {
|
||||||
|
sortOrder = 2;
|
||||||
|
dashboard.request = config.shb.lldap.dashboard.request;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Manage Groups {#blocks-lldap-manage-groups}
|
## Manage Groups {#blocks-lldap-manage-groups}
|
||||||
|
|
||||||
The following snippet will create group named "family" if it does not exist yet.
|
The following snippet will create group named "family" if it does not exist yet.
|
||||||
|
|
|
||||||
|
|
@ -247,6 +247,21 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.monitoring.subdomain}.\${config.shb.monitoring.domain}";
|
||||||
|
internalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
internalUrlText = "https://\${config.shb.monitoring.subdomain}.\${config.shb.monitoring.domain}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,12 @@ This block sets up the monitoring stack for Self Host Blocks. It is composed of:
|
||||||
- Registration is enabled through SSO.
|
- Registration is enabled through SSO.
|
||||||
- Access through [subdomain](#blocks-monitoring-options-shb.monitoring.subdomain) using reverse proxy.
|
- Access through [subdomain](#blocks-monitoring-options-shb.monitoring.subdomain) using reverse proxy.
|
||||||
- Access through [HTTPS](#blocks-monitoring-options-shb.monitoring.ssl) using reverse proxy.
|
- Access through [HTTPS](#blocks-monitoring-options-shb.monitoring.ssl) using reverse proxy.
|
||||||
|
- Integration with the [dashboard contract](contracts-dashboard.html) for displaying user facing application in a dashboard. [Manual](#blocks-monitoring-usage-applicationdashboard)
|
||||||
|
|
||||||
## Usage {#blocks-monitoring-usage}
|
## Usage {#blocks-monitoring-usage}
|
||||||
|
|
||||||
|
### Initial Configuration {#blocks-monitoring-usage-configuration}
|
||||||
|
|
||||||
The following snippet assumes a few blocks have been setup already:
|
The following snippet assumes a few blocks have been setup already:
|
||||||
|
|
||||||
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
||||||
|
|
@ -110,6 +113,22 @@ You might for example want to update the metrics retention time with:
|
||||||
services.prometheus.retentionTime = "60d";
|
services.prometheus.retentionTime = "60d";
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Application Dashboard {#blocks-monitoring-usage-applicationdashboard}
|
||||||
|
|
||||||
|
Integration with the [dashboard contract](contracts-dashboard.html) is provided
|
||||||
|
by the [dashboard option](#blocks-monitoring-options-shb.monitoring.dashboard).
|
||||||
|
|
||||||
|
For example using the [Homepage](services-homepage.html) service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Admin.services.Grafana = {
|
||||||
|
sortOrder = 10;
|
||||||
|
dashboard.request = config.shb.monitoring.dashboard.request;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Provisioning {#blocks-monitoring-provisioning}
|
## Provisioning {#blocks-monitoring-provisioning}
|
||||||
|
|
||||||
Self Host Blocks will create automatically the following resources:
|
Self Host Blocks will create automatically the following resources:
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,9 @@ Here is an example module defining such a `backup` option:
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
myservice.backup = mkOption {
|
myservice.backup = mkOption {
|
||||||
type = contracts.backup.request;
|
type = lib.types.submodule {
|
||||||
|
options = contracts.backup.request;
|
||||||
|
};
|
||||||
default = {
|
default = {
|
||||||
user = "myservice";
|
user = "myservice";
|
||||||
sourceDirectories = [
|
sourceDirectories = [
|
||||||
|
|
|
||||||
77
modules/contracts/dashboard.nix
Normal file
77
modules/contracts/dashboard.nix
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
{ lib, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib) mkOption;
|
||||||
|
inherit (lib.types)
|
||||||
|
nullOr
|
||||||
|
submodule
|
||||||
|
str
|
||||||
|
;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
mkRequest =
|
||||||
|
{
|
||||||
|
serviceName ? "",
|
||||||
|
externalUrl ? "",
|
||||||
|
externalUrlText ? null,
|
||||||
|
internalUrl ? null,
|
||||||
|
internalUrlText ? null,
|
||||||
|
apiKey ? null,
|
||||||
|
}:
|
||||||
|
mkOption {
|
||||||
|
description = ''
|
||||||
|
Request part of the dashboard contract.
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = submodule {
|
||||||
|
options = {
|
||||||
|
externalUrl =
|
||||||
|
mkOption {
|
||||||
|
description = ''
|
||||||
|
URL at which the service can be accessed.
|
||||||
|
|
||||||
|
This URL should go through the reverse proxy.
|
||||||
|
'';
|
||||||
|
type = str;
|
||||||
|
default = externalUrl;
|
||||||
|
example = "https://jellyfin.example.com";
|
||||||
|
}
|
||||||
|
// (lib.optionalAttrs (externalUrlText != null) {
|
||||||
|
defaultText = externalUrlText;
|
||||||
|
});
|
||||||
|
|
||||||
|
internalUrl =
|
||||||
|
mkOption {
|
||||||
|
description = ''
|
||||||
|
URL at which the service can be accessed directly.
|
||||||
|
|
||||||
|
This URL should bypass the reverse proxy.
|
||||||
|
It can be used for example to ping the service
|
||||||
|
and making sure it is up and running correctly.
|
||||||
|
'';
|
||||||
|
type = nullOr str;
|
||||||
|
default = internalUrl;
|
||||||
|
example = "http://127.0.0.1:8081";
|
||||||
|
}
|
||||||
|
// (lib.optionalAttrs (internalUrlText != null) {
|
||||||
|
defaultText = internalUrlText;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
mkResult =
|
||||||
|
{
|
||||||
|
}:
|
||||||
|
mkOption {
|
||||||
|
description = ''
|
||||||
|
Result part of the dashboard contract.
|
||||||
|
|
||||||
|
No option is provided here.
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = submodule {
|
||||||
|
options = {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
65
modules/contracts/dashboard/docs/default.md
Normal file
65
modules/contracts/dashboard/docs/default.md
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
# Dashboard Contract {#contract-dashboard}
|
||||||
|
|
||||||
|
This NixOS contract is used for user-facing services
|
||||||
|
that want to be displayed on a dashboard.
|
||||||
|
|
||||||
|
It is a contract between a service that can be accessed through an URL
|
||||||
|
and a service that wants to show a list of those services.
|
||||||
|
|
||||||
|
## Providers {#contract-dashboard-providers}
|
||||||
|
|
||||||
|
The providers of this contract in SHB are:
|
||||||
|
|
||||||
|
<!-- Somehow generate this list -->
|
||||||
|
|
||||||
|
- The homepage service under its [shb.homepage.servicesGroups.<name>.services.<name>.dashboard](#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.dashboard) option.
|
||||||
|
|
||||||
|
## Usage {#contracts-dashboard-usage}
|
||||||
|
|
||||||
|
A service that can be shown on a dashboard will provide a `dashboard` option.
|
||||||
|
|
||||||
|
Here is an example module defining such a requester option for this dashboard contract:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
myservice.dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${config.myservice.subdomain}.${config.myservice.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${config.myservice.port}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, plug both consumer and provider together in the `config`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
config = {
|
||||||
|
<provider-module> = {
|
||||||
|
dashboard.request = config.myservice.dashboard.request;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And that's it for the contract part.
|
||||||
|
For more specific details on each provider, go to their respective manual pages.
|
||||||
|
|
||||||
|
## Contract Reference {#contract-dashboard-options}
|
||||||
|
|
||||||
|
These are all the options that are expected to exist for this contract to be respected.
|
||||||
|
|
||||||
|
```{=include=} options
|
||||||
|
id-prefix: contracts-dashboard-options-
|
||||||
|
list-id: selfhostblocks-options
|
||||||
|
source: @OPTIONS_JSON@
|
||||||
|
```
|
||||||
30
modules/contracts/dashboard/dummyModule.nix
Normal file
30
modules/contracts/dashboard/dummyModule.nix
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
{ lib, shb, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib) mkOption;
|
||||||
|
inherit (lib.types) submodule;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
../../../lib/module.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
options.shb.contracts.dashboard = mkOption {
|
||||||
|
description = ''
|
||||||
|
Contract for user-facing services that want to
|
||||||
|
be displayed on a dashboard.
|
||||||
|
|
||||||
|
The requester communicates to the provider
|
||||||
|
how to access the service
|
||||||
|
through the `request` options.
|
||||||
|
|
||||||
|
The provider reads from the `request` options
|
||||||
|
and configures what is necessary on its side
|
||||||
|
to show the service and check its availability.
|
||||||
|
It does not communicate back to the requester.
|
||||||
|
'';
|
||||||
|
|
||||||
|
type = submodule {
|
||||||
|
options = shb.contracts.dashboard.contract;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -48,14 +48,19 @@ let
|
||||||
importContract =
|
importContract =
|
||||||
module:
|
module:
|
||||||
let
|
let
|
||||||
importedModule = pkgs.callPackage module { inherit shb; };
|
importedModule = pkgs.callPackage module {
|
||||||
|
shb = shb // {
|
||||||
|
inherit contracts;
|
||||||
|
};
|
||||||
|
};
|
||||||
in
|
in
|
||||||
mkContractFunctions {
|
mkContractFunctions {
|
||||||
inherit (importedModule) mkRequest mkResult;
|
inherit (importedModule) mkRequest mkResult;
|
||||||
};
|
};
|
||||||
in
|
|
||||||
{
|
contracts = {
|
||||||
databasebackup = importContract ./databasebackup.nix;
|
databasebackup = importContract ./databasebackup.nix;
|
||||||
|
dashboard = importContract ./dashboard.nix;
|
||||||
backup = importContract ./backup.nix;
|
backup = importContract ./backup.nix;
|
||||||
mount = pkgs.callPackage ./mount.nix { };
|
mount = pkgs.callPackage ./mount.nix { };
|
||||||
secret = importContract ./secret.nix;
|
secret = importContract ./secret.nix;
|
||||||
|
|
@ -65,4 +70,6 @@ in
|
||||||
databasebackup = pkgs.callPackage ./databasebackup/test.nix { inherit shb; };
|
databasebackup = pkgs.callPackage ./databasebackup/test.nix { inherit shb; };
|
||||||
backup = pkgs.callPackage ./backup/test.nix { inherit shb; };
|
backup = pkgs.callPackage ./backup/test.nix { inherit shb; };
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
in
|
||||||
|
contracts
|
||||||
|
|
|
||||||
|
|
@ -392,6 +392,20 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.${name}.subdomain}.${cfg.${name}.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.arr.${name}.subdomain}.\${config.shb.arr.${name}.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString cfg.${name}.settings.Port}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
// (c.moreOptions or { });
|
// (c.moreOptions or { });
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,242 @@
|
||||||
Defined in [`/modules/services/arr.nix`](@REPO@/modules/services/arr.nix).
|
Defined in [`/modules/services/arr.nix`](@REPO@/modules/services/arr.nix).
|
||||||
|
|
||||||
This NixOS module sets up multiple [Servarr](https://wiki.servarr.com/) services.
|
This NixOS module sets up multiple [Servarr](https://wiki.servarr.com/) services.
|
||||||
|
## Features {#services-arr-features}
|
||||||
|
|
||||||
Compared to the stock module from nixpkgs,
|
Compared to the stock module from nixpkgs,
|
||||||
this one sets up, in a fully declarative manner
|
this one sets up, in a fully declarative manner
|
||||||
LDAP and SSO integration as well as the API key.
|
LDAP and SSO integration as well as the API key.
|
||||||
|
|
||||||
This manual page is under construction.
|
## Usage {#services-arr-usage}
|
||||||
|
|
||||||
|
### Initial Configuration {#services-arr-usage-configuration}
|
||||||
|
|
||||||
|
The following snippet assumes a few blocks have been setup already:
|
||||||
|
|
||||||
|
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
||||||
|
- the [`shb.ssl` block](blocks-ssl.html#usage),
|
||||||
|
- the [`shb.lldap` block](blocks-lldap.html#blocks-lldap-global-setup).
|
||||||
|
- the [`shb.authelia` block](blocks-authelia.html#blocks-sso-global-setup).
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.certs.certs.letsencrypt.${domain}.extraDomains = [
|
||||||
|
"moviesdl.${domain}"
|
||||||
|
"seriesdl.${domain}"
|
||||||
|
"subtitlesdl.${domain}"
|
||||||
|
"booksdl.${domain}"
|
||||||
|
"musicdl.${domain}"
|
||||||
|
"indexer.${domain}"
|
||||||
|
];
|
||||||
|
|
||||||
|
shb.arr = {
|
||||||
|
radarr = {
|
||||||
|
inherit domain;
|
||||||
|
enable = true;
|
||||||
|
ssl = config.shb.certs.certs.letsencrypt.${domain};
|
||||||
|
authEndpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
|
||||||
|
};
|
||||||
|
sonarr = {
|
||||||
|
inherit domain;
|
||||||
|
enable = true;
|
||||||
|
ssl = config.shb.certs.certs.letsencrypt."${domain}";
|
||||||
|
authEndpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
|
||||||
|
};
|
||||||
|
bazarr = {
|
||||||
|
inherit domain;
|
||||||
|
enable = true;
|
||||||
|
ssl = config.shb.certs.certs.letsencrypt."${domain}";
|
||||||
|
authEndpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
|
||||||
|
};
|
||||||
|
readarr = {
|
||||||
|
inherit domain;
|
||||||
|
enable = true;
|
||||||
|
ssl = config.shb.certs.certs.letsencrypt."${domain}";
|
||||||
|
authEndpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
|
||||||
|
};
|
||||||
|
lidarr = {
|
||||||
|
inherit domain;
|
||||||
|
enable = true;
|
||||||
|
ssl = config.shb.certs.certs.letsencrypt."${domain}";
|
||||||
|
authEndpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
|
||||||
|
};
|
||||||
|
jackett = {
|
||||||
|
inherit domain;
|
||||||
|
enable = true;
|
||||||
|
ssl = config.shb.certs.certs.letsencrypt."${domain}";
|
||||||
|
authEndpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The user and admin LDAP groups are created automatically.
|
||||||
|
|
||||||
|
### API Keys {#services-arr-usage-apikeys}
|
||||||
|
|
||||||
|
The API keys for each arr service can be created declaratively.
|
||||||
|
|
||||||
|
First, generate one secret for each service with `nix run nixpkgs#openssl -- rand -hex 64`
|
||||||
|
and store it in your secrets file (for example the SOPS file).
|
||||||
|
|
||||||
|
Then, add the API key to each service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.arr = {
|
||||||
|
radarr = {
|
||||||
|
settings = {
|
||||||
|
ApiKey.source = config.shb.sops.secret."radarr/apikey".result.path;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
sonarr = {
|
||||||
|
settings = {
|
||||||
|
ApiKey.source = config.shb.sops.secret."sonarr/apikey".result.path;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
bazarr = {
|
||||||
|
settings = {
|
||||||
|
ApiKey.source = config.shb.sops.secret."bazarr/apikey".result.path;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
readarr = {
|
||||||
|
settings = {
|
||||||
|
ApiKey.source = config.shb.sops.secret."readarr/apikey".result.path;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
lidarr = {
|
||||||
|
settings = {
|
||||||
|
ApiKey.source = config.shb.sops.secret."lidarr/apikey".result.path;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
jackett = {
|
||||||
|
settings = {
|
||||||
|
ApiKey.source = config.shb.sops.secret."jackett/apikey".result.path;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.sops.secret."radarr/apikey".request = {
|
||||||
|
mode = "0440";
|
||||||
|
owner = "radarr";
|
||||||
|
group = "radarr";
|
||||||
|
restartUnits = [ "radarr.service" ];
|
||||||
|
};
|
||||||
|
shb.sops.secret."sonarr/apikey".request = {
|
||||||
|
mode = "0440";
|
||||||
|
owner = "sonarr";
|
||||||
|
group = "sonarr";
|
||||||
|
restartUnits = [ "sonarr.service" ];
|
||||||
|
};
|
||||||
|
shb.sops.secret."bazarr/apikey".request = {
|
||||||
|
mode = "0440";
|
||||||
|
owner = "bazarr";
|
||||||
|
group = "bazarr";
|
||||||
|
restartUnits = [ "bazarr.service" ];
|
||||||
|
};
|
||||||
|
shb.sops.secret."readarr/apikey".request = {
|
||||||
|
mode = "0440";
|
||||||
|
owner = "readarr";
|
||||||
|
group = "readarr";
|
||||||
|
restartUnits = [ "readarr.service" ];
|
||||||
|
};
|
||||||
|
shb.sops.secret."lidarr/apikey".request = {
|
||||||
|
mode = "0440";
|
||||||
|
owner = "lidarr";
|
||||||
|
group = "lidarr";
|
||||||
|
restartUnits = [ "lidarr.service" ];
|
||||||
|
};
|
||||||
|
shb.sops.secret."jackett/apikey".request = {
|
||||||
|
mode = "0440";
|
||||||
|
owner = "jackett";
|
||||||
|
group = "jackett";
|
||||||
|
restartUnits = [ "jackett.service" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Application Dashboard {#services-arr-usage-applicationdashboard}
|
||||||
|
|
||||||
|
Integration with the [dashboard contract](contracts-dashboard.html) is provided
|
||||||
|
by the various dashboard options.
|
||||||
|
|
||||||
|
For example using the [Homepage](services-homepage.html) service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Media.services.Radarr = {
|
||||||
|
sortOrder = 10;
|
||||||
|
dashboard.request = config.shb.arr.radarr.dashboard.request;
|
||||||
|
apiKey.result = config.shb.sops.secret."radarr/homepageApiKey".result;
|
||||||
|
};
|
||||||
|
shb.sops.secret."radarr/homepageApiKey" = {
|
||||||
|
settings.key = "radarr/apikey";
|
||||||
|
request = config.shb.homepage.servicesGroups.Media.services.Radarr.apiKey.request;
|
||||||
|
};
|
||||||
|
shb.homepage.servicesGroups.Media.services.Sonarr = {
|
||||||
|
sortOrder = 11;
|
||||||
|
dashboard.request = config.shb.arr.sonarr.dashboard.request;
|
||||||
|
apiKey.result = config.shb.sops.secret."sonarr/homepageApiKey".result;
|
||||||
|
};
|
||||||
|
shb.sops.secret."sonarr/homepageApiKey" = {
|
||||||
|
settings.key = "sonarr/apikey";
|
||||||
|
request = config.shb.homepage.servicesGroups.Media.services.Sonarr.apiKey.request;
|
||||||
|
};
|
||||||
|
shb.homepage.servicesGroups.Media.services.Bazarr = {
|
||||||
|
sortOrder = 12;
|
||||||
|
dashboard.request = config.shb.arr.bazarr.dashboard.request;
|
||||||
|
apiKey.result = config.shb.sops.secret."bazarr/homepageApiKey".result;
|
||||||
|
};
|
||||||
|
shb.sops.secret."bazarr/homepageApiKey" = {
|
||||||
|
settings.key = "bazarr/apikey";
|
||||||
|
request = config.shb.homepage.servicesGroups.Media.services.Bazarr.apiKey.request;
|
||||||
|
};
|
||||||
|
shb.homepage.servicesGroups.Media.services.Readarr = {
|
||||||
|
sortOrder = 13;
|
||||||
|
dashboard.request = config.shb.arr.readarr.dashboard.request;
|
||||||
|
apiKey.result = config.shb.sops.secret."readarr/homepageApiKey".result;
|
||||||
|
};
|
||||||
|
shb.sops.secret."readarr/homepageApiKey" = {
|
||||||
|
settings.key = "readarr/apikey";
|
||||||
|
request = config.shb.homepage.servicesGroups.Media.services.Readarr.apiKey.request;
|
||||||
|
};
|
||||||
|
shb.homepage.servicesGroups.Media.services.Lidarr = {
|
||||||
|
sortOrder = 14;
|
||||||
|
dashboard.request = config.shb.arr.lidarr.dashboard.request;
|
||||||
|
apiKey.result = config.shb.sops.secret."lidarr/homepageApiKey".result;
|
||||||
|
};
|
||||||
|
shb.sops.secret."lidarr/homepageApiKey" = {
|
||||||
|
settings.key = "lidarr/apikey";
|
||||||
|
request = config.shb.homepage.servicesGroups.Media.services.Lidarr.apiKey.request;
|
||||||
|
};
|
||||||
|
shb.homepage.servicesGroups.Media.services.Jackett = {
|
||||||
|
sortOrder = 15;
|
||||||
|
dashboard.request = config.shb.arr.jackett.dashboard.request;
|
||||||
|
apiKey.result = config.shb.sops.secret."jackett/homepageApiKey".result;
|
||||||
|
};
|
||||||
|
shb.sops.secret."jackett/homepageApiKey" = {
|
||||||
|
settings.key = "jackett/apikey";
|
||||||
|
request = config.shb.homepage.servicesGroups.Media.services.Jackett.apiKey.request;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This example reuses the API keys generated declaratively from the previous section.
|
||||||
|
|
||||||
|
### Jackett Proxy {#services-arr-usage-jackett-proxy}
|
||||||
|
|
||||||
|
The Jackett service can be made to use a proxy with:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.arr.jackett = {
|
||||||
|
settings = {
|
||||||
|
ProxyType = "0";
|
||||||
|
ProxyUrl = "127.0.0.1:1234";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## Options Reference {#services-arr-options}
|
## Options Reference {#services-arr-options}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,20 @@ in
|
||||||
default = false;
|
default = false;
|
||||||
example = true;
|
example = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.audiobookshelf.subdomain}.\${config.shb.audiobookshelf.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString cfg.webPort}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable (
|
config = lib.mkIf cfg.enable (
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ in
|
||||||
options.shb.deluge = {
|
options.shb.deluge = {
|
||||||
enable = lib.mkEnableOption "the SHB Deluge service";
|
enable = lib.mkEnableOption "the SHB Deluge service";
|
||||||
|
|
||||||
enableDashboard = lib.mkEnableOption "the Torrents SHB dashboard" // {
|
enableDashboard = lib.mkEnableOption "the Torrents SHB monitoring dashboard" // {
|
||||||
default = true;
|
default = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -301,6 +301,20 @@ in
|
||||||
default = null;
|
default = null;
|
||||||
example = "info";
|
example = "info";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${fqdn}";
|
||||||
|
externalUrlText = "https://\${config.shb.deluge.subdomain}.\${config.shb.deluge.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString cfg.webPort}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable (
|
config = lib.mkIf cfg.enable (
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@ let
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
|
../blocks/nginx.nix
|
||||||
|
../blocks/lldap.nix
|
||||||
|
|
||||||
../../lib/module.nix
|
../../lib/module.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -293,6 +296,22 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.firefly-iii.subdomain}.\${config.shb.firefly-iii.domain}";
|
||||||
|
# This works thanks to the Personal Access Token.
|
||||||
|
internalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
internalUrlText = "https://\${config.shb.firefly-iii.subdomain}.\${config.shb.firefly-iii.domain}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable (
|
config = lib.mkIf cfg.enable (
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,14 @@ It also sets up the Firefly-iii data importer service
|
||||||
and nearly automatically links it to the Firefly-iii instance using a Personal Account Token.
|
and nearly automatically links it to the Firefly-iii instance using a Personal Account Token.
|
||||||
Instructions on how to do so is given in the next section.
|
Instructions on how to do so is given in the next section.
|
||||||
|
|
||||||
|
## Features {#services-firefly-iii-features}
|
||||||
|
|
||||||
|
- Integration with the [dashboard contract](contracts-dashboard.html) for displaying user facing application in a dashboard. [Manual](#services-firefly-iii-usage-applicationdashboard)
|
||||||
|
|
||||||
## Usage {#services-firefly-iii-usage}
|
## Usage {#services-firefly-iii-usage}
|
||||||
|
|
||||||
|
### Initial Configuration {#services-firefly-iii-usage-configuration}
|
||||||
|
|
||||||
The following snippet assumes a few blocks have been setup already:
|
The following snippet assumes a few blocks have been setup already:
|
||||||
|
|
||||||
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
||||||
|
|
@ -127,6 +133,38 @@ shb.lldap.ensureUsers.USERNAME.groups = [
|
||||||
];
|
];
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Application Dashboard {#services-firefly-iii-usage-applicationdashboard}
|
||||||
|
|
||||||
|
Integration with the [dashboard contract](contracts-dashboard.html) is provided
|
||||||
|
by the [dashboard option](#services-firefly-iii-options-shb.firefly-iii.dashboard).
|
||||||
|
|
||||||
|
For example using the [Homepage](services-homepage.html) service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Finance.services.Firefly-iii = {
|
||||||
|
sortOrder = 1;
|
||||||
|
dashboard.request = config.shb.firefly-iii.dashboard.request;
|
||||||
|
settings.widget.type = "firefly";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The widget type needs to be set manually otherwise it is not displayed correctly.
|
||||||
|
|
||||||
|
An API key can be set to show extra info:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Finance.services.Firefly-iii = {
|
||||||
|
apiKey.result = config.shb.sops.secret."firefly-iii/homepageApiKey".result;
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.sops.secret."firefly-iii/homepageApiKey".request =
|
||||||
|
config.shb.homepage.servicesGroups.Finance.services.Firefly-iii.apiKey.request;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Database Inspection {#services-firefly-iii-database-inspection}
|
## Database Inspection {#services-firefly-iii-database-inspection}
|
||||||
|
|
||||||
Access the database with:
|
Access the database with:
|
||||||
|
|
|
||||||
|
|
@ -408,6 +408,21 @@ in
|
||||||
type = bool;
|
type = bool;
|
||||||
default = false;
|
default = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.forgejo.subdomain}.\${config.shb.forgejo.domain}";
|
||||||
|
internalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
internalUrlText = "https://\${config.shb.forgejo.subdomain}.\${config.shb.forgejo.domain}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkMerge [
|
config = mkMerge [
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ LDAP and SSO integration as well as one local runner.
|
||||||
- Access through [subdomain](#services-forgejo-options-shb.forgejo.subdomain) using reverse proxy. [Manual](#services-forgejo-usage-configuration).
|
- Access through [subdomain](#services-forgejo-options-shb.forgejo.subdomain) using reverse proxy. [Manual](#services-forgejo-usage-configuration).
|
||||||
- Access through [HTTPS](#services-forgejo-options-shb.forgejo.ssl) using reverse proxy. [Manual](#services-forgejo-usage-configuration).
|
- Access through [HTTPS](#services-forgejo-options-shb.forgejo.ssl) using reverse proxy. [Manual](#services-forgejo-usage-configuration).
|
||||||
- [Backup](#services-forgejo-options-shb.forgejo.sso) through the [backup block](./blocks-backup.html). [Manual](#services-forgejo-usage-backup).
|
- [Backup](#services-forgejo-options-shb.forgejo.sso) through the [backup block](./blocks-backup.html). [Manual](#services-forgejo-usage-backup).
|
||||||
|
- Integration with the [dashboard contract](contracts-dashboard.html) for displaying user facing application in a dashboard. [Manual](#services-forgejo-usage-applicationdashboard)
|
||||||
|
|
||||||
## Usage {#services-forgejo-usage}
|
## Usage {#services-forgejo-usage}
|
||||||
|
|
||||||
|
|
@ -206,6 +207,22 @@ The name `"forgejo"` in the `instances` can be anything.
|
||||||
The `config.shb.forgejo.backup` option provides what directories to backup.
|
The `config.shb.forgejo.backup` option provides what directories to backup.
|
||||||
You can define any number of Restic instances to backup Forgejo multiple times.
|
You can define any number of Restic instances to backup Forgejo multiple times.
|
||||||
|
|
||||||
|
### Application Dashboard {#services-forgejo-usage-applicationdashboard}
|
||||||
|
|
||||||
|
Integration with the [dashboard contract](contracts-dashboard.html) is provided
|
||||||
|
by the [dashboard option](#services-forgejo-options-shb.forgejo.dashboard).
|
||||||
|
|
||||||
|
For example using the [Homepage](services-homepage.html) service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Admin.services.Forgejo = {
|
||||||
|
sortOrder = 1;
|
||||||
|
dashboard.request = config.shb.forgejo.dashboard.request;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Extra Settings {#services-forgejo-usage-extra-settings}
|
### Extra Settings {#services-forgejo-usage-extra-settings}
|
||||||
|
|
||||||
Other Forgejo settings can be accessed through the nixpkgs [stock service][].
|
Other Forgejo settings can be accessed through the nixpkgs [stock service][].
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,21 @@ in
|
||||||
default = false;
|
default = false;
|
||||||
example = true;
|
example = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.grocy.subdomain}.\${config.shb.grocy.domain}";
|
||||||
|
internalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
internalUrlText = "https://\${config.shb.grocy.subdomain}.\${config.shb.grocy.domain}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable (
|
config = lib.mkIf cfg.enable (
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,21 @@ in
|
||||||
default = [ "--forecast" ];
|
default = [ "--forecast" ];
|
||||||
type = lib.types.listOf lib.types.str;
|
type = lib.types.listOf lib.types.str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.hledger.subdomain}.\${config.shb.hledger.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString config.services.hledger-web.port}";
|
||||||
|
internalUrlText = "http://127.0.0.1:\${config.services.hledger-web.port}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,21 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.home-assistant.subdomain}.\${config.shb.home-assistant.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString config.services.home-assistant.config.http.server_port}";
|
||||||
|
internalUrlText = "http://127.0.0.1:\${config.services.home-assistant.config.http.server_port}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ LDAP and SSO integration.
|
||||||
- Access through [subdomain](#services-home-assistant-options-shb.home-assistant.subdomain) using reverse proxy. [Manual](#services-home-assistant-usage-configuration).
|
- Access through [subdomain](#services-home-assistant-options-shb.home-assistant.subdomain) using reverse proxy. [Manual](#services-home-assistant-usage-configuration).
|
||||||
- Access through [HTTPS](#services-home-assistant-options-shb.home-assistant.ssl) using reverse proxy. [Manual](#services-home-assistant-usage-configuration).
|
- Access through [HTTPS](#services-home-assistant-options-shb.home-assistant.ssl) using reverse proxy. [Manual](#services-home-assistant-usage-configuration).
|
||||||
- [Backup](#services-home-assistant-options-shb.home-assistant.backup) through the [backup block](./blocks-backup.html). [Manual](#services-home-assistant-usage-backup).
|
- [Backup](#services-home-assistant-options-shb.home-assistant.backup) through the [backup block](./blocks-backup.html). [Manual](#services-home-assistant-usage-backup).
|
||||||
|
- Integration with the [dashboard contract](contracts-dashboard.html) for displaying user facing application in a dashboard. [Manual](#services-home-assistant-usage-applicationdashboard)
|
||||||
|
|
||||||
- Not yet: declarative SSO.
|
- Not yet: declarative SSO.
|
||||||
|
|
||||||
|
|
@ -163,6 +164,57 @@ You can define any number of Restic instances to backup Home-Assistant multiple
|
||||||
You will then need to configure more options like the `repository`,
|
You will then need to configure more options like the `repository`,
|
||||||
as explained in the [restic](blocks-restic.html) documentation.
|
as explained in the [restic](blocks-restic.html) documentation.
|
||||||
|
|
||||||
|
### Application Dashboard {#services-home-assistant-usage-applicationdashboard}
|
||||||
|
|
||||||
|
Integration with the [dashboard contract](contracts-dashboard.html) is provided
|
||||||
|
by the [dashboard option](#services-home-assistant-options-shb.home-assistant.dashboard).
|
||||||
|
|
||||||
|
For example using the [Homepage](services-homepage.html) service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Home.services.HomeAssistant = {
|
||||||
|
sortOrder = 1;
|
||||||
|
dashboard.request = config.shb.home-assistant.dashboard.request;
|
||||||
|
settings.icon = "si-homeassistant";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The icon needs to be set manually otherwise it is not displayed correctly.
|
||||||
|
|
||||||
|
An API key can be set to show extra info:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Home.services.HomeAssistant = {
|
||||||
|
apiKey.result = config.shb.sops.secret."home-assistant/homepageApiKey".result;
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.sops.secret."home-assistant/homepageApiKey".request =
|
||||||
|
config.shb.homepage.servicesGroups.Home.services.HomeAssistant.apiKey.request;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Custom widgets can be set using Home Assistant templating:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Home.services.HomeAssistant = {
|
||||||
|
settings.widget.custom = [
|
||||||
|
{
|
||||||
|
template = "{{ states('sensor.power_consumption_power_consumption', with_unit=True, rounded=True) }}";
|
||||||
|
label = "energy now";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
state = "sensor.power_consumption_daily_power_consumption";
|
||||||
|
label = "energy today";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Extra Components {#services-home-assistant-usage-extra-components}
|
### Extra Components {#services-home-assistant-usage-extra-components}
|
||||||
|
|
||||||
Packaged components can be found in the documentation of the corresponding option
|
Packaged components can be found in the documentation of the corresponding option
|
||||||
|
|
|
||||||
286
modules/services/homepage.nix
Normal file
286
modules/services/homepage.nix
Normal file
|
|
@ -0,0 +1,286 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
shb,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.shb.homepage;
|
||||||
|
|
||||||
|
inherit (lib) types;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
../../lib/module.nix
|
||||||
|
|
||||||
|
../blocks/lldap.nix
|
||||||
|
../blocks/nginx.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
options.shb.homepage = {
|
||||||
|
enable = lib.mkEnableOption "the SHB homepage service";
|
||||||
|
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
Subdomain under which homepage will be served.
|
||||||
|
|
||||||
|
```
|
||||||
|
<subdomain>.<domain>
|
||||||
|
```
|
||||||
|
'';
|
||||||
|
example = "homepage";
|
||||||
|
};
|
||||||
|
|
||||||
|
domain = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Domain under which homepage is served.
|
||||||
|
|
||||||
|
```
|
||||||
|
<subdomain>.<domain>
|
||||||
|
```
|
||||||
|
'';
|
||||||
|
type = types.str;
|
||||||
|
example = "domain.com";
|
||||||
|
};
|
||||||
|
|
||||||
|
ssl = lib.mkOption {
|
||||||
|
description = "Path to SSL files";
|
||||||
|
type = types.nullOr shb.contracts.ssl.certs;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
servicesGroups = lib.mkOption {
|
||||||
|
description = "Group of services that should be showed on the dashboard.";
|
||||||
|
default = { };
|
||||||
|
type = types.attrsOf (
|
||||||
|
types.submodule (
|
||||||
|
{ name, ... }:
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
name = lib.mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Display name of the group. Defaults to the attr name.";
|
||||||
|
default = name;
|
||||||
|
};
|
||||||
|
sortOrder = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Order in which groups will be shown.
|
||||||
|
|
||||||
|
The rules are:
|
||||||
|
|
||||||
|
- Lowest number is shown first.
|
||||||
|
- Two groups having the same number are shown in a consistent (same across multiple deploys) but undefined order.
|
||||||
|
- Default is null which means at the end.
|
||||||
|
'';
|
||||||
|
type = types.nullOr types.int;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
services = lib.mkOption {
|
||||||
|
description = "Services that should be showed in the group on the dashboard.";
|
||||||
|
default = { };
|
||||||
|
type = types.attrsOf (
|
||||||
|
types.submodule (
|
||||||
|
{ name, ... }:
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
name = lib.mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Display name of the service. Defaults to the attr name.";
|
||||||
|
default = name;
|
||||||
|
};
|
||||||
|
sortOrder = lib.mkOption {
|
||||||
|
type = types.nullOr types.int;
|
||||||
|
description = ''
|
||||||
|
Order in which groups will be shown.
|
||||||
|
|
||||||
|
The rules are:
|
||||||
|
|
||||||
|
- Lowest number is shown first.
|
||||||
|
- Two groups having the same number are shown in a consistent (same across multiple deploys) but undefined order.
|
||||||
|
- Default is null which means at the end.
|
||||||
|
'';
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Provider of the dashboard contract.
|
||||||
|
|
||||||
|
By default:
|
||||||
|
|
||||||
|
- The `serviceName` option comes from the attr name.
|
||||||
|
- The `icon` option comes from applying `toLower` on the attr name.
|
||||||
|
- The `siteMonitor` option is set only if `internalUrl` is set.
|
||||||
|
'';
|
||||||
|
type = types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkProvider {
|
||||||
|
resultCfg = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
apiKey = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
API key used to access the service.
|
||||||
|
|
||||||
|
This can be used to get data from the service.
|
||||||
|
'';
|
||||||
|
default = null;
|
||||||
|
type = types.nullOr (
|
||||||
|
lib.types.submodule {
|
||||||
|
options = shb.contracts.secret.mkRequester {
|
||||||
|
owner = "root";
|
||||||
|
restartUnits = [ "homepage-dashboard.service" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
settings = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Extra options to pass to the homepage service.
|
||||||
|
|
||||||
|
Check https://gethomepage.dev/configs/services/#icons
|
||||||
|
if the default icon is not correct.
|
||||||
|
|
||||||
|
And check https://gethomepage.dev/widgets
|
||||||
|
if the default widget type is not correct.
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = types.attrsOf types.anything;
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
{
|
||||||
|
icon = "si-homeassistant";
|
||||||
|
widget.type = "firefly";
|
||||||
|
widget.custom = [
|
||||||
|
{
|
||||||
|
template = "{{ states('sensor.total_power', with_unit=True, rounded=True) }}";
|
||||||
|
label = "energy now";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
state = "sensor.total_power_today";
|
||||||
|
label = "energy today";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ldap = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Setup LDAP integration.
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = types.submodule {
|
||||||
|
options = {
|
||||||
|
userGroup = lib.mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Group users must belong to be able to login.";
|
||||||
|
default = "homepage_user";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sso = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Setup SSO integration.
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = types.submodule {
|
||||||
|
options = {
|
||||||
|
enable = lib.mkEnableOption "SSO integration.";
|
||||||
|
|
||||||
|
authEndpoint = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Endpoint to the SSO provider.";
|
||||||
|
example = "https://authelia.example.com";
|
||||||
|
};
|
||||||
|
|
||||||
|
authorization_policy = lib.mkOption {
|
||||||
|
type = types.enum [
|
||||||
|
"one_factor"
|
||||||
|
"two_factor"
|
||||||
|
];
|
||||||
|
description = "Require one factor (password) or two factor (device) authentication.";
|
||||||
|
default = "one_factor";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services.homepage-dashboard = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
allowedHosts = "${cfg.subdomain}.${cfg.domain}";
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
baseUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
startUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
disableUpdateCheck = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
bookmarks = [ ];
|
||||||
|
|
||||||
|
services = shb.homepage.asServiceGroup cfg.servicesGroups;
|
||||||
|
|
||||||
|
widgets = [ ];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.homepage-dashboard.serviceConfig =
|
||||||
|
let
|
||||||
|
keys = shb.homepage.allKeys cfg.servicesGroups;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# LoadCredential = [
|
||||||
|
# "Media_Jellyfin:/path"
|
||||||
|
# ];
|
||||||
|
LoadCredential = lib.mapAttrsToList (name: path: "${name}:${path}") keys;
|
||||||
|
# Environment = [
|
||||||
|
# "HOMEPAGE_FILE_Media_Jellyfin=%d/Media_Jellyfin"
|
||||||
|
# ];
|
||||||
|
Environment = lib.mapAttrsToList (name: path: "HOMEPAGE_FILE_${name}=%d/${name}") keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
# This should be using a contract instead of setting the option directly.
|
||||||
|
shb.lldap = lib.mkIf config.shb.lldap.enable {
|
||||||
|
ensureGroups = {
|
||||||
|
${cfg.ldap.userGroup} = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.nginx.vhosts = [
|
||||||
|
(
|
||||||
|
{
|
||||||
|
inherit (cfg) subdomain domain ssl;
|
||||||
|
|
||||||
|
upstream = "http://127.0.0.1:${toString config.services.homepage-dashboard.listenPort}/";
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
'';
|
||||||
|
autheliaRules = lib.optionals (cfg.sso.enable) [
|
||||||
|
{
|
||||||
|
domain = "${cfg.subdomain}.${cfg.domain}";
|
||||||
|
policy = cfg.sso.authorization_policy;
|
||||||
|
subject = [ "group:${cfg.ldap.userGroup}" ];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
// lib.optionalAttrs cfg.sso.enable {
|
||||||
|
inherit (cfg.sso) authEndpoint;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
BIN
modules/services/homepage/docs/Screenshot.png
Normal file
BIN
modules/services/homepage/docs/Screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 128 KiB |
191
modules/services/homepage/docs/default.md
Normal file
191
modules/services/homepage/docs/default.md
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
# Homepage Service {#services-homepage}
|
||||||
|
|
||||||
|
Defined in [`/modules/services/homepage.nix`](@REPO@/modules/services/homepage.nix),
|
||||||
|
found in the `selfhostblocks.nixosModules.homepage` module.
|
||||||
|
See [the manual](usage.html#usage-flake) for how to import the module in your code.
|
||||||
|
|
||||||
|
This service sets up [Homepage Dashboard][] which provides
|
||||||
|
a highly customizable homepage Docker and service API integrations.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
[Homepage Dashboard]: https://github.com/gethomepage/homepage
|
||||||
|
|
||||||
|
## Features {#services-homepage-features}
|
||||||
|
|
||||||
|
- Declarative SSO login through forward authentication.
|
||||||
|
Only users of the [Homepage LDAP user group][] can access the web UI.
|
||||||
|
This is enforced using the [Authelia block][] which integrates with the LLDAP block.
|
||||||
|
- Access through [subdomain][] using the reverse proxy.
|
||||||
|
It is implemented with the [Nginx block][].
|
||||||
|
- Access through [HTTPS][] using the reverse proxy.
|
||||||
|
It is implemented with the [SSL block][].
|
||||||
|
- Integration with [secrets contract][] to set the API key for a widget.
|
||||||
|
|
||||||
|
[Homepage LDAP user group]: #services-homepage-options-shb.homepage.ldap.userGroup
|
||||||
|
[Authelia block]: blocks-authelia.html
|
||||||
|
[subdomain]: #services-open-webui-options-shb.open-webui.subdomain
|
||||||
|
[HTTPS]: #services-open-webui-options-shb.open-webui.ssl
|
||||||
|
[Nginx block]: blocks-nginx.html
|
||||||
|
[SSL block]: blocks-ssl.html
|
||||||
|
[secrets contract]: contracts-secret.html
|
||||||
|
|
||||||
|
::: {.note}
|
||||||
|
The service does not use state so no backup or impermanence integration is provided.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Usage {#services-homepage-usage}
|
||||||
|
|
||||||
|
The following snippet assumes a few blocks have been setup already:
|
||||||
|
|
||||||
|
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
||||||
|
- the [`shb.ssl` block](blocks-ssl.html#usage),
|
||||||
|
- the [`shb.lldap` block](blocks-lldap.html#blocks-lldap-global-setup).
|
||||||
|
- the [`shb.authelia` block](blocks-authelia.html#blocks-sso-global-setup).
|
||||||
|
|
||||||
|
::: {.note}
|
||||||
|
Part of the configuration is done through the `shb.homepage` option described here
|
||||||
|
and the rest is done through the upstream [`services.homepage-dashboard`][] option.
|
||||||
|
:::
|
||||||
|
|
||||||
|
[`services.homepage-dashboard`]: https://search.nixos.org/options?query=services.homepage-dashboard
|
||||||
|
|
||||||
|
### Main service configuration {#services-homepage-usage-main}
|
||||||
|
|
||||||
|
This part sets up the web UI and its integration with the other SHB services.
|
||||||
|
It also creates the various service groups which will hold each service.
|
||||||
|
The names are arbitrary and you can order them as you wish through the `sortOrder` option.
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.certs.certs.letsencrypt.${domain}.extraDomains = [
|
||||||
|
"${config.shb.homepage.subdomain}.${config.shb.homepage.domain}"
|
||||||
|
];
|
||||||
|
shb.homepage = {
|
||||||
|
enable = true;
|
||||||
|
subdomain = "home";
|
||||||
|
inherit domain;
|
||||||
|
ssl = config.shb.certs.certs.letsencrypt.${domain};
|
||||||
|
|
||||||
|
sso = {
|
||||||
|
enable = true;
|
||||||
|
authEndpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
|
||||||
|
};
|
||||||
|
|
||||||
|
servicesGroups = {
|
||||||
|
Home.sortOrder = 1;
|
||||||
|
Documents.sortOrder = 2;
|
||||||
|
Finance.sortOrder = 3;
|
||||||
|
Media.sortOrder = 4;
|
||||||
|
Admin.sortOrder = 5;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.homepage-dashboard = {
|
||||||
|
settings = {
|
||||||
|
statusStyle = "dot";
|
||||||
|
disableIndexing = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
widgets = [
|
||||||
|
{
|
||||||
|
locale = "fr";
|
||||||
|
format = {
|
||||||
|
dateStyle = "long";
|
||||||
|
timeStyle = "long";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The [Homepage LDAP user group][] is created automatically and users can be added declaratively to the group with:.
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.lldap.ensureUsers.${user}.groups = [
|
||||||
|
config.shb.homepage.ldap.userGroup
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Display SHB service {#services-homepage-usage-service}
|
||||||
|
|
||||||
|
A service consumer of the dashboard contract provides a `dashboard` option that can be used like so:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Media.services.Jellyfin = {
|
||||||
|
sortOrder = 2;
|
||||||
|
dashboard.request = config.shb.jellyfin.dashboard.request;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
By default:
|
||||||
|
|
||||||
|
- The `serviceName` option comes from the attr name, here `Jellyfin`.
|
||||||
|
- The `icon` option comes from applying `toLower` on the attr name.
|
||||||
|
- The `siteMonitor` option is set only if `internalUrl` is set.
|
||||||
|
|
||||||
|
They can be overridden by setting them in the [settings](#services-homepage-options-shb.homepage.servicesGroups._name_.services._name_.settings option) (see option documentation for examples):
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Media.services.Jellyfin = {
|
||||||
|
sortOrder = 2;
|
||||||
|
dashboard.request = config.shb.<service>.dashboard.request;
|
||||||
|
settings = {
|
||||||
|
// custom options here.
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Secrets can be randomly generated with `nix run nixpkgs#openssl -- rand -hex 64`.
|
||||||
|
|
||||||
|
### Display custom service {#services-homepage-usage-custom}
|
||||||
|
|
||||||
|
To display a service that does not provide a `dashboard` option like in the previous section, set the values of the request manually:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Media.services.Jellyfin = {
|
||||||
|
sortOrder = 2;
|
||||||
|
dashboard.request = {
|
||||||
|
externalUrl = "https://jellyfin.example.com";
|
||||||
|
internalUrl = "http://127.0.0.1:8081";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add API key for widget {#services-homepage-usage-widget}
|
||||||
|
|
||||||
|
For services [supporting a widget](https://gethomepage.dev/widgets/),
|
||||||
|
create an API key through the service's web UI if available
|
||||||
|
then store it securely (using SOPS for example) and provide it through the
|
||||||
|
`apiKey` option:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Media.services.Jellyfin = {
|
||||||
|
sortOrder = 1;
|
||||||
|
dashboard.request = config.shb.jellyfin.dashboard.request;
|
||||||
|
apiKey.result = config.shb.sops.secret."jellyfin/homepageApiKey".result;
|
||||||
|
};
|
||||||
|
shb.sops.secret."jellyfin/homepageApiKey".request =
|
||||||
|
config.shb.homepage.servicesGroups.Media.services.Jellyfin.apiKey.request;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Unfortunately creating API keys declaratively is rarely supported by upstream services.
|
||||||
|
|
||||||
|
## Options Reference {#services-homepage-options}
|
||||||
|
|
||||||
|
```{=include=} options
|
||||||
|
id-prefix: services-homepage-options-
|
||||||
|
list-id: selfhostblocks-service-homepage-options
|
||||||
|
source: @OPTIONS_JSON@
|
||||||
|
```
|
||||||
|
|
@ -465,6 +465,20 @@ in
|
||||||
default = false;
|
default = false;
|
||||||
example = true;
|
example = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${fqdn}";
|
||||||
|
externalUrlText = "https://\${config.shb.immich.subdomain}.\${config.shb.immich.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString cfg.port}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
|
|
||||||
|
|
@ -317,6 +317,20 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${fqdn}";
|
||||||
|
externalUrlText = "https://\${config.shb.jellyfin.subdomain}.\${config.shb.jellyfin.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString cfg.port}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,12 @@ this one sets up, in a fully declarative manner:
|
||||||
- Declarative [LDAP](#services-jellyfin-options-shb.jellyfin.ldap) configuration.
|
- Declarative [LDAP](#services-jellyfin-options-shb.jellyfin.ldap) configuration.
|
||||||
- Declarative [SSO](#services-jellyfin-options-shb.jellyfin.sso) configuration.
|
- Declarative [SSO](#services-jellyfin-options-shb.jellyfin.sso) configuration.
|
||||||
- [Backup](#services-jellyfin-options-shb.jellyfin.backup) through the [backup block](./blocks-backup.html). [Manual](#services-jellyfin-usage-backup).
|
- [Backup](#services-jellyfin-options-shb.jellyfin.backup) through the [backup block](./blocks-backup.html). [Manual](#services-jellyfin-usage-backup).
|
||||||
|
- Integration with the [dashboard contract](contracts-dashboard.html) for displaying user facing application in a dashboard. [Manual](#services-jellyfin-usage-applicationdashboard)
|
||||||
|
|
||||||
## Usage {#services-jellyfin-usage}
|
## Usage {#services-jellyfin-usage}
|
||||||
|
|
||||||
|
### Initial Configuration {#services-jellyfin-usage-configuration}
|
||||||
|
|
||||||
The following snippet assumes a few blocks have been setup already:
|
The following snippet assumes a few blocks have been setup already:
|
||||||
|
|
||||||
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
||||||
|
|
@ -133,6 +136,35 @@ shb.lldap.ensureUsers.USERNAME.groups = [
|
||||||
];
|
];
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Application Dashboard {#services-jellyfin-usage-applicationdashboard}
|
||||||
|
|
||||||
|
Integration with the [dashboard contract](contracts-dashboard.html) is provided
|
||||||
|
by the [dashboard option](#services-jellyfin-options-shb.jellyfin.dashboard).
|
||||||
|
|
||||||
|
For example using the [Homepage](services-homepage.html) service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Media.services.Jellyfin = {
|
||||||
|
sortOrder = 1;
|
||||||
|
dashboard.request = config.shb.jellyfin.dashboard.request;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
An API key can be set to show extra info:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Media.services.Jellyfin = {
|
||||||
|
apiKey.result = config.shb.sops.secret."jellyfin/homepageApiKey".result;
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.sops.secret."jellyfin/homepageApiKey".request =
|
||||||
|
config.shb.homepage.servicesGroups.Media.services.Jellyfin.apiKey.request;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Debug {#services-jellyfin-debug}
|
## Debug {#services-jellyfin-debug}
|
||||||
|
|
||||||
In case of an issue, check the logs for systemd service `jellyfin.service`.
|
In case of an issue, check the logs for systemd service `jellyfin.service`.
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,20 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.karakeep.subdomain}.\${config.shb.karakeep.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString cfg.port}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = (
|
config = (
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,12 @@ It integrates well with [Ollama][].
|
||||||
- Access through [subdomain](#services-karakeep-options-shb.karakeep.subdomain) using reverse proxy.
|
- Access through [subdomain](#services-karakeep-options-shb.karakeep.subdomain) using reverse proxy.
|
||||||
- Access through [HTTPS](#services-karakeep-options-shb.karakeep.ssl) using reverse proxy.
|
- Access through [HTTPS](#services-karakeep-options-shb.karakeep.ssl) using reverse proxy.
|
||||||
- [Backup](#services-karakeep-options-shb.karakeep.sso) through the [backup block](./blocks-backup.html).
|
- [Backup](#services-karakeep-options-shb.karakeep.sso) through the [backup block](./blocks-backup.html).
|
||||||
|
- Integration with the [dashboard contract](contracts-dashboard.html) for displaying user facing application in a dashboard. [Manual](#services-karakeep-usage-applicationdashboard)
|
||||||
|
|
||||||
## Usage {#services-karakeep-usage}
|
## Usage {#services-karakeep-usage}
|
||||||
|
|
||||||
|
### Initial Configuration {#services-karakeep-usage-configuration}
|
||||||
|
|
||||||
The following snippet assumes a few blocks have been setup already:
|
The following snippet assumes a few blocks have been setup already:
|
||||||
|
|
||||||
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
||||||
|
|
@ -66,6 +69,35 @@ The [user](#services-open-webui-options-shb.open-webui.ldap.userGroup)
|
||||||
and [admin](#services-open-webui-options-shb.open-webui.ldap.adminGroup)
|
and [admin](#services-open-webui-options-shb.open-webui.ldap.adminGroup)
|
||||||
LDAP groups are created automatically.
|
LDAP groups are created automatically.
|
||||||
|
|
||||||
|
### Application Dashboard {#services-karakeep-usage-applicationdashboard}
|
||||||
|
|
||||||
|
Integration with the [dashboard contract](contracts-dashboard.html) is provided
|
||||||
|
by the [dashboard option](#services-karakeep-options-shb.karakeep.dashboard).
|
||||||
|
|
||||||
|
For example using the [Homepage](services-homepage.html) service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Documents.services.Karakeep = {
|
||||||
|
sortOrder = 3;
|
||||||
|
dashboard.request = config.shb.karakeep.dashboard.request;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
An API key can be set to show extra info:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Documents.services.Karakeep = {
|
||||||
|
apiKey.result = config.shb.sops.secret."karakeep/homepageApiKey".result;
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.sops.secret."karakeep/homepageApiKey".request =
|
||||||
|
config.shb.homepage.servicesGroups.Documents.services.Karakeep.apiKey.request;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Integration with Ollama {#services-karakeep-ollama}
|
## Integration with Ollama {#services-karakeep-ollama}
|
||||||
|
|
||||||
Assuming ollama is enabled, it will be available on port `config.services.ollama.port`.
|
Assuming ollama is enabled, it will be available on port `config.services.ollama.port`.
|
||||||
|
|
|
||||||
|
|
@ -694,6 +694,21 @@ in
|
||||||
but Self Host Blocks assumes that it will not be the case for most users.
|
but Self Host Blocks assumes that it will not be the case for most users.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${fqdn}";
|
||||||
|
externalUrlText = "https://\${config.shb.nextcloud.subdomain}.\${config.shb.nextcloud.domain}";
|
||||||
|
internalUrl = "https://${fqdn}";
|
||||||
|
internalUrlText = "https://\${config.shb.nextcloud.subdomain}.\${config.shb.nextcloud.domain}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,8 @@ It is based on the nixpkgs Nextcloud server and provides opinionated defaults.
|
||||||
- Forces PostgreSQL as the database.
|
- Forces PostgreSQL as the database.
|
||||||
- Forces Redis as the cache and sets good defaults.
|
- Forces Redis as the cache and sets good defaults.
|
||||||
- Backup of the [`shb.nextcloud.dataDir`][dataDir] through the [backup block](./blocks-backup.html).
|
- Backup of the [`shb.nextcloud.dataDir`][dataDir] through the [backup block](./blocks-backup.html).
|
||||||
- [Dashboard](#services-nextcloudserver-dashboard) for monitoring of reverse proxy, PHP-FPM, and database backups through the [monitoring
|
- [Monitoring Dashboard](#services-nextcloudserver-dashboard) for monitoring of reverse proxy, PHP-FPM, and database backups through the [monitoring block](./blocks-monitoring.html).
|
||||||
block](./blocks-monitoring.html).
|
- Integration with the [dashboard contract](contracts-dashboard.html) for displaying user facing application in a dashboard.
|
||||||
- [Integration Tests](@REPO@/test/services/nextcloud.nix)
|
- [Integration Tests](@REPO@/test/services/nextcloud.nix)
|
||||||
- Tests system cron job is setup correctly.
|
- Tests system cron job is setup correctly.
|
||||||
- Tests initial admin user and password are setup correctly.
|
- Tests initial admin user and password are setup correctly.
|
||||||
|
|
@ -344,6 +344,22 @@ Note that this will backup the whole PostgreSQL instance,
|
||||||
not just the Nextcloud database.
|
not just the Nextcloud database.
|
||||||
This limitation will be lifted in the future.
|
This limitation will be lifted in the future.
|
||||||
|
|
||||||
|
### Application Dashboard {#services-nextcloudserver-usage-applicationdashboard}
|
||||||
|
|
||||||
|
Integration with the [dashboard contract](contracts-dashboard.html) is provided
|
||||||
|
by the [dashboard option](#services-nextcloudserver-options-shb.nextcloud.dashboard).
|
||||||
|
|
||||||
|
For example using the [Homepage](services-homepage.html) service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Documents.services.Nextcloud = {
|
||||||
|
sortOrder = 1;
|
||||||
|
dashboard.request = config.shb.nextcloud.dashboard.request;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Enable Preview Generator App {#services-nextcloudserver-usage-previewgenerator}
|
### Enable Preview Generator App {#services-nextcloudserver-usage-previewgenerator}
|
||||||
|
|
||||||
The following snippet installs and enables the [Preview
|
The following snippet installs and enables the [Preview
|
||||||
|
|
@ -537,7 +553,7 @@ by issuing the command `nextcloud-occ config:system:delete instanceid`.
|
||||||
Head over to the [Nextcloud demo](demo-nextcloud-server.html) for a demo that installs Nextcloud with or
|
Head over to the [Nextcloud demo](demo-nextcloud-server.html) for a demo that installs Nextcloud with or
|
||||||
without LDAP integration on a VM with minimal manual steps.
|
without LDAP integration on a VM with minimal manual steps.
|
||||||
|
|
||||||
## Dashboard {#services-nextcloudserver-dashboard}
|
## Monitoring Dashboard {#services-nextcloudserver-dashboard}
|
||||||
|
|
||||||
The dashboard is added to Grafana automatically under "Self Host Blocks > Nextcloud"
|
The dashboard is added to Grafana automatically under "Self Host Blocks > Nextcloud"
|
||||||
as long as the Nextcloud service is [enabled][]
|
as long as the Nextcloud service is [enabled][]
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,20 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.open-webui.subdomain}.\${config.shb.open-webui.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString cfg.port}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = (
|
config = (
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,12 @@ This service sets up [Open WebUI][] which provides a frontend to various LLMs.
|
||||||
- Access through [subdomain](#services-open-webui-options-shb.open-webui.subdomain) using reverse proxy.
|
- Access through [subdomain](#services-open-webui-options-shb.open-webui.subdomain) using reverse proxy.
|
||||||
- Access through [HTTPS](#services-open-webui-options-shb.open-webui.ssl) using reverse proxy.
|
- Access through [HTTPS](#services-open-webui-options-shb.open-webui.ssl) using reverse proxy.
|
||||||
- [Backup](#services-open-webui-options-shb.open-webui.sso) through the [backup block](./blocks-backup.html).
|
- [Backup](#services-open-webui-options-shb.open-webui.sso) through the [backup block](./blocks-backup.html).
|
||||||
|
- Integration with the [dashboard contract](contracts-dashboard.html) for displaying user facing application in a dashboard. [Manual](#services-open-webui-usage-applicationdashboard)
|
||||||
|
|
||||||
## Usage {#services-open-webui-usage}
|
## Usage {#services-open-webui-usage}
|
||||||
|
|
||||||
|
### Initial Configuration {#services-open-webui-usage-configuration}
|
||||||
|
|
||||||
The following snippet assumes a few blocks have been setup already:
|
The following snippet assumes a few blocks have been setup already:
|
||||||
|
|
||||||
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
||||||
|
|
@ -63,6 +66,25 @@ The [user](#services-open-webui-options-shb.open-webui.ldap.userGroup)
|
||||||
and [admin](#services-open-webui-options-shb.open-webui.ldap.adminGroup)
|
and [admin](#services-open-webui-options-shb.open-webui.ldap.adminGroup)
|
||||||
LDAP groups are created automatically.
|
LDAP groups are created automatically.
|
||||||
|
|
||||||
|
### Application Dashboard {#services-open-webui-usage-applicationdashboard}
|
||||||
|
|
||||||
|
Integration with the [dashboard contract](contracts-dashboard.html) is provided
|
||||||
|
by the [dashboard option](#services-open-webui-options-shb.open-webui.dashboard).
|
||||||
|
|
||||||
|
For example using the [Homepage](services-homepage.html) service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Documents.services.OpenWebUI = {
|
||||||
|
sortOrder = 1;
|
||||||
|
dashboard.request = config.shb.home-assistant.dashboard.request;
|
||||||
|
settings.icon = "sh-open-webui";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The icon needs to be set manually otherwise it is not displayed correctly.
|
||||||
|
|
||||||
## Integration with OLLAMA {#services-open-webui-ollama}
|
## Integration with OLLAMA {#services-open-webui-ollama}
|
||||||
|
|
||||||
Assuming ollama is enabled, it will be available on port `config.services.ollama.port`.
|
Assuming ollama is enabled, it will be available on port `config.services.ollama.port`.
|
||||||
|
|
|
||||||
|
|
@ -59,10 +59,8 @@ let
|
||||||
mkIf
|
mkIf
|
||||||
lists
|
lists
|
||||||
mkOption
|
mkOption
|
||||||
optionals
|
|
||||||
;
|
;
|
||||||
inherit (lib.types)
|
inherit (lib.types)
|
||||||
attrs
|
|
||||||
attrsOf
|
attrsOf
|
||||||
bool
|
bool
|
||||||
enum
|
enum
|
||||||
|
|
@ -346,6 +344,20 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.paperless.subdomain}.\${config.shb.paperless.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString cfg.port}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
|
||||||
shb,
|
shb,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
|
@ -132,6 +131,20 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.pinchflat.subdomain}.\${config.shb.pinchflat.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString cfg.port}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,14 @@ this one sets up, in a fully declarative manner,
|
||||||
LDAP and SSO integration
|
LDAP and SSO integration
|
||||||
and has a nicer option for secrets.
|
and has a nicer option for secrets.
|
||||||
|
|
||||||
|
## Features {#services-pinchflat-features}
|
||||||
|
|
||||||
|
- Integration with the [dashboard contract](contracts-dashboard.html) for displaying user facing application in a dashboard. [Manual](#services-pinchflat-usage-applicationdashboard)
|
||||||
|
|
||||||
## Usage {#services-pinchflat-usage}
|
## Usage {#services-pinchflat-usage}
|
||||||
|
|
||||||
|
### Initial Configuration {#services-pinchflat-usage-configuration}
|
||||||
|
|
||||||
The following snippet assumes a few blocks have been setup already:
|
The following snippet assumes a few blocks have been setup already:
|
||||||
|
|
||||||
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
- the [secrets block](usage.html#usage-secrets) with SOPS,
|
||||||
|
|
@ -46,7 +52,7 @@ Secrets can be randomly generated with `nix run nixpkgs#openssl -- rand -hex 64`
|
||||||
The [user](#services-pinchflat-options-shb.pinchflat.ldap.userGroup)
|
The [user](#services-pinchflat-options-shb.pinchflat.ldap.userGroup)
|
||||||
LDAP group is created automatically.
|
LDAP group is created automatically.
|
||||||
|
|
||||||
## Backup {#services-pinchflat-usage-backup}
|
### Backup {#services-pinchflat-usage-backup}
|
||||||
|
|
||||||
Backing up Pinchflat using the [Restic block](blocks-restic.html) is done like so:
|
Backing up Pinchflat using the [Restic block](blocks-restic.html) is done like so:
|
||||||
|
|
||||||
|
|
@ -63,6 +69,22 @@ The name `"pinchflat"` in the `instances` can be anything.
|
||||||
The `config.shb.pinchflat.backup` option provides what directories to backup.
|
The `config.shb.pinchflat.backup` option provides what directories to backup.
|
||||||
You can define any number of Restic instances to backup Pinchflat multiple times.
|
You can define any number of Restic instances to backup Pinchflat multiple times.
|
||||||
|
|
||||||
|
### Application Dashboard {#services-pinchflat-usage-applicationdashboard}
|
||||||
|
|
||||||
|
Integration with the [dashboard contract](contracts-dashboard.html) is provided
|
||||||
|
by the [dashboard option](#services-pinchflat-options-shb.pinchflat.dashboard).
|
||||||
|
|
||||||
|
For example using the [Homepage](services-homepage.html) service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Media.services.Pinchflat = {
|
||||||
|
sortOrder = 2;
|
||||||
|
dashboard.request = config.shb.pinchflat.dashboard.request;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Options Reference {#services-pinchflat-options}
|
## Options Reference {#services-pinchflat-options}
|
||||||
|
|
||||||
```{=include=} options
|
```{=include=} options
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,20 @@ in
|
||||||
default = false;
|
default = false;
|
||||||
example = true;
|
example = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dashboard = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Dashboard contract consumer
|
||||||
|
'';
|
||||||
|
default = { };
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = shb.contracts.dashboard.mkRequester {
|
||||||
|
externalUrl = "https://${cfg.subdomain}.${cfg.domain}";
|
||||||
|
externalUrlText = "https://\${config.shb.vaultwarden.subdomain}.\${config.shb.vaultwarden.domain}";
|
||||||
|
internalUrl = "http://127.0.0.1:${toString cfg.port}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ This NixOS module is a service that sets up a [Vaultwarden Server](https://githu
|
||||||
- Backup of the data directory through the [backup contract](./contracts-backup.html).
|
- Backup of the data directory through the [backup contract](./contracts-backup.html).
|
||||||
- [Integration Tests](@REPO@/test/services/vaultwarden.nix)
|
- [Integration Tests](@REPO@/test/services/vaultwarden.nix)
|
||||||
- Tests /admin can only be accessed when authenticated with SSO.
|
- Tests /admin can only be accessed when authenticated with SSO.
|
||||||
- Access to advanced options not exposed here thanks to how NixOS modules work.
|
- Integration with the [dashboard contract](contracts-dashboard.html) for displaying user facing application in a dashboard.
|
||||||
|
|
||||||
## Usage {#services-vaultwarden-usage}
|
## Usage {#services-vaultwarden-usage}
|
||||||
|
|
||||||
|
|
@ -120,6 +120,22 @@ The name `"vaultwarden"` in the `instances` can be anything.
|
||||||
The `config.shb.vaultwarden.backup` option provides what directories to backup.
|
The `config.shb.vaultwarden.backup` option provides what directories to backup.
|
||||||
You can define any number of Restic instances to backup Vaultwarden multiple times.
|
You can define any number of Restic instances to backup Vaultwarden multiple times.
|
||||||
|
|
||||||
|
### Application Dashboard {#services-vaultwarden-usage-applicationdashboard}
|
||||||
|
|
||||||
|
Integration with the [dashboard contract](contracts-dashboard.html) is provided
|
||||||
|
by the [dashboard option](#services-vaultwarden-options-shb.vaultwarden.dashboard).
|
||||||
|
|
||||||
|
For example using the [Homepage](services-homepage.html) service:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
shb.homepage.servicesGroups.Documents.services.Vaultwarden = {
|
||||||
|
sortOrder = 10;
|
||||||
|
dashboard.request = config.shb.vaultwarden.dashboard.request;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Maintenance {#services-vaultwarden-maintenance}
|
## Maintenance {#services-vaultwarden-maintenance}
|
||||||
|
|
||||||
No command-line tool is provided to administer Vaultwarden.
|
No command-line tool is provided to administer Vaultwarden.
|
||||||
|
|
|
||||||
269
test/modules/homepage.nix
Normal file
269
test/modules/homepage.nix
Normal file
|
|
@ -0,0 +1,269 @@
|
||||||
|
{ shb }:
|
||||||
|
{
|
||||||
|
testHomepageAsServiceGroup = {
|
||||||
|
expected = [
|
||||||
|
{
|
||||||
|
"Media" = [
|
||||||
|
{
|
||||||
|
"Jellyfin" = {
|
||||||
|
"href" = "https://example.com/jellyfin";
|
||||||
|
"icon" = "sh-jellyfin";
|
||||||
|
"siteMonitor" = "http://127.0.0.1:8096";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
expr = shb.homepage.asServiceGroup {
|
||||||
|
Media = {
|
||||||
|
services = {
|
||||||
|
Jellyfin = {
|
||||||
|
dashboard.request = {
|
||||||
|
externalUrl = "https://example.com/jellyfin";
|
||||||
|
internalUrl = "http://127.0.0.1:8096";
|
||||||
|
};
|
||||||
|
apiKey = null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testHomepageAsServiceGroupApiKey = {
|
||||||
|
expected = [
|
||||||
|
{
|
||||||
|
"Media" = [
|
||||||
|
{
|
||||||
|
"Jellyfin" = {
|
||||||
|
"href" = "https://example.com/jellyfin";
|
||||||
|
"icon" = "sh-jellyfin";
|
||||||
|
"siteMonitor" = "http://127.0.0.1:8096";
|
||||||
|
"widget" = {
|
||||||
|
"key" = "{{HOMEPAGE_FILE_Media_Jellyfin}}";
|
||||||
|
"password" = "{{HOMEPAGE_FILE_Media_Jellyfin}}";
|
||||||
|
"type" = "jellyfin";
|
||||||
|
"url" = "http://127.0.0.1:8096";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
expr = shb.homepage.asServiceGroup {
|
||||||
|
Media = {
|
||||||
|
services = {
|
||||||
|
Jellyfin = {
|
||||||
|
dashboard.request = {
|
||||||
|
externalUrl = "https://example.com/jellyfin";
|
||||||
|
internalUrl = "http://127.0.0.1:8096";
|
||||||
|
};
|
||||||
|
apiKey.result.path = "path_D";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testHomepageAsServiceGroupNoServiceMonitor = {
|
||||||
|
expected = [
|
||||||
|
{
|
||||||
|
"Media" = [
|
||||||
|
{
|
||||||
|
"Jellyfin" = {
|
||||||
|
"href" = "https://example.com/jellyfin";
|
||||||
|
"icon" = "sh-jellyfin";
|
||||||
|
"siteMonitor" = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
expr = shb.homepage.asServiceGroup {
|
||||||
|
Media = {
|
||||||
|
services = {
|
||||||
|
Jellyfin = {
|
||||||
|
dashboard.request = {
|
||||||
|
externalUrl = "https://example.com/jellyfin";
|
||||||
|
internalUrl = null;
|
||||||
|
};
|
||||||
|
apiKey = null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testHomepageAsServiceGroupOverride = {
|
||||||
|
expected = [
|
||||||
|
{
|
||||||
|
"Media" = [
|
||||||
|
{
|
||||||
|
"Jellyfin" = {
|
||||||
|
"href" = "https://example.com/jellyfin";
|
||||||
|
"icon" = "sh-icon";
|
||||||
|
"siteMonitor" = "http://127.0.0.1:8096";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
expr = shb.homepage.asServiceGroup {
|
||||||
|
Media = {
|
||||||
|
services = {
|
||||||
|
Jellyfin = {
|
||||||
|
dashboard.request = {
|
||||||
|
externalUrl = "https://example.com/jellyfin";
|
||||||
|
internalUrl = "http://127.0.0.1:8096";
|
||||||
|
};
|
||||||
|
settings = {
|
||||||
|
icon = "sh-icon";
|
||||||
|
};
|
||||||
|
apiKey = null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testHomepageAsServiceGroupSortOrder = {
|
||||||
|
expected = [
|
||||||
|
{ "C" = [ ]; }
|
||||||
|
{ "A" = [ ]; }
|
||||||
|
{ "B" = [ ]; }
|
||||||
|
];
|
||||||
|
|
||||||
|
expr = shb.homepage.asServiceGroup {
|
||||||
|
A = {
|
||||||
|
sortOrder = 2;
|
||||||
|
services = { };
|
||||||
|
};
|
||||||
|
B = {
|
||||||
|
sortOrder = 3;
|
||||||
|
services = { };
|
||||||
|
};
|
||||||
|
C = {
|
||||||
|
sortOrder = 1;
|
||||||
|
services = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testHomepageAsServiceServicesSortOrder = {
|
||||||
|
expected = [
|
||||||
|
{
|
||||||
|
"Media" = [
|
||||||
|
{
|
||||||
|
"A" = {
|
||||||
|
"href" = "https://example.com/a";
|
||||||
|
"icon" = "sh-a";
|
||||||
|
"siteMonitor" = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"C" = {
|
||||||
|
"href" = "https://example.com/c";
|
||||||
|
"icon" = "sh-c";
|
||||||
|
"siteMonitor" = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"B" = {
|
||||||
|
"href" = "https://example.com/b";
|
||||||
|
"icon" = "sh-b";
|
||||||
|
"siteMonitor" = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
expr = shb.homepage.asServiceGroup {
|
||||||
|
Media = {
|
||||||
|
sortOrder = null;
|
||||||
|
services = {
|
||||||
|
A = {
|
||||||
|
sortOrder = 1;
|
||||||
|
dashboard.request = {
|
||||||
|
externalUrl = "https://example.com/a";
|
||||||
|
internalUrl = null;
|
||||||
|
};
|
||||||
|
apiKey = null;
|
||||||
|
};
|
||||||
|
B = {
|
||||||
|
sortOrder = 3;
|
||||||
|
dashboard.request = {
|
||||||
|
externalUrl = "https://example.com/b";
|
||||||
|
internalUrl = null;
|
||||||
|
};
|
||||||
|
apiKey = null;
|
||||||
|
};
|
||||||
|
C = {
|
||||||
|
sortOrder = 2;
|
||||||
|
dashboard.request = {
|
||||||
|
externalUrl = "https://example.com/c";
|
||||||
|
internalUrl = null;
|
||||||
|
};
|
||||||
|
apiKey = null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testHomepageAllKeys = {
|
||||||
|
expected = {
|
||||||
|
"A_A" = "path_A";
|
||||||
|
"A_B" = "path_B";
|
||||||
|
"B_D" = "path_D";
|
||||||
|
};
|
||||||
|
|
||||||
|
expr = shb.homepage.allKeys {
|
||||||
|
A = {
|
||||||
|
sortOrder = 1;
|
||||||
|
services = {
|
||||||
|
A = {
|
||||||
|
sortOrder = 1;
|
||||||
|
dashboard.request = {
|
||||||
|
externalUrl = "https://example.com/a";
|
||||||
|
internalUrl = null;
|
||||||
|
};
|
||||||
|
apiKey.result.path = "path_A";
|
||||||
|
};
|
||||||
|
B = {
|
||||||
|
sortOrder = 2;
|
||||||
|
dashboard.request = {
|
||||||
|
externalUrl = "https://example.com/b";
|
||||||
|
internalUrl = null;
|
||||||
|
};
|
||||||
|
apiKey.result.path = "path_B";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
B = {
|
||||||
|
sortOrder = 2;
|
||||||
|
services = {
|
||||||
|
C = {
|
||||||
|
sortOrder = 1;
|
||||||
|
dashboard.request = {
|
||||||
|
externalUrl = "https://example.com/a";
|
||||||
|
internalUrl = null;
|
||||||
|
};
|
||||||
|
apiKey = null;
|
||||||
|
};
|
||||||
|
D = {
|
||||||
|
sortOrder = 2;
|
||||||
|
dashboard.request = {
|
||||||
|
externalUrl = "https://example.com/b";
|
||||||
|
internalUrl = null;
|
||||||
|
};
|
||||||
|
apiKey.result.path = "path_D";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -131,3 +131,4 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// import ./homepage.nix { inherit shb; }
|
||||||
|
|
|
||||||
209
test/services/homepage.nix
Normal file
209
test/services/homepage.nix
Normal file
|
|
@ -0,0 +1,209 @@
|
||||||
|
{ shb, ... }:
|
||||||
|
let
|
||||||
|
commonTestScript = shb.test.mkScripts {
|
||||||
|
hasSSL = { node, ... }: !(isNull node.config.shb.homepage.ssl);
|
||||||
|
waitForServices =
|
||||||
|
{ ... }:
|
||||||
|
[
|
||||||
|
"homepage-dashboard.service"
|
||||||
|
"nginx.service"
|
||||||
|
];
|
||||||
|
waitForPorts =
|
||||||
|
{ node, ... }:
|
||||||
|
[
|
||||||
|
node.config.services.homepage-dashboard.listenPort
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
basic =
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
shb.test.baseModule
|
||||||
|
../../modules/blocks/hardcodedsecret.nix
|
||||||
|
../../modules/services/homepage.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
test = {
|
||||||
|
subdomain = "h";
|
||||||
|
};
|
||||||
|
|
||||||
|
shb.homepage = {
|
||||||
|
enable = true;
|
||||||
|
inherit (config.test) subdomain domain;
|
||||||
|
|
||||||
|
servicesGroups.MyHomeGroup.services.TestService.dashboard = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
clientLogin =
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
shb.test.baseModule
|
||||||
|
shb.test.clientLoginModule
|
||||||
|
];
|
||||||
|
test = {
|
||||||
|
subdomain = "h";
|
||||||
|
};
|
||||||
|
|
||||||
|
test.login = {
|
||||||
|
startUrl = "http://${config.test.fqdn}";
|
||||||
|
# There is no login without SSO integration.
|
||||||
|
testLoginWith = [
|
||||||
|
{
|
||||||
|
username = null;
|
||||||
|
password = null;
|
||||||
|
nextPageExpect = [
|
||||||
|
"expect(page.get_by_text('TestService')).to_be_visible()"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
https =
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
shb.homepage = {
|
||||||
|
ssl = config.shb.certs.certs.selfsigned.n;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ldap =
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
shb.homepage = {
|
||||||
|
ldap = {
|
||||||
|
userGroup = "user_group";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
clientLoginSso =
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
shb.test.baseModule
|
||||||
|
shb.test.clientLoginModule
|
||||||
|
];
|
||||||
|
test = {
|
||||||
|
subdomain = "h";
|
||||||
|
};
|
||||||
|
|
||||||
|
test.login = {
|
||||||
|
startUrl = "https://${config.test.fqdn}";
|
||||||
|
usernameFieldLabelRegex = "Username";
|
||||||
|
passwordFieldLabelRegex = "Password";
|
||||||
|
loginButtonNameRegex = "[sS]ign [iI]n";
|
||||||
|
testLoginWith = [
|
||||||
|
{
|
||||||
|
username = "alice";
|
||||||
|
password = "NotAlicePassword";
|
||||||
|
nextPageExpect = [
|
||||||
|
"expect(page.get_by_text(re.compile('[Ii]ncorrect'))).to_be_visible()"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
username = "alice";
|
||||||
|
password = "AlicePassword";
|
||||||
|
nextPageExpect = [
|
||||||
|
"expect(page.get_by_text(re.compile('[Ii]ncorrect'))).not_to_be_visible()"
|
||||||
|
"expect(page.get_by_role('button', name=re.compile('Sign In'))).not_to_be_visible()"
|
||||||
|
"expect(page.get_by_text('TestService')).to_be_visible(timeout=10000)"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
# Bob, with its admin role only, cannot login into Karakeep because admins do not exist in Karakeep.
|
||||||
|
{
|
||||||
|
username = "charlie";
|
||||||
|
password = "NotCharliePassword";
|
||||||
|
nextPageExpect = [
|
||||||
|
"expect(page.get_by_text(re.compile('[Ii]ncorrect'))).to_be_visible()"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
username = "charlie";
|
||||||
|
password = "CharliePassword";
|
||||||
|
nextPageExpect = [
|
||||||
|
"expect(page).to_have_url(re.compile('.*/authenticated'))"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sso =
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
shb.homepage = {
|
||||||
|
sso = {
|
||||||
|
enable = true;
|
||||||
|
authEndpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
basic = shb.test.runNixOSTest {
|
||||||
|
name = "homepage_basic";
|
||||||
|
|
||||||
|
nodes.client = {
|
||||||
|
imports = [
|
||||||
|
clientLogin
|
||||||
|
];
|
||||||
|
};
|
||||||
|
nodes.server = {
|
||||||
|
imports = [
|
||||||
|
basic
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = commonTestScript.access;
|
||||||
|
};
|
||||||
|
|
||||||
|
https = shb.test.runNixOSTest {
|
||||||
|
name = "homepage_https";
|
||||||
|
|
||||||
|
nodes.client = {
|
||||||
|
imports = [
|
||||||
|
clientLogin
|
||||||
|
];
|
||||||
|
};
|
||||||
|
nodes.server = {
|
||||||
|
imports = [
|
||||||
|
basic
|
||||||
|
shb.test.certs
|
||||||
|
https
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = commonTestScript.access;
|
||||||
|
};
|
||||||
|
|
||||||
|
sso = shb.test.runNixOSTest {
|
||||||
|
name = "homepage_sso";
|
||||||
|
|
||||||
|
nodes.client = {
|
||||||
|
imports = [
|
||||||
|
clientLoginSso
|
||||||
|
];
|
||||||
|
};
|
||||||
|
nodes.server =
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
basic
|
||||||
|
shb.test.certs
|
||||||
|
https
|
||||||
|
shb.test.ldap
|
||||||
|
ldap
|
||||||
|
(shb.test.sso config.shb.certs.certs.selfsigned.n)
|
||||||
|
sso
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = commonTestScript.access.override {
|
||||||
|
redirectSSO = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue