diff --git a/lib/lists.nix b/lib/lists.nix deleted file mode 100644 index 190198e..0000000 --- a/lib/lists.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ 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 9149917..0a5fcf1 100644 --- a/modules/services/blog.nix +++ b/modules/services/blog.nix @@ -4,12 +4,28 @@ let cfg = config.my.services.blog; domain = config.networking.domain; - makeHostInfo = subdomain: { - inherit subdomain; - root = "/var/www/${subdomain}"; + makeHostInfo = name: { + name = "${name}.${domain}"; + value = "/var/www/${name}"; }; - hostsInfo = map makeHostInfo [ "cv" "dev" "key" ]; + 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); + }; in { options.my.services.blog = { @@ -17,17 +33,7 @@ in }; config = lib.mkIf cfg.enable { - 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; + services.nginx.virtualHosts = with lib.attrsets; + mapAttrs' makeVirtualHost hosts; }; } diff --git a/modules/services/calibre-web.nix b/modules/services/calibre-web.nix index a62b74c..d4d7ece 100644 --- a/modules/services/calibre-web.nix +++ b/modules/services/calibre-web.nix @@ -1,6 +1,8 @@ { config, lib, ... }: let cfg = config.my.services.calibre-web; + domain = config.networking.domain; + calibreDomain = "library.${domain}"; in { options.my.services.calibre-web = with lib; { @@ -37,12 +39,12 @@ in }; }; - my.services.nginx.virtualHosts = [ - { - subdomain = "library"; - inherit (cfg) port; - } - ]; + services.nginx.virtualHosts."${calibreDomain}" = { + forceSSL = true; + useACMEHost = domain; + + locations."/".proxyPass = "http://127.0.0.1:${toString cfg.port}/"; + }; my.services.backup = { paths = [ diff --git a/modules/services/drone.nix b/modules/services/drone.nix index 7a9b668..b1e80ea 100644 --- a/modules/services/drone.nix +++ b/modules/services/drone.nix @@ -6,6 +6,9 @@ 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; @@ -56,7 +59,7 @@ in ]; Environment = [ "DRONE_DATABASE_DATASOURCE=postgres:///drone?host=/run/postgresql" - "DRONE_SERVER_HOST=drone.${config.networking.domain}" + "DRONE_SERVER_HOST=${droneDomain}" "DRONE_SERVER_PROTO=https" "DRONE_DATABASE_DRIVER=postgres" "DRONE_SERVER_PORT=:${toString cfg.port}" @@ -88,12 +91,12 @@ in }]; }; - my.services.nginx.virtualHosts = [ - { - subdomain = "drone"; - inherit (cfg) port; - } - ]; + services.nginx.virtualHosts."${droneDomain}" = { + forceSSL = true; + useACMEHost = domain; + + locations."/".proxyPass = "http://127.0.0.1:${toString cfg.port}"; + }; # Docker runner systemd.services.drone-runner-docker = lib.mkIf (hasRunner "docker") { @@ -104,7 +107,7 @@ in confinement.enable = true; serviceConfig = { Environment = [ - "DRONE_SERVER_HOST=drone.${config.networking.domain}" + "DRONE_SERVER_HOST=${droneDomain}" "DRONE_SERVER_PROTO=https" "DRONE_RUNNER_CAPACITY=10" "CLIENT_DRONE_RPC_HOST=127.0.0.1:${toString cfg.port}" @@ -153,7 +156,7 @@ in ]; serviceConfig = { Environment = [ - "DRONE_SERVER_HOST=drone.${config.networking.domain}" + "DRONE_SERVER_HOST=${droneDomain}" "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 ae8e219..70988cb 100644 --- a/modules/services/flood.nix +++ b/modules/services/flood.nix @@ -2,6 +2,9 @@ { config, lib, pkgs, ... }: let cfg = config.my.services.flood; + + domain = config.networking.domain; + webuiDomain = "flood.${domain}"; in { options.my.services.flood = with lib; { @@ -40,11 +43,11 @@ in }; }; - my.services.nginx.virtualHosts = [ - { - subdomain = "flood"; - inherit (cfg) port; - } - ]; + services.nginx.virtualHosts."${webuiDomain}" = { + forceSSL = true; + useACMEHost = domain; + + locations."/".proxyPass = "http://127.0.0.1:${toString cfg.port}"; + }; }; } diff --git a/modules/services/gitea.nix b/modules/services/gitea.nix index 0ece12c..ea739d5 100644 --- a/modules/services/gitea.nix +++ b/modules/services/gitea.nix @@ -2,6 +2,8 @@ { config, lib, ... }: let cfg = config.my.services.gitea; + domain = config.networking.domain; + giteaDomain = "gitea.${config.networking.domain}"; in { options.my.services.gitea = with lib; { @@ -15,38 +17,34 @@ in }; config = lib.mkIf cfg.enable { - services.gitea = - let - giteaDomain = "gitea.${config.networking.domain}"; - in - { - enable = true; + services.gitea = { + 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 - }; - - # 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; + 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; + }; + users.users.git = { description = "Gitea Service"; home = config.services.gitea.stateDir; @@ -62,12 +60,12 @@ in users.groups.git = { }; # Proxy to Gitea - my.services.nginx.virtualHosts = [ - { - subdomain = "gitea"; - inherit (cfg) port; - } - ]; + services.nginx.virtualHosts."${giteaDomain}" = { + forceSSL = true; + useACMEHost = domain; + + locations."/".proxyPass = "http://127.0.0.1:${toString cfg.port}/"; + }; my.services.backup = { paths = [ diff --git a/modules/services/indexers.nix b/modules/services/indexers.nix index 6ee32c0..11d525c 100644 --- a/modules/services/indexers.nix +++ b/modules/services/indexers.nix @@ -3,6 +3,10 @@ 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 @@ -25,19 +29,25 @@ 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; }; - my.services.nginx.virtualHosts = [ - { - subdomain = "jackett"; - port = jackettPort; - } - { - subdomain = "nzbhydra"; - port = nzbhydraPort; - } - ]; + services.nginx.virtualHosts."${nzbhydraDomain}" = + lib.mkIf cfg.nzbhydra.enable { + forceSSL = true; + useACMEHost = domain; + + locations."/".proxyPass = "http://127.0.0.1:${toString nzbhydraPort}/"; + }; }; } diff --git a/modules/services/jellyfin.nix b/modules/services/jellyfin.nix index 771f2c5..122a70c 100644 --- a/modules/services/jellyfin.nix +++ b/modules/services/jellyfin.nix @@ -2,6 +2,8 @@ { config, lib, ... }: let cfg = config.my.services.jellyfin; + domain = config.networking.domain; + jellyfinDomain = "jellyfin.${config.networking.domain}"; in { options.my.services.jellyfin = { @@ -14,23 +16,22 @@ in group = "media"; }; - 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; - }; - }; - } - ]; + # 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; + }; + }; }; } diff --git a/modules/services/lohr.nix b/modules/services/lohr.nix index 45ae3d7..57f4feb 100644 --- a/modules/services/lohr.nix +++ b/modules/services/lohr.nix @@ -4,6 +4,9 @@ let cfg = config.my.services.lohr; settingsFormat = pkgs.formats.yaml { }; + domain = config.networking.domain; + lohrDomain = "lohr.${config.networking.domain}"; + lohrPkg = pkgs.ambroisie.lohr; in { @@ -72,11 +75,13 @@ in }; users.groups.lohr = { }; - my.services.nginx.virtualHosts = [ - { - subdomain = "lohr"; - inherit (cfg) port; - } - ]; + services.nginx.virtualHosts."${lohrDomain}" = { + forceSSL = true; + useACMEHost = domain; + + locations."/" = { + proxyPass = "http://127.0.0.1:${toString cfg.port}/"; + }; + }; }; } diff --git a/modules/services/matrix.nix b/modules/services/matrix.nix index 4d6394e..5d81448 100644 --- a/modules/services/matrix.nix +++ b/modules/services/matrix.nix @@ -118,35 +118,6 @@ 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; @@ -221,6 +192,34 @@ 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 d223850..035bfaf 100644 --- a/modules/services/miniflux.nix +++ b/modules/services/miniflux.nix @@ -2,6 +2,9 @@ { config, lib, ... }: let cfg = config.my.services.miniflux; + + domain = config.networking.domain; + minifluxDomain = "reader.${config.networking.domain}"; in { options.my.services.miniflux = with lib; { @@ -20,7 +23,7 @@ in description = "Password of the admin user"; }; - port = mkOption { + privatePort = mkOption { type = types.port; default = 9876; example = 8080; @@ -42,8 +45,8 @@ in config = { # Virtual hosts settings - BASE_URL = "https://reader.${config.networking.domain}"; - LISTEN_ADDR = "localhost:${toString cfg.port}"; + BASE_URL = "https://${minifluxDomain}"; + LISTEN_ADDR = "localhost:${toString cfg.privatePort}"; # I want fast updates POLLING_FREQUENCY = "30"; BATCH_SIZE = "50"; @@ -53,11 +56,12 @@ in }; }; - my.services.nginx.virtualHosts = [ - { - subdomain = "reader"; - inherit (cfg) port; - } - ]; + # Proxy to Jellyfin + services.nginx.virtualHosts."${minifluxDomain}" = { + forceSSL = true; + useACMEHost = domain; + + locations."/".proxyPass = "http://127.0.0.1:${toString cfg.privatePort}/"; + }; }; } diff --git a/modules/services/monitoring.nix b/modules/services/monitoring.nix index ba5adf3..a86e2ce 100644 --- a/modules/services/monitoring.nix +++ b/modules/services/monitoring.nix @@ -2,6 +2,9 @@ { 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; { @@ -49,7 +52,7 @@ in config = lib.mkIf cfg.enable { services.grafana = { enable = true; - domain = "monitoring.${config.networking.domain}"; + domain = grafanaDomain; port = cfg.grafana.port; addr = "127.0.0.1"; # Proxied through Nginx @@ -112,11 +115,16 @@ in ]; }; - my.services.nginx.virtualHosts = [ - { - subdomain = "monitoring"; - inherit (cfg.grafana) port; - } - ]; + services.nginx = { + virtualHosts.${grafanaDomain} = { + forceSSL = true; + useACMEHost = domain; + + locations."/" = { + proxyPass = "http://127.0.0.1:${toString cfg.grafana.port}"; + proxyWebsockets = true; + }; + }; + }; }; } diff --git a/modules/services/navidrome.nix b/modules/services/navidrome.nix index 6c001fd..779884e 100644 --- a/modules/services/navidrome.nix +++ b/modules/services/navidrome.nix @@ -2,6 +2,8 @@ { 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; { @@ -21,7 +23,7 @@ in ''; }; - port = mkOption { + privatePort = mkOption { type = types.port; default = 4533; example = 8080; @@ -40,18 +42,21 @@ in enable = true; settings = cfg.settings // { - Port = cfg.port; + Port = cfg.privatePort; Address = "127.0.0.1"; # Behind reverse proxy, so only loopback MusicFolder = cfg.musicFolder; LogLevel = "info"; }; }; - my.services.nginx.virtualHosts = [ - { - subdomain = "music"; - inherit (cfg) port; - } - ]; + services.nginx.virtualHosts."${navidromeDomain}" = { + forceSSL = true; + useACMEHost = domain; + + locations."/" = { + proxyPass = "http://127.0.0.1:${toString cfg.privatePort}/"; + proxyWebsockets = true; + }; + }; }; } diff --git a/modules/services/nextcloud.nix b/modules/services/nextcloud.nix index b66b8ff..d615903 100644 --- a/modules/services/nextcloud.nix +++ b/modules/services/nextcloud.nix @@ -2,6 +2,8 @@ { 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; { @@ -29,7 +31,7 @@ in services.nextcloud = { enable = true; package = pkgs.nextcloud22; - hostName = "nextcloud.${config.networking.domain}"; + hostName = nextcloudDomain; home = "/var/lib/nextcloud"; maxUploadSize = cfg.maxSize; config = { @@ -57,10 +59,11 @@ in after = [ "postgresql.service" ]; }; - # The service above configures the domain, no need for my wrapper - services.nginx.virtualHosts."nextcloud.${config.networking.domain}" = { + services.nginx.virtualHosts."${nextcloudDomain}" = { forceSSL = true; - useACMEHost = config.networking.domain; + useACMEHost = domain; + + locations."/".proxyPass = "http://127.0.0.1:3000/"; }; my.services.backup = { diff --git a/modules/services/nginx.nix b/modules/services/nginx.nix index 2a64c65..ac70c48 100644 --- a/modules/services/nginx.nix +++ b/modules/services/nginx.nix @@ -1,147 +1,12 @@ -# A simple abstraction layer for almost all of my services' needs +# Configuration shamelessly stolen from [1] +# +# [1]: https://github.com/delroth/infra.delroth.net/blob/master/common/nginx.nix { 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 { - 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 - ) - ; - + # Whenever something defines an nginx vhost, ensure that nginx defaults are + # properly set. + config = lib.mkIf ((builtins.attrNames config.services.nginx.virtualHosts) != [ ]) { services.nginx = { enable = true; statusPage = true; # For monitoring scraping. @@ -150,33 +15,6 @@ in 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 ]; @@ -184,10 +22,10 @@ in # 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; @@ -202,8 +40,8 @@ in }; }; }; - - services.grafana.provision.dashboards = lib.mkIf cfg.monitoring.enable [ + # Setup monitoring + services.grafana.provision.dashboards = [ { name = "NGINX"; options.path = pkgs.nur.repos.alarsyo.grafanaDashboards.nginx; @@ -211,7 +49,7 @@ in } ]; - services.prometheus = lib.mkIf cfg.monitoring.enable { + services.prometheus = { exporters.nginx = { enable = true; listenAddress = "127.0.0.1"; diff --git a/modules/services/pirate.nix b/modules/services/pirate.nix index a2c62ca..2eb490b 100644 --- a/modules/services/pirate.nix +++ b/modules/services/pirate.nix @@ -5,6 +5,7 @@ { config, lib, ... }: let cfg = config.my.services.pirate; + domain = config.networking.domain; ports = { sonarr = 8989; @@ -21,8 +22,15 @@ let }) ports); - redirections = lib.flip lib.mapAttrsToList ports - (subdomain: port: { inherit subdomain port; }); + 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); in { options.my.services.pirate = { @@ -30,7 +38,6 @@ in }; config = lib.mkIf cfg.enable { - services = managers; - my.services.nginx.virtualHosts = redirections; + services = managers // { nginx.virtualHosts = redirections; }; }; } diff --git a/modules/services/podgrab.nix b/modules/services/podgrab.nix index bc16178..7926fc2 100644 --- a/modules/services/podgrab.nix +++ b/modules/services/podgrab.nix @@ -2,6 +2,9 @@ { config, lib, pkgs, ... }: let cfg = config.my.services.podgrab; + + domain = config.networking.domain; + podgrabDomain = "podgrab.${domain}"; in { options.my.services.podgrab = with lib; { @@ -31,11 +34,11 @@ in inherit (cfg) passwordFile port; }; - my.services.nginx.virtualHosts = [ - { - subdomain = "podgrab"; - inherit (cfg) port; - } - ]; + services.nginx.virtualHosts."${podgrabDomain}" = { + forceSSL = true; + useACMEHost = domain; + + locations."/".proxyPass = "http://127.0.0.1:${toString cfg.port}"; + }; }; } diff --git a/modules/services/rss-bridge.nix b/modules/services/rss-bridge.nix index 85e37c2..ad5141b 100644 --- a/modules/services/rss-bridge.nix +++ b/modules/services/rss-bridge.nix @@ -2,6 +2,8 @@ { 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 = { @@ -12,13 +14,12 @@ in services.rss-bridge = { enable = true; whitelist = [ "*" ]; # Whitelist all - virtualHost = "rss-bridge.${config.networking.domain}"; + virtualHost = rss-bridgeDomain; # Setup virtual host }; - # The service above configures the domain, no need for my wrapper - services.nginx.virtualHosts."rss-bridge.${config.networking.domain}" = { + services.nginx.virtualHosts."${rss-bridgeDomain}" = { forceSSL = true; - useACMEHost = config.networking.domain; + useACMEHost = domain; }; }; } diff --git a/modules/services/sabnzbd.nix b/modules/services/sabnzbd.nix index 653f853..ebeef8b 100644 --- a/modules/services/sabnzbd.nix +++ b/modules/services/sabnzbd.nix @@ -2,6 +2,9 @@ { config, lib, ... }: let cfg = config.my.services.sabnzbd; + + domain = config.networking.domain; + sabnzbdDomain = "sabnzbd.${domain}"; port = 9090; # NOTE: not declaratively set... in { @@ -15,11 +18,11 @@ in group = "media"; }; - my.services.nginx.virtualHosts = [ - { - subdomain = "sabnzbd"; - inherit port; - } - ]; + services.nginx.virtualHosts."${sabnzbdDomain}" = { + forceSSL = true; + useACMEHost = domain; + + locations."/".proxyPass = "http://127.0.0.1:${toString port}"; + }; }; } diff --git a/modules/services/transmission.nix b/modules/services/transmission.nix index 2f27990..29e181b 100644 --- a/modules/services/transmission.nix +++ b/modules/services/transmission.nix @@ -6,6 +6,9 @@ { config, lib, ... }: let cfg = config.my.services.transmission; + + domain = config.networking.domain; + webuiDomain = "transmission.${domain}"; in { options.my.services.transmission = with lib; { @@ -31,7 +34,7 @@ in description = "Download base directory"; }; - port = mkOption { + privatePort = mkOption { type = types.port; default = 9091; example = 8080; @@ -60,7 +63,7 @@ in peer-port = cfg.peerPort; rpc-enabled = true; - rpc-port = cfg.port; + rpc-port = cfg.privatePort; rpc-authentication-required = true; rpc-username = cfg.username; @@ -74,12 +77,12 @@ in # Default transmission webui, I prefer combustion but its development # seems to have stalled - my.services.nginx.virtualHosts = [ - { - subdomain = "transmission"; - inherit (cfg) port; - } - ]; + services.nginx.virtualHosts."${webuiDomain}" = { + forceSSL = true; + useACMEHost = domain; + + locations."/".proxyPass = "http://127.0.0.1:${toString cfg.privatePort}"; + }; networking.firewall = { allowedTCPPorts = [ cfg.peerPort ];