From 2f8d666060f20d35730309945be4f0c9acce0cae Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Mon, 17 Aug 2026 23:50:57 +0300 Subject: [PATCH 1/2] test frontend redirect hosts --- nix/checks/module-eval.nix | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/nix/checks/module-eval.nix b/nix/checks/module-eval.nix index f9f2a97..b1f0dc4 100644 --- a/nix/checks/module-eval.nix +++ b/nix/checks/module-eval.nix @@ -23,7 +23,10 @@ let borgPassphrase = "/run/secrets/borg-passphrase"; borgPrivateKey = "/run/secrets/borg-private-key"; }; - frontend.hostName = "www.example.test"; + frontend = { + hostName = "example.test"; + redirectHostNames = [ "www.example.test" ]; + }; backend = { hostName = "api.example.test"; environmentFile = "/run/secrets/rabbi-gerzi.env"; @@ -35,6 +38,10 @@ let evaluatedHostName = evaluatedConfig.services.rabbi-gerzi.backend.hostName; + evaluatedFrontendHostName = evaluatedConfig.services.rabbi-gerzi.frontend.hostName; + + frontendRedirectVirtualHost = evaluatedConfig.services.nginx.virtualHosts."www.example.test"; + backendVirtualHost = evaluatedConfig.services.nginx.virtualHosts.${evaluatedHostName}; phpOptions = evaluatedConfig.services.phpfpm.pools.rabbi-gerzi.phpOptions; @@ -66,6 +73,18 @@ let passed = lib.hasInfix expectedNginxClientMaxBodySize backendVirtualHost.extraConfig; message = "nginx client_max_body_size is not 6m"; } + { + passed = frontendRedirectVirtualHost.globalRedirect == evaluatedFrontendHostName; + message = "frontend redirect does not target the canonical host"; + } + { + passed = frontendRedirectVirtualHost.forceSSL; + message = "frontend redirect does not force HTTPS"; + } + { + passed = frontendRedirectVirtualHost.enableACME; + message = "frontend redirect does not enable ACME"; + } { passed = backupConfig.repo == "ssh://mgjjruz9@mgjjruz9.repo.borgbase.com/./repo"; message = "Borg repository is not the Rabbi Gerzi repository"; From 4cdbebe7f9e929801ece7517668593121763a28b Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Mon, 17 Aug 2026 23:52:24 +0300 Subject: [PATCH 2/2] add frontend redirect hosts --- README.md | 5 ++- nix/nixos-module.nix | 90 +++++++++++++++++++++++++------------------- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 2360599..60ae8d3 100644 --- a/README.md +++ b/README.md @@ -417,7 +417,10 @@ Example host configuration: config.sops.secrets."borg-private-key".path; }; - frontend.hostName = "rabbigerzi.com"; + frontend = { + hostName = "rabbigerzi.com"; + redirectHostNames = [ "www.rabbigerzi.com" ]; + }; backend = { hostName = "api.rabbigerzi.com"; diff --git a/nix/nixos-module.nix b/nix/nixos-module.nix index 30f8ddf..2a04c00 100644 --- a/nix/nixos-module.nix +++ b/nix/nixos-module.nix @@ -120,6 +120,12 @@ in description = "Frontend nginx virtual host name."; }; + redirectHostNames = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Frontend host names that redirect to the canonical host."; + }; + publicUrl = lib.mkOption { type = lib.types.str; default = "https://${cfg.frontend.hostName}"; @@ -403,49 +409,55 @@ in recommendedProxySettings = lib.mkDefault true; recommendedTlsSettings = lib.mkDefault true; - virtualHosts = { - ${cfg.frontend.hostName} = lib.mkMerge [ - cfg.frontend.nginx - { - root = "${frontendPackage}"; - locations."/" = { - tryFiles = "$uri $uri/ /index.html"; - }; - } - ]; - - ${cfg.backend.hostName} = lib.mkMerge [ - cfg.backend.nginx - { - root = "${appDir}/public"; - extraConfig = '' - client_max_body_size ${uploadLimits.nginxClientMaxBodySize}; - ''; - locations = { - "/" = { - index = "index.php"; - tryFiles = "$uri $uri/ /index.php?$query_string"; + virtualHosts = + lib.genAttrs cfg.frontend.redirectHostNames (redirectHostName: { + enableACME = true; + forceSSL = true; + globalRedirect = cfg.frontend.hostName; + }) + // { + ${cfg.frontend.hostName} = lib.mkMerge [ + cfg.frontend.nginx + { + root = "${frontendPackage}"; + locations."/" = { + tryFiles = "$uri $uri/ /index.html"; }; + } + ]; - "/storage/" = { - alias = "${storagePath}/app/public/"; - extraConfig = '' - expires 30d; - access_log off; - ''; - }; + ${cfg.backend.hostName} = lib.mkMerge [ + cfg.backend.nginx + { + root = "${appDir}/public"; + extraConfig = '' + client_max_body_size ${uploadLimits.nginxClientMaxBodySize}; + ''; + locations = { + "/" = { + index = "index.php"; + tryFiles = "$uri $uri/ /index.php?$query_string"; + }; - "~ \\.php$" = { - extraConfig = '' - include ${pkgs.nginx}/conf/fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_pass unix:${config.services.phpfpm.pools.${poolName}.socket}; - ''; + "/storage/" = { + alias = "${storagePath}/app/public/"; + extraConfig = '' + expires 30d; + access_log off; + ''; + }; + + "~ \\.php$" = { + extraConfig = '' + include ${pkgs.nginx}/conf/fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_pass unix:${config.services.phpfpm.pools.${poolName}.socket}; + ''; + }; }; - }; - } - ]; - }; + } + ]; + }; }; }; }