caddy support multi domain
This commit is contained in:
parent
f15e521895
commit
fdcc829acf
13 changed files with 344 additions and 141 deletions
|
|
@ -6,11 +6,20 @@
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
tailscaleMagicDNS = "neon-dory.ts.net";
|
tailscaleMagicDNS = "neon-dory.ts.net";
|
||||||
|
publicDomain = "pazpi.top";
|
||||||
|
tsDomain = "tegola.pro";
|
||||||
|
email = "pasettodavide@gmail.com";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
|
||||||
age.secrets = {
|
age.secrets = {
|
||||||
|
searx-secret.file = ../../secrets/searx-secret.age;
|
||||||
tailscale-authKey.file = ../../secrets/tailscale-authKey.age;
|
tailscale-authKey.file = ../../secrets/tailscale-authKey.age;
|
||||||
|
cloudflare-tegola-apiKey = {
|
||||||
|
file = ../../secrets/cloudflare-tegola-apiKey.age;
|
||||||
|
owner = config.services.caddy.user;
|
||||||
|
group = config.services.caddy.group;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
my = {
|
my = {
|
||||||
|
|
@ -18,10 +27,20 @@ in
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
|
|
||||||
|
dashy = {
|
||||||
|
enable = true;
|
||||||
|
settings = import ./dashy-settings.nix;
|
||||||
|
proxy = {
|
||||||
|
enable = true;
|
||||||
|
domain = tsDomain;
|
||||||
|
host = "caddy.internal";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
media-mgr = {
|
media-mgr = {
|
||||||
proxy = {
|
proxy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
domain = "tegola.pro";
|
domain = tsDomain;
|
||||||
host = "arr.internal";
|
host = "arr.internal";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -29,15 +48,25 @@ in
|
||||||
nextcloud = {
|
nextcloud = {
|
||||||
proxy = {
|
proxy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
domain = "tegola.pro";
|
domain = tsDomain;
|
||||||
host = "nextcloud.internal";
|
host = "nextcloud.internal";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
searx = {
|
||||||
|
enable = true;
|
||||||
|
secretFile = config.age.secrets.searx-secret.path;
|
||||||
|
proxy = {
|
||||||
|
enable = true;
|
||||||
|
domain = tsDomain;
|
||||||
|
host = "caddy.internal";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
vaultwarden = {
|
vaultwarden = {
|
||||||
proxy = {
|
proxy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
domain = "tegola.pro";
|
domain = tsDomain;
|
||||||
host = "vaultwarden.internal";
|
host = "vaultwarden.internal";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -48,7 +77,7 @@ in
|
||||||
prometheus = {
|
prometheus = {
|
||||||
proxy = {
|
proxy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
domain = "tegola.pro";
|
domain = tsDomain;
|
||||||
host = "metrics.internal";
|
host = "metrics.internal";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -56,7 +85,7 @@ in
|
||||||
grafana = {
|
grafana = {
|
||||||
proxy = {
|
proxy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
domain = "tegola.pro";
|
domain = tsDomain;
|
||||||
host = "metrics.internal";
|
host = "metrics.internal";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -71,14 +100,27 @@ in
|
||||||
|
|
||||||
caddy = {
|
caddy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
email = "pasettodavide@gmail.com";
|
domainsList = [
|
||||||
domain = "tegola.pro";
|
{
|
||||||
|
domain = tsDomain;
|
||||||
|
email = email;
|
||||||
|
cloudflareApiKeyFile = config.age.secrets.cloudflare-tegola-apiKey.path;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
# email = "pasettodavide@gmail.com";
|
||||||
|
# domain = tsDomain;
|
||||||
|
# claudflareApiKeyFile = config.age.secrets.cloudflare-tegola-apiKey.path;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
virtualisation = {
|
virtualisation = {
|
||||||
proxmox.enable = true;
|
proxmox.enable = true;
|
||||||
|
portainer.proxy = {
|
||||||
|
enable = true;
|
||||||
|
domain = tsDomain;
|
||||||
|
host = "portainer.internal";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,10 @@ in
|
||||||
|
|
||||||
age.secrets = {
|
age.secrets = {
|
||||||
tailscale-authKey.file = ../../secrets/tailscale-authKey.age;
|
tailscale-authKey.file = ../../secrets/tailscale-authKey.age;
|
||||||
|
grafana-admin-pwd = {
|
||||||
|
file = ../../secrets/grafana-admin-pwd.age;
|
||||||
|
owner = "grafana";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
my = {
|
my = {
|
||||||
|
|
@ -21,7 +25,10 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
monitoring = {
|
monitoring = {
|
||||||
grafana.enable = true;
|
grafana = {
|
||||||
|
enable = true;
|
||||||
|
adminPasswordFile = config.age.secrets.grafana-admin-pwd.path;
|
||||||
|
};
|
||||||
prometheus.enable = true;
|
prometheus.enable = true;
|
||||||
loki.enable = true;
|
loki.enable = true;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,22 @@
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
|
||||||
|
age.secrets = {
|
||||||
|
nextcloud-admin-pwd = {
|
||||||
|
file = ../../secrets/nextcloud-admin-pwd.age;
|
||||||
|
owner = "nextcloud";
|
||||||
|
group = "nextcloud";
|
||||||
|
mode = "770";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
my = {
|
my = {
|
||||||
utils.commons.enable = true;
|
utils.commons.enable = true;
|
||||||
|
|
||||||
services.nextcloud = {
|
services.nextcloud = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
adminPasswordFile = config.age.secrets.nextcloud-admin-pwd.path;
|
||||||
proxy.domain = "tegola.pro";
|
proxy.domain = "tegola.pro";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,14 @@
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
|
||||||
|
age.secrets.vaultwarden-admin-pwd.file = ../../secrets/vaultwarden-admin-pwd.age;
|
||||||
|
|
||||||
my = {
|
my = {
|
||||||
utils.commons.enable = true;
|
utils.commons.enable = true;
|
||||||
services.vaultwarden = {
|
services.vaultwarden = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
adminPasswordFile = config.age.secrets.vaultwarden-admin-pwd.path;
|
||||||
proxy.domain = "tegola.pro";
|
proxy.domain = "tegola.pro";
|
||||||
};
|
};
|
||||||
virtualisation.proxmox.enable = true;
|
virtualisation.proxmox.enable = true;
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,14 @@ in
|
||||||
options.my.monitoring.grafana = {
|
options.my.monitoring.grafana = {
|
||||||
enable = lib.mkEnableOption "Enable grafana as a data visualization";
|
enable = lib.mkEnableOption "Enable grafana as a data visualization";
|
||||||
|
|
||||||
|
adminPasswordFile = lib.mkOption {
|
||||||
|
default = "";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
Path to the file containing the admin password for Grafana
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
proxy = {
|
proxy = {
|
||||||
enable = lib.mkEnableOption "Set the proxy entry for this service";
|
enable = lib.mkEnableOption "Set the proxy entry for this service";
|
||||||
|
|
||||||
|
|
@ -26,6 +34,14 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
default = "grafana";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
The subdomain where Grafana is reachable
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
host = lib.mkOption {
|
host = lib.mkOption {
|
||||||
default = "localhost";
|
default = "localhost";
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
|
|
@ -41,13 +57,6 @@ in
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
(lib.mkIf cfg.enable {
|
(lib.mkIf cfg.enable {
|
||||||
|
|
||||||
age.secrets = {
|
|
||||||
grafana-admin-pwd = {
|
|
||||||
file = ../../secrets/grafana-admin-pwd.age;
|
|
||||||
owner = "grafana";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
|
|
||||||
grafana = {
|
grafana = {
|
||||||
|
|
@ -63,13 +72,14 @@ in
|
||||||
};
|
};
|
||||||
security = {
|
security = {
|
||||||
admin_user = "pazpi";
|
admin_user = "pazpi";
|
||||||
admin_password = "$__file{${config.age.secrets.grafana-admin-pwd.path}}";
|
admin_password = "$__file{${cfg.adminPasswordFile}}";
|
||||||
};
|
};
|
||||||
server = {
|
server = {
|
||||||
domain = "grafana.neon-dory.ts.net";
|
# domain = "grafana.neon-dory.ts.net";
|
||||||
|
domain = cfg.proxy.domain;
|
||||||
http_addr = "0.0.0.0";
|
http_addr = "0.0.0.0";
|
||||||
http_port = 3000;
|
http_port = 3000;
|
||||||
# root_url = "https://grafana.${cfg.proxy.domain}";
|
root_url = "https://${cfg.proxy.subdomain}.${cfg.proxy.domain}";
|
||||||
enable_gzip = true;
|
enable_gzip = true;
|
||||||
};
|
};
|
||||||
users = {
|
users = {
|
||||||
|
|
@ -111,9 +121,9 @@ in
|
||||||
|
|
||||||
(lib.mkIf cfg.proxy.enable {
|
(lib.mkIf cfg.proxy.enable {
|
||||||
services.caddy = with cfg.proxy; {
|
services.caddy = with cfg.proxy; {
|
||||||
virtualHosts."grafana.${domain}".extraConfig = ''
|
virtualHosts."${subdomain}.${domain}".extraConfig = ''
|
||||||
reverse_proxy http://${host}:3000
|
reverse_proxy http://${host}:3000
|
||||||
import cloudflare
|
import cloudflare_${domain}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,14 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
default = "prometheus";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
The subdomain where Prometheus is reachable
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
host = lib.mkOption {
|
host = lib.mkOption {
|
||||||
default = "localhost";
|
default = "localhost";
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
|
|
@ -94,9 +102,9 @@ in
|
||||||
|
|
||||||
(lib.mkIf cfg.proxy.enable {
|
(lib.mkIf cfg.proxy.enable {
|
||||||
services.caddy = with cfg.proxy; {
|
services.caddy = with cfg.proxy; {
|
||||||
virtualHosts."prometheus.${domain}".extraConfig = ''
|
virtualHosts."${subdomain}.${domain}".extraConfig = ''
|
||||||
reverse_proxy http://${host}:9090
|
reverse_proxy http://${host}:9090
|
||||||
import cloudflare
|
import cloudflare_${domain}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ in
|
||||||
services.caddy = with cfg.proxy; {
|
services.caddy = with cfg.proxy; {
|
||||||
virtualHosts."up.${domain}".extraConfig = ''
|
virtualHosts."up.${domain}".extraConfig = ''
|
||||||
reverse_proxy http://${host}:${port}
|
reverse_proxy http://${host}:${port}
|
||||||
import cloudflare
|
import cloudflare_${domain}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -14,53 +14,81 @@ in
|
||||||
options.my.networking.caddy = {
|
options.my.networking.caddy = {
|
||||||
enable = lib.mkEnableOption "Enable caddy as reverse proxy";
|
enable = lib.mkEnableOption "Enable caddy as reverse proxy";
|
||||||
|
|
||||||
domain = lib.mkOption {
|
domainsList = lib.mkOption {
|
||||||
default = "example.com";
|
type = lib.types.listOf (lib.types.attrsOf lib.types.str);
|
||||||
type = lib.types.str;
|
|
||||||
description = ''
|
description = ''
|
||||||
The domain where Caddy is reachable
|
A list of sets, each containing three parameters of type string: domain, email, and cloudflareApiKeyFile.
|
||||||
'';
|
'';
|
||||||
|
default = [
|
||||||
|
{
|
||||||
|
domain = "example.com";
|
||||||
|
email = "user@domain.com";
|
||||||
|
cloudflareApiKeyFile = "/path/to/cloudflare/api/key";
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
email = lib.mkOption {
|
# claudflareApiKeyFile = lib.mkOption {
|
||||||
default = "user@domain.com";
|
# default = "";
|
||||||
type = lib.types.str;
|
# type = lib.types.str;
|
||||||
description = ''
|
# description = ''
|
||||||
Email for Certbot
|
# Cloudflare API key file
|
||||||
'';
|
# '';
|
||||||
};
|
# };
|
||||||
|
|
||||||
|
# domain = lib.mkOption {
|
||||||
|
# default = "example.com";
|
||||||
|
# type = lib.types.str;
|
||||||
|
# description = ''
|
||||||
|
# The domain where Caddy is reachable
|
||||||
|
# '';
|
||||||
|
# };
|
||||||
|
|
||||||
|
# email = lib.mkOption {
|
||||||
|
# default = "user@domain.com";
|
||||||
|
# type = lib.types.str;
|
||||||
|
# description = ''
|
||||||
|
# Email for Certbot
|
||||||
|
# '';
|
||||||
|
# };
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
age.secrets = {
|
|
||||||
cloudflare-tegola-apiKey = {
|
|
||||||
file = ../../secrets/cloudflare-tegola-apiKey.age;
|
|
||||||
owner = config.services.caddy.user;
|
|
||||||
group = config.services.caddy.group;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Insted on relying on caddy to provide TLS, we use certbot to get a certificate
|
# Insted on relying on caddy to provide TLS, we use certbot to get a certificate
|
||||||
# https://aottr.dev/posts/2024/08/homelab-setting-up-caddy-reverse-proxy-with-ssl-on-nixos/
|
# https://aottr.dev/posts/2024/08/homelab-setting-up-caddy-reverse-proxy-with-ssl-on-nixos/
|
||||||
security.acme = {
|
security.acme = {
|
||||||
acceptTerms = true;
|
acceptTerms = true;
|
||||||
defaults.email = cfg.email;
|
|
||||||
|
|
||||||
# TESTING ONLY!
|
# TESTING ONLY!
|
||||||
# defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory";
|
# defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory";
|
||||||
|
|
||||||
certs."${cfg.domain}" = {
|
certs = lib.mkMerge (
|
||||||
group = config.services.caddy.group;
|
map (domainConfig: {
|
||||||
|
"${domainConfig.domain}" = {
|
||||||
|
group = config.services.caddy.group;
|
||||||
|
email = domainConfig.email;
|
||||||
|
domain = domainConfig.domain;
|
||||||
|
extraDomainNames = [ "*.${domainConfig.domain}" ];
|
||||||
|
dnsProvider = "cloudflare";
|
||||||
|
dnsResolver = "1.1.1.1:53";
|
||||||
|
dnsPropagationCheck = true;
|
||||||
|
environmentFile = domainConfig.cloudflareApiKeyFile;
|
||||||
|
};
|
||||||
|
}) cfg.domainsList
|
||||||
|
);
|
||||||
|
|
||||||
domain = "${cfg.domain}";
|
# certs."${cfg.domain}" = {
|
||||||
extraDomainNames = [ "*.${cfg.domain}" ];
|
# group = config.services.caddy.group;
|
||||||
dnsProvider = "cloudflare";
|
|
||||||
dnsResolver = "1.1.1.1:53";
|
# domain = "${cfg.domain}";
|
||||||
dnsPropagationCheck = true;
|
# extraDomainNames = [ "*.${cfg.domain}" ];
|
||||||
environmentFile = config.age.secrets.cloudflare-tegola-apiKey.path;
|
# dnsProvider = "cloudflare";
|
||||||
};
|
# dnsResolver = "1.1.1.1:53";
|
||||||
|
# dnsPropagationCheck = true;
|
||||||
|
# environmentFile = cfg.claudflareApiKeyFile;
|
||||||
|
# };
|
||||||
};
|
};
|
||||||
|
|
||||||
services.caddy = {
|
services.caddy = {
|
||||||
|
|
@ -72,17 +100,33 @@ in
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
extraConfig =
|
extraConfig = lib.concatStringsSep "\n" (
|
||||||
let
|
map (
|
||||||
certPath = config.security.acme.certs."${cfg.domain}".directory;
|
domainConfig:
|
||||||
in
|
let
|
||||||
''
|
certPath = config.security.acme.certs."${domainConfig.domain}".directory;
|
||||||
(cloudflare) {
|
in
|
||||||
tls ${certPath}/cert.pem ${certPath}/key.pem {
|
''
|
||||||
protocols tls1.3
|
(cloudflare_${domainConfig.domain}) {
|
||||||
|
tls ${certPath}/cert.pem ${certPath}/key.pem {
|
||||||
|
protocols tls1.3
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
''
|
||||||
'';
|
) cfg.domainsList
|
||||||
|
);
|
||||||
|
|
||||||
|
# extraConfig =
|
||||||
|
# let
|
||||||
|
# certPath = config.security.acme.certs."${cfg.domain}".directory;
|
||||||
|
# in
|
||||||
|
# ''
|
||||||
|
# (cloudflare) {
|
||||||
|
# tls ${certPath}/cert.pem ${certPath}/key.pem {
|
||||||
|
# protocols tls1.3
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# '';
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.caddy.serviceConfig = {
|
systemd.services.caddy.serviceConfig = {
|
||||||
|
|
|
||||||
|
|
@ -135,31 +135,31 @@ in
|
||||||
services.caddy = with cfg.proxy; {
|
services.caddy = with cfg.proxy; {
|
||||||
virtualHosts."prowlarr.${domain}".extraConfig = ''
|
virtualHosts."prowlarr.${domain}".extraConfig = ''
|
||||||
reverse_proxy http://${host}:9696
|
reverse_proxy http://${host}:9696
|
||||||
import cloudflare
|
import cloudflare_${domain}
|
||||||
'';
|
'';
|
||||||
virtualHosts."radarr.${domain}".extraConfig = ''
|
virtualHosts."radarr.${domain}".extraConfig = ''
|
||||||
reverse_proxy http://${host}:7878
|
reverse_proxy http://${host}:7878
|
||||||
import cloudflare
|
import cloudflare_${domain}
|
||||||
'';
|
'';
|
||||||
virtualHosts."sonarr.${domain}".extraConfig = ''
|
virtualHosts."sonarr.${domain}".extraConfig = ''
|
||||||
reverse_proxy http://${host}:8989
|
reverse_proxy http://${host}:8989
|
||||||
import cloudflare
|
import cloudflare_${domain}
|
||||||
'';
|
'';
|
||||||
virtualHosts."lidarr.${domain}".extraConfig = ''
|
virtualHosts."lidarr.${domain}".extraConfig = ''
|
||||||
reverse_proxy http://${host}:8686
|
reverse_proxy http://${host}:8686
|
||||||
import cloudflare
|
import cloudflare_${domain}
|
||||||
'';
|
'';
|
||||||
virtualHosts."readarr.${domain}".extraConfig = ''
|
virtualHosts."readarr.${domain}".extraConfig = ''
|
||||||
reverse_proxy http://${host}:8787
|
reverse_proxy http://${host}:8787
|
||||||
import cloudflare
|
import cloudflare_${domain}
|
||||||
'';
|
'';
|
||||||
virtualHosts."bazarr.${domain}".extraConfig = ''
|
virtualHosts."bazarr.${domain}".extraConfig = ''
|
||||||
reverse_proxy http://${host}:6767
|
reverse_proxy http://${host}:6767
|
||||||
import cloudflare
|
import cloudflare_${domain}
|
||||||
'';
|
'';
|
||||||
virtualHosts."jellyseerr.${domain}".extraConfig = ''
|
virtualHosts."jellyseerr.${domain}".extraConfig = ''
|
||||||
reverse_proxy http://${host}:5055
|
reverse_proxy http://${host}:5055
|
||||||
import cloudflare
|
import cloudflare_${domain}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,14 @@ in
|
||||||
options.my.services.nextcloud = {
|
options.my.services.nextcloud = {
|
||||||
enable = lib.mkEnableOption "Enable Nextcloud module";
|
enable = lib.mkEnableOption "Enable Nextcloud module";
|
||||||
|
|
||||||
|
adminPasswordFile = lib.mkOption {
|
||||||
|
default = "";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
Path to the file containing the admin password for Nextcloud
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
proxy = {
|
proxy = {
|
||||||
enable = lib.mkEnableOption "Set the proxy entry for this service";
|
enable = lib.mkEnableOption "Set the proxy entry for this service";
|
||||||
|
|
||||||
|
|
@ -23,6 +31,22 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
default = "nextcloud";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
The subdomain where Nextcloud is reachable
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
officeSubdomain = lib.mkOption {
|
||||||
|
default = "office";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
The subdomain where Collabora Online is reachable
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
host = lib.mkOption {
|
host = lib.mkOption {
|
||||||
default = "localhost";
|
default = "localhost";
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
|
|
@ -37,15 +61,6 @@ in
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
(lib.mkIf cfg.enable {
|
(lib.mkIf cfg.enable {
|
||||||
|
|
||||||
age.secrets = {
|
|
||||||
nextcloud-admin-pwd = {
|
|
||||||
file = ../../secrets/nextcloud-admin-pwd.age;
|
|
||||||
owner = "nextcloud";
|
|
||||||
group = "nextcloud";
|
|
||||||
mode = "770";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
|
|
||||||
nextcloud = {
|
nextcloud = {
|
||||||
|
|
@ -90,7 +105,7 @@ in
|
||||||
config = {
|
config = {
|
||||||
dbtype = "pgsql";
|
dbtype = "pgsql";
|
||||||
adminuser = "admin";
|
adminuser = "admin";
|
||||||
adminpassFile = config.age.secrets.nextcloud-admin-pwd.path;
|
adminpassFile = cfg.adminPasswordFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Let NixOS install and configure the database automatically.
|
# Let NixOS install and configure the database automatically.
|
||||||
|
|
@ -160,12 +175,12 @@ in
|
||||||
|
|
||||||
(lib.mkIf cfg.proxy.enable {
|
(lib.mkIf cfg.proxy.enable {
|
||||||
services.caddy = with cfg.proxy; {
|
services.caddy = with cfg.proxy; {
|
||||||
virtualHosts."cloud.${domain}".extraConfig = ''
|
virtualHosts."${subdomain}.${domain}".extraConfig = ''
|
||||||
reverse_proxy http://${host}:80
|
reverse_proxy http://${host}:80
|
||||||
import cloudflare
|
import cloudflare_${domain}
|
||||||
'';
|
'';
|
||||||
virtualHosts."office.${domain}".extraConfig = ''
|
virtualHosts."${officeSubdomain}.${domain}".extraConfig = ''
|
||||||
import cloudflare
|
import cloudflare_${domain}
|
||||||
reverse_proxy http://${host}:${toString config.services.collabora-online.port} {
|
reverse_proxy http://${host}:${toString config.services.collabora-online.port} {
|
||||||
# Required to circumvent bug of Onlyoffice loading mixed non-https content
|
# Required to circumvent bug of Onlyoffice loading mixed non-https content
|
||||||
header_up X-Forwarded-Proto https
|
header_up X-Forwarded-Proto https
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,14 @@ in
|
||||||
options.my.services.searx = {
|
options.my.services.searx = {
|
||||||
enable = lib.mkEnableOption "Enable searXNG module";
|
enable = lib.mkEnableOption "Enable searXNG module";
|
||||||
|
|
||||||
|
secretFile = lib.mkOption {
|
||||||
|
default = "";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
Path to the file containing the secret for searXNG
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
proxy = {
|
proxy = {
|
||||||
enable = lib.mkEnableOption "Set the proxy entry for this service";
|
enable = lib.mkEnableOption "Set the proxy entry for this service";
|
||||||
|
|
||||||
|
|
@ -37,12 +45,10 @@ in
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
(lib.mkIf cfg.enable {
|
(lib.mkIf cfg.enable {
|
||||||
|
|
||||||
age.secrets.searx-secret.file = ../../secrets/searx-secret.age;
|
services.searx = {
|
||||||
|
|
||||||
services.searcx = {
|
|
||||||
enable = true;
|
enable = true;
|
||||||
redisCreateLocally = true;
|
redisCreateLocally = true;
|
||||||
environmentFile = config.age.secrets.searx-secret.path;
|
environmentFile = cfg.secretFile;
|
||||||
settings = {
|
settings = {
|
||||||
general = {
|
general = {
|
||||||
open_metrics = "@METRICS_SECRET@";
|
open_metrics = "@METRICS_SECRET@";
|
||||||
|
|
@ -63,7 +69,7 @@ in
|
||||||
services.caddy = with cfg.proxy; {
|
services.caddy = with cfg.proxy; {
|
||||||
virtualHosts."search.${domain}".extraConfig = ''
|
virtualHosts."search.${domain}".extraConfig = ''
|
||||||
reverse_proxy http://${host}:8080
|
reverse_proxy http://${host}:8080
|
||||||
import cloudflare
|
import cloudflare_${domain}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,14 @@ in
|
||||||
options.my.services.vaultwarden = {
|
options.my.services.vaultwarden = {
|
||||||
enable = lib.mkEnableOption "Enable Vaultwarden module";
|
enable = lib.mkEnableOption "Enable Vaultwarden module";
|
||||||
|
|
||||||
|
adminPasswordFile = lib.mkOption {
|
||||||
|
default = "";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
Path to the file containing the admin password for Vaultwarden
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
proxy = {
|
proxy = {
|
||||||
enable = lib.mkEnableOption "Set the proxy entry for this service";
|
enable = lib.mkEnableOption "Set the proxy entry for this service";
|
||||||
|
|
||||||
|
|
@ -24,6 +32,14 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
default = "vault";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
The subdomain where Vaultwarden is reachable
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
host = lib.mkOption {
|
host = lib.mkOption {
|
||||||
default = "localhost";
|
default = "localhost";
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
|
|
@ -38,8 +54,6 @@ in
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
(lib.mkIf cfg.enable {
|
(lib.mkIf cfg.enable {
|
||||||
|
|
||||||
age.secrets.vaultwarden-admin-pwd.file = ../../secrets/vaultwarden-admin-pwd.age;
|
|
||||||
|
|
||||||
my.services.postgresql = {
|
my.services.postgresql = {
|
||||||
enable = true;
|
enable = true;
|
||||||
ensures = [
|
ensures = [
|
||||||
|
|
@ -53,7 +67,7 @@ in
|
||||||
services.vaultwarden = {
|
services.vaultwarden = {
|
||||||
enable = true;
|
enable = true;
|
||||||
dbBackend = "postgresql";
|
dbBackend = "postgresql";
|
||||||
environmentFile = config.age.secrets.vaultwarden-admin-pwd.path;
|
environmentFile = cfg.adminPasswordFile;
|
||||||
config = {
|
config = {
|
||||||
DOMAIN = "https://vault.${cfg.proxy.domain}";
|
DOMAIN = "https://vault.${cfg.proxy.domain}";
|
||||||
SENDS_ALLOWED = true;
|
SENDS_ALLOWED = true;
|
||||||
|
|
@ -75,9 +89,9 @@ in
|
||||||
|
|
||||||
(lib.mkIf cfg.proxy.enable {
|
(lib.mkIf cfg.proxy.enable {
|
||||||
services.caddy = with cfg.proxy; {
|
services.caddy = with cfg.proxy; {
|
||||||
virtualHosts."vault.${domain}".extraConfig = ''
|
virtualHosts."${subdomain}.${domain}".extraConfig = ''
|
||||||
reverse_proxy http://${host}:${toString rocketPort}
|
reverse_proxy http://${host}:${toString rocketPort}
|
||||||
import cloudflare
|
import cloudflare_${domain}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -43,61 +43,103 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
proxy = {
|
||||||
|
enable = lib.mkEnableOption "Set the proxy entry for this service";
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
|
|
||||||
my.virtualisation.docker.enable = true;
|
|
||||||
|
|
||||||
virtualisation.oci-containers = {
|
|
||||||
backend = "docker"; # Use Docker as the backend
|
|
||||||
|
|
||||||
containers = {
|
|
||||||
portainer = {
|
|
||||||
image = "portainer/portainer-ce:latest";
|
|
||||||
ports = [ "9000:9000" ];
|
|
||||||
volumes = [
|
|
||||||
"/var/run/docker.sock:/var/run/docker.sock"
|
|
||||||
"${cfg.portainerDataDir}:/data" # Add persistent volume for Portainer data
|
|
||||||
];
|
|
||||||
environmentFiles = [ cfg.environmentSecrets ];
|
|
||||||
labels = {
|
|
||||||
"com.centurylinklabs.watchtower.enable" = "true";
|
|
||||||
};
|
|
||||||
autoStart = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
watchtower = lib.mkIf cfg.enableWatchtower {
|
|
||||||
image = "containrrr/watchtower";
|
|
||||||
volumes = [ "/var/run/docker.sock:/var/run/docker.sock" ];
|
|
||||||
autoStart = true;
|
|
||||||
environmentFiles = [ cfg.environmentSecrets ];
|
|
||||||
environment = {
|
|
||||||
"TZ" = "Europe/Rome";
|
|
||||||
"WATCHTOWER_CLEANUP" = "true";
|
|
||||||
"WATCHTOWER_SCHEDULE" = "0 0 4 * * *"; # Run every day at 4am
|
|
||||||
"WATCHTOWER_LABEL_ENABLE" = "true"; # Only update labeled containers
|
|
||||||
"WATCHTOWER_NOTIFICATIONS" = "shoutrrr"; # Use shoutrrr for notifications
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
domain = lib.mkOption {
|
||||||
|
default = "example.com";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
The domain where Caddy is reachable
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
default = "portainer";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
The subdomain where Portainer will be reachable
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
host = lib.mkOption {
|
||||||
|
default = "localhost";
|
||||||
|
type = lib.types.str;
|
||||||
|
description = ''
|
||||||
|
host name where the download manager stack is running
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Ensure the directory exists and has the correct permissions
|
};
|
||||||
systemd.tmpfiles.settings = {
|
|
||||||
"10-portainerDataDir" = {
|
config = lib.mkMerge [
|
||||||
${cfg.portainerDataDir} = {
|
(lib.mkIf cfg.enable {
|
||||||
d = {
|
|
||||||
group = "root";
|
my.virtualisation.docker.enable = true;
|
||||||
mode = "0755";
|
|
||||||
user = "root";
|
virtualisation.oci-containers = {
|
||||||
|
backend = "docker"; # Use Docker as the backend
|
||||||
|
|
||||||
|
containers = {
|
||||||
|
portainer = {
|
||||||
|
image = "portainer/portainer-ce:latest";
|
||||||
|
ports = [ "9000:9000" ];
|
||||||
|
volumes = [
|
||||||
|
"/var/run/docker.sock:/var/run/docker.sock"
|
||||||
|
"${cfg.portainerDataDir}:/data" # Add persistent volume for Portainer data
|
||||||
|
];
|
||||||
|
environmentFiles = [ cfg.environmentSecrets ];
|
||||||
|
labels = {
|
||||||
|
"com.centurylinklabs.watchtower.enable" = "true";
|
||||||
|
};
|
||||||
|
autoStart = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
watchtower = lib.mkIf cfg.enableWatchtower {
|
||||||
|
image = "containrrr/watchtower";
|
||||||
|
volumes = [ "/var/run/docker.sock:/var/run/docker.sock" ];
|
||||||
|
autoStart = true;
|
||||||
|
environmentFiles = [ cfg.environmentSecrets ];
|
||||||
|
environment = {
|
||||||
|
"TZ" = "Europe/Rome";
|
||||||
|
"WATCHTOWER_CLEANUP" = "true";
|
||||||
|
"WATCHTOWER_SCHEDULE" = "0 0 4 * * *"; # Run every day at 4am
|
||||||
|
"WATCHTOWER_LABEL_ENABLE" = "true"; # Only update labeled containers
|
||||||
|
"WATCHTOWER_NOTIFICATIONS" = "shoutrrr"; # Use shoutrrr for notifications
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Ensure the directory exists and has the correct permissions
|
||||||
|
systemd.tmpfiles.settings = {
|
||||||
|
"10-portainerDataDir" = {
|
||||||
|
${cfg.portainerDataDir} = {
|
||||||
|
d = {
|
||||||
|
group = "root";
|
||||||
|
mode = "0755";
|
||||||
|
user = "root";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ 9000 ];
|
networking.firewall.allowedTCPPorts = [ 9000 ];
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
(lib.mkIf cfg.proxy.enable {
|
||||||
|
services.caddy = with cfg.proxy; {
|
||||||
|
virtualHosts."${subdomain}.${domain}".extraConfig = ''
|
||||||
|
reverse_proxy http://${host}:9000
|
||||||
|
import cloudflare_${domain}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue