diff --git a/lib/lists.nix b/lib/lists.nix new file mode 100644 index 0000000..190198e --- /dev/null +++ b/lib/lists.nix @@ -0,0 +1,27 @@ +{ lib, ... }: +let + inherit (lib) filter foldl'; +in +{ + # Count the number of appararitions of each value in a list. + # + # countValues :: + # [ any ] -> ({ any = int; }) + countValues = + let + addToCount = acc: x: + let + v = toString x; + in + acc // { ${v} = (acc.${v} or 0) + 1; }; + in + foldl' addToCount { }; + + # Filter a list using a predicate function after applying a map. + # + # mapFilter :: + # (value -> bool) + # (any -> value) + # [ any ] + mapFilter = pred: f: attrs: filter pred (map f attrs); +} diff --git a/modules/services/blog.nix b/modules/services/blog.nix index 0a5fcf1..9149917 100644 --- a/modules/services/blog.nix +++ b/modules/services/blog.nix @@ -4,28 +4,12 @@ let cfg = config.my.services.blog; domain = config.networking.domain; - makeHostInfo = name: { - name = "${name}.${domain}"; - value = "/var/www/${name}"; + makeHostInfo = subdomain: { + inherit subdomain; + root = "/var/www/${subdomain}"; }; - hostsInfo = [ - { - name = domain; - value = "/var/www/blog"; - } - ] ++ builtins.map makeHostInfo [ "cv" "dev" "key" ]; - - hosts = builtins.listToAttrs hostsInfo; - - makeVirtualHost = with lib.attrsets; - name: root: nameValuePair "${name}" { - forceSSL = true; - useACMEHost = domain; - inherit root; - # Make my blog the default landing site - default = (name == domain); - }; + hostsInfo = map makeHostInfo [ "cv" "dev" "key" ]; in { options.my.services.blog = { @@ -33,7 +17,17 @@ in }; config = lib.mkIf cfg.enable { - services.nginx.virtualHosts = with lib.attrsets; - mapAttrs' makeVirtualHost hosts; + services.nginx.virtualHosts = { + # This is not a subdomain, cannot use my nginx wrapper module + ${domain} = { + forceSSL = true; + useACMEHost = domain; + root = "/var/www/blog"; + default = true; # Redirect to my blog + }; + }; + + # Those are all subdomains, no problem + my.services.nginx.virtualHosts = hostsInfo; }; } diff --git a/modules/services/calibre-web.nix b/modules/services/calibre-web.nix index d4d7ece..a62b74c 100644 --- a/modules/services/calibre-web.nix +++ b/modules/services/calibre-web.nix @@ -1,8 +1,6 @@ { config, lib, ... }: let cfg = config.my.services.calibre-web; - domain = config.networking.domain; - calibreDomain = "library.${domain}"; in { options.my.services.calibre-web = with lib; { @@ -39,12 +37,12 @@ in }; }; - services.nginx.virtualHosts."${calibreDomain}" = { - forceSSL = true; - useACMEHost = domain; - - locations."/".proxyPass = "http://127.0.0.1:${toString cfg.port}/"; - }; + my.services.nginx.virtualHosts = [ + { + subdomain = "library"; + inherit (cfg) port; + } + ]; my.services.backup = { paths = [ diff --git a/modules/services/drone.nix b/modules/services/drone.nix index b1e80ea..7a9b668 100644 --- a/modules/services/drone.nix +++ b/modules/services/drone.nix @@ -6,9 +6,6 @@ let cfg = config.my.services.drone; - domain = config.networking.domain; - droneDomain = "drone.${domain}"; - hasRunner = (name: builtins.elem name cfg.runners); execPkg = pkgs.drone-runner-exec; @@ -59,7 +56,7 @@ in ]; Environment = [ "DRONE_DATABASE_DATASOURCE=postgres:///drone?host=/run/postgresql" - "DRONE_SERVER_HOST=${droneDomain}" + "DRONE_SERVER_HOST=drone.${config.networking.domain}" "DRONE_SERVER_PROTO=https" "DRONE_DATABASE_DRIVER=postgres" "DRONE_SERVER_PORT=:${toString cfg.port}" @@ -91,12 +88,12 @@ in }]; }; - services.nginx.virtualHosts."${droneDomain}" = { - forceSSL = true; - useACMEHost = domain; - - locations."/".proxyPass = "http://127.0.0.1:${toString cfg.port}"; - }; + my.services.nginx.virtualHosts = [ + { + subdomain = "drone"; + inherit (cfg) port; + } + ]; # Docker runner systemd.services.drone-runner-docker = lib.mkIf (hasRunner "docker") { @@ -107,7 +104,7 @@ in confinement.enable = true; serviceConfig = { Environment = [ - "DRONE_SERVER_HOST=${droneDomain}" + "DRONE_SERVER_HOST=drone.${config.networking.domain}" "DRONE_SERVER_PROTO=https" "DRONE_RUNNER_CAPACITY=10" "CLIENT_DRONE_RPC_HOST=127.0.0.1:${toString cfg.port}" @@ -156,7 +153,7 @@ in ]; serviceConfig = { Environment = [ - "DRONE_SERVER_HOST=${droneDomain}" + "DRONE_SERVER_HOST=drone.${config.networking.domain}" "DRONE_SERVER_PROTO=https" "DRONE_RUNNER_CAPACITY=10" "CLIENT_DRONE_RPC_HOST=127.0.0.1:${toString cfg.port}" diff --git a/modules/services/flood.nix b/modules/services/flood.nix index 70988cb..ae8e219 100644 --- a/modules/services/flood.nix +++ b/modules/services/flood.nix @@ -2,9 +2,6 @@ { config, lib, pkgs, ... }: let cfg = config.my.services.flood; - - domain = config.networking.domain; - webuiDomain = "flood.${domain}"; in { options.my.services.flood = with lib; { @@ -43,11 +40,11 @@ in }; }; - services.nginx.virtualHosts."${webuiDomain}" = { - forceSSL = true; - useACMEHost = domain; - - locations."/".proxyPass = "http://127.0.0.1:${toString cfg.port}"; - }; + my.services.nginx.virtualHosts = [ + { + subdomain = "flood"; + inherit (cfg) port; + } + ]; }; } diff --git a/modules/services/gitea.nix b/modules/services/gitea.nix index ea739d5..0ece12c 100644 --- a/modules/services/gitea.nix +++ b/modules/services/gitea.nix @@ -2,8 +2,6 @@ { config, lib, ... }: let cfg = config.my.services.gitea; - domain = config.networking.domain; - giteaDomain = "gitea.${config.networking.domain}"; in { options.my.services.gitea = with lib; { @@ -17,34 +15,38 @@ in }; config = lib.mkIf cfg.enable { - services.gitea = { - enable = true; + services.gitea = + let + giteaDomain = "gitea.${config.networking.domain}"; + in + { + enable = true; - appName = "Ambroisie's forge"; - httpPort = cfg.port; - domain = giteaDomain; - rootUrl = "https://${giteaDomain}"; + appName = "Ambroisie's forge"; + httpPort = cfg.port; + domain = giteaDomain; + rootUrl = "https://${giteaDomain}"; - user = "git"; - lfs.enable = true; + user = "git"; + lfs.enable = true; - useWizard = false; - disableRegistration = true; + useWizard = false; + disableRegistration = true; - # only send cookies via HTTPS - cookieSecure = true; + # only send cookies via HTTPS + cookieSecure = true; - database = { - type = "postgres"; # Automatic setup - user = "git"; # User needs to be the same as gitea user + database = { + type = "postgres"; # Automatic setup + user = "git"; # User needs to be the same as gitea user + }; + + # NixOS module uses `gitea dump` to backup repositories and the database, + # but it produces a single .zip file that's not very backup friendly. + # I configure my backup system manually below. + dump.enable = false; }; - # NixOS module uses `gitea dump` to backup repositories and the database, - # but it produces a single .zip file that's not very backup friendly. - # I configure my backup system manually below. - dump.enable = false; - }; - users.users.git = { description = "Gitea Service"; home = config.services.gitea.stateDir; @@ -60,12 +62,12 @@ in users.groups.git = { }; # Proxy to Gitea - services.nginx.virtualHosts."${giteaDomain}" = { - forceSSL = true; - useACMEHost = domain; - - locations."/".proxyPass = "http://127.0.0.1:${toString cfg.port}/"; - }; + my.services.nginx.virtualHosts = [ + { + subdomain = "gitea"; + inherit (cfg) port; + } + ]; my.services.backup = { paths = [ diff --git a/modules/services/indexers.nix b/modules/services/indexers.nix index 11d525c..6ee32c0 100644 --- a/modules/services/indexers.nix +++ b/modules/services/indexers.nix @@ -3,10 +3,6 @@ let cfg = config.my.services.indexers; - domain = config.networking.domain; - jackettDomain = "jackett.${config.networking.domain}"; - nzbhydraDomain = "nzbhydra.${config.networking.domain}"; - jackettPort = 9117; nzbhydraPort = 5076; in @@ -29,25 +25,19 @@ in }; }; - - services.nginx.virtualHosts."${jackettDomain}" = - lib.mkIf cfg.jackett.enable { - forceSSL = true; - useACMEHost = domain; - - locations."/".proxyPass = "http://127.0.0.1:${toString jackettPort}/"; - }; - services.nzbhydra2 = lib.mkIf cfg.nzbhydra.enable { enable = true; }; - services.nginx.virtualHosts."${nzbhydraDomain}" = - lib.mkIf cfg.nzbhydra.enable { - forceSSL = true; - useACMEHost = domain; - - locations."/".proxyPass = "http://127.0.0.1:${toString nzbhydraPort}/"; - }; + my.services.nginx.virtualHosts = [ + { + subdomain = "jackett"; + port = jackettPort; + } + { + subdomain = "nzbhydra"; + port = nzbhydraPort; + } + ]; }; } diff --git a/modules/services/jellyfin.nix b/modules/services/jellyfin.nix index 122a70c..771f2c5 100644 --- a/modules/services/jellyfin.nix +++ b/modules/services/jellyfin.nix @@ -2,8 +2,6 @@ { config, lib, ... }: let cfg = config.my.services.jellyfin; - domain = config.networking.domain; - jellyfinDomain = "jellyfin.${config.networking.domain}"; in { options.my.services.jellyfin = { @@ -16,22 +14,23 @@ in group = "media"; }; - # Proxy to Jellyfin - services.nginx.virtualHosts."${jellyfinDomain}" = { - forceSSL = true; - useACMEHost = domain; - - locations."/" = { - proxyPass = "http://127.0.0.1:8096/"; - extraConfig = '' - proxy_buffering off; - ''; - }; - - locations."/socket" = { - proxyPass = "http://127.0.0.1:8096/"; - proxyWebsockets = true; - }; - }; + my.services.nginx.virtualHosts = [ + { + subdomain = "jellyfin"; + port = 8096; + extraConfig = { + locations."/" = { + extraConfig = '' + proxy_buffering off; + ''; + }; + # Too bad for the repetition... + locations."/socket" = { + proxyPass = "http://127.0.0.1:8096/"; + proxyWebsockets = true; + }; + }; + } + ]; }; } diff --git a/modules/services/lohr.nix b/modules/services/lohr.nix index 57f4feb..45ae3d7 100644 --- a/modules/services/lohr.nix +++ b/modules/services/lohr.nix @@ -4,9 +4,6 @@ let cfg = config.my.services.lohr; settingsFormat = pkgs.formats.yaml { }; - domain = config.networking.domain; - lohrDomain = "lohr.${config.networking.domain}"; - lohrPkg = pkgs.ambroisie.lohr; in { @@ -75,13 +72,11 @@ in }; users.groups.lohr = { }; - services.nginx.virtualHosts."${lohrDomain}" = { - forceSSL = true; - useACMEHost = domain; - - locations."/" = { - proxyPass = "http://127.0.0.1:${toString cfg.port}/"; - }; - }; + my.services.nginx.virtualHosts = [ + { + subdomain = "lohr"; + inherit (cfg) port; + } + ]; }; } diff --git a/modules/services/matrix.nix b/modules/services/matrix.nix index 5d81448..4d6394e 100644 --- a/modules/services/matrix.nix +++ b/modules/services/matrix.nix @@ -118,6 +118,35 @@ in ''; }; + my.services.nginx.virtualHosts = [ + # Element Web app deployment + { + subdomain = "chat"; + root = pkgs.element-web.override { + conf = { + default_server_config = { + "m.homeserver" = { + "base_url" = "https://matrix.${domain}"; + "server_name" = domain; + }; + "m.identity_server" = { + "base_url" = "https://vector.im"; + }; + }; + showLabsSettings = true; + defaultCountryCode = "FR"; # cocorico + roomDirectory = { + "servers" = [ + "matrix.org" + "mozilla.org" + ]; + }; + }; + }; + } + ]; + + # Those are too complicated to use my wrapper... services.nginx.virtualHosts = { "matrix.${domain}" = { onlySSL = true; @@ -192,34 +221,6 @@ in return 200 '${builtins.toJSON client}'; ''; }; - - # Element Web app deployment - "chat.${domain}" = { - useACMEHost = domain; - forceSSL = true; - - root = pkgs.element-web.override { - conf = { - default_server_config = { - "m.homeserver" = { - "base_url" = "https://matrix.${domain}"; - "server_name" = domain; - }; - "m.identity_server" = { - "base_url" = "https://vector.im"; - }; - }; - showLabsSettings = true; - defaultCountryCode = "FR"; # cocorico - roomDirectory = { - "servers" = [ - "matrix.org" - "mozilla.org" - ]; - }; - }; - }; - }; }; # For administration tools. diff --git a/modules/services/miniflux.nix b/modules/services/miniflux.nix index 035bfaf..d223850 100644 --- a/modules/services/miniflux.nix +++ b/modules/services/miniflux.nix @@ -2,9 +2,6 @@ { config, lib, ... }: let cfg = config.my.services.miniflux; - - domain = config.networking.domain; - minifluxDomain = "reader.${config.networking.domain}"; in { options.my.services.miniflux = with lib; { @@ -23,7 +20,7 @@ in description = "Password of the admin user"; }; - privatePort = mkOption { + port = mkOption { type = types.port; default = 9876; example = 8080; @@ -45,8 +42,8 @@ in config = { # Virtual hosts settings - BASE_URL = "https://${minifluxDomain}"; - LISTEN_ADDR = "localhost:${toString cfg.privatePort}"; + BASE_URL = "https://reader.${config.networking.domain}"; + LISTEN_ADDR = "localhost:${toString cfg.port}"; # I want fast updates POLLING_FREQUENCY = "30"; BATCH_SIZE = "50"; @@ -56,12 +53,11 @@ in }; }; - # Proxy to Jellyfin - services.nginx.virtualHosts."${minifluxDomain}" = { - forceSSL = true; - useACMEHost = domain; - - locations."/".proxyPass = "http://127.0.0.1:${toString cfg.privatePort}/"; - }; + my.services.nginx.virtualHosts = [ + { + subdomain = "reader"; + inherit (cfg) port; + } + ]; }; } diff --git a/modules/services/monitoring.nix b/modules/services/monitoring.nix index a86e2ce..ba5adf3 100644 --- a/modules/services/monitoring.nix +++ b/modules/services/monitoring.nix @@ -2,9 +2,6 @@ { config, lib, pkgs, ... }: let cfg = config.my.services.monitoring; - - domain = config.networking.domain; - grafanaDomain = "monitoring.${config.networking.domain}"; in { options.my.services.monitoring = with lib; { @@ -52,7 +49,7 @@ in config = lib.mkIf cfg.enable { services.grafana = { enable = true; - domain = grafanaDomain; + domain = "monitoring.${config.networking.domain}"; port = cfg.grafana.port; addr = "127.0.0.1"; # Proxied through Nginx @@ -115,16 +112,11 @@ in ]; }; - services.nginx = { - virtualHosts.${grafanaDomain} = { - forceSSL = true; - useACMEHost = domain; - - locations."/" = { - proxyPass = "http://127.0.0.1:${toString cfg.grafana.port}"; - proxyWebsockets = true; - }; - }; - }; + my.services.nginx.virtualHosts = [ + { + subdomain = "monitoring"; + inherit (cfg.grafana) port; + } + ]; }; } diff --git a/modules/services/navidrome.nix b/modules/services/navidrome.nix index 779884e..6c001fd 100644 --- a/modules/services/navidrome.nix +++ b/modules/services/navidrome.nix @@ -2,8 +2,6 @@ { config, lib, pkgs, ... }: let cfg = config.my.services.navidrome; - domain = config.networking.domain; - navidromeDomain = "music.${config.networking.domain}"; in { options.my.services.navidrome = with lib; { @@ -23,7 +21,7 @@ in ''; }; - privatePort = mkOption { + port = mkOption { type = types.port; default = 4533; example = 8080; @@ -42,21 +40,18 @@ in enable = true; settings = cfg.settings // { - Port = cfg.privatePort; + Port = cfg.port; Address = "127.0.0.1"; # Behind reverse proxy, so only loopback MusicFolder = cfg.musicFolder; LogLevel = "info"; }; }; - services.nginx.virtualHosts."${navidromeDomain}" = { - forceSSL = true; - useACMEHost = domain; - - locations."/" = { - proxyPass = "http://127.0.0.1:${toString cfg.privatePort}/"; - proxyWebsockets = true; - }; - }; + my.services.nginx.virtualHosts = [ + { + subdomain = "music"; + inherit (cfg) port; + } + ]; }; } diff --git a/modules/services/nextcloud.nix b/modules/services/nextcloud.nix index d615903..b66b8ff 100644 --- a/modules/services/nextcloud.nix +++ b/modules/services/nextcloud.nix @@ -2,8 +2,6 @@ { config, lib, pkgs, ... }: let cfg = config.my.services.nextcloud; - domain = config.networking.domain; - nextcloudDomain = "nextcloud.${config.networking.domain}"; in { options.my.services.nextcloud = with lib; { @@ -31,7 +29,7 @@ in services.nextcloud = { enable = true; package = pkgs.nextcloud22; - hostName = nextcloudDomain; + hostName = "nextcloud.${config.networking.domain}"; home = "/var/lib/nextcloud"; maxUploadSize = cfg.maxSize; config = { @@ -59,11 +57,10 @@ in after = [ "postgresql.service" ]; }; - services.nginx.virtualHosts."${nextcloudDomain}" = { + # The service above configures the domain, no need for my wrapper + services.nginx.virtualHosts."nextcloud.${config.networking.domain}" = { forceSSL = true; - useACMEHost = domain; - - locations."/".proxyPass = "http://127.0.0.1:3000/"; + useACMEHost = config.networking.domain; }; my.services.backup = { diff --git a/modules/services/nginx.nix b/modules/services/nginx.nix index ac70c48..2a64c65 100644 --- a/modules/services/nginx.nix +++ b/modules/services/nginx.nix @@ -1,12 +1,147 @@ -# Configuration shamelessly stolen from [1] -# -# [1]: https://github.com/delroth/infra.delroth.net/blob/master/common/nginx.nix +# A simple abstraction layer for almost all of my services' needs { config, lib, pkgs, ... }: +let + cfg = config.my.services.nginx; + virtualHostOption = with lib; types.submodule { + options = { + subdomain = mkOption { + type = types.str; + example = "dev"; + description = '' + Which subdomain, under config.networking.domain, to use + for this virtual host. + ''; + }; + + port = mkOption { + type = with types; nullOr port; + default = null; + example = 8080; + description = '' + Which port to proxy to, through 127.0.0.1, for this virtual host. + This option is incompatible with `root`. + ''; + }; + + root = mkOption { + type = with types; nullOr path; + default = null; + example = "/var/www/blog"; + description = '' + The root folder for this virtual host. This option is incompatible + with `port`. + ''; + }; + + extraConfig = mkOption { + type = types.attrs; # FIXME: forward type of virtualHosts + example = litteralExample '' + { + locations."/socket" = { + proxyPass = "http://127.0.0.1:8096/"; + proxyWebsockets = true; + }; + } + ''; + default = { }; + description = '' + Any extra configuration that should be applied to this virtual host. + ''; + }; + }; + }; +in { - # Whenever something defines an nginx vhost, ensure that nginx defaults are - # properly set. - config = lib.mkIf ((builtins.attrNames config.services.nginx.virtualHosts) != [ ]) { + options.my.services.nginx = with lib; { + enable = + mkEnableOption "Nginx, activates when `virtualHosts` is not empty" // { + default = builtins.length cfg.virtualHosts != 0; + }; + + monitoring = { + enable = my.mkDisableOption "monitoring through grafana and prometheus"; + }; + + virtualHosts = mkOption { + type = types.listOf virtualHostOption; + default = [ ]; + example = litteralExample '' + [ + { + subdomain = "gitea"; + port = 8080; + } + { + subdomain = "dev"; + root = "/var/www/dev"; + } + { + subdomain = "jellyfin"; + port = 8096; + extraConfig = { + locations."/socket" = { + proxyPass = "http://127.0.0.1:8096/"; + proxyWebsockets = true; + }; + }; + } + ] + ''; + description = '' + List of virtual hosts to set-up using default settings. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ ] + ++ (lib.flip builtins.map cfg.virtualHosts ({ subdomain, ... } @ args: + let + conflicts = [ "port" "root" ]; + optionsNotNull = builtins.map (v: args.${v} != null) conflicts; + optionsSet = lib.filter lib.id optionsNotNull; + in + { + assertion = builtins.length optionsSet == 1; + message = '' + Subdomain '${subdomain}' must have exactly one of ${ + lib.concatStringsSep ", " (builtins.map (v: "'${v}'") conflicts) + } configured. + ''; + })) + ++ ( + let + ports = lib.my.mapFilter + (v: v != null) + ({ port, ... }: port) + cfg.virtualHosts; + portCounts = lib.my.countValues ports; + nonUniquesCounts = lib.filterAttrs (_: v: v != 1) portCounts; + nonUniques = builtins.attrNames nonUniquesCounts; + mkAssertion = port: { + assertion = false; + message = "Port ${port} cannot appear in multiple virtual hosts."; + }; + in + map mkAssertion nonUniques + ) ++ ( + let + subs = map ({ subdomain, ... }: subdomain) cfg.virtualHosts; + subsCounts = lib.my.countValues subs; + nonUniquesCounts = lib.filterAttrs (_: v: v != 1) subsCounts; + nonUniques = builtins.attrNames nonUniquesCounts; + mkAssertion = v: { + assertion = false; + message = '' + Subdomain '${v}' cannot appear in multiple virtual hosts. + ''; + }; + in + map mkAssertion nonUniques + ) + ; + services.nginx = { enable = true; statusPage = true; # For monitoring scraping. @@ -15,6 +150,33 @@ recommendedOptimisation = true; recommendedTlsSettings = true; recommendedProxySettings = true; + + virtualHosts = + let + domain = config.networking.domain; + mkVHost = ({ subdomain, ... } @ args: lib.nameValuePair + "${subdomain}.${domain}" + (builtins.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}"; + }) + # Serve filesystem content + (lib.optionalAttrs (args.root != null) { + inherit (args) root; + }) + # VHost specific configuration + args.extraConfig + ]) + ); + in + lib.my.genAttrs' cfg.virtualHosts mkVHost; }; networking.firewall.allowedTCPPorts = [ 80 443 ]; @@ -22,10 +184,10 @@ # Nginx needs to be able to read the certificates users.users.nginx.extraGroups = [ "acme" ]; - # Use DNS wildcard certificate security.acme = { email = "bruno.acme@belanyi.fr"; acceptTerms = true; + # Use DNS wildcard certificate certs = let domain = config.networking.domain; @@ -40,8 +202,8 @@ }; }; }; - # Setup monitoring - services.grafana.provision.dashboards = [ + + services.grafana.provision.dashboards = lib.mkIf cfg.monitoring.enable [ { name = "NGINX"; options.path = pkgs.nur.repos.alarsyo.grafanaDashboards.nginx; @@ -49,7 +211,7 @@ } ]; - services.prometheus = { + services.prometheus = lib.mkIf cfg.monitoring.enable { exporters.nginx = { enable = true; listenAddress = "127.0.0.1"; diff --git a/modules/services/pirate.nix b/modules/services/pirate.nix index 2eb490b..a2c62ca 100644 --- a/modules/services/pirate.nix +++ b/modules/services/pirate.nix @@ -5,7 +5,6 @@ { config, lib, ... }: let cfg = config.my.services.pirate; - domain = config.networking.domain; ports = { sonarr = 8989; @@ -22,15 +21,8 @@ let }) ports); - redirections = with lib.attrsets; - (mapAttrs' - (service: port: nameValuePair "${service}.${domain}" { - forceSSL = true; - useACMEHost = domain; - - locations."/".proxyPass = "http://127.0.0.1:${builtins.toString port}/"; - }) - ports); + redirections = lib.flip lib.mapAttrsToList ports + (subdomain: port: { inherit subdomain port; }); in { options.my.services.pirate = { @@ -38,6 +30,7 @@ in }; config = lib.mkIf cfg.enable { - services = managers // { nginx.virtualHosts = redirections; }; + services = managers; + my.services.nginx.virtualHosts = redirections; }; } diff --git a/modules/services/podgrab.nix b/modules/services/podgrab.nix index 7926fc2..bc16178 100644 --- a/modules/services/podgrab.nix +++ b/modules/services/podgrab.nix @@ -2,9 +2,6 @@ { config, lib, pkgs, ... }: let cfg = config.my.services.podgrab; - - domain = config.networking.domain; - podgrabDomain = "podgrab.${domain}"; in { options.my.services.podgrab = with lib; { @@ -34,11 +31,11 @@ in inherit (cfg) passwordFile port; }; - services.nginx.virtualHosts."${podgrabDomain}" = { - forceSSL = true; - useACMEHost = domain; - - locations."/".proxyPass = "http://127.0.0.1:${toString cfg.port}"; - }; + my.services.nginx.virtualHosts = [ + { + subdomain = "podgrab"; + inherit (cfg) port; + } + ]; }; } diff --git a/modules/services/rss-bridge.nix b/modules/services/rss-bridge.nix index ad5141b..85e37c2 100644 --- a/modules/services/rss-bridge.nix +++ b/modules/services/rss-bridge.nix @@ -2,8 +2,6 @@ { config, lib, ... }: let cfg = config.my.services.rss-bridge; - domain = config.networking.domain; - rss-bridgeDomain = "rss-bridge.${config.networking.domain}"; in { options.my.services.rss-bridge = { @@ -14,12 +12,13 @@ in services.rss-bridge = { enable = true; whitelist = [ "*" ]; # Whitelist all - virtualHost = rss-bridgeDomain; # Setup virtual host + virtualHost = "rss-bridge.${config.networking.domain}"; }; - services.nginx.virtualHosts."${rss-bridgeDomain}" = { + # The service above configures the domain, no need for my wrapper + services.nginx.virtualHosts."rss-bridge.${config.networking.domain}" = { forceSSL = true; - useACMEHost = domain; + useACMEHost = config.networking.domain; }; }; } diff --git a/modules/services/sabnzbd.nix b/modules/services/sabnzbd.nix index ebeef8b..653f853 100644 --- a/modules/services/sabnzbd.nix +++ b/modules/services/sabnzbd.nix @@ -2,9 +2,6 @@ { config, lib, ... }: let cfg = config.my.services.sabnzbd; - - domain = config.networking.domain; - sabnzbdDomain = "sabnzbd.${domain}"; port = 9090; # NOTE: not declaratively set... in { @@ -18,11 +15,11 @@ in group = "media"; }; - services.nginx.virtualHosts."${sabnzbdDomain}" = { - forceSSL = true; - useACMEHost = domain; - - locations."/".proxyPass = "http://127.0.0.1:${toString port}"; - }; + my.services.nginx.virtualHosts = [ + { + subdomain = "sabnzbd"; + inherit port; + } + ]; }; } diff --git a/modules/services/transmission.nix b/modules/services/transmission.nix index 29e181b..2f27990 100644 --- a/modules/services/transmission.nix +++ b/modules/services/transmission.nix @@ -6,9 +6,6 @@ { config, lib, ... }: let cfg = config.my.services.transmission; - - domain = config.networking.domain; - webuiDomain = "transmission.${domain}"; in { options.my.services.transmission = with lib; { @@ -34,7 +31,7 @@ in description = "Download base directory"; }; - privatePort = mkOption { + port = mkOption { type = types.port; default = 9091; example = 8080; @@ -63,7 +60,7 @@ in peer-port = cfg.peerPort; rpc-enabled = true; - rpc-port = cfg.privatePort; + rpc-port = cfg.port; rpc-authentication-required = true; rpc-username = cfg.username; @@ -77,12 +74,12 @@ in # Default transmission webui, I prefer combustion but its development # seems to have stalled - services.nginx.virtualHosts."${webuiDomain}" = { - forceSSL = true; - useACMEHost = domain; - - locations."/".proxyPass = "http://127.0.0.1:${toString cfg.privatePort}"; - }; + my.services.nginx.virtualHosts = [ + { + subdomain = "transmission"; + inherit (cfg) port; + } + ]; networking.firewall = { allowedTCPPorts = [ cfg.peerPort ];