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:
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 ];
+ };
+}