mirror of
https://github.com/Stunkymonkey/nixos.git
synced 2025-05-24 09:54:40 +02:00
treewide: avoid repetitive keys in attrSets
This commit is contained in:
parent
2a3f606557
commit
4b21221569
19 changed files with 994 additions and 947 deletions
|
@ -65,13 +65,15 @@ let
|
||||||
# Uncomment this to disable compression and speed up image creation time
|
# Uncomment this to disable compression and speed up image creation time
|
||||||
#isoImage.squashfsCompression = "gzip -Xcompression-level 1";
|
#isoImage.squashfsCompression = "gzip -Xcompression-level 1";
|
||||||
|
|
||||||
boot.kernelPackages = linuxPackages_latest;
|
boot = {
|
||||||
# Always copytoram so that, if the image is booted from, e.g., a
|
kernelPackages = linuxPackages_latest;
|
||||||
# USB stick, nothing is mistakenly written to persistent storage.
|
# Always copytoram so that, if the image is booted from, e.g., a
|
||||||
boot.kernelParams = [ "copytoram" ];
|
# USB stick, nothing is mistakenly written to persistent storage.
|
||||||
# Secure defaults
|
kernelParams = [ "copytoram" ];
|
||||||
boot.tmp.cleanOnBoot = true;
|
# Secure defaults
|
||||||
boot.kernel.sysctl = { "kernel.unprivileged_bpf_disabled" = 1; };
|
tmp.cleanOnBoot = true;
|
||||||
|
kernel.sysctl = { "kernel.unprivileged_bpf_disabled" = 1; };
|
||||||
|
};
|
||||||
|
|
||||||
services.pcscd.enable = true;
|
services.pcscd.enable = true;
|
||||||
services.udev.packages = [ yubikey-personalization ];
|
services.udev.packages = [ yubikey-personalization ];
|
||||||
|
@ -121,14 +123,16 @@ let
|
||||||
# Disable networking so the system is air-gapped
|
# Disable networking so the system is air-gapped
|
||||||
# Comment all of these lines out if you'll need internet access
|
# Comment all of these lines out if you'll need internet access
|
||||||
boot.initrd.network.enable = false;
|
boot.initrd.network.enable = false;
|
||||||
networking.dhcpcd.enable = false;
|
networking = {
|
||||||
networking.dhcpcd.allowInterfaces = [ ];
|
dhcpcd.enable = false;
|
||||||
networking.interfaces = { };
|
dhcpcd.allowInterfaces = [ ];
|
||||||
networking.firewall.enable = true;
|
interfaces = { };
|
||||||
networking.useDHCP = false;
|
firewall.enable = true;
|
||||||
networking.useNetworkd = false;
|
useDHCP = false;
|
||||||
networking.wireless.enable = false;
|
useNetworkd = false;
|
||||||
networking.networkmanager.enable = lib.mkForce false;
|
wireless.enable = false;
|
||||||
|
networkmanager.enable = lib.mkForce false;
|
||||||
|
};
|
||||||
|
|
||||||
# Unset history so it's never stored
|
# Unset history so it's never stored
|
||||||
# Set GNUPGHOME to an ephemeral location and configure GPG with the
|
# Set GNUPGHOME to an ephemeral location and configure GPG with the
|
||||||
|
|
|
@ -4,28 +4,30 @@ let
|
||||||
inherit (config.sops) secrets;
|
inherit (config.sops) secrets;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sops.secrets."acme/inwx" = { };
|
sops.secrets = {
|
||||||
sops.secrets."borgbackup/password" = { };
|
"acme/inwx" = { };
|
||||||
sops.secrets."borgbackup/ssh_key" = { };
|
"borgbackup/password" = { };
|
||||||
sops.secrets."sso/auth-key" = { };
|
"borgbackup/ssh_key" = { };
|
||||||
sops.secrets."sso/felix/password-hash" = { };
|
"sso/auth-key" = { };
|
||||||
sops.secrets."sso/felix/totp-secret" = { };
|
"sso/felix/password-hash" = { };
|
||||||
sops.secrets."paperless/password" = { };
|
"sso/felix/totp-secret" = { };
|
||||||
sops.secrets."nextcloud/password" = {
|
"paperless/password" = { };
|
||||||
owner = config.users.users.nextcloud.name;
|
"nextcloud/password" = {
|
||||||
};
|
owner = config.users.users.nextcloud.name;
|
||||||
sops.secrets."nextcloud-exporter/password" = {
|
};
|
||||||
owner = config.users.users.nextcloud-exporter.name;
|
"nextcloud-exporter/password" = {
|
||||||
};
|
owner = config.users.users.nextcloud-exporter.name;
|
||||||
sops.secrets."freshrss/password" = {
|
};
|
||||||
owner = config.users.users.freshrss.name;
|
"freshrss/password" = {
|
||||||
};
|
owner = config.users.users.freshrss.name;
|
||||||
sops.secrets."photoprism/password" = { };
|
};
|
||||||
sops.secrets."grafana/password" = {
|
"photoprism/password" = { };
|
||||||
owner = config.users.users.grafana.name;
|
"grafana/password" = {
|
||||||
};
|
owner = config.users.users.grafana.name;
|
||||||
sops.secrets."matrix-bot/password" = {
|
};
|
||||||
owner = config.systemd.services.go-neb.serviceConfig.User;
|
"matrix-bot/password" = {
|
||||||
|
owner = config.systemd.services.go-neb.serviceConfig.User;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# List services that you want to enable:
|
# List services that you want to enable:
|
||||||
|
|
|
@ -4,16 +4,18 @@ let
|
||||||
inherit (config.sops) secrets;
|
inherit (config.sops) secrets;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
sops.secrets."acme/inwx" = { };
|
sops.secrets = {
|
||||||
sops.secrets."borgbackup/password" = { };
|
"acme/inwx" = { };
|
||||||
sops.secrets."borgbackup/ssh_key" = { };
|
"borgbackup/password" = { };
|
||||||
sops.secrets."dyndns/password" = { };
|
"borgbackup/ssh_key" = { };
|
||||||
sops.secrets."sso/auth-key" = { };
|
"dyndns/password" = { };
|
||||||
sops.secrets."sso/felix/password-hash" = { };
|
"sso/auth-key" = { };
|
||||||
sops.secrets."sso/felix/totp-secret" = { };
|
"sso/felix/password-hash" = { };
|
||||||
sops.secrets."prowlarr/apikey" = { };
|
"sso/felix/totp-secret" = { };
|
||||||
sops.secrets."radarr/apikey" = { };
|
"prowlarr/apikey" = { };
|
||||||
sops.secrets."sonarr/apikey" = { };
|
"radarr/apikey" = { };
|
||||||
|
"sonarr/apikey" = { };
|
||||||
|
};
|
||||||
|
|
||||||
# List services that you want to enable:
|
# List services that you want to enable:
|
||||||
my.services = {
|
my.services = {
|
||||||
|
|
|
@ -25,108 +25,110 @@ in
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
services.prometheus = {
|
services = {
|
||||||
alertmanager = {
|
prometheus = {
|
||||||
enable = true;
|
alertmanager = {
|
||||||
listenAddress = "127.0.0.1";
|
enable = true;
|
||||||
inherit (cfg) port;
|
listenAddress = "127.0.0.1";
|
||||||
configuration = import ./config.nix;
|
inherit (cfg) port;
|
||||||
webExternalUrl = "https://alerts.${domain}";
|
configuration = import ./config.nix;
|
||||||
# fix issue: https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4556
|
webExternalUrl = "https://alerts.${domain}";
|
||||||
extraFlags = [ "--cluster.advertise-address 127.0.0.1:${toString cfg.port}" ];
|
# fix issue: https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4556
|
||||||
|
extraFlags = [ "--cluster.advertise-address 127.0.0.1:${toString cfg.port}" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
alertmanagers = [
|
||||||
|
{
|
||||||
|
static_configs = [
|
||||||
|
{
|
||||||
|
targets = [ "localhost:${toString cfg.port}" ];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
scrapeConfigs = [
|
||||||
|
{
|
||||||
|
job_name = "alertmanager";
|
||||||
|
static_configs = [{
|
||||||
|
targets = [ "127.0.0.1:${toString cfg.port}" ];
|
||||||
|
labels = {
|
||||||
|
instance = config.networking.hostName;
|
||||||
|
};
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
alertmanagers = [
|
grafana.provision = {
|
||||||
{
|
datasources.settings.datasources = [
|
||||||
static_configs = [
|
{
|
||||||
{
|
name = "Alertmanager";
|
||||||
targets = [ "localhost:${toString cfg.port}" ];
|
type = "alertmanager";
|
||||||
}
|
url = "http://127.0.0.1:${toString cfg.port}";
|
||||||
];
|
jsonData = {
|
||||||
}
|
implementation = "prometheus";
|
||||||
];
|
handleGrafanaManagedAlerts = config.services.prometheus.enable;
|
||||||
scrapeConfigs = [
|
|
||||||
{
|
|
||||||
job_name = "alertmanager";
|
|
||||||
static_configs = [{
|
|
||||||
targets = [ "127.0.0.1:${toString cfg.port}" ];
|
|
||||||
labels = {
|
|
||||||
instance = config.networking.hostName;
|
|
||||||
};
|
};
|
||||||
}];
|
}
|
||||||
}
|
];
|
||||||
];
|
};
|
||||||
};
|
|
||||||
|
|
||||||
services.grafana.provision = {
|
grafana.provision = {
|
||||||
datasources.settings.datasources = [
|
dashboards.settings.providers = [
|
||||||
|
{
|
||||||
|
name = "Alertmanager";
|
||||||
|
options.path = pkgs.grafana-dashboards.alertmanager;
|
||||||
|
disableDeletion = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# for mail delivery
|
||||||
|
postfix.enable = true;
|
||||||
|
|
||||||
|
go-neb.config.services = [
|
||||||
{
|
{
|
||||||
name = "Alertmanager";
|
ID = "alertmanager_service";
|
||||||
type = "alertmanager";
|
Type = "alertmanager";
|
||||||
url = "http://127.0.0.1:${toString cfg.port}";
|
UserId = config.my.services.matrix-bot.Username;
|
||||||
jsonData = {
|
Config = {
|
||||||
implementation = "prometheus";
|
# url contains "alertmanager_service" encoded as base64
|
||||||
handleGrafanaManagedAlerts = config.services.prometheus.enable;
|
webhook_url = "http://localhost:4050/services/hooks/YWxlcnRtYW5hZ2VyX3NlcnZpY2U";
|
||||||
};
|
rooms = {
|
||||||
}
|
"${config.my.services.matrix-bot.RoomID}" = {
|
||||||
];
|
#bots:nixos.org
|
||||||
};
|
text_template = ''
|
||||||
|
{{range .Alerts -}} [{{ .Status }}] {{index .Labels "alertname" }}: {{index .Annotations "description"}} {{ end -}}
|
||||||
services.grafana.provision = {
|
'';
|
||||||
dashboards.settings.providers = [
|
# $$severity otherwise envsubst replaces $severity with an empty string
|
||||||
{
|
html_template = ''
|
||||||
name = "Alertmanager";
|
{{range .Alerts -}}
|
||||||
options.path = pkgs.grafana-dashboards.alertmanager;
|
{{ $$severity := index .Labels "severity" }}
|
||||||
disableDeletion = true;
|
{{ if eq .Status "firing" }}
|
||||||
}
|
{{ if eq $$severity "critical"}}
|
||||||
];
|
<font color='red'><b>[FIRING - CRITICAL]</b></font>
|
||||||
};
|
{{ else if eq $$severity "warning"}}
|
||||||
|
<font color='orange'><b>[FIRING - WARNING]</b></font>
|
||||||
# for mail delivery
|
{{ else }}
|
||||||
services.postfix.enable = true;
|
<b>[FIRING - {{ $$severity }}]</b>
|
||||||
|
{{ end }}
|
||||||
services.go-neb.config.services = [
|
|
||||||
{
|
|
||||||
ID = "alertmanager_service";
|
|
||||||
Type = "alertmanager";
|
|
||||||
UserId = config.my.services.matrix-bot.Username;
|
|
||||||
Config = {
|
|
||||||
# url contains "alertmanager_service" encoded as base64
|
|
||||||
webhook_url = "http://localhost:4050/services/hooks/YWxlcnRtYW5hZ2VyX3NlcnZpY2U";
|
|
||||||
rooms = {
|
|
||||||
"${config.my.services.matrix-bot.RoomID}" = {
|
|
||||||
#bots:nixos.org
|
|
||||||
text_template = ''
|
|
||||||
{{range .Alerts -}} [{{ .Status }}] {{index .Labels "alertname" }}: {{index .Annotations "description"}} {{ end -}}
|
|
||||||
'';
|
|
||||||
# $$severity otherwise envsubst replaces $severity with an empty string
|
|
||||||
html_template = ''
|
|
||||||
{{range .Alerts -}}
|
|
||||||
{{ $$severity := index .Labels "severity" }}
|
|
||||||
{{ if eq .Status "firing" }}
|
|
||||||
{{ if eq $$severity "critical"}}
|
|
||||||
<font color='red'><b>[FIRING - CRITICAL]</b></font>
|
|
||||||
{{ else if eq $$severity "warning"}}
|
|
||||||
<font color='orange'><b>[FIRING - WARNING]</b></font>
|
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<b>[FIRING - {{ $$severity }}]</b>
|
<font color='green'><b>[RESOLVED]</b></font>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ else }}
|
{{ index .Labels "alertname"}}: {{ index .Annotations "summary"}}
|
||||||
<font color='green'><b>[RESOLVED]</b></font>
|
(
|
||||||
{{ end }}
|
<a href="{{ index .Annotations "grafana" }}">📈 Grafana</a>,
|
||||||
{{ index .Labels "alertname"}}: {{ index .Annotations "summary"}}
|
<a href="{{ .GeneratorURL }}">🔥 Prometheus</a>,
|
||||||
(
|
<a href="{{ .SilenceURL }}">🔕 Silence</a>
|
||||||
<a href="{{ index .Annotations "grafana" }}">📈 Grafana</a>,
|
)<br/>
|
||||||
<a href="{{ .GeneratorURL }}">🔥 Prometheus</a>,
|
{{end -}}'';
|
||||||
<a href="{{ .SilenceURL }}">🔕 Silence</a>
|
msg_type = "m.text"; # Must be either `m.text` or `m.notice`
|
||||||
)<br/>
|
};
|
||||||
{{end -}}'';
|
|
||||||
msg_type = "m.text"; # Must be either `m.text` or `m.notice`
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
}
|
];
|
||||||
];
|
};
|
||||||
|
|
||||||
my.services.prometheus.rules = {
|
my.services.prometheus.rules = {
|
||||||
alerts_silences_changed = {
|
alerts_silences_changed = {
|
||||||
|
|
|
@ -42,40 +42,49 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
services.prometheus.exporters.blackbox = {
|
services = {
|
||||||
enable = true;
|
prometheus.exporters.blackbox = {
|
||||||
configFile = pkgs.writeText "blackbox-config.yml" (builtins.toJSON blackBoxConfig);
|
enable = true;
|
||||||
};
|
configFile = pkgs.writeText "blackbox-config.yml" (builtins.toJSON blackBoxConfig);
|
||||||
|
};
|
||||||
|
|
||||||
# relabels as in https://github.com/prometheus/blackbox_exporter#prometheus-configuration
|
# relabels as in https://github.com/prometheus/blackbox_exporter#prometheus-configuration
|
||||||
services.prometheus = {
|
prometheus = {
|
||||||
scrapeConfigs = [
|
scrapeConfigs = [
|
||||||
|
{
|
||||||
|
job_name = "blackbox";
|
||||||
|
metrics_path = "/probe";
|
||||||
|
params.module = [ "http_2xx" ];
|
||||||
|
static_configs = [
|
||||||
|
{
|
||||||
|
targets = cfg.http_endpoints;
|
||||||
|
labels = {
|
||||||
|
instance = config.networking.hostName;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
relabel_configs = [
|
||||||
|
{
|
||||||
|
source_labels = [ "__address__" ];
|
||||||
|
target_label = "__param_target";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
source_labels = [ "__param_target" ];
|
||||||
|
target_label = "instance";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
target_label = "__address__";
|
||||||
|
replacement = "127.0.0.1:${toString config.services.prometheus.exporters.blackbox.port}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
grafana.provision.dashboards.settings.providers = [
|
||||||
{
|
{
|
||||||
job_name = "blackbox";
|
name = "Blackbox";
|
||||||
metrics_path = "/probe";
|
options.path = pkgs.grafana-dashboards.blackbox;
|
||||||
params.module = [ "http_2xx" ];
|
disableDeletion = true;
|
||||||
static_configs = [
|
|
||||||
{
|
|
||||||
targets = cfg.http_endpoints;
|
|
||||||
labels = {
|
|
||||||
instance = config.networking.hostName;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
relabel_configs = [
|
|
||||||
{
|
|
||||||
source_labels = [ "__address__" ];
|
|
||||||
target_label = "__param_target";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
source_labels = [ "__param_target" ];
|
|
||||||
target_label = "instance";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
target_label = "__address__";
|
|
||||||
replacement = "127.0.0.1:${toString config.services.prometheus.exporters.blackbox.port}";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
@ -143,12 +152,5 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
services.grafana.provision.dashboards.settings.providers = [
|
|
||||||
{
|
|
||||||
name = "Blackbox";
|
|
||||||
options.path = pkgs.grafana-dashboards.blackbox;
|
|
||||||
disableDeletion = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,46 +27,48 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
services.blocky = {
|
services = {
|
||||||
enable = true;
|
blocky = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
ports = {
|
ports = {
|
||||||
tls = "853";
|
tls = "853";
|
||||||
http = cfg.httpPort;
|
http = cfg.httpPort;
|
||||||
};
|
};
|
||||||
upstream = {
|
upstream = {
|
||||||
default = [
|
default = [
|
||||||
"dns2.digitalcourage.de2" # classic
|
"dns2.digitalcourage.de2" # classic
|
||||||
"tcp-tls:dns3.digitalcourage.de" # DoT
|
"tcp-tls:dns3.digitalcourage.de" # DoT
|
||||||
"https://dns.digitale-gesellschaft.ch/dns-query" # DoH
|
"https://dns.digitale-gesellschaft.ch/dns-query" # DoH
|
||||||
|
];
|
||||||
|
};
|
||||||
|
prometheus.enable = config.services.prometheus.enable;
|
||||||
|
} // cfg.settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
prometheus.scrapeConfigs = [
|
||||||
|
{
|
||||||
|
job_name = "blocky";
|
||||||
|
static_configs = [
|
||||||
|
{
|
||||||
|
targets = [ "127.0.0.1:${toString cfg.httpPort}" ];
|
||||||
|
labels = {
|
||||||
|
instance = config.networking.hostName;
|
||||||
|
};
|
||||||
|
}
|
||||||
];
|
];
|
||||||
};
|
}
|
||||||
prometheus.enable = config.services.prometheus.enable;
|
];
|
||||||
} // cfg.settings;
|
|
||||||
|
# untested
|
||||||
|
grafana.provision.dashboards.settings.providers = [
|
||||||
|
{
|
||||||
|
name = "Blocky";
|
||||||
|
options.path = pkgs.grafana-dashboards.blocky;
|
||||||
|
disableDeletion = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
services.prometheus.scrapeConfigs = [
|
|
||||||
{
|
|
||||||
job_name = "blocky";
|
|
||||||
static_configs = [
|
|
||||||
{
|
|
||||||
targets = [ "127.0.0.1:${toString cfg.httpPort}" ];
|
|
||||||
labels = {
|
|
||||||
instance = config.networking.hostName;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
# untested
|
|
||||||
services.grafana.provision.dashboards.settings.providers = [
|
|
||||||
{
|
|
||||||
name = "Blocky";
|
|
||||||
options.path = pkgs.grafana-dashboards.blocky;
|
|
||||||
disableDeletion = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,66 +16,70 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
services.gitea = {
|
services = {
|
||||||
enable = true;
|
gitea = {
|
||||||
settings = {
|
enable = true;
|
||||||
server = {
|
settings = {
|
||||||
HTTP_PORT = cfg.port;
|
server = {
|
||||||
ROOT_URL = "https://code.${domain}";
|
HTTP_PORT = cfg.port;
|
||||||
|
ROOT_URL = "https://code.${domain}";
|
||||||
|
};
|
||||||
|
session.COOKIE_SECURE = true;
|
||||||
|
service.DISABLE_REGISTRATION = true;
|
||||||
|
ui.DEFAULT_THEME = "arc-green";
|
||||||
|
log.LEVEL = "Warn";
|
||||||
|
metrics.ENABLED = config.services.prometheus.enable;
|
||||||
};
|
};
|
||||||
session.COOKIE_SECURE = true;
|
lfs.enable = true;
|
||||||
service.DISABLE_REGISTRATION = true;
|
};
|
||||||
ui.DEFAULT_THEME = "arc-green";
|
|
||||||
log.LEVEL = "Warn";
|
prometheus = {
|
||||||
metrics.ENABLED = config.services.prometheus.enable;
|
scrapeConfigs = [
|
||||||
|
{
|
||||||
|
job_name = "gitea";
|
||||||
|
static_configs = [
|
||||||
|
{
|
||||||
|
targets = [ "127.0.0.1:${toString cfg.port}" ];
|
||||||
|
labels = {
|
||||||
|
instance = config.networking.hostName;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
grafana.provision = {
|
||||||
|
dashboards.settings.providers = [
|
||||||
|
{
|
||||||
|
name = "Gitea";
|
||||||
|
options.path = pkgs.grafana-dashboards.gitea;
|
||||||
|
disableDeletion = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
lfs.enable = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Proxy to Gitea
|
# Proxy to Gitea
|
||||||
my.services.nginx.virtualHosts = [
|
my.services = {
|
||||||
{
|
nginx.virtualHosts = [
|
||||||
subdomain = "code";
|
|
||||||
inherit (cfg) port;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
my.services.backup = {
|
|
||||||
paths = [
|
|
||||||
config.services.gitea.lfs.contentDir
|
|
||||||
config.services.gitea.repositoryRoot
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
services.prometheus = {
|
|
||||||
scrapeConfigs = [
|
|
||||||
{
|
{
|
||||||
job_name = "gitea";
|
subdomain = "code";
|
||||||
static_configs = [
|
inherit (cfg) port;
|
||||||
{
|
|
||||||
targets = [ "127.0.0.1:${toString cfg.port}" ];
|
|
||||||
labels = {
|
|
||||||
instance = config.networking.hostName;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
|
||||||
services.grafana.provision = {
|
|
||||||
dashboards.settings.providers = [
|
|
||||||
{
|
|
||||||
name = "Gitea";
|
|
||||||
options.path = pkgs.grafana-dashboards.gitea;
|
|
||||||
disableDeletion = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
my.services.prometheus.rules = {
|
backup = {
|
||||||
gitea = {
|
paths = [
|
||||||
condition = ''rate(promhttp_metric_handler_requests_total{job="gitea", code="500"}[5m]) > 3'';
|
config.services.gitea.lfs.contentDir
|
||||||
description = "{{$labels.instance}}: gitea instances error rate went up: {{$value}} errors in 5 minutes";
|
config.services.gitea.repositoryRoot
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
prometheus.rules = {
|
||||||
|
gitea = {
|
||||||
|
condition = ''rate(promhttp_metric_handler_requests_total{job="gitea", code="500"}[5m]) > 3'';
|
||||||
|
description = "{{$labels.instance}}: gitea instances error rate went up: {{$value}} errors in 5 minutes";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,48 +31,51 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
services.hedgedoc = {
|
services = {
|
||||||
enable = true;
|
hedgedoc = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
domain = "notes.${domain}";
|
domain = "notes.${domain}";
|
||||||
inherit (cfg) port;
|
inherit (cfg) port;
|
||||||
host = "127.0.0.1";
|
host = "127.0.0.1";
|
||||||
protocolUseSSL = true;
|
protocolUseSSL = true;
|
||||||
db = {
|
db = {
|
||||||
dialect = "sqlite";
|
dialect = "sqlite";
|
||||||
storage = "/var/lib/hedgedoc/hedgedoc.sqlite";
|
storage = "/var/lib/hedgedoc/hedgedoc.sqlite";
|
||||||
};
|
};
|
||||||
} // cfg.settings;
|
} // cfg.settings;
|
||||||
};
|
};
|
||||||
|
|
||||||
# temporary fix for: https://github.com/NixOS/nixpkgs/issues/198250
|
prometheus = {
|
||||||
#systemd.services.hedgedoc.serviceConfig.StateDirectory = lib.mkForce "/var/lib/hedgedoc";
|
scrapeConfigs = [
|
||||||
systemd.services.hedgedoc.serviceConfig.StateDirectory = lib.mkForce "hedgedoc";
|
{
|
||||||
|
job_name = "hedgedoc";
|
||||||
|
static_configs = [
|
||||||
|
{
|
||||||
|
targets = [ "127.0.0.1:${toString cfg.port}" ];
|
||||||
|
labels = {
|
||||||
|
instance = config.networking.hostName;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
services.prometheus = {
|
grafana.provision.dashboards.settings.providers = [
|
||||||
scrapeConfigs = [
|
|
||||||
{
|
{
|
||||||
job_name = "hedgedoc";
|
name = "Hedgedoc";
|
||||||
static_configs = [
|
options.path = pkgs.grafana-dashboards.hedgedoc;
|
||||||
{
|
disableDeletion = true;
|
||||||
targets = [ "127.0.0.1:${toString cfg.port}" ];
|
|
||||||
labels = {
|
|
||||||
instance = config.networking.hostName;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
services.grafana.provision.dashboards.settings.providers = [
|
# TODO remove for 23.11
|
||||||
{
|
# temporary fix for: https://github.com/NixOS/nixpkgs/issues/198250
|
||||||
name = "Hedgedoc";
|
#systemd.services.hedgedoc.serviceConfig.StateDirectory = lib.mkForce "/var/lib/hedgedoc";
|
||||||
options.path = pkgs.grafana-dashboards.hedgedoc;
|
systemd.services.hedgedoc.serviceConfig.StateDirectory = lib.mkForce "hedgedoc";
|
||||||
disableDeletion = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
my.services.nginx.virtualHosts = [
|
my.services.nginx.virtualHosts = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,53 +37,55 @@
|
||||||
type = lib.types.attrsOf
|
type = lib.types.attrsOf
|
||||||
(lib.types.submodule {
|
(lib.types.submodule {
|
||||||
options = {
|
options = {
|
||||||
dashboard.url = lib.mkOption {
|
dashboard = {
|
||||||
type = lib.types.nullOr lib.types.str;
|
url = lib.mkOption {
|
||||||
description = ''
|
type = lib.types.nullOr lib.types.str;
|
||||||
Url to webapp
|
description = ''
|
||||||
'';
|
Url to webapp
|
||||||
example = "http://192.168.1.10:1234";
|
'';
|
||||||
default = null;
|
example = "http://192.168.1.10:1234";
|
||||||
};
|
default = null;
|
||||||
dashboard.name = lib.mkOption {
|
};
|
||||||
type = lib.types.nullOr lib.types.str;
|
name = lib.mkOption {
|
||||||
description = ''
|
type = lib.types.nullOr lib.types.str;
|
||||||
Application name.
|
description = ''
|
||||||
'';
|
Application name.
|
||||||
example = "App";
|
'';
|
||||||
default = null;
|
example = "App";
|
||||||
};
|
default = null;
|
||||||
dashboard.category = lib.mkOption {
|
};
|
||||||
type = lib.types.nullOr lib.types.str;
|
category = lib.mkOption {
|
||||||
description = ''
|
type = lib.types.nullOr lib.types.str;
|
||||||
App category tag.
|
description = ''
|
||||||
'';
|
App category tag.
|
||||||
example = "app";
|
'';
|
||||||
default = null;
|
example = "app";
|
||||||
};
|
default = null;
|
||||||
dashboard.icon = lib.mkOption {
|
};
|
||||||
type = lib.types.nullOr lib.types.str;
|
icon = lib.mkOption {
|
||||||
description = ''
|
type = lib.types.nullOr lib.types.str;
|
||||||
Font Awesome application icon.
|
description = ''
|
||||||
'';
|
Font Awesome application icon.
|
||||||
example = "rss";
|
'';
|
||||||
default = null;
|
example = "rss";
|
||||||
};
|
default = null;
|
||||||
dashboard.type = lib.mkOption {
|
};
|
||||||
type = lib.types.nullOr lib.types.str;
|
type = lib.mkOption {
|
||||||
description = ''
|
type = lib.types.nullOr lib.types.str;
|
||||||
application type.
|
description = ''
|
||||||
'';
|
application type.
|
||||||
example = "Ping";
|
'';
|
||||||
default = "Ping";
|
example = "Ping";
|
||||||
};
|
default = "Ping";
|
||||||
dashboard.method = lib.mkOption {
|
};
|
||||||
type = lib.types.enum [ "get" "head" ];
|
method = lib.mkOption {
|
||||||
description = ''
|
type = lib.types.enum [ "get" "head" ];
|
||||||
method of request used
|
description = ''
|
||||||
'';
|
method of request used
|
||||||
example = "get";
|
'';
|
||||||
default = "head";
|
example = "get";
|
||||||
|
default = "head";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -62,80 +62,98 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
services.loki = {
|
services = {
|
||||||
enable = true;
|
loki = {
|
||||||
configuration = {
|
enable = true;
|
||||||
server = {
|
configuration = {
|
||||||
http_listen_address = "127.0.0.1";
|
server = {
|
||||||
http_listen_port = cfg.port;
|
http_listen_address = "127.0.0.1";
|
||||||
};
|
http_listen_port = cfg.port;
|
||||||
auth_enabled = false;
|
};
|
||||||
|
auth_enabled = false;
|
||||||
|
|
||||||
common = {
|
common = {
|
||||||
instance_addr = "127.0.0.1";
|
instance_addr = "127.0.0.1";
|
||||||
ring.kvstore.store = "inmemory";
|
ring.kvstore.store = "inmemory";
|
||||||
replication_factor = 1;
|
replication_factor = 1;
|
||||||
path_prefix = "/tmp/loki";
|
path_prefix = "/tmp/loki";
|
||||||
};
|
|
||||||
|
|
||||||
ruler = lib.mkIf config.my.services.alertmanager.enable {
|
|
||||||
storage = {
|
|
||||||
type = "local";
|
|
||||||
local = {
|
|
||||||
# having the "fake" directory is important, because loki is running in single-tenant mode
|
|
||||||
directory = pkgs.writeTextDir "fake/loki-rules.yml" (builtins.toJSON {
|
|
||||||
groups = [
|
|
||||||
{
|
|
||||||
name = "alerting-rules";
|
|
||||||
rules = lib.mapAttrsToList
|
|
||||||
(name: opts: {
|
|
||||||
alert = name;
|
|
||||||
inherit (opts) condition labels;
|
|
||||||
for = opts.time;
|
|
||||||
annotations.description = opts.description;
|
|
||||||
})
|
|
||||||
cfg.rules;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
alertmanager_url = "http://127.0.0.1:${toString config.my.services.alertmanager.port}";
|
ruler = lib.mkIf config.my.services.alertmanager.enable {
|
||||||
enable_alertmanager_v2 = true;
|
storage = {
|
||||||
};
|
type = "local";
|
||||||
|
local = {
|
||||||
schema_config = {
|
# having the "fake" directory is important, because loki is running in single-tenant mode
|
||||||
configs = [{
|
directory = pkgs.writeTextDir "fake/loki-rules.yml" (builtins.toJSON {
|
||||||
from = "2020-05-15";
|
groups = [
|
||||||
store = "boltdb-shipper";
|
{
|
||||||
object_store = "filesystem";
|
name = "alerting-rules";
|
||||||
schema = "v11";
|
rules = lib.mapAttrsToList
|
||||||
index = {
|
(name: opts: {
|
||||||
prefix = "index_";
|
alert = name;
|
||||||
period = "24h";
|
inherit (opts) condition labels;
|
||||||
|
for = opts.time;
|
||||||
|
annotations.description = opts.description;
|
||||||
|
})
|
||||||
|
cfg.rules;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}];
|
|
||||||
|
alertmanager_url = "http://127.0.0.1:${toString config.my.services.alertmanager.port}";
|
||||||
|
enable_alertmanager_v2 = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
schema_config = {
|
||||||
|
configs = [{
|
||||||
|
from = "2020-05-15";
|
||||||
|
store = "boltdb-shipper";
|
||||||
|
object_store = "filesystem";
|
||||||
|
schema = "v11";
|
||||||
|
index = {
|
||||||
|
prefix = "index_";
|
||||||
|
period = "24h";
|
||||||
|
};
|
||||||
|
}];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
services.grafana.provision = {
|
grafana.provision = {
|
||||||
datasources.settings.datasources = [
|
datasources.settings.datasources = [
|
||||||
{
|
{
|
||||||
name = "Loki";
|
name = "Loki";
|
||||||
type = "loki";
|
type = "loki";
|
||||||
access = "proxy";
|
access = "proxy";
|
||||||
url = "http://127.0.0.1:${toString cfg.port}";
|
url = "http://127.0.0.1:${toString cfg.port}";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
dashboards.settings.providers = [
|
dashboards.settings.providers = [
|
||||||
{
|
{
|
||||||
name = "Loki";
|
name = "Loki";
|
||||||
options.path = pkgs.grafana-dashboards.loki;
|
options.path = pkgs.grafana-dashboards.loki;
|
||||||
disableDeletion = true;
|
disableDeletion = true;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
prometheus = {
|
||||||
|
scrapeConfigs = [
|
||||||
|
{
|
||||||
|
job_name = "loki";
|
||||||
|
static_configs = [
|
||||||
|
{
|
||||||
|
targets = [ "127.0.0.1:${toString cfg.port}" ];
|
||||||
|
labels = {
|
||||||
|
instance = config.networking.hostName;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
my.services.loki.rules = {
|
my.services.loki.rules = {
|
||||||
|
@ -144,21 +162,5 @@ in
|
||||||
description = "Loki has a high logging rate";
|
description = "Loki has a high logging rate";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services.prometheus = {
|
|
||||||
scrapeConfigs = [
|
|
||||||
{
|
|
||||||
job_name = "loki";
|
|
||||||
static_configs = [
|
|
||||||
{
|
|
||||||
targets = [ "127.0.0.1:${toString cfg.port}" ];
|
|
||||||
labels = {
|
|
||||||
instance = config.networking.hostName;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,15 +39,49 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
services.navidrome = {
|
services = {
|
||||||
enable = true;
|
navidrome = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
settings = cfg.settings // {
|
settings = cfg.settings // {
|
||||||
Port = cfg.port;
|
Port = cfg.port;
|
||||||
Address = "127.0.0.1";
|
Address = "127.0.0.1";
|
||||||
MusicFolder = cfg.musicFolder;
|
MusicFolder = cfg.musicFolder;
|
||||||
LogLevel = "info";
|
LogLevel = "info";
|
||||||
Prometheus.Enabled = config.services.prometheus.enable;
|
Prometheus.Enabled = config.services.prometheus.enable;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
prometheus = {
|
||||||
|
scrapeConfigs = [
|
||||||
|
{
|
||||||
|
job_name = "navidrome";
|
||||||
|
static_configs = [
|
||||||
|
{
|
||||||
|
targets = [ "127.0.0.1:${toString cfg.port}" ];
|
||||||
|
labels = {
|
||||||
|
instance = config.networking.hostName;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
grafana.provision = {
|
||||||
|
dashboards.settings.providers = [
|
||||||
|
{
|
||||||
|
name = "Navidrome";
|
||||||
|
options.path = pkgs.grafana-dashboards.navidrome;
|
||||||
|
disableDeletion = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
my.services.prometheus.rules = {
|
||||||
|
navidrome_not_enough_albums = {
|
||||||
|
condition = ''http_navidrome_album_count != 1'';
|
||||||
|
description = "navidrome: not enough albums as expected: {{$value}}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,38 +92,6 @@ in
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
services.prometheus = {
|
|
||||||
scrapeConfigs = [
|
|
||||||
{
|
|
||||||
job_name = "navidrome";
|
|
||||||
static_configs = [
|
|
||||||
{
|
|
||||||
targets = [ "127.0.0.1:${toString cfg.port}" ];
|
|
||||||
labels = {
|
|
||||||
instance = config.networking.hostName;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
services.grafana.provision = {
|
|
||||||
dashboards.settings.providers = [
|
|
||||||
{
|
|
||||||
name = "Navidrome";
|
|
||||||
options.path = pkgs.grafana-dashboards.navidrome;
|
|
||||||
disableDeletion = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
my.services.prometheus.rules = {
|
|
||||||
navidrome_not_enough_albums = {
|
|
||||||
condition = ''http_navidrome_album_count != 1'';
|
|
||||||
description = "navidrome: not enough albums as expected: {{$value}}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
webapps.apps.navidrome = {
|
webapps.apps.navidrome = {
|
||||||
dashboard = {
|
dashboard = {
|
||||||
name = "Music";
|
name = "Music";
|
||||||
|
|
|
@ -51,70 +51,103 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
services.nextcloud = {
|
services = {
|
||||||
enable = true;
|
nextcloud = {
|
||||||
package = pkgs.nextcloud27;
|
enable = true;
|
||||||
hostName = "cloud.${domain}";
|
package = pkgs.nextcloud27;
|
||||||
maxUploadSize = cfg.maxSize;
|
hostName = "cloud.${domain}";
|
||||||
autoUpdateApps.enable = true;
|
maxUploadSize = cfg.maxSize;
|
||||||
config = {
|
autoUpdateApps.enable = true;
|
||||||
adminuser = cfg.admin;
|
config = {
|
||||||
adminpassFile = cfg.passwordFile;
|
adminuser = cfg.admin;
|
||||||
inherit (cfg) defaultPhoneRegion;
|
adminpassFile = cfg.passwordFile;
|
||||||
|
inherit (cfg) defaultPhoneRegion;
|
||||||
|
|
||||||
overwriteProtocol = "https"; # Nginx only allows SSL
|
overwriteProtocol = "https"; # Nginx only allows SSL
|
||||||
|
|
||||||
#dbtype = "pgsql";
|
#dbtype = "pgsql";
|
||||||
#dbhost = "/run/postgresql";
|
#dbhost = "/run/postgresql";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraApps = {
|
||||||
|
calendar = let version = "4.5.2"; in pkgs.fetchNextcloudApp {
|
||||||
|
url = "https://github.com/nextcloud-releases/calendar/releases/download/v${version}/calendar-v${version}.tar.gz";
|
||||||
|
sha256 = "sha256-n7GjgAyw2SLoZTEfakmI3IllWUk6o1MF89Zt3WGhR6A=";
|
||||||
|
};
|
||||||
|
contacts = let version = "5.4.2"; in pkgs.fetchNextcloudApp {
|
||||||
|
url = "https://github.com/nextcloud-releases/contacts/releases/download/v${version}/contacts-v${version}.tar.gz";
|
||||||
|
sha256 = "sha256-IkKHJ3MY/UPZqa4H86WGOEOypffMIHyJ9WvMqkq/4t8=";
|
||||||
|
};
|
||||||
|
tasks = let version = "0.15.0"; in pkgs.fetchNextcloudApp {
|
||||||
|
url = "https://github.com/nextcloud/tasks/releases/download/v${version}/tasks.tar.gz";
|
||||||
|
sha256 = "sha256-zMMqtEWiXmhB1C2IeWk8hgP7eacaXLkT7Tgi4NK6PCg=";
|
||||||
|
};
|
||||||
|
deck = let version = "1.11.0"; in pkgs.fetchNextcloudApp {
|
||||||
|
url = "https://github.com/nextcloud/deck/releases/download/v${version}/deck.tar.gz";
|
||||||
|
sha256 = "sha256-stb9057pP8WXIhztNl7H8ymLqSZzSulgKgB2cbib2pQ=";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
extraApps = {
|
#postgresql = {
|
||||||
calendar = let version = "4.5.2"; in pkgs.fetchNextcloudApp {
|
# enable = true;
|
||||||
url = "https://github.com/nextcloud-releases/calendar/releases/download/v${version}/calendar-v${version}.tar.gz";
|
# ensureDatabases = [ "nextcloud" ];
|
||||||
sha256 = "sha256-n7GjgAyw2SLoZTEfakmI3IllWUk6o1MF89Zt3WGhR6A=";
|
# ensureUsers = [
|
||||||
};
|
# {
|
||||||
contacts = let version = "5.4.2"; in pkgs.fetchNextcloudApp {
|
# name = "nextcloud";
|
||||||
url = "https://github.com/nextcloud-releases/contacts/releases/download/v${version}/contacts-v${version}.tar.gz";
|
# ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES";
|
||||||
sha256 = "sha256-IkKHJ3MY/UPZqa4H86WGOEOypffMIHyJ9WvMqkq/4t8=";
|
# }
|
||||||
};
|
# ];
|
||||||
tasks = let version = "0.15.0"; in pkgs.fetchNextcloudApp {
|
#};
|
||||||
url = "https://github.com/nextcloud/tasks/releases/download/v${version}/tasks.tar.gz";
|
|
||||||
sha256 = "sha256-zMMqtEWiXmhB1C2IeWk8hgP7eacaXLkT7Tgi4NK6PCg=";
|
# The service above configures the domain, no need for my wrapper
|
||||||
};
|
nginx.virtualHosts."cloud.${domain}" = {
|
||||||
deck = let version = "1.11.0"; in pkgs.fetchNextcloudApp {
|
forceSSL = true;
|
||||||
url = "https://github.com/nextcloud/deck/releases/download/v${version}/deck.tar.gz";
|
useACMEHost = domain;
|
||||||
sha256 = "sha256-stb9057pP8WXIhztNl7H8ymLqSZzSulgKgB2cbib2pQ=";
|
|
||||||
};
|
# so homer can get the online status
|
||||||
|
extraConfig = lib.optionalString config.my.services.homer.enable ''
|
||||||
|
add_header Access-Control-Allow-Origin https://${domain};
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
prometheus.exporters.nextcloud = {
|
||||||
|
enable = true;
|
||||||
|
url = "https://cloud.${domain}";
|
||||||
|
username = cfg.admin;
|
||||||
|
passwordFile = cfg.exporterPasswordFile;
|
||||||
|
port = cfg.exporterPort;
|
||||||
|
};
|
||||||
|
|
||||||
|
prometheus.scrapeConfigs = [
|
||||||
|
{
|
||||||
|
job_name = "nextcloud";
|
||||||
|
static_configs = [
|
||||||
|
{
|
||||||
|
targets = [ "127.0.0.1:${toString cfg.exporterPort}" ];
|
||||||
|
labels = {
|
||||||
|
instance = config.networking.hostName;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
grafana.provision = {
|
||||||
|
dashboards.settings.providers = [
|
||||||
|
{
|
||||||
|
name = "Nextcloud";
|
||||||
|
options.path = pkgs.grafana-dashboards.nextcloud;
|
||||||
|
disableDeletion = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#services.postgresql = {
|
|
||||||
# enable = true;
|
|
||||||
# ensureDatabases = [ "nextcloud" ];
|
|
||||||
# ensureUsers = [
|
|
||||||
# {
|
|
||||||
# name = "nextcloud";
|
|
||||||
# ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES";
|
|
||||||
# }
|
|
||||||
# ];
|
|
||||||
#};
|
|
||||||
|
|
||||||
#systemd.services."nextcloud-setup" = {
|
#systemd.services."nextcloud-setup" = {
|
||||||
# requires = [ "postgresql.service" ];
|
# requires = [ "postgresql.service" ];
|
||||||
# after = [ "postgresql.service" ];
|
# after = [ "postgresql.service" ];
|
||||||
#};
|
#};
|
||||||
|
|
||||||
# The service above configures the domain, no need for my wrapper
|
|
||||||
services.nginx.virtualHosts."cloud.${domain}" = {
|
|
||||||
forceSSL = true;
|
|
||||||
useACMEHost = domain;
|
|
||||||
|
|
||||||
# so homer can get the online status
|
|
||||||
extraConfig = lib.optionalString config.my.services.homer.enable ''
|
|
||||||
add_header Access-Control-Allow-Origin https://${domain};
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
my.services.backup = {
|
my.services.backup = {
|
||||||
exclude = [
|
exclude = [
|
||||||
# image previews can take up a lot of space
|
# image previews can take up a lot of space
|
||||||
|
@ -122,37 +155,6 @@ in
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
services.prometheus.exporters.nextcloud = {
|
|
||||||
enable = true;
|
|
||||||
url = "https://cloud.${domain}";
|
|
||||||
username = cfg.admin;
|
|
||||||
passwordFile = cfg.exporterPasswordFile;
|
|
||||||
port = cfg.exporterPort;
|
|
||||||
};
|
|
||||||
|
|
||||||
services.prometheus.scrapeConfigs = [
|
|
||||||
{
|
|
||||||
job_name = "nextcloud";
|
|
||||||
static_configs = [
|
|
||||||
{
|
|
||||||
targets = [ "127.0.0.1:${toString cfg.exporterPort}" ];
|
|
||||||
labels = {
|
|
||||||
instance = config.networking.hostName;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
services.grafana.provision = {
|
|
||||||
dashboards.settings.providers = [
|
|
||||||
{
|
|
||||||
name = "Nextcloud";
|
|
||||||
options.path = pkgs.grafana-dashboards.nextcloud;
|
|
||||||
disableDeletion = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
webapps.apps.nextcloud = {
|
webapps.apps.nextcloud = {
|
||||||
dashboard = {
|
dashboard = {
|
||||||
name = "Cloud";
|
name = "Cloud";
|
||||||
|
|
|
@ -153,8 +153,7 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
assertions = [ ]
|
assertions = lib.flip builtins.map cfg.virtualHosts ({ subdomain, ... } @ args:
|
||||||
++ (lib.flip builtins.map cfg.virtualHosts ({ subdomain, ... } @ args:
|
|
||||||
let
|
let
|
||||||
conflicts = [ "port" "root" ];
|
conflicts = [ "port" "root" ];
|
||||||
optionsNotNull = builtins.map (v: args.${v} != null) conflicts;
|
optionsNotNull = builtins.map (v: args.${v} != null) conflicts;
|
||||||
|
@ -167,7 +166,7 @@ in
|
||||||
lib.concatStringsSep ", " (builtins.map (v: "'${v}'") conflicts)
|
lib.concatStringsSep ", " (builtins.map (v: "'${v}'") conflicts)
|
||||||
} configured.
|
} configured.
|
||||||
'';
|
'';
|
||||||
}))
|
})
|
||||||
# ++ (
|
# ++ (
|
||||||
# let
|
# let
|
||||||
# ports = lib.my.mapFilter
|
# ports = lib.my.mapFilter
|
||||||
|
@ -201,184 +200,219 @@ in
|
||||||
# map mkAssertion nonUniques
|
# map mkAssertion nonUniques
|
||||||
# )
|
# )
|
||||||
;
|
;
|
||||||
services.nginx = {
|
services = {
|
||||||
enable = true;
|
nginx = {
|
||||||
statusPage = true; # For monitoring scraping.
|
|
||||||
|
|
||||||
recommendedGzipSettings = true;
|
|
||||||
recommendedOptimisation = true;
|
|
||||||
recommendedTlsSettings = true;
|
|
||||||
recommendedProxySettings = true;
|
|
||||||
recommendedBrotliSettings = true;
|
|
||||||
|
|
||||||
# Only allow PFS-enabled ciphers with AES256
|
|
||||||
sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";
|
|
||||||
|
|
||||||
commonHttpConfig = ''
|
|
||||||
# Add HSTS header with preloading to HTTPS requests.
|
|
||||||
# Adding this header to HTTP requests is discouraged
|
|
||||||
map $scheme $hsts_header {
|
|
||||||
https "max-age=31536000; includeSubdomains; preload";
|
|
||||||
}
|
|
||||||
add_header Strict-Transport-Security $hsts_header;
|
|
||||||
|
|
||||||
# CORS header
|
|
||||||
# some applications set it to wildcard, therefore this overrides it
|
|
||||||
proxy_hide_header Access-Control-Allow-Origin;
|
|
||||||
add_header Access-Control-Allow-Origin https://${config.networking.domain};
|
|
||||||
|
|
||||||
# Minimize information leaked to other domains
|
|
||||||
add_header 'Referrer-Policy' 'strict-origin-when-cross-origin';
|
|
||||||
|
|
||||||
# Disable embedding as a frame
|
|
||||||
add_header X-Frame-Options DENY;
|
|
||||||
|
|
||||||
# Prevent injection of code in other mime types (XSS Attacks)
|
|
||||||
add_header X-Content-Type-Options nosniff;
|
|
||||||
|
|
||||||
# Enable XSS protection of the browser.
|
|
||||||
# May be unnecessary when CSP is configured properly (see above)
|
|
||||||
add_header X-XSS-Protection "1; mode=block";
|
|
||||||
|
|
||||||
# This might create errors
|
|
||||||
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
|
|
||||||
|
|
||||||
# Enable CSP for your services.
|
|
||||||
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
|
|
||||||
'';
|
|
||||||
|
|
||||||
virtualHosts =
|
|
||||||
let
|
|
||||||
genAttrs' = values: f: lib.listToAttrs (map f values);
|
|
||||||
inherit (config.networking) domain;
|
|
||||||
mkVHost = { subdomain, ... } @ args: lib.nameValuePair
|
|
||||||
"${subdomain}.${domain}"
|
|
||||||
(lib.foldl lib.recursiveUpdate { } [
|
|
||||||
# Base configuration
|
|
||||||
{
|
|
||||||
forceSSL = true;
|
|
||||||
useACMEHost = domain;
|
|
||||||
}
|
|
||||||
# Proxy to port
|
|
||||||
(lib.optionalAttrs (args.port != null) {
|
|
||||||
locations."/".proxyPass =
|
|
||||||
"http://127.0.0.1:${toString args.port}";
|
|
||||||
# TODO make ipv6 possible
|
|
||||||
# http://[::1]:${toString args.port};
|
|
||||||
})
|
|
||||||
# Serve filesystem content
|
|
||||||
(lib.optionalAttrs (args.root != null) {
|
|
||||||
inherit (args) root;
|
|
||||||
})
|
|
||||||
# VHost specific configuration
|
|
||||||
args.extraConfig
|
|
||||||
# SSO configuration
|
|
||||||
(lib.optionalAttrs args.sso.enable {
|
|
||||||
extraConfig = (args.extraConfig.extraConfig or "") + ''
|
|
||||||
error_page 401 = @error401;
|
|
||||||
'';
|
|
||||||
locations."@error401".return = ''
|
|
||||||
302 https://${cfg.sso.subdomain}.${config.networking.domain}/login?go=$scheme://$http_host$request_uri
|
|
||||||
'';
|
|
||||||
locations."/" = {
|
|
||||||
extraConfig =
|
|
||||||
(args.extraConfig.locations."/".extraConfig or "") + ''
|
|
||||||
# Use SSO
|
|
||||||
auth_request /sso-auth;
|
|
||||||
# Set username through header
|
|
||||||
auth_request_set $username $upstream_http_x_username;
|
|
||||||
proxy_set_header X-User $username;
|
|
||||||
# Renew SSO cookie on request
|
|
||||||
auth_request_set $cookie $upstream_http_set_cookie;
|
|
||||||
add_header Set-Cookie $cookie;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
locations."/sso-auth" = {
|
|
||||||
proxyPass = "http://localhost:${toString cfg.sso.port}/auth";
|
|
||||||
extraConfig = ''
|
|
||||||
# Do not allow requests from outside
|
|
||||||
internal;
|
|
||||||
# Do not forward the request body
|
|
||||||
proxy_pass_request_body off;
|
|
||||||
proxy_set_header Content-Length "";
|
|
||||||
# Set X-Application according to subdomain for matching
|
|
||||||
proxy_set_header X-Application "${subdomain}";
|
|
||||||
# Set origin URI for matching
|
|
||||||
proxy_set_header X-Origin-URI $request_uri;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
})
|
|
||||||
])
|
|
||||||
;
|
|
||||||
in
|
|
||||||
genAttrs' cfg.virtualHosts mkVHost;
|
|
||||||
sso = {
|
|
||||||
enable = true;
|
enable = true;
|
||||||
configuration = {
|
statusPage = true; # For monitoring scraping.
|
||||||
listen = {
|
|
||||||
addr = "127.0.0.1";
|
recommendedGzipSettings = true;
|
||||||
inherit (cfg.sso) port;
|
recommendedOptimisation = true;
|
||||||
};
|
recommendedTlsSettings = true;
|
||||||
audit_log = {
|
recommendedProxySettings = true;
|
||||||
target = [
|
recommendedBrotliSettings = true;
|
||||||
"fd://stdout"
|
|
||||||
];
|
# Only allow PFS-enabled ciphers with AES256
|
||||||
events = [
|
sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";
|
||||||
"access_denied"
|
|
||||||
"login_success"
|
commonHttpConfig = ''
|
||||||
"login_failure"
|
# Add HSTS header with preloading to HTTPS requests.
|
||||||
"logout"
|
# Adding this header to HTTP requests is discouraged
|
||||||
"validate"
|
map $scheme $hsts_header {
|
||||||
];
|
https "max-age=31536000; includeSubdomains; preload";
|
||||||
headers = [
|
}
|
||||||
"x-origin-uri"
|
add_header Strict-Transport-Security $hsts_header;
|
||||||
"x-application"
|
|
||||||
];
|
# CORS header
|
||||||
};
|
# some applications set it to wildcard, therefore this overrides it
|
||||||
cookie = {
|
proxy_hide_header Access-Control-Allow-Origin;
|
||||||
domain = ".${config.networking.domain}";
|
add_header Access-Control-Allow-Origin https://${config.networking.domain};
|
||||||
secure = true;
|
|
||||||
authentication_key = {
|
# Minimize information leaked to other domains
|
||||||
_secret = cfg.sso.authKeyFile;
|
add_header 'Referrer-Policy' 'strict-origin-when-cross-origin';
|
||||||
};
|
|
||||||
};
|
# Disable embedding as a frame
|
||||||
login = {
|
add_header X-Frame-Options DENY;
|
||||||
title = "Bühlers's SSO";
|
|
||||||
default_method = "simple";
|
# Prevent injection of code in other mime types (XSS Attacks)
|
||||||
hide_mfa_field = false;
|
add_header X-Content-Type-Options nosniff;
|
||||||
names = {
|
|
||||||
simple = "Username / Password";
|
# Enable XSS protection of the browser.
|
||||||
};
|
# May be unnecessary when CSP is configured properly (see above)
|
||||||
};
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
providers = {
|
|
||||||
simple =
|
# This might create errors
|
||||||
let
|
proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
|
||||||
applyUsers = lib.flip lib.mapAttrs cfg.sso.users;
|
|
||||||
in
|
# Enable CSP for your services.
|
||||||
{
|
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
|
||||||
users = applyUsers (_: v: { _secret = v.passwordHashFile; });
|
'';
|
||||||
mfa = applyUsers (_: v: [{
|
|
||||||
provider = "totp";
|
virtualHosts =
|
||||||
attributes = {
|
let
|
||||||
secret = {
|
genAttrs' = values: f: lib.listToAttrs (map f values);
|
||||||
_secret = v.totpSecretFile;
|
inherit (config.networking) domain;
|
||||||
|
mkVHost = { subdomain, ... } @ args: lib.nameValuePair
|
||||||
|
"${subdomain}.${domain}"
|
||||||
|
(lib.foldl lib.recursiveUpdate { } [
|
||||||
|
# Base configuration
|
||||||
|
{
|
||||||
|
forceSSL = true;
|
||||||
|
useACMEHost = domain;
|
||||||
|
}
|
||||||
|
# Proxy to port
|
||||||
|
(lib.optionalAttrs (args.port != null) {
|
||||||
|
locations."/".proxyPass =
|
||||||
|
"http://127.0.0.1:${toString args.port}";
|
||||||
|
# TODO make ipv6 possible
|
||||||
|
# http://[::1]:${toString args.port};
|
||||||
|
})
|
||||||
|
# Serve filesystem content
|
||||||
|
(lib.optionalAttrs (args.root != null) {
|
||||||
|
inherit (args) root;
|
||||||
|
})
|
||||||
|
# VHost specific configuration
|
||||||
|
args.extraConfig
|
||||||
|
# SSO configuration
|
||||||
|
(lib.optionalAttrs args.sso.enable {
|
||||||
|
extraConfig = (args.extraConfig.extraConfig or "") + ''
|
||||||
|
error_page 401 = @error401;
|
||||||
|
'';
|
||||||
|
locations = {
|
||||||
|
"@error401".return = ''
|
||||||
|
302 https://${cfg.sso.subdomain}.${config.networking.domain}/login?go=$scheme://$http_host$request_uri
|
||||||
|
'';
|
||||||
|
"/" = {
|
||||||
|
extraConfig =
|
||||||
|
(args.extraConfig.locations."/".extraConfig or "") + ''
|
||||||
|
# Use SSO
|
||||||
|
auth_request /sso-auth;
|
||||||
|
# Set username through header
|
||||||
|
auth_request_set $username $upstream_http_x_username;
|
||||||
|
proxy_set_header X-User $username;
|
||||||
|
# Renew SSO cookie on request
|
||||||
|
auth_request_set $cookie $upstream_http_set_cookie;
|
||||||
|
add_header Set-Cookie $cookie;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
"/sso-auth" = {
|
||||||
|
proxyPass = "http://localhost:${toString cfg.sso.port}/auth";
|
||||||
|
extraConfig = ''
|
||||||
|
# Do not allow requests from outside
|
||||||
|
internal;
|
||||||
|
# Do not forward the request body
|
||||||
|
proxy_pass_request_body off;
|
||||||
|
proxy_set_header Content-Length "";
|
||||||
|
# Set X-Application according to subdomain for matching
|
||||||
|
proxy_set_header X-Application "${subdomain}";
|
||||||
|
# Set origin URI for matching
|
||||||
|
proxy_set_header X-Origin-URI $request_uri;
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}]);
|
})
|
||||||
inherit (cfg.sso) groups;
|
])
|
||||||
|
;
|
||||||
|
in
|
||||||
|
genAttrs' cfg.virtualHosts mkVHost;
|
||||||
|
sso = {
|
||||||
|
enable = true;
|
||||||
|
configuration = {
|
||||||
|
listen = {
|
||||||
|
addr = "127.0.0.1";
|
||||||
|
inherit (cfg.sso) port;
|
||||||
|
};
|
||||||
|
audit_log = {
|
||||||
|
target = [
|
||||||
|
"fd://stdout"
|
||||||
|
];
|
||||||
|
events = [
|
||||||
|
"access_denied"
|
||||||
|
"login_success"
|
||||||
|
"login_failure"
|
||||||
|
"logout"
|
||||||
|
"validate"
|
||||||
|
];
|
||||||
|
headers = [
|
||||||
|
"x-origin-uri"
|
||||||
|
"x-application"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
cookie = {
|
||||||
|
domain = ".${config.networking.domain}";
|
||||||
|
secure = true;
|
||||||
|
authentication_key = {
|
||||||
|
_secret = cfg.sso.authKeyFile;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
acl = {
|
login = {
|
||||||
rule_sets = [
|
title = "Bühlers's SSO";
|
||||||
{
|
default_method = "simple";
|
||||||
rules = [{ field = "x-application"; present = true; }];
|
hide_mfa_field = false;
|
||||||
allow = [ "@root" ];
|
names = {
|
||||||
}
|
simple = "Username / Password";
|
||||||
];
|
};
|
||||||
|
};
|
||||||
|
providers = {
|
||||||
|
simple =
|
||||||
|
let
|
||||||
|
applyUsers = lib.flip lib.mapAttrs cfg.sso.users;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
users = applyUsers (_: v: { _secret = v.passwordHashFile; });
|
||||||
|
mfa = applyUsers (_: v: [{
|
||||||
|
provider = "totp";
|
||||||
|
attributes = {
|
||||||
|
secret = {
|
||||||
|
_secret = v.totpSecretFile;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
inherit (cfg.sso) groups;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
acl = {
|
||||||
|
rule_sets = [
|
||||||
|
{
|
||||||
|
rules = [{ field = "x-application"; present = true; }];
|
||||||
|
allow = [ "@root" ];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# services.prometheus = lib.mkIf cfg.monitoring.enable {
|
||||||
|
prometheus = {
|
||||||
|
exporters.nginx = {
|
||||||
|
enable = true;
|
||||||
|
listenAddress = "127.0.0.1";
|
||||||
|
};
|
||||||
|
scrapeConfigs = [
|
||||||
|
{
|
||||||
|
job_name = "nginx";
|
||||||
|
static_configs = [
|
||||||
|
{
|
||||||
|
targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.nginx.port}" ];
|
||||||
|
labels = {
|
||||||
|
instance = config.networking.hostName;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
grafana.provision = {
|
||||||
|
dashboards.settings.providers = [
|
||||||
|
{
|
||||||
|
name = "Nginx";
|
||||||
|
options.path = pkgs.grafana-dashboards.nginx;
|
||||||
|
disableDeletion = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
my.services.nginx.virtualHosts = [
|
my.services.nginx.virtualHosts = [
|
||||||
{
|
{
|
||||||
subdomain = "login";
|
subdomain = "login";
|
||||||
|
@ -407,35 +441,5 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# services.prometheus = lib.mkIf cfg.monitoring.enable {
|
|
||||||
services.prometheus = {
|
|
||||||
exporters.nginx = {
|
|
||||||
enable = true;
|
|
||||||
listenAddress = "127.0.0.1";
|
|
||||||
};
|
|
||||||
scrapeConfigs = [
|
|
||||||
{
|
|
||||||
job_name = "nginx";
|
|
||||||
static_configs = [
|
|
||||||
{
|
|
||||||
targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.nginx.port}" ];
|
|
||||||
labels = {
|
|
||||||
instance = config.networking.hostName;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
services.grafana.provision = {
|
|
||||||
dashboards.settings.providers = [
|
|
||||||
{
|
|
||||||
name = "Nginx";
|
|
||||||
options.path = pkgs.grafana-dashboards.nginx;
|
|
||||||
disableDeletion = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,112 +78,116 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
services.prometheus = {
|
services = {
|
||||||
enable = true;
|
prometheus = {
|
||||||
webExternalUrl = "https://monitor.${domain}";
|
enable = true;
|
||||||
inherit (cfg) port;
|
webExternalUrl = "https://monitor.${domain}";
|
||||||
listenAddress = "127.0.0.1";
|
|
||||||
|
|
||||||
inherit (cfg) retentionTime;
|
|
||||||
|
|
||||||
globalConfig = {
|
|
||||||
scrape_interval = cfg.scrapeInterval;
|
|
||||||
};
|
|
||||||
|
|
||||||
ruleFiles = [
|
|
||||||
(pkgs.writeText "prometheus-rules.yml" (builtins.toJSON {
|
|
||||||
groups = [
|
|
||||||
{
|
|
||||||
name = "alerting-rules";
|
|
||||||
rules = lib.mapAttrsToList
|
|
||||||
(name: opts: {
|
|
||||||
alert = name;
|
|
||||||
expr = opts.condition;
|
|
||||||
for = opts.time;
|
|
||||||
inherit (opts) labels;
|
|
||||||
annotations = {
|
|
||||||
inherit (opts) description;
|
|
||||||
grafana = lib.optionalString config.services.grafana.enable "https://visualization.${domain}";
|
|
||||||
};
|
|
||||||
})
|
|
||||||
cfg.rules;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}))
|
|
||||||
];
|
|
||||||
|
|
||||||
scrapeConfigs = [
|
|
||||||
{
|
|
||||||
job_name = "prometheus";
|
|
||||||
static_configs = [{
|
|
||||||
targets = [ "127.0.0.1:${toString cfg.port}" ];
|
|
||||||
labels = {
|
|
||||||
instance = config.networking.hostName;
|
|
||||||
};
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
my.services.node-exporter.enable = true;
|
|
||||||
|
|
||||||
services.grafana.provision = {
|
|
||||||
datasources.settings.datasources = [
|
|
||||||
{
|
|
||||||
name = "Prometheus";
|
|
||||||
type = "prometheus";
|
|
||||||
isDefault = true;
|
|
||||||
url = "http://127.0.0.1:${toString config.services.prometheus.port}";
|
|
||||||
jsonData = {
|
|
||||||
prometheusType = "Prometheus";
|
|
||||||
prometheusVersion = toString pkgs.prometheus.version;
|
|
||||||
timeInterval = config.services.prometheus.globalConfig.scrape_interval;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
dashboards.settings.providers = [
|
|
||||||
{
|
|
||||||
name = "Prometheus";
|
|
||||||
options.path = pkgs.grafana-dashboards.prometheus;
|
|
||||||
disableDeletion = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
my.services.prometheus.rules = {
|
|
||||||
prometheus_too_many_restarts = {
|
|
||||||
condition = ''changes(process_start_time_seconds{job=~"prometheus|alertmanager"}[15m]) > 2'';
|
|
||||||
description = "Prometheus has restarted more than twice in the last 15 minutes. It might be crashlooping";
|
|
||||||
};
|
|
||||||
|
|
||||||
alert_manager_config_not_synced = {
|
|
||||||
condition = ''count(count_values("config_hash", alertmanager_config_hash)) > 1'';
|
|
||||||
description = "Configurations of AlertManager cluster instances are out of sync";
|
|
||||||
};
|
|
||||||
|
|
||||||
prometheus_not_connected_to_alertmanager = {
|
|
||||||
condition = "prometheus_notifications_alertmanagers_discovered < 1";
|
|
||||||
description = "Prometheus cannot connect the alertmanager\n VALUE = {{ $value }}\n LABELS = {{ $labels }}";
|
|
||||||
};
|
|
||||||
|
|
||||||
prometheus_rule_evaluation_failures = {
|
|
||||||
condition = "increase(prometheus_rule_evaluation_failures_total[3m]) > 0";
|
|
||||||
description = "Prometheus encountered {{ $value }} rule evaluation failures, leading to potentially ignored alerts.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}";
|
|
||||||
};
|
|
||||||
|
|
||||||
prometheus_template_expansion_failures = {
|
|
||||||
condition = "increase(prometheus_template_text_expansion_failures_total[3m]) > 0";
|
|
||||||
time = "0m";
|
|
||||||
description = "Prometheus encountered {{ $value }} template text expansion failures\n VALUE = {{ $value }}\n LABELS = {{ $labels }}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
my.services.nginx.virtualHosts = [
|
|
||||||
{
|
|
||||||
subdomain = "monitor";
|
|
||||||
inherit (cfg) port;
|
inherit (cfg) port;
|
||||||
}
|
listenAddress = "127.0.0.1";
|
||||||
];
|
|
||||||
|
inherit (cfg) retentionTime;
|
||||||
|
|
||||||
|
globalConfig = {
|
||||||
|
scrape_interval = cfg.scrapeInterval;
|
||||||
|
};
|
||||||
|
|
||||||
|
ruleFiles = [
|
||||||
|
(pkgs.writeText "prometheus-rules.yml" (builtins.toJSON {
|
||||||
|
groups = [
|
||||||
|
{
|
||||||
|
name = "alerting-rules";
|
||||||
|
rules = lib.mapAttrsToList
|
||||||
|
(name: opts: {
|
||||||
|
alert = name;
|
||||||
|
expr = opts.condition;
|
||||||
|
for = opts.time;
|
||||||
|
inherit (opts) labels;
|
||||||
|
annotations = {
|
||||||
|
inherit (opts) description;
|
||||||
|
grafana = lib.optionalString config.services.grafana.enable "https://visualization.${domain}";
|
||||||
|
};
|
||||||
|
})
|
||||||
|
cfg.rules;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}))
|
||||||
|
];
|
||||||
|
|
||||||
|
scrapeConfigs = [
|
||||||
|
{
|
||||||
|
job_name = "prometheus";
|
||||||
|
static_configs = [{
|
||||||
|
targets = [ "127.0.0.1:${toString cfg.port}" ];
|
||||||
|
labels = {
|
||||||
|
instance = config.networking.hostName;
|
||||||
|
};
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
grafana.provision = {
|
||||||
|
datasources.settings.datasources = [
|
||||||
|
{
|
||||||
|
name = "Prometheus";
|
||||||
|
type = "prometheus";
|
||||||
|
isDefault = true;
|
||||||
|
url = "http://127.0.0.1:${toString config.services.prometheus.port}";
|
||||||
|
jsonData = {
|
||||||
|
prometheusType = "Prometheus";
|
||||||
|
prometheusVersion = toString pkgs.prometheus.version;
|
||||||
|
timeInterval = config.services.prometheus.globalConfig.scrape_interval;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
dashboards.settings.providers = [
|
||||||
|
{
|
||||||
|
name = "Prometheus";
|
||||||
|
options.path = pkgs.grafana-dashboards.prometheus;
|
||||||
|
disableDeletion = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
my.services = {
|
||||||
|
node-exporter.enable = true;
|
||||||
|
|
||||||
|
prometheus.rules = {
|
||||||
|
prometheus_too_many_restarts = {
|
||||||
|
condition = ''changes(process_start_time_seconds{job=~"prometheus|alertmanager"}[15m]) > 2'';
|
||||||
|
description = "Prometheus has restarted more than twice in the last 15 minutes. It might be crashlooping";
|
||||||
|
};
|
||||||
|
|
||||||
|
alert_manager_config_not_synced = {
|
||||||
|
condition = ''count(count_values("config_hash", alertmanager_config_hash)) > 1'';
|
||||||
|
description = "Configurations of AlertManager cluster instances are out of sync";
|
||||||
|
};
|
||||||
|
|
||||||
|
prometheus_not_connected_to_alertmanager = {
|
||||||
|
condition = "prometheus_notifications_alertmanagers_discovered < 1";
|
||||||
|
description = "Prometheus cannot connect the alertmanager\n VALUE = {{ $value }}\n LABELS = {{ $labels }}";
|
||||||
|
};
|
||||||
|
|
||||||
|
prometheus_rule_evaluation_failures = {
|
||||||
|
condition = "increase(prometheus_rule_evaluation_failures_total[3m]) > 0";
|
||||||
|
description = "Prometheus encountered {{ $value }} rule evaluation failures, leading to potentially ignored alerts.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}";
|
||||||
|
};
|
||||||
|
|
||||||
|
prometheus_template_expansion_failures = {
|
||||||
|
condition = "increase(prometheus_template_text_expansion_failures_total[3m]) > 0";
|
||||||
|
time = "0m";
|
||||||
|
description = "Prometheus encountered {{ $value }} template text expansion failures\n VALUE = {{ $value }}\n LABELS = {{ $labels }}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nginx.virtualHosts = [
|
||||||
|
{
|
||||||
|
subdomain = "monitor";
|
||||||
|
inherit (cfg) port;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
webapps.apps = {
|
webapps.apps = {
|
||||||
prometheus.dashboard = {
|
prometheus.dashboard = {
|
||||||
|
|
|
@ -19,32 +19,34 @@ in
|
||||||
autoPrune.enable = true;
|
autoPrune.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.cadvisor.enable = config.services.prometheus.enable;
|
services = {
|
||||||
|
cadvisor.enable = config.services.prometheus.enable;
|
||||||
|
|
||||||
services.prometheus = {
|
prometheus = {
|
||||||
scrapeConfigs = [
|
scrapeConfigs = [
|
||||||
{
|
{
|
||||||
job_name = "docker";
|
job_name = "docker";
|
||||||
static_configs = [
|
static_configs = [
|
||||||
{
|
{
|
||||||
targets = [ "127.0.0.1:${toString config.services.cadvisor.port}" ];
|
targets = [ "127.0.0.1:${toString config.services.cadvisor.port}" ];
|
||||||
labels = {
|
labels = {
|
||||||
instance = config.networking.hostName;
|
instance = config.networking.hostName;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
# dashboard untested
|
# dashboard untested
|
||||||
services.grafana.provision = {
|
grafana.provision = {
|
||||||
dashboards.settings.providers = [
|
dashboards.settings.providers = [
|
||||||
{
|
{
|
||||||
name = "Docker";
|
name = "Docker";
|
||||||
options.path = pkgs.grafana-dashboards.cadvisor;
|
options.path = pkgs.grafana-dashboards.cadvisor;
|
||||||
disableDeletion = true;
|
disableDeletion = true;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,10 @@ in
|
||||||
|
|
||||||
programs.steam.enable = true;
|
programs.steam.enable = true;
|
||||||
|
|
||||||
hardware.opengl.driSupport32Bit = true;
|
hardware = {
|
||||||
hardware.opengl.extraPackages32 = with pkgs.pkgsi686Linux; [ libva ];
|
opengl.driSupport32Bit = true;
|
||||||
hardware.pulseaudio.support32Bit = true;
|
opengl.extraPackages32 = with pkgs.pkgsi686Linux; [ libva ];
|
||||||
|
pulseaudio.support32Bit = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ in
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
programs.gnome-disks.enable = true;
|
programs.gnome-disks.enable = true;
|
||||||
services.udisks2.enable = true;
|
|
||||||
|
|
||||||
xdg.mime.enable = true;
|
xdg.mime.enable = true;
|
||||||
|
|
||||||
|
@ -17,9 +16,12 @@ in
|
||||||
programs.dconf.enable = true;
|
programs.dconf.enable = true;
|
||||||
|
|
||||||
# gnome services
|
# gnome services
|
||||||
services.dbus.packages = [ pkgs.dconf ];
|
services = {
|
||||||
services.udev.packages = [ pkgs.gnome.gnome-settings-daemon ];
|
udisks2.enable = true;
|
||||||
services.gnome.gnome-keyring.enable = true;
|
dbus.packages = [ pkgs.dconf ];
|
||||||
|
udev.packages = [ pkgs.gnome.gnome-settings-daemon ];
|
||||||
|
gnome.gnome-keyring.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
glib
|
glib
|
||||||
|
|
|
@ -14,24 +14,26 @@ in
|
||||||
# enable trash & network-mount
|
# enable trash & network-mount
|
||||||
services.gvfs.enable = true;
|
services.gvfs.enable = true;
|
||||||
|
|
||||||
environment.sessionVariables.NAUTILUS_4_EXTENSION_DIR = "${config.system.path}/lib/nautilus/extensions-4";
|
|
||||||
environment.pathsToLink = [
|
|
||||||
"/share/nautilus-python/extensions"
|
|
||||||
];
|
|
||||||
|
|
||||||
services.gnome.glib-networking.enable = true; # network-mount
|
services.gnome.glib-networking.enable = true; # network-mount
|
||||||
|
|
||||||
# default-programs
|
# default-programs
|
||||||
xdg.mime.enable = true;
|
xdg.mime.enable = true;
|
||||||
xdg.icons.enable = true;
|
xdg.icons.enable = true;
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment = {
|
||||||
gnome.nautilus
|
systemPackages = with pkgs; [
|
||||||
|
gnome.nautilus
|
||||||
|
|
||||||
ffmpegthumbnailer # thumbnails
|
ffmpegthumbnailer # thumbnails
|
||||||
gnome.nautilus-python # enable plugins
|
gnome.nautilus-python # enable plugins
|
||||||
gst_all_1.gst-libav # thumbnails
|
gst_all_1.gst-libav # thumbnails
|
||||||
nautilus-open-any-terminal # terminal-context-entry
|
nautilus-open-any-terminal # terminal-context-entry
|
||||||
];
|
];
|
||||||
|
|
||||||
|
sessionVariables.NAUTILUS_4_EXTENSION_DIR = "${config.system.path}/lib/nautilus/extensions-4";
|
||||||
|
pathsToLink = [
|
||||||
|
"/share/nautilus-python/extensions"
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,48 +28,50 @@ in
|
||||||
];
|
];
|
||||||
environment.pathsToLink = [ "/libexec" ];
|
environment.pathsToLink = [ "/libexec" ];
|
||||||
|
|
||||||
programs.wshowkeys.enable = true;
|
programs = {
|
||||||
programs.light.enable = true;
|
wshowkeys.enable = true;
|
||||||
|
light.enable = true;
|
||||||
|
|
||||||
programs.sway = {
|
sway = {
|
||||||
enable = true;
|
enable = true;
|
||||||
wrapperFeatures = {
|
wrapperFeatures = {
|
||||||
gtk = true;
|
gtk = true;
|
||||||
base = true;
|
base = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
extraPackages = with pkgs; [
|
||||||
|
brightnessctl
|
||||||
|
dmenu
|
||||||
|
foot
|
||||||
|
gammastep
|
||||||
|
grim
|
||||||
|
i3status-rust
|
||||||
|
mako
|
||||||
|
slurp
|
||||||
|
swayidle
|
||||||
|
swaylock
|
||||||
|
wdisplays
|
||||||
|
wf-recorder
|
||||||
|
wl-clipboard
|
||||||
|
wofi
|
||||||
|
xwayland
|
||||||
|
# wshowkeys
|
||||||
|
];
|
||||||
|
|
||||||
|
extraSessionCommands = ''
|
||||||
|
export XDG_SESSION_TYPE=wayland
|
||||||
|
export XDG_CURRENT_DESKTOP=sway
|
||||||
|
export SDL_VIDEODRIVER=wayland
|
||||||
|
export QT_QPA_PLATFORM=wayland
|
||||||
|
export QT_WAYLAND_DISABLE_WINDOWDECORATION="1"
|
||||||
|
export _JAVA_AWT_WM_NONREPARENTING=1
|
||||||
|
export CLUTTER_BACKEND=wayland
|
||||||
|
export SAL_USE_VCLPLUGIN=gtk3
|
||||||
|
export MOZ_ENABLE_WAYLAND=1
|
||||||
|
export MOZ_USE_XINPUT2=1
|
||||||
|
export NIXOS_OZONE_WL=1
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
extraPackages = with pkgs; [
|
|
||||||
brightnessctl
|
|
||||||
dmenu
|
|
||||||
foot
|
|
||||||
gammastep
|
|
||||||
grim
|
|
||||||
i3status-rust
|
|
||||||
mako
|
|
||||||
slurp
|
|
||||||
swayidle
|
|
||||||
swaylock
|
|
||||||
wdisplays
|
|
||||||
wf-recorder
|
|
||||||
wl-clipboard
|
|
||||||
wofi
|
|
||||||
xwayland
|
|
||||||
# wshowkeys
|
|
||||||
];
|
|
||||||
|
|
||||||
extraSessionCommands = ''
|
|
||||||
export XDG_SESSION_TYPE=wayland
|
|
||||||
export XDG_CURRENT_DESKTOP=sway
|
|
||||||
export SDL_VIDEODRIVER=wayland
|
|
||||||
export QT_QPA_PLATFORM=wayland
|
|
||||||
export QT_WAYLAND_DISABLE_WINDOWDECORATION="1"
|
|
||||||
export _JAVA_AWT_WM_NONREPARENTING=1
|
|
||||||
export CLUTTER_BACKEND=wayland
|
|
||||||
export SAL_USE_VCLPLUGIN=gtk3
|
|
||||||
export MOZ_ENABLE_WAYLAND=1
|
|
||||||
export MOZ_USE_XINPUT2=1
|
|
||||||
export NIXOS_OZONE_WL=1
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue