From e8acca9eab29f11f315aa21d690d4e60c9bca12b Mon Sep 17 00:00:00 2001 From: sinavir Date: Mon, 12 Dec 2022 16:02:50 +0100 Subject: [PATCH 1/7] Module pour lychee v1 --- modules/default.nix | 1 + modules/lychee.nix | 256 +++++++++++++++++++++++++++++++ pkgs/default.nix | 7 +- pkgs/web-apps/lychee-gallery.nix | 15 ++ 4 files changed, 276 insertions(+), 3 deletions(-) create mode 100644 modules/lychee.nix create mode 100644 pkgs/web-apps/lychee-gallery.nix diff --git a/modules/default.nix b/modules/default.nix index ea1b3d7..c2e7b57 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -3,4 +3,5 @@ drone-server = ./servers/drone.nix; drone-exec-runner = ./servers/drone-exec-runner.nix; wordpress = ./web-apps/wordpress; + lychee = ./web-apps/lychee.nix; } diff --git a/modules/lychee.nix b/modules/lychee.nix new file mode 100644 index 0000000..3152606 --- /dev/null +++ b/modules/lychee.nix @@ -0,0 +1,256 @@ +{ pkgs, lib, config, ... }: +let + cfg = config.services.lychee; + src = pkgs.lychee-gallery; + envConf = cfg.settings; +in +{ + options.services.lychee = { + enable = lib.mkEnableOption "Whether to enable lychee"; + website = lib.mkOption { + type = lib.types.str; + default = "localhost"; + example = "www.example.com"; + }; + forceSSL = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Whether to force SSL for the nginx virtual host"; + }; + enableACME = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Whether to enableACME for the nginx virtual host"; + }; + upload_max_filesize = lib.mkOption { + type = lib.types.ints.positive; + default = 30; + description = "Max uploaded file size"; + }; + post_max_size = lib.mkOption { + type = lib.types.ints.positive; + default = 100; + description = "Max post request size"; + }; + user = lib.mkOption { + type = lib.types.str; + default = "lychee"; + description = "The user that will operate on mutable files"; + }; + stateDirectory = lib.mkOption { + type = lib.types.path; + default = "/var/lib/lychee"; + }; + settings = lib.mkOption { + default = {}; + type = lib.types.submodule { + freeformType = with lib.types; attrsOf str; + options = { + DB_DATABASE= lib.mkOption { + type = lib.types.str; + default = "${cfg.stateDirectory}/db.sqlite"; + }; + APP_NAME= lib.mkOption { + type = lib.types.str; + default = "Lychee"; + }; + APP_ENV = lib.mkOption { + type = lib.types.str; + default = "production"; + }; + APP_DEBUG = lib.mkOption { + type = lib.types.str; + default = "\"false\""; + }; + APP_URL = lib.mkOption { + type = lib.types.str; + default = "https://${cfg.website}"; + }; + DEBUGBAR_ENABLED = lib.mkOption { + type = lib.types.str; + default = "\"false\""; + }; + DB_CONNECTION = lib.mkOption { + type = lib.types.str; + default = "sqlite"; + }; + DB_LOG_SQL = lib.mkOption { + type = lib.types.str; + default = "\"false\""; + }; + LYCHEE_UPLOADS = lib.mkOption { + type = lib.types.path; + default = "${cfg.stateDirectory}/www/public/uploads"; + }; + CACHE_DRIVER = lib.mkOption { + type = lib.types.str; + default = "file"; + }; + SESSION_DRIVER = lib.mkOption { + type = lib.types.str; + default = "file"; + }; + SESSION_LIFETIME = lib.mkOption { + type = lib.types.str; + default = "120"; + }; + SECURITY_HEADER_HSTS_ENABLE = lib.mkOption { + type = lib.types.str; + default = "\"false\""; + }; + SESSION_SECURE_COOKIE = lib.mkOption { + type = lib.types.str; + default = "\"false\""; + }; + REDIS_PASSWORD = lib.mkOption { + type = lib.types.str; + default = "\"null\""; + }; + REDIS_PORT = lib.mkOption { + type = lib.types.str; + default = "6379"; + }; + MAIL_DRIVER = lib.mkOption { + type = lib.types.str; + default = "smtp"; + }; + TRUSTED_PROXIES = lib.mkOption { + type = lib.types.str; + default = "\"null\""; + }; + }; + }; + }; + }; + config = let srcDirsToBindMount = [ + "app" + "bootstrap" + "config" + "resources" + "routes" + "scripts" + "vendor" + ]; + in lib.mkIf cfg.enable { + services.nginx = { + enable = true; + virtualHosts.${cfg.website} = { + root = cfg.stateDirectory + "/www/public/"; + forceSSL = lib.mkDefault cfg.forceSSL; + enableACME = lib.mkDefault cfg.enableACME; + locations = { + "^~ /index.php" = { + fastcgiParams = { + SCRIPT_FILENAME = "$document_root$fastcgi_script_name"; + }; + extraConfig = '' + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + fastcgi_pass unix:${config.services.phpfpm.pools."${cfg.website}".socket}; + fastcgi_index index.php; + client_max_body_size ${builtins.toString cfg.upload_max_filesize}M; + ''; + }; + "~ [^/]\.php(/|$)" = { + return = "403"; + }; + "/uploads/" = { + alias = cfg.settings.LYCHEE_UPLOADS; + }; + }; + extraConfig = '' + index index.php; + if (!-e $request_filename) + { + rewrite ^/(.*)$ /index.php?/$1 last; + break; + } + ''; + }; + }; + systemd.tmpfiles.rules = let srcDirToTmpFile = dir: "d ${cfg.stateDirectory}/www/${dir} 0750 ${cfg.user} ${config.services.nginx.group}"; + in [ + "d ${cfg.stateDirectory} 0750 ${cfg.user} ${config.services.nginx.group}" + "d ${cfg.stateDirectory}/www 0750 ${cfg.user} ${config.services.nginx.group}" + "C ${cfg.stateDirectory}/public - ${cfg.user} ${config.services.nginx.group} - ${src}/public" + "Z ${cfg.stateDirectory}/public 0750 ${cfg.user} ${config.services.nginx.group} - -" + "C ${cfg.stateDirectory}/database - ${cfg.user} ${config.services.nginx.group} - ${src}/database" + "Z ${cfg.stateDirectory}/database 0750 ${cfg.user} ${config.services.nginx.group} - -" + "C ${cfg.stateDirectory}/bootstrap-cache - ${cfg.user} ${config.services.nginx.group} - ${src}/bootstrap/cache" + "Z ${cfg.stateDirectory}/bootstrap-cache 0750 ${cfg.user} ${config.services.nginx.group} - -" + "C ${cfg.stateDirectory}/storage - ${cfg.user} ${config.services.nginx.group} - ${src}/storage" + "Z ${cfg.stateDirectory}/storage 0750 ${cfg.user} ${config.services.nginx.group} - -" + "C ${cfg.settings.LYCHEE_UPLOADS} - ${cfg.user} ${config.services.nginx.group} - ${src}/public/uploads" + "Z ${cfg.settings.LYCHEE_UPLOADS} 0750 ${cfg.user} ${config.services.nginx.group} - -" + "f ${cfg.settings.DB_DATABASE} 0750 ${cfg.user} ${cfg.user}" + "L ${cfg.stateDirectory}/www/artisan - - - - ${src}/artisan" + "L ${cfg.stateDirectory}/www/composer.json - - - - ${src}/composer.json" + "L ${cfg.stateDirectory}/www/composer.lock - - - - ${src}/composer.lock" + "L ${cfg.stateDirectory}/www/version.md - - - - ${src}/version.md" + "L ${cfg.stateDirectory}/www/simple_error_template.html - - - - ${src}/simple_error_template.html" + ] ++ (builtins.map srcDirToTmpFile srcDirsToBindMount); + systemd.mounts = let sourceDirToSystemdMount = dir: { + before = [ "phpfpm-${cfg.website}.service" ]; + wantedBy = [ "phpfpm-${cfg.website}.service" ]; + what = "${src}/${dir}"; + where = cfg.stateDirectory + "/www/${dir}"; + options = "bind"; + }; + in [{ + before = [ "phpfpm-${cfg.website}.service" ]; + wantedBy = [ "phpfpm-${cfg.website}.service" ]; + what = cfg.stateDirectory + "/storage"; + where = cfg.stateDirectory + "/www/storage"; + options = "bind"; + }] ++ (builtins.map sourceDirToSystemdMount srcDirsToBindMount) ++ [{ + before = [ "phpfpm-${cfg.website}.service" ]; + wantedBy = [ "phpfpm-${cfg.website}.service" ]; + what = cfg.stateDirectory + "/bootstrap-cache"; + where = cfg.stateDirectory + "/www/bootstrap/cache"; + options = "bind"; + } + { + before = [ "phpfpm-${cfg.website}.service" ]; + wantedBy = [ "phpfpm-${cfg.website}.service" ]; + what = cfg.stateDirectory + "/database"; + where = cfg.stateDirectory + "/www/database"; + options = "bind"; + } + { + before = [ "phpfpm-${cfg.website}.service" ]; + wantedBy = [ "phpfpm-${cfg.website}.service" ]; + what = cfg.stateDirectory + "/public"; + where = cfg.stateDirectory + "/www/public"; + options = "bind"; + }]; + services.phpfpm.pools.${cfg.website} = { + user = cfg.user; + phpPackage = pkgs.php81.withExtensions ({ enabled, all }: + enabled ++ [ all.imagick all.bcmath all.mbstring all.gd]); + phpOptions = '' + upload_max_filesize = ${builtins.toString cfg.upload_max_filesize}M + post_max_size = ${builtins.toString cfg.post_max_size}M + ''; + settings = { + "pm" = "dynamic"; + "pm.max_children" = 75; + "pm.start_servers" = 10; + "pm.min_spare_servers" = 5; + "pm.max_spare_servers" = 20; + "pm.max_requests" = 500; + "listen.owner" = config.services.nginx.user; + "listen.group" = config.services.nginx.group; + }; + phpEnv = { + "PATH" = lib.makeBinPath [ pkgs.ffmpeg ]; + } // envConf; + }; + users.users.${cfg.user} = { + isSystemUser = true; + home = src; + group = cfg.user; + }; + users.groups.${cfg.user} = { }; + networking.firewall.allowedTCPPorts = [ 80 443 ]; + }; +} + diff --git a/pkgs/default.nix b/pkgs/default.nix index 862bbb9..fb72abd 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -7,8 +7,9 @@ let subsetArgs = builtins.listToAttrs [{ name = attrName; value = mergedSubset; }]; in callPackage f (subsetArgs // extraArgs); - self = rec { - acme-dns = callPackage ./servers/acme-dns.nix {}; - }; + self = rec { + acme-dns = callPackage ./servers/acme-dns.nix {}; + lychee-gallery = callPackage ./web-apps/lychee-gallery.nix {}; + }; in self diff --git a/pkgs/web-apps/lychee-gallery.nix b/pkgs/web-apps/lychee-gallery.nix new file mode 100644 index 0000000..212fc43 --- /dev/null +++ b/pkgs/web-apps/lychee-gallery.nix @@ -0,0 +1,15 @@ +{ stdenv, fetchzip, pkgs, env ? {} }: +stdenv.mkDerivation rec { + pname = "Lychee"; + version = "4.6.2"; + src = fetchzip { + url = "https://github.com/LycheeOrg/Lychee/releases/download/v${version}/Lychee.zip"; + sha256 = "sha256-dNujUTGaxvc6uZgyanNh9kIzRqfFA9yFhAtexu1sVc4="; + }; + installPhase = '' + shopt -s dotglob + mkdir $out + mv .env.example .env + mv * $out/ + ''; +} -- 2.46.1 From 74e0802c114b260054a591f082148171748c64fd Mon Sep 17 00:00:00 2001 From: sinavir Date: Mon, 12 Dec 2022 18:05:47 +0100 Subject: [PATCH 2/7] right location for lychee module --- modules/{ => web-apps}/lychee.nix | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename modules/{ => web-apps}/lychee.nix (100%) diff --git a/modules/lychee.nix b/modules/web-apps/lychee.nix similarity index 100% rename from modules/lychee.nix rename to modules/web-apps/lychee.nix -- 2.46.1 From 4656f9c678fdd2935fb2b1f0ffe2ff81ba3ba163 Mon Sep 17 00:00:00 2001 From: sinavir Date: Mon, 12 Dec 2022 18:09:54 +0100 Subject: [PATCH 3/7] add option to set package --- modules/web-apps/lychee.nix | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/web-apps/lychee.nix b/modules/web-apps/lychee.nix index 3152606..da7a24a 100644 --- a/modules/web-apps/lychee.nix +++ b/modules/web-apps/lychee.nix @@ -1,7 +1,7 @@ { pkgs, lib, config, ... }: let cfg = config.services.lychee; - src = pkgs.lychee-gallery; + src = cfg.package; envConf = cfg.settings; in { @@ -12,6 +12,9 @@ in default = "localhost"; example = "www.example.com"; }; + package = lib.mkOption { + type = lib.types.path; + }; forceSSL = lib.mkOption { type = lib.types.bool; default = true; -- 2.46.1 From cdfc2b380e254ce073c13b4a274166e8dcaf5f27 Mon Sep 17 00:00:00 2001 From: sinavir Date: Tue, 13 Dec 2022 21:25:44 +0100 Subject: [PATCH 4/7] lychee module improvment --- modules/default.nix | 2 +- .../{lychee.nix => lychee/default.nix} | 145 +++++------------- modules/web-apps/lychee/test.nix | 31 ++++ 3 files changed, 72 insertions(+), 106 deletions(-) rename modules/web-apps/{lychee.nix => lychee/default.nix} (50%) create mode 100644 modules/web-apps/lychee/test.nix diff --git a/modules/default.nix b/modules/default.nix index c2e7b57..2c5da97 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -3,5 +3,5 @@ drone-server = ./servers/drone.nix; drone-exec-runner = ./servers/drone-exec-runner.nix; wordpress = ./web-apps/wordpress; - lychee = ./web-apps/lychee.nix; + lychee = ./web-apps/lychee; } diff --git a/modules/web-apps/lychee.nix b/modules/web-apps/lychee/default.nix similarity index 50% rename from modules/web-apps/lychee.nix rename to modules/web-apps/lychee/default.nix index da7a24a..1387f34 100644 --- a/modules/web-apps/lychee.nix +++ b/modules/web-apps/lychee/default.nix @@ -17,12 +17,12 @@ in }; forceSSL = lib.mkOption { type = lib.types.bool; - default = true; + default = false; description = "Whether to force SSL for the nginx virtual host"; }; enableACME = lib.mkOption { type = lib.types.bool; - default = true; + default = false; description = "Whether to enableACME for the nginx virtual host"; }; upload_max_filesize = lib.mkOption { @@ -40,38 +40,14 @@ in default = "lychee"; description = "The user that will operate on mutable files"; }; - stateDirectory = lib.mkOption { - type = lib.types.path; - default = "/var/lib/lychee"; - }; settings = lib.mkOption { default = {}; type = lib.types.submodule { freeformType = with lib.types; attrsOf str; options = { - DB_DATABASE= lib.mkOption { - type = lib.types.str; - default = "${cfg.stateDirectory}/db.sqlite"; - }; - APP_NAME= lib.mkOption { - type = lib.types.str; - default = "Lychee"; - }; - APP_ENV = lib.mkOption { - type = lib.types.str; - default = "production"; - }; - APP_DEBUG = lib.mkOption { - type = lib.types.str; - default = "\"false\""; - }; APP_URL = lib.mkOption { type = lib.types.str; - default = "https://${cfg.website}"; - }; - DEBUGBAR_ENABLED = lib.mkOption { - type = lib.types.str; - default = "\"false\""; + default = "http://${cfg.website}"; }; DB_CONNECTION = lib.mkOption { type = lib.types.str; @@ -81,10 +57,6 @@ in type = lib.types.str; default = "\"false\""; }; - LYCHEE_UPLOADS = lib.mkOption { - type = lib.types.path; - default = "${cfg.stateDirectory}/www/public/uploads"; - }; CACHE_DRIVER = lib.mkOption { type = lib.types.str; default = "file"; @@ -117,28 +89,15 @@ in type = lib.types.str; default = "smtp"; }; - TRUSTED_PROXIES = lib.mkOption { - type = lib.types.str; - default = "\"null\""; - }; }; }; }; }; - config = let srcDirsToBindMount = [ - "app" - "bootstrap" - "config" - "resources" - "routes" - "scripts" - "vendor" - ]; - in lib.mkIf cfg.enable { + config = lib.mkIf cfg.enable { services.nginx = { enable = true; virtualHosts.${cfg.website} = { - root = cfg.stateDirectory + "/www/public/"; + root = "/var/lib/lychee/public/"; forceSSL = lib.mkDefault cfg.forceSSL; enableACME = lib.mkDefault cfg.enableACME; locations = { @@ -156,9 +115,6 @@ in "~ [^/]\.php(/|$)" = { return = "403"; }; - "/uploads/" = { - alias = cfg.settings.LYCHEE_UPLOADS; - }; }; extraConfig = '' index index.php; @@ -170,61 +126,40 @@ in ''; }; }; - systemd.tmpfiles.rules = let srcDirToTmpFile = dir: "d ${cfg.stateDirectory}/www/${dir} 0750 ${cfg.user} ${config.services.nginx.group}"; - in [ - "d ${cfg.stateDirectory} 0750 ${cfg.user} ${config.services.nginx.group}" - "d ${cfg.stateDirectory}/www 0750 ${cfg.user} ${config.services.nginx.group}" - "C ${cfg.stateDirectory}/public - ${cfg.user} ${config.services.nginx.group} - ${src}/public" - "Z ${cfg.stateDirectory}/public 0750 ${cfg.user} ${config.services.nginx.group} - -" - "C ${cfg.stateDirectory}/database - ${cfg.user} ${config.services.nginx.group} - ${src}/database" - "Z ${cfg.stateDirectory}/database 0750 ${cfg.user} ${config.services.nginx.group} - -" - "C ${cfg.stateDirectory}/bootstrap-cache - ${cfg.user} ${config.services.nginx.group} - ${src}/bootstrap/cache" - "Z ${cfg.stateDirectory}/bootstrap-cache 0750 ${cfg.user} ${config.services.nginx.group} - -" - "C ${cfg.stateDirectory}/storage - ${cfg.user} ${config.services.nginx.group} - ${src}/storage" - "Z ${cfg.stateDirectory}/storage 0750 ${cfg.user} ${config.services.nginx.group} - -" - "C ${cfg.settings.LYCHEE_UPLOADS} - ${cfg.user} ${config.services.nginx.group} - ${src}/public/uploads" - "Z ${cfg.settings.LYCHEE_UPLOADS} 0750 ${cfg.user} ${config.services.nginx.group} - -" - "f ${cfg.settings.DB_DATABASE} 0750 ${cfg.user} ${cfg.user}" - "L ${cfg.stateDirectory}/www/artisan - - - - ${src}/artisan" - "L ${cfg.stateDirectory}/www/composer.json - - - - ${src}/composer.json" - "L ${cfg.stateDirectory}/www/composer.lock - - - - ${src}/composer.lock" - "L ${cfg.stateDirectory}/www/version.md - - - - ${src}/version.md" - "L ${cfg.stateDirectory}/www/simple_error_template.html - - - - ${src}/simple_error_template.html" - ] ++ (builtins.map srcDirToTmpFile srcDirsToBindMount); - systemd.mounts = let sourceDirToSystemdMount = dir: { - before = [ "phpfpm-${cfg.website}.service" ]; + systemd.services."lychee-install" = { wantedBy = [ "phpfpm-${cfg.website}.service" ]; - what = "${src}/${dir}"; - where = cfg.stateDirectory + "/www/${dir}"; - options = "bind"; + script = let rsync = pkgs.rsync; in '' + ${rsync}/bin/rsync -a --ignore-existing ${src}/ $STATE_DIRECTORY + chmod u+w $STATE_DIRECTORY/ + chmod u+w $STATE_DIRECTORY/.env + chmod u+w $STATE_DIRECTORY/database/ + chmod u+w $STATE_DIRECTORY/database/database.sqlite + chmod -R u+w $STATE_DIRECTORY/storage/ + chmod -R u+w $STATE_DIRECTORY/public/ + chmod -R u+w $STATE_DIRECTORY/bootstrap/cache/ + ''; + serviceConfig = { + Type = "oneshot"; + StateDirectory = "lychee"; + User = cfg.user; + Restart = "on-failure"; + ProtectHome = true; + ProtectSystem = "strict"; + PrivateTmp = true; + PrivateDevices = true; + ProtectHostname = true; + ProtectClock = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + NoNewPrivileges = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + RemoveIPC = true; + PrivateMounts = true; + }; }; - in [{ - before = [ "phpfpm-${cfg.website}.service" ]; - wantedBy = [ "phpfpm-${cfg.website}.service" ]; - what = cfg.stateDirectory + "/storage"; - where = cfg.stateDirectory + "/www/storage"; - options = "bind"; - }] ++ (builtins.map sourceDirToSystemdMount srcDirsToBindMount) ++ [{ - before = [ "phpfpm-${cfg.website}.service" ]; - wantedBy = [ "phpfpm-${cfg.website}.service" ]; - what = cfg.stateDirectory + "/bootstrap-cache"; - where = cfg.stateDirectory + "/www/bootstrap/cache"; - options = "bind"; - } - { - before = [ "phpfpm-${cfg.website}.service" ]; - wantedBy = [ "phpfpm-${cfg.website}.service" ]; - what = cfg.stateDirectory + "/database"; - where = cfg.stateDirectory + "/www/database"; - options = "bind"; - } - { - before = [ "phpfpm-${cfg.website}.service" ]; - wantedBy = [ "phpfpm-${cfg.website}.service" ]; - what = cfg.stateDirectory + "/public"; - where = cfg.stateDirectory + "/www/public"; - options = "bind"; - }]; services.phpfpm.pools.${cfg.website} = { user = cfg.user; phpPackage = pkgs.php81.withExtensions ({ enabled, all }: @@ -248,9 +183,9 @@ in } // envConf; }; users.users.${cfg.user} = { - isSystemUser = true; - home = src; - group = cfg.user; + isSystemUser = lib.mkDefault true; + home = lib.mkDefault src; + group = lib.mkDefault cfg.user; }; users.groups.${cfg.user} = { }; networking.firewall.allowedTCPPorts = [ 80 443 ]; diff --git a/modules/web-apps/lychee/test.nix b/modules/web-apps/lychee/test.nix new file mode 100644 index 0000000..9ab0608 --- /dev/null +++ b/modules/web-apps/lychee/test.nix @@ -0,0 +1,31 @@ +{ pkgs ? import {}, myPkgs ? import ../.. {}}: +pkgs.nixosTest ({ + # NixOS tests are run inside a virtual machine, and here we specify system of the machine. + nodes = { + server = { config, pkgs, ... }: { + imports = [ myPkgs.modules.lychee ]; + + security.acme.acceptTerms = true; + security.acme.defaults.email = "test@test.fr"; + services.lychee = { + enable = true; + package = myPkgs.lychee-gallery; + forceSSL = true; + enableACME = true; + }; + environment.systemPackages = [ pkgs.w3m ]; + + users = { + mutableUsers = false; + users = { + # For ease of debugging the VM as the `root` user + root.password = ""; + }; + }; + }; + }; + testScript = '' + start_all() + server.wait_for_unit("default.target") + ''; +}) -- 2.46.1 From 5000b09caa871fe58876faeddcda49c08ee2ec51 Mon Sep 17 00:00:00 2001 From: sinavir Date: Tue, 13 Dec 2022 21:53:13 +0100 Subject: [PATCH 5/7] nixfmt; better phpfpm settings; working systemd unit --- modules/web-apps/lychee/default.nix | 50 ++++++++++++----------------- modules/web-apps/lychee/test.nix | 6 ++-- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/modules/web-apps/lychee/default.nix b/modules/web-apps/lychee/default.nix index 1387f34..9989a1e 100644 --- a/modules/web-apps/lychee/default.nix +++ b/modules/web-apps/lychee/default.nix @@ -3,8 +3,7 @@ let cfg = config.services.lychee; src = cfg.package; envConf = cfg.settings; -in -{ +in { options.services.lychee = { enable = lib.mkEnableOption "Whether to enable lychee"; website = lib.mkOption { @@ -12,9 +11,7 @@ in default = "localhost"; example = "www.example.com"; }; - package = lib.mkOption { - type = lib.types.path; - }; + package = lib.mkOption { type = lib.types.path; }; forceSSL = lib.mkOption { type = lib.types.bool; default = false; @@ -41,7 +38,7 @@ in description = "The user that will operate on mutable files"; }; settings = lib.mkOption { - default = {}; + default = { }; type = lib.types.submodule { freeformType = with lib.types; attrsOf str; options = { @@ -55,7 +52,7 @@ in }; DB_LOG_SQL = lib.mkOption { type = lib.types.str; - default = "\"false\""; + default = ''"false"''; }; CACHE_DRIVER = lib.mkOption { type = lib.types.str; @@ -71,15 +68,15 @@ in }; SECURITY_HEADER_HSTS_ENABLE = lib.mkOption { type = lib.types.str; - default = "\"false\""; + default = ''"false"''; }; SESSION_SECURE_COOKIE = lib.mkOption { type = lib.types.str; - default = "\"false\""; + default = ''"false"''; }; REDIS_PASSWORD = lib.mkOption { type = lib.types.str; - default = "\"null\""; + default = ''"null"''; }; REDIS_PORT = lib.mkOption { type = lib.types.str; @@ -107,14 +104,16 @@ in }; extraConfig = '' fastcgi_split_path_info ^(.+?\.php)(/.*)$; - fastcgi_pass unix:${config.services.phpfpm.pools."${cfg.website}".socket}; + fastcgi_pass unix:${ + config.services.phpfpm.pools."${cfg.website}".socket + }; fastcgi_index index.php; - client_max_body_size ${builtins.toString cfg.upload_max_filesize}M; + client_max_body_size ${ + builtins.toString cfg.upload_max_filesize + }M; ''; }; - "~ [^/]\.php(/|$)" = { - return = "403"; - }; + "~ [^/].php(/|$)" = { return = "403"; }; }; extraConfig = '' index index.php; @@ -128,7 +127,9 @@ in }; systemd.services."lychee-install" = { wantedBy = [ "phpfpm-${cfg.website}.service" ]; - script = let rsync = pkgs.rsync; in '' + before = [ "phpfpm-${cfg.website}.service" ]; + script = let rsync = pkgs.rsync; + in '' ${rsync}/bin/rsync -a --ignore-existing ${src}/ $STATE_DIRECTORY chmod u+w $STATE_DIRECTORY/ chmod u+w $STATE_DIRECTORY/.env @@ -137,7 +138,7 @@ in chmod -R u+w $STATE_DIRECTORY/storage/ chmod -R u+w $STATE_DIRECTORY/public/ chmod -R u+w $STATE_DIRECTORY/bootstrap/cache/ - ''; + ''; serviceConfig = { Type = "oneshot"; StateDirectory = "lychee"; @@ -163,24 +164,16 @@ in services.phpfpm.pools.${cfg.website} = { user = cfg.user; phpPackage = pkgs.php81.withExtensions ({ enabled, all }: - enabled ++ [ all.imagick all.bcmath all.mbstring all.gd]); + enabled ++ [ all.imagick all.bcmath all.mbstring all.gd ]); phpOptions = '' upload_max_filesize = ${builtins.toString cfg.upload_max_filesize}M post_max_size = ${builtins.toString cfg.post_max_size}M - ''; + ''; settings = { - "pm" = "dynamic"; - "pm.max_children" = 75; - "pm.start_servers" = 10; - "pm.min_spare_servers" = 5; - "pm.max_spare_servers" = 20; - "pm.max_requests" = 500; "listen.owner" = config.services.nginx.user; "listen.group" = config.services.nginx.group; }; - phpEnv = { - "PATH" = lib.makeBinPath [ pkgs.ffmpeg ]; - } // envConf; + phpEnv = { "PATH" = lib.makeBinPath [ pkgs.ffmpeg ]; } // envConf; }; users.users.${cfg.user} = { isSystemUser = lib.mkDefault true; @@ -188,7 +181,6 @@ in group = lib.mkDefault cfg.user; }; users.groups.${cfg.user} = { }; - networking.firewall.allowedTCPPorts = [ 80 443 ]; }; } diff --git a/modules/web-apps/lychee/test.nix b/modules/web-apps/lychee/test.nix index 9ab0608..65a489d 100644 --- a/modules/web-apps/lychee/test.nix +++ b/modules/web-apps/lychee/test.nix @@ -1,4 +1,4 @@ -{ pkgs ? import {}, myPkgs ? import ../.. {}}: +{ pkgs ? import { }, myPkgs ? import ../.. { } }: pkgs.nixosTest ({ # NixOS tests are run inside a virtual machine, and here we specify system of the machine. nodes = { @@ -26,6 +26,6 @@ pkgs.nixosTest ({ }; testScript = '' start_all() - server.wait_for_unit("default.target") - ''; + server.wait_for_unit("phpfpm-localhost.service") + ''; }) -- 2.46.1 From 9c43904eb242455ca3db9466c5679c81aa92741f Mon Sep 17 00:00:00 2001 From: sinavir Date: Tue, 13 Dec 2022 21:56:48 +0100 Subject: [PATCH 6/7] Module pour lychee (#4) Serveur photos Co-authored-by: sinavir Reviewed-on: https://git.rz.ens.wtf/Klub-RZ/nur/pulls/4 Co-authored-by: sinavir Co-committed-by: sinavir --- modules/default.nix | 1 + modules/web-apps/lychee/default.nix | 186 ++++++++++++++++++++++++++++ modules/web-apps/lychee/test.nix | 31 +++++ pkgs/default.nix | 7 +- pkgs/web-apps/lychee-gallery.nix | 15 +++ 5 files changed, 237 insertions(+), 3 deletions(-) create mode 100644 modules/web-apps/lychee/default.nix create mode 100644 modules/web-apps/lychee/test.nix create mode 100644 pkgs/web-apps/lychee-gallery.nix diff --git a/modules/default.nix b/modules/default.nix index ea1b3d7..2c5da97 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -3,4 +3,5 @@ drone-server = ./servers/drone.nix; drone-exec-runner = ./servers/drone-exec-runner.nix; wordpress = ./web-apps/wordpress; + lychee = ./web-apps/lychee; } diff --git a/modules/web-apps/lychee/default.nix b/modules/web-apps/lychee/default.nix new file mode 100644 index 0000000..9989a1e --- /dev/null +++ b/modules/web-apps/lychee/default.nix @@ -0,0 +1,186 @@ +{ pkgs, lib, config, ... }: +let + cfg = config.services.lychee; + src = cfg.package; + envConf = cfg.settings; +in { + options.services.lychee = { + enable = lib.mkEnableOption "Whether to enable lychee"; + website = lib.mkOption { + type = lib.types.str; + default = "localhost"; + example = "www.example.com"; + }; + package = lib.mkOption { type = lib.types.path; }; + forceSSL = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether to force SSL for the nginx virtual host"; + }; + enableACME = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether to enableACME for the nginx virtual host"; + }; + upload_max_filesize = lib.mkOption { + type = lib.types.ints.positive; + default = 30; + description = "Max uploaded file size"; + }; + post_max_size = lib.mkOption { + type = lib.types.ints.positive; + default = 100; + description = "Max post request size"; + }; + user = lib.mkOption { + type = lib.types.str; + default = "lychee"; + description = "The user that will operate on mutable files"; + }; + settings = lib.mkOption { + default = { }; + type = lib.types.submodule { + freeformType = with lib.types; attrsOf str; + options = { + APP_URL = lib.mkOption { + type = lib.types.str; + default = "http://${cfg.website}"; + }; + DB_CONNECTION = lib.mkOption { + type = lib.types.str; + default = "sqlite"; + }; + DB_LOG_SQL = lib.mkOption { + type = lib.types.str; + default = ''"false"''; + }; + CACHE_DRIVER = lib.mkOption { + type = lib.types.str; + default = "file"; + }; + SESSION_DRIVER = lib.mkOption { + type = lib.types.str; + default = "file"; + }; + SESSION_LIFETIME = lib.mkOption { + type = lib.types.str; + default = "120"; + }; + SECURITY_HEADER_HSTS_ENABLE = lib.mkOption { + type = lib.types.str; + default = ''"false"''; + }; + SESSION_SECURE_COOKIE = lib.mkOption { + type = lib.types.str; + default = ''"false"''; + }; + REDIS_PASSWORD = lib.mkOption { + type = lib.types.str; + default = ''"null"''; + }; + REDIS_PORT = lib.mkOption { + type = lib.types.str; + default = "6379"; + }; + MAIL_DRIVER = lib.mkOption { + type = lib.types.str; + default = "smtp"; + }; + }; + }; + }; + }; + config = lib.mkIf cfg.enable { + services.nginx = { + enable = true; + virtualHosts.${cfg.website} = { + root = "/var/lib/lychee/public/"; + forceSSL = lib.mkDefault cfg.forceSSL; + enableACME = lib.mkDefault cfg.enableACME; + locations = { + "^~ /index.php" = { + fastcgiParams = { + SCRIPT_FILENAME = "$document_root$fastcgi_script_name"; + }; + extraConfig = '' + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + fastcgi_pass unix:${ + config.services.phpfpm.pools."${cfg.website}".socket + }; + fastcgi_index index.php; + client_max_body_size ${ + builtins.toString cfg.upload_max_filesize + }M; + ''; + }; + "~ [^/].php(/|$)" = { return = "403"; }; + }; + extraConfig = '' + index index.php; + if (!-e $request_filename) + { + rewrite ^/(.*)$ /index.php?/$1 last; + break; + } + ''; + }; + }; + systemd.services."lychee-install" = { + wantedBy = [ "phpfpm-${cfg.website}.service" ]; + before = [ "phpfpm-${cfg.website}.service" ]; + script = let rsync = pkgs.rsync; + in '' + ${rsync}/bin/rsync -a --ignore-existing ${src}/ $STATE_DIRECTORY + chmod u+w $STATE_DIRECTORY/ + chmod u+w $STATE_DIRECTORY/.env + chmod u+w $STATE_DIRECTORY/database/ + chmod u+w $STATE_DIRECTORY/database/database.sqlite + chmod -R u+w $STATE_DIRECTORY/storage/ + chmod -R u+w $STATE_DIRECTORY/public/ + chmod -R u+w $STATE_DIRECTORY/bootstrap/cache/ + ''; + serviceConfig = { + Type = "oneshot"; + StateDirectory = "lychee"; + User = cfg.user; + Restart = "on-failure"; + ProtectHome = true; + ProtectSystem = "strict"; + PrivateTmp = true; + PrivateDevices = true; + ProtectHostname = true; + ProtectClock = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + NoNewPrivileges = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + RemoveIPC = true; + PrivateMounts = true; + }; + }; + services.phpfpm.pools.${cfg.website} = { + user = cfg.user; + phpPackage = pkgs.php81.withExtensions ({ enabled, all }: + enabled ++ [ all.imagick all.bcmath all.mbstring all.gd ]); + phpOptions = '' + upload_max_filesize = ${builtins.toString cfg.upload_max_filesize}M + post_max_size = ${builtins.toString cfg.post_max_size}M + ''; + settings = { + "listen.owner" = config.services.nginx.user; + "listen.group" = config.services.nginx.group; + }; + phpEnv = { "PATH" = lib.makeBinPath [ pkgs.ffmpeg ]; } // envConf; + }; + users.users.${cfg.user} = { + isSystemUser = lib.mkDefault true; + home = lib.mkDefault src; + group = lib.mkDefault cfg.user; + }; + users.groups.${cfg.user} = { }; + }; +} + diff --git a/modules/web-apps/lychee/test.nix b/modules/web-apps/lychee/test.nix new file mode 100644 index 0000000..65a489d --- /dev/null +++ b/modules/web-apps/lychee/test.nix @@ -0,0 +1,31 @@ +{ pkgs ? import { }, myPkgs ? import ../.. { } }: +pkgs.nixosTest ({ + # NixOS tests are run inside a virtual machine, and here we specify system of the machine. + nodes = { + server = { config, pkgs, ... }: { + imports = [ myPkgs.modules.lychee ]; + + security.acme.acceptTerms = true; + security.acme.defaults.email = "test@test.fr"; + services.lychee = { + enable = true; + package = myPkgs.lychee-gallery; + forceSSL = true; + enableACME = true; + }; + environment.systemPackages = [ pkgs.w3m ]; + + users = { + mutableUsers = false; + users = { + # For ease of debugging the VM as the `root` user + root.password = ""; + }; + }; + }; + }; + testScript = '' + start_all() + server.wait_for_unit("phpfpm-localhost.service") + ''; +}) diff --git a/pkgs/default.nix b/pkgs/default.nix index 862bbb9..fb72abd 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -7,8 +7,9 @@ let subsetArgs = builtins.listToAttrs [{ name = attrName; value = mergedSubset; }]; in callPackage f (subsetArgs // extraArgs); - self = rec { - acme-dns = callPackage ./servers/acme-dns.nix {}; - }; + self = rec { + acme-dns = callPackage ./servers/acme-dns.nix {}; + lychee-gallery = callPackage ./web-apps/lychee-gallery.nix {}; + }; in self diff --git a/pkgs/web-apps/lychee-gallery.nix b/pkgs/web-apps/lychee-gallery.nix new file mode 100644 index 0000000..212fc43 --- /dev/null +++ b/pkgs/web-apps/lychee-gallery.nix @@ -0,0 +1,15 @@ +{ stdenv, fetchzip, pkgs, env ? {} }: +stdenv.mkDerivation rec { + pname = "Lychee"; + version = "4.6.2"; + src = fetchzip { + url = "https://github.com/LycheeOrg/Lychee/releases/download/v${version}/Lychee.zip"; + sha256 = "sha256-dNujUTGaxvc6uZgyanNh9kIzRqfFA9yFhAtexu1sVc4="; + }; + installPhase = '' + shopt -s dotglob + mkdir $out + mv .env.example .env + mv * $out/ + ''; +} -- 2.46.1 From b7a96472eb157a790f18cfc32b68db6dd979113f Mon Sep 17 00:00:00 2001 From: sinavir Date: Wed, 25 Jan 2023 20:09:41 +0100 Subject: [PATCH 7/7] phpfpm: pm=dynamic --- modules/web-apps/lychee/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/web-apps/lychee/default.nix b/modules/web-apps/lychee/default.nix index 9989a1e..1876be2 100644 --- a/modules/web-apps/lychee/default.nix +++ b/modules/web-apps/lychee/default.nix @@ -170,6 +170,7 @@ in { post_max_size = ${builtins.toString cfg.post_max_size}M ''; settings = { + "pm" = "dynamic"; "listen.owner" = config.services.nginx.user; "listen.group" = config.services.nginx.group; }; -- 2.46.1