flake

Francesco Saccone's Nix flake.
git clone git://git.francescosaccone.com/flake
Log | Files | Refs | README | LICENSE

commit 5b87f50daf73c5cad72c3e181b9334c205163b78
parent 59d479fb9868925c2f81b229cc0610b4c0cfcbdb
Author: Francesco Saccone <francesco@francescosaccone.com>
Date:   Wed, 16 Apr 2025 18:15:33 +0200

feat: replace Darkhttpd with Quark web server

Signed-off-by: Francesco Saccone <francesco@francescosaccone.com>

Diffstat:
Mhosts/git-server/default.nix | 6+++---
Mhosts/main-server/default.nix | 12++++++------
Dmodules/nixos/darkhttpd/acme/default.nix | 85-------------------------------------------------------------------------------
Dmodules/nixos/darkhttpd/default.nix | 165-------------------------------------------------------------------------------
Dmodules/nixos/darkhttpd/tls/default.nix | 76----------------------------------------------------------------------------
Mmodules/nixos/default.nix | 2+-
Amodules/nixos/quark/acme/default.nix | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/nixos/quark/default.nix | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/nixos/quark/tls/default.nix | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 files changed, 333 insertions(+), 336 deletions(-)

diff --git a/hosts/git-server/default.nix b/hosts/git-server/default.nix @@ -13,7 +13,7 @@ let scripts = import ./scripts.nix { inherit config pkgs inputs; }; stagit = { - destDir = config.modules.darkhttpd.directory; + destDir = config.modules.quark.directory; reposDir = config.modules.git.directory; }; in @@ -28,7 +28,7 @@ in domain = rootDomain; records = import "${mainServer}/dns.nix" rootDomain; }; - darkhttpd = { + quark = { enable = true; preStart = { scripts = @@ -60,7 +60,7 @@ in enable = true; pemFiles = let - inherit (config.modules.darkhttpd.acme) directory; + inherit (config.modules.quark.acme) directory; in [ "${directory}/${gitDomain}/fullchain.pem" diff --git a/hosts/main-server/default.nix b/hosts/main-server/default.nix @@ -61,32 +61,32 @@ rec { inherit (networking) domain; records = import ./dns.nix domain; }; - darkhttpd = { + quark = { enable = true; preStart = { scripts = let generateAtom = builtins.concatStringsSep " " [ "${inputs.site}/scripts/generate-atom.sh" - config.modules.darkhttpd.directory + config.modules.quark.directory "\"Francesco Saccone's blog\"" "https://${domain}" ]; generateSitemap = builtins.concatStringsSep " " [ "${inputs.site}/scripts/generate-sitemap.sh" - config.modules.darkhttpd.directory + config.modules.quark.directory "https://${domain}" ]; generateHtml = builtins.concatStringsSep " " [ "${inputs.site}/scripts/generate-html.sh" - config.modules.darkhttpd.directory + config.modules.quark.directory ]; copyStaticContent = pkgs.writeShellScript "copy-static-content" '' ${pkgs.sbase}/bin/cp -r \ ${inputs.site}/public \ ${inputs.site}/favicon.ico \ ${inputs.site}/robots.txt \ - ${config.modules.darkhttpd.directory} + ${config.modules.quark.directory} ''; in [ @@ -112,7 +112,7 @@ rec { enable = true; pemFiles = let - inherit (config.modules.darkhttpd.acme) directory; + inherit (config.modules.quark.acme) directory; in [ "${directory}/${domain}/fullchain.pem" diff --git a/modules/nixos/darkhttpd/acme/default.nix b/modules/nixos/darkhttpd/acme/default.nix @@ -1,85 +0,0 @@ -{ - lib, - options, - config, - pkgs, - ... -}: -{ - options.modules.darkhttpd.acme = { - enable = lib.mkOption { - description = "Whether to enable the Certbot ACME client."; - default = false; - type = lib.types.bool; - }; - directory = lib.mkOption { - description = '' - The directory containing fetched Let's Encrypt certificates. - ''; - default = "/etc/letsencrypt/live"; - readOnly = true; - type = lib.types.uniq lib.types.path; - }; - email = lib.mkOption { - description = "The email used for the Let's Encrypt account."; - type = lib.types.uniq lib.types.str; - }; - domain = lib.mkOption { - description = "The domain to fetch the certificate for."; - type = lib.types.uniq lib.types.str; - }; - extraDomains = lib.mkOption { - description = "The extra domains of the certificate."; - default = [ ]; - type = lib.types.listOf lib.types.str; - }; - }; - - config = - let - inherit (config.modules.darkhttpd) acme; - in - lib.mkIf (acme.enable && config.modules.darkhttpd.enable) { - systemd = { - services = { - acme = { - enable = true; - wantedBy = [ "multi-user.target" ]; - after = [ "darkhttpd-setup.service" ]; - serviceConfig = - let - domains = [ acme.domain ] ++ acme.extraDomains; - - script = pkgs.writeShellScriptBin "script" '' - if ${pkgs.certbot}/bin/certbot certificates \ - | ${pkgs.gnugrep}/bin/grep -q "No certificates"; then - ${pkgs.certbot}/bin/certbot certonly --quiet --webroot \ - --agree-tos --email ${acme.email} \ - -w ${config.modules.darkhttpd.directory} \ - -d ${builtins.concatStringsSep " -d " domains} - else - ${pkgs.certbot}/bin/certbot renew --quiet - fi - ''; - in - { - User = "root"; - Group = "root"; - Type = "oneshot"; - ExecStart = "${script}/bin/script"; - }; - }; - }; - timers = { - acme = { - enable = true; - wantedBy = [ "multi-user.target" ]; - timerConfig = { - OnCalendar = "weekly"; - Persistent = true; - }; - }; - }; - }; - }; -} diff --git a/modules/nixos/darkhttpd/default.nix b/modules/nixos/darkhttpd/default.nix @@ -1,165 +0,0 @@ -{ - lib, - options, - config, - pkgs, - ... -}: -{ - imports = [ - ./acme - ./tls - ]; - - options.modules.darkhttpd = { - enable = lib.mkOption { - description = "Whether to enable Darkhttpd."; - default = false; - type = lib.types.bool; - }; - directory = lib.mkOption { - description = "The root directory to statically host."; - default = "/var/www"; - readOnly = true; - type = lib.types.uniq lib.types.path; - }; - symlinks = lib.mkOption { - description = '' - For each symlink name, which will be created in the root directory, its - target. - ''; - default = { }; - type = lib.types.attrsOf lib.types.path; - }; - preStart = { - scripts = lib.mkOption { - description = '' - The list of scripts to run before starting the server. - ''; - default = [ ]; - type = lib.types.listOf lib.types.path; - }; - packages = lib.mkOption { - description = "The list of packages required by the scripts."; - default = [ ]; - type = lib.types.listOf lib.types.package; - }; - }; - }; - - config = lib.mkIf config.modules.darkhttpd.enable { - users = { - users = { - darkhttpd = { - hashedPassword = "!"; - isSystemUser = true; - group = "darkhttpd"; - createHome = true; - home = config.modules.darkhttpd.directory; - }; - }; - groups = { - darkhttpd = { }; - }; - }; - - systemd = { - services = { - darkhttpd-setup = { - enable = true; - wantedBy = [ "multi-user.target" ]; - serviceConfig = - let - permissions = pkgs.writeShellScriptBin "permissions" '' - ${pkgs.sbase}/bin/chmod -R g+rwx \ - ${config.modules.darkhttpd.directory} - ''; - clean = pkgs.writeShellScriptBin "clean" '' - ${pkgs.sbase}/bin/rm -rf \ - ${config.modules.darkhttpd.directory}/* - ''; - symlinks = - config.modules.darkhttpd.symlinks - |> builtins.mapAttrs ( - name: target: - let - inherit (config.modules.darkhttpd) directory; - in - '' - ${pkgs.sbase}/bin/mkdir -p \ - ${directory}/${builtins.dirOf name} - - ${pkgs.sbase}/bin/ln -sf ${target} \ - ${directory}/${name} - - ${pkgs.sbase}/bin/chown -Rh darkhttpd:darkhttpd \ - ${directory}/${name} - '' - ) - |> builtins.attrValues - |> builtins.concatStringsSep "\n" - |> pkgs.writeShellScriptBin "symlinks"; - in - { - User = "root"; - Group = "root"; - Type = "oneshot"; - ExecStart = [ - "${permissions}/bin/permissions" - "${clean}/bin/clean" - "${symlinks}/bin/symlinks" - ]; - }; - }; - darkhttpd = - let - inherit (config.modules.darkhttpd) preStart; - in - rec { - enable = true; - wantedBy = [ "multi-user.target" ]; - requires = [ "darkhttpd-setup.service" ]; - after = [ "network.target" ]; - path = preStart.packages; - serviceConfig = - let - inherit (config.modules.darkhttpd) customHeaderScripts tls; - script = pkgs.writeShellScriptBin "script" '' - ${builtins.concatStringsSep "\n" preStart.scripts} - - ${pkgs.darkhttpd}/bin/darkhttpd \ - ${config.modules.darkhttpd.directory} \ - --port 80 \ - --index index.html \ - --no-listing \ - --uid darkhttpd \ - --gid darkhttpd \ - --no-server-id \ - --ipv6 ${if tls.enable then "--forward-https" else ""} - ''; - in - { - User = "root"; - Group = "root"; - Restart = "on-failure"; - Type = "simple"; - ExecStart = "${script}/bin/script"; - }; - }; - }; - paths = { - darkhttpd = { - enable = true; - wantedBy = [ "multi-user.target" ]; - pathConfig = { - PathModified = [ - config.modules.darkhttpd.directory - ] ++ builtins.attrValues config.modules.darkhttpd.symlinks; - }; - }; - }; - }; - - networking.firewall.allowedTCPPorts = [ 80 ]; - }; -} diff --git a/modules/nixos/darkhttpd/tls/default.nix b/modules/nixos/darkhttpd/tls/default.nix @@ -1,76 +0,0 @@ -{ - lib, - options, - config, - pkgs, - ... -}: -{ - options.modules.darkhttpd.tls = { - enable = lib.mkOption { - description = "Whether to enable the Hitch reverse proxy."; - default = false; - type = lib.types.bool; - }; - pemFiles = lib.mkOption { - description = "The list of PEM files to pass to Hitch."; - type = lib.types.listOf lib.types.path; - }; - }; - - config = - let - inherit (config.modules.darkhttpd) tls; - in - lib.mkIf (tls.enable && config.modules.darkhttpd.enable) { - users = { - users = { - hitch = { - hashedPassword = "!"; - isSystemUser = true; - group = "darkhttpd"; - createHome = true; - home = "/var/lib/hitch"; - }; - }; - groups = { - hitch = { }; - }; - }; - - systemd.services.hitch = { - enable = true; - wantedBy = [ "multi-user.target" ]; - after = [ - "acme.service" - ]; - serviceConfig = - let - script = pkgs.writeShellScriptBin "script" '' - ${pkgs.sbase}/bin/cat \ - ${builtins.concatStringsSep " " tls.pemFiles} > \ - /var/lib/hitch/full.pem - - ${pkgs.hitch}/bin/hitch \ - --backend [localhost]:80 \ - --frontend [*]:443 \ - --backend-connect-timeout 30 \ - --ssl-handshake-timeout 30 \ - --ocsp-dir /var/lib/hitch \ - --user hitch \ - --group hitch \ - /var/lib/hitch/full.pem - ''; - in - { - User = "root"; - Group = "root"; - Type = "simple"; - Restart = "on-failure"; - ExecStart = "${script}/bin/script"; - }; - }; - - networking.firewall.allowedTCPPorts = [ 443 ]; - }; -} diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix @@ -3,13 +3,13 @@ imports = [ ./agate ./bind - ./darkhttpd ./doas ./git ./ly ./monero ./networkmanager ./openssh + ./quark ./sway ./tlp ]; diff --git a/modules/nixos/quark/acme/default.nix b/modules/nixos/quark/acme/default.nix @@ -0,0 +1,85 @@ +{ + lib, + options, + config, + pkgs, + ... +}: +{ + options.modules.quark.acme = { + enable = lib.mkOption { + description = "Whether to enable the Certbot ACME client."; + default = false; + type = lib.types.bool; + }; + directory = lib.mkOption { + description = '' + The directory containing fetched Let's Encrypt certificates. + ''; + default = "/etc/letsencrypt/live"; + readOnly = true; + type = lib.types.uniq lib.types.path; + }; + email = lib.mkOption { + description = "The email used for the Let's Encrypt account."; + type = lib.types.uniq lib.types.str; + }; + domain = lib.mkOption { + description = "The domain to fetch the certificate for."; + type = lib.types.uniq lib.types.str; + }; + extraDomains = lib.mkOption { + description = "The extra domains of the certificate."; + default = [ ]; + type = lib.types.listOf lib.types.str; + }; + }; + + config = + let + inherit (config.modules.quark) acme; + in + lib.mkIf (acme.enable && config.modules.quark.enable) { + systemd = { + services = { + acme = { + enable = true; + wantedBy = [ "multi-user.target" ]; + after = [ "quark-setup.service" ]; + serviceConfig = + let + domains = [ acme.domain ] ++ acme.extraDomains; + + script = pkgs.writeShellScriptBin "script" '' + if ${pkgs.certbot}/bin/certbot certificates \ + | ${pkgs.gnugrep}/bin/grep -q "No certificates"; then + ${pkgs.certbot}/bin/certbot certonly --quiet --webroot \ + --agree-tos --email ${acme.email} \ + -w ${config.modules.quark.directory} \ + -d ${builtins.concatStringsSep " -d " domains} + else + ${pkgs.certbot}/bin/certbot renew --quiet + fi + ''; + in + { + User = "root"; + Group = "root"; + Type = "oneshot"; + ExecStart = "${script}/bin/script"; + }; + }; + }; + timers = { + acme = { + enable = true; + wantedBy = [ "multi-user.target" ]; + timerConfig = { + OnCalendar = "weekly"; + Persistent = true; + }; + }; + }; + }; + }; +} diff --git a/modules/nixos/quark/default.nix b/modules/nixos/quark/default.nix @@ -0,0 +1,162 @@ +{ + lib, + options, + config, + pkgs, + ... +}: +{ + imports = [ + ./acme + ./tls + ]; + + options.modules.quark = { + enable = lib.mkOption { + description = "Whether to enable Quark web server."; + default = false; + type = lib.types.bool; + }; + directory = lib.mkOption { + description = "The root directory to statically host."; + default = "/var/www"; + readOnly = true; + type = lib.types.uniq lib.types.path; + }; + symlinks = lib.mkOption { + description = '' + For each symlink name, which will be created in the root directory, its + target. + ''; + default = { }; + type = lib.types.attrsOf lib.types.path; + }; + preStart = { + scripts = lib.mkOption { + description = '' + The list of scripts to run before starting the server. + ''; + default = [ ]; + type = lib.types.listOf lib.types.path; + }; + packages = lib.mkOption { + description = "The list of packages required by the scripts."; + default = [ ]; + type = lib.types.listOf lib.types.package; + }; + }; + }; + + config = lib.mkIf config.modules.quark.enable { + users = { + users = { + quark = { + hashedPassword = "!"; + isSystemUser = true; + group = "quark"; + createHome = true; + home = config.modules.quark.directory; + }; + }; + groups = { + quark = { }; + }; + }; + + systemd = { + services = { + quark-setup = { + enable = true; + wantedBy = [ "multi-user.target" ]; + serviceConfig = + let + permissions = pkgs.writeShellScriptBin "permissions" '' + ${pkgs.sbase}/bin/chmod -R g+rwx \ + ${config.modules.quark.directory} + ''; + clean = pkgs.writeShellScriptBin "clean" '' + ${pkgs.sbase}/bin/rm -rf \ + ${config.modules.quark.directory}/* + ''; + symlinks = + config.modules.quark.symlinks + |> builtins.mapAttrs ( + name: target: + let + inherit (config.modules.quark) directory; + in + '' + ${pkgs.sbase}/bin/mkdir -p \ + ${directory}/${builtins.dirOf name} + + ${pkgs.sbase}/bin/ln -sf ${target} \ + ${directory}/${name} + + ${pkgs.sbase}/bin/chown -Rh darkhttpd:darkhttpd \ + ${directory}/${name} + '' + ) + |> builtins.attrValues + |> builtins.concatStringsSep "\n" + |> pkgs.writeShellScriptBin "symlinks"; + in + { + User = "root"; + Group = "root"; + Type = "oneshot"; + ExecStart = [ + "${permissions}/bin/permissions" + "${clean}/bin/clean" + "${symlinks}/bin/symlinks" + ]; + }; + }; + quark = + let + inherit (config.modules.quark) preStart; + in + rec { + enable = true; + wantedBy = [ "multi-user.target" ]; + requires = [ "quark-setup.service" ]; + after = [ "network.target" ]; + path = preStart.packages; + serviceConfig = + let + inherit (config.modules.quark) customHeaderScripts tls; + script = pkgs.writeShellScriptBin "script" '' + ${builtins.concatStringsSep "\n" preStart.scripts} + + ${pkgs.quark}/bin/quark \ + -p 80 \ + -d ${config.modules.quark.directory} \ + -u quark \ + -g quark \ + -i index.html + ''; + in + { + User = "root"; + Group = "root"; + Restart = "on-failure"; + Type = "simple"; + ExecStart = "${script}/bin/script"; + }; + }; + }; + paths = { + quark = { + enable = true; + wantedBy = [ "multi-user.target" ]; + pathConfig = { + PathModified = [ + config.modules.quark.directory + ] ++ builtins.attrValues config.modules.quark.symlinks; + }; + }; + }; + }; + + networking.firewall.allowedTCPPorts = [ 80 ]; + }; +} diff --git a/modules/nixos/quark/tls/default.nix b/modules/nixos/quark/tls/default.nix @@ -0,0 +1,76 @@ +{ + lib, + options, + config, + pkgs, + ... +}: +{ + options.modules.quark.tls = { + enable = lib.mkOption { + description = "Whether to enable the Hitch reverse proxy."; + default = false; + type = lib.types.bool; + }; + pemFiles = lib.mkOption { + description = "The list of PEM files to pass to Hitch."; + type = lib.types.listOf lib.types.path; + }; + }; + + config = + let + inherit (config.modules.quark) tls; + in + lib.mkIf (tls.enable && config.modules.quark.enable) { + users = { + users = { + hitch = { + hashedPassword = "!"; + isSystemUser = true; + group = "quark"; + createHome = true; + home = "/var/lib/hitch"; + }; + }; + groups = { + hitch = { }; + }; + }; + + systemd.services.hitch = { + enable = true; + wantedBy = [ "multi-user.target" ]; + after = [ + "acme.service" + ]; + serviceConfig = + let + script = pkgs.writeShellScriptBin "script" '' + ${pkgs.sbase}/bin/cat \ + ${builtins.concatStringsSep " " tls.pemFiles} > \ + /var/lib/hitch/full.pem + + ${pkgs.hitch}/bin/hitch \ + --backend [localhost]:80 \ + --frontend [*]:443 \ + --backend-connect-timeout 30 \ + --ssl-handshake-timeout 30 \ + --ocsp-dir /var/lib/hitch \ + --user hitch \ + --group hitch \ + /var/lib/hitch/full.pem + ''; + in + { + User = "root"; + Group = "root"; + Type = "simple"; + Restart = "on-failure"; + ExecStart = "${script}/bin/script"; + }; + }; + + networking.firewall.allowedTCPPorts = [ 443 ]; + }; +}