commit
87fdc06a97
@ -789,6 +789,7 @@
|
|||||||
./services/web-apps/mattermost.nix
|
./services/web-apps/mattermost.nix
|
||||||
./services/web-apps/mediawiki.nix
|
./services/web-apps/mediawiki.nix
|
||||||
./services/web-apps/miniflux.nix
|
./services/web-apps/miniflux.nix
|
||||||
|
./services/web-apps/moodle.nix
|
||||||
./services/web-apps/nextcloud.nix
|
./services/web-apps/nextcloud.nix
|
||||||
./services/web-apps/nexus.nix
|
./services/web-apps/nexus.nix
|
||||||
./services/web-apps/pgpkeyserver-lite.nix
|
./services/web-apps/pgpkeyserver-lite.nix
|
||||||
|
300
nixos/modules/services/web-apps/moodle.nix
Normal file
300
nixos/modules/services/web-apps/moodle.nix
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption types;
|
||||||
|
inherit (lib) concatStringsSep literalExample mapAttrsToList optional optionalString;
|
||||||
|
|
||||||
|
cfg = config.services.moodle;
|
||||||
|
fpm = config.services.phpfpm.pools.moodle;
|
||||||
|
|
||||||
|
user = "moodle";
|
||||||
|
group = config.services.httpd.group;
|
||||||
|
stateDir = "/var/lib/moodle";
|
||||||
|
|
||||||
|
moodleConfig = pkgs.writeText "config.php" ''
|
||||||
|
<?php // Moodle configuration file
|
||||||
|
|
||||||
|
unset($CFG);
|
||||||
|
global $CFG;
|
||||||
|
$CFG = new stdClass();
|
||||||
|
|
||||||
|
$CFG->dbtype = '${ { "mysql" = "mariadb"; "pgsql" = "pgsql"; }.${cfg.database.type} }';
|
||||||
|
$CFG->dblibrary = 'native';
|
||||||
|
$CFG->dbhost = '${cfg.database.host}';
|
||||||
|
$CFG->dbname = '${cfg.database.name}';
|
||||||
|
$CFG->dbuser = '${cfg.database.user}';
|
||||||
|
${optionalString (cfg.database.passwordFile != null) "$CFG->dbpass = file_get_contents('${cfg.database.passwordFile}');"}
|
||||||
|
$CFG->prefix = 'mdl_';
|
||||||
|
$CFG->dboptions = array (
|
||||||
|
'dbpersist' => 0,
|
||||||
|
'dbport' => '${toString cfg.database.port}',
|
||||||
|
${optionalString (cfg.database.socket != null) "'dbsocket' => '${cfg.database.socket}',"}
|
||||||
|
'dbcollation' => 'utf8mb4_unicode_ci',
|
||||||
|
);
|
||||||
|
|
||||||
|
$CFG->wwwroot = '${if cfg.virtualHost.enableSSL then "https" else "http"}://${cfg.virtualHost.hostName}';
|
||||||
|
$CFG->dataroot = '${stateDir}';
|
||||||
|
$CFG->admin = 'admin';
|
||||||
|
|
||||||
|
$CFG->directorypermissions = 02777;
|
||||||
|
$CFG->disableupdateautodeploy = true;
|
||||||
|
|
||||||
|
$CFG->pathtogs = '${pkgs.ghostscript}/bin/gs';
|
||||||
|
$CFG->pathtophp = '${pkgs.php}/bin/php';
|
||||||
|
$CFG->pathtodu = '${pkgs.coreutils}/bin/du';
|
||||||
|
$CFG->aspellpath = '${pkgs.aspell}/bin/aspell';
|
||||||
|
$CFG->pathtodot = '${pkgs.graphviz}/bin/dot';
|
||||||
|
|
||||||
|
require_once('${cfg.package}/share/moodle/lib/setup.php');
|
||||||
|
|
||||||
|
// There is no php closing tag in this file,
|
||||||
|
// it is intentional because it prevents trailing whitespace problems!
|
||||||
|
'';
|
||||||
|
|
||||||
|
mysqlLocal = cfg.database.createLocally && cfg.database.type == "mysql";
|
||||||
|
pgsqlLocal = cfg.database.createLocally && cfg.database.type == "pgsql";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# interface
|
||||||
|
options.services.moodle = {
|
||||||
|
enable = mkEnableOption "Moodle web application";
|
||||||
|
|
||||||
|
package = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
default = pkgs.moodle;
|
||||||
|
defaultText = "pkgs.moodle";
|
||||||
|
description = "The Moodle package to use.";
|
||||||
|
};
|
||||||
|
|
||||||
|
initialPassword = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "correcthorsebatterystaple";
|
||||||
|
description = ''
|
||||||
|
Specifies the initial password for the admin, i.e. the password assigned if the user does not already exist.
|
||||||
|
The password specified here is world-readable in the Nix store, so it should be changed promptly.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
database = {
|
||||||
|
type = mkOption {
|
||||||
|
type = types.enum [ "mysql" "pgsql" ];
|
||||||
|
default = "mysql";
|
||||||
|
description = ''Database engine to use.'';
|
||||||
|
};
|
||||||
|
|
||||||
|
host = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "localhost";
|
||||||
|
description = "Database host address.";
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
description = "Database host port.";
|
||||||
|
default = {
|
||||||
|
"mysql" = 3306;
|
||||||
|
"pgsql" = 5432;
|
||||||
|
}.${cfg.database.type};
|
||||||
|
defaultText = "3306";
|
||||||
|
};
|
||||||
|
|
||||||
|
name = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "moodle";
|
||||||
|
description = "Database name.";
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "moodle";
|
||||||
|
description = "Database user.";
|
||||||
|
};
|
||||||
|
|
||||||
|
passwordFile = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = null;
|
||||||
|
example = "/run/keys/moodle-dbpassword";
|
||||||
|
description = ''
|
||||||
|
A file containing the password corresponding to
|
||||||
|
<option>database.user</option>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
socket = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default =
|
||||||
|
if mysqlLocal then "/run/mysqld/mysqld.sock"
|
||||||
|
else if pgsqlLocal then "/run/postgresql"
|
||||||
|
else null;
|
||||||
|
defaultText = "/run/mysqld/mysqld.sock";
|
||||||
|
description = "Path to the unix socket file to use for authentication.";
|
||||||
|
};
|
||||||
|
|
||||||
|
createLocally = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Create the database and database user locally.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
virtualHost = mkOption {
|
||||||
|
type = types.submodule ({
|
||||||
|
options = import ../web-servers/apache-httpd/per-server-options.nix {
|
||||||
|
inherit lib;
|
||||||
|
forMainServer = false;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
example = {
|
||||||
|
hostName = "moodle.example.org";
|
||||||
|
enableSSL = true;
|
||||||
|
adminAddr = "webmaster@example.org";
|
||||||
|
sslServerCert = "/var/lib/acme/moodle.example.org/full.pem";
|
||||||
|
sslServerKey = "/var/lib/acme/moodle.example.org/key.pem";
|
||||||
|
};
|
||||||
|
description = ''
|
||||||
|
Apache configuration can be done by adapting <option>services.httpd.virtualHosts</option>.
|
||||||
|
See <xref linkend="opt-services.httpd.virtualHosts"/> for further information.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
poolConfig = mkOption {
|
||||||
|
type = with types; attrsOf (oneOf [ str int bool ]);
|
||||||
|
default = {
|
||||||
|
"pm" = "dynamic";
|
||||||
|
"pm.max_children" = 32;
|
||||||
|
"pm.start_servers" = 2;
|
||||||
|
"pm.min_spare_servers" = 2;
|
||||||
|
"pm.max_spare_servers" = 4;
|
||||||
|
"pm.max_requests" = 500;
|
||||||
|
};
|
||||||
|
description = ''
|
||||||
|
Options for the Moodle PHP pool. See the documentation on <literal>php-fpm.conf</literal>
|
||||||
|
for details on configuration directives.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# implementation
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
|
assertions = [
|
||||||
|
{ assertion = cfg.database.createLocally -> cfg.database.user == user;
|
||||||
|
message = "services.moodle.database.user must be set to ${user} if services.moodle.database.createLocally is set true";
|
||||||
|
}
|
||||||
|
{ assertion = cfg.database.createLocally -> cfg.database.passwordFile == null;
|
||||||
|
message = "a password cannot be specified if services.moodle.database.createLocally is set to true";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
services.mysql = mkIf mysqlLocal {
|
||||||
|
enable = true;
|
||||||
|
package = mkDefault pkgs.mariadb;
|
||||||
|
ensureDatabases = [ cfg.database.name ];
|
||||||
|
ensureUsers = [
|
||||||
|
{ name = cfg.database.user;
|
||||||
|
ensurePermissions = {
|
||||||
|
"${cfg.database.name}.*" = "SELECT, INSERT, UPDATE, DELETE, CREATE, CREATE TEMPORARY TABLES, DROP, INDEX, ALTER";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.postgresql = mkIf pgsqlLocal {
|
||||||
|
enable = true;
|
||||||
|
ensureDatabases = [ cfg.database.name ];
|
||||||
|
ensureUsers = [
|
||||||
|
{ name = cfg.database.user;
|
||||||
|
ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; };
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.phpfpm.pools.moodle = {
|
||||||
|
inherit user group;
|
||||||
|
phpEnv.MOODLE_CONFIG = "${moodleConfig}";
|
||||||
|
phpOptions = ''
|
||||||
|
zend_extension = opcache.so
|
||||||
|
opcache.enable = 1
|
||||||
|
'';
|
||||||
|
settings = {
|
||||||
|
"listen.owner" = config.services.httpd.user;
|
||||||
|
"listen.group" = config.services.httpd.group;
|
||||||
|
} // cfg.poolConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.httpd = {
|
||||||
|
enable = true;
|
||||||
|
adminAddr = mkDefault cfg.virtualHost.adminAddr;
|
||||||
|
extraModules = [ "proxy_fcgi" ];
|
||||||
|
virtualHosts = [ (mkMerge [
|
||||||
|
cfg.virtualHost {
|
||||||
|
documentRoot = mkForce "${cfg.package}/share/moodle";
|
||||||
|
extraConfig = ''
|
||||||
|
<Directory "${cfg.package}/share/moodle">
|
||||||
|
<FilesMatch "\.php$">
|
||||||
|
<If "-f %{REQUEST_FILENAME}">
|
||||||
|
SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
|
||||||
|
</If>
|
||||||
|
</FilesMatch>
|
||||||
|
Options -Indexes
|
||||||
|
DirectoryIndex index.php
|
||||||
|
</Directory>
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
]) ];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d '${stateDir}' 0750 ${user} ${group} - -"
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.services.moodle-init = {
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
before = [ "phpfpm-moodle.service" ];
|
||||||
|
after = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service";
|
||||||
|
environment.MOODLE_CONFIG = moodleConfig;
|
||||||
|
script = ''
|
||||||
|
${pkgs.php}/bin/php ${cfg.package}/share/moodle/admin/cli/check_database_schema.php && rc=$? || rc=$?
|
||||||
|
|
||||||
|
[ "$rc" == 1 ] && ${pkgs.php}/bin/php ${cfg.package}/share/moodle/admin/cli/upgrade.php \
|
||||||
|
--non-interactive \
|
||||||
|
--allow-unstable
|
||||||
|
|
||||||
|
[ "$rc" == 2 ] && ${pkgs.php}/bin/php ${cfg.package}/share/moodle/admin/cli/install_database.php \
|
||||||
|
--agree-license \
|
||||||
|
--adminpass=${cfg.initialPassword}
|
||||||
|
|
||||||
|
true
|
||||||
|
'';
|
||||||
|
serviceConfig = {
|
||||||
|
User = user;
|
||||||
|
Group = group;
|
||||||
|
Type = "oneshot";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.moodle-cron = {
|
||||||
|
description = "Moodle cron service";
|
||||||
|
after = [ "moodle-init.service" ];
|
||||||
|
environment.MOODLE_CONFIG = moodleConfig;
|
||||||
|
serviceConfig = {
|
||||||
|
User = user;
|
||||||
|
Group = group;
|
||||||
|
ExecStart = "${pkgs.php}/bin/php ${cfg.package}/share/moodle/admin/cli/cron.php";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.timers.moodle-cron = {
|
||||||
|
description = "Moodle cron timer";
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = "minutely";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.httpd.after = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service";
|
||||||
|
|
||||||
|
users.users."${user}".group = group;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
@ -161,6 +161,7 @@ in
|
|||||||
minio = handleTest ./minio.nix {};
|
minio = handleTest ./minio.nix {};
|
||||||
misc = handleTest ./misc.nix {};
|
misc = handleTest ./misc.nix {};
|
||||||
mongodb = handleTest ./mongodb.nix {};
|
mongodb = handleTest ./mongodb.nix {};
|
||||||
|
moodle = handleTest ./moodle.nix {};
|
||||||
morty = handleTest ./morty.nix {};
|
morty = handleTest ./morty.nix {};
|
||||||
mosquitto = handleTest ./mosquitto.nix {};
|
mosquitto = handleTest ./mosquitto.nix {};
|
||||||
mpd = handleTest ./mpd.nix {};
|
mpd = handleTest ./mpd.nix {};
|
||||||
|
22
nixos/tests/moodle.nix
Normal file
22
nixos/tests/moodle.nix
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import ./make-test.nix ({ pkgs, lib, ... }: {
|
||||||
|
name = "moodle";
|
||||||
|
meta.maintainers = [ lib.maintainers.aanderse ];
|
||||||
|
|
||||||
|
machine =
|
||||||
|
{ ... }:
|
||||||
|
{ services.moodle.enable = true;
|
||||||
|
services.moodle.virtualHost.hostName = "localhost";
|
||||||
|
services.moodle.virtualHost.adminAddr = "root@example.com";
|
||||||
|
services.moodle.initialPassword = "correcthorsebatterystaple";
|
||||||
|
|
||||||
|
# Ensure the virtual machine has enough memory to avoid errors like:
|
||||||
|
# Fatal error: Out of memory (allocated 152047616) (tried to allocate 33554440 bytes)
|
||||||
|
virtualisation.memorySize = 2000;
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
startAll;
|
||||||
|
$machine->waitForUnit('phpfpm-moodle.service');
|
||||||
|
$machine->succeed('curl http://localhost/') =~ /You are not logged in/ or die;
|
||||||
|
'';
|
||||||
|
})
|
40
pkgs/servers/web-apps/moodle/default.nix
Normal file
40
pkgs/servers/web-apps/moodle/default.nix
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{ stdenv, fetchurl, writeText }:
|
||||||
|
|
||||||
|
let
|
||||||
|
version = "3.7.1";
|
||||||
|
stableVersion = builtins.substring 0 2 (builtins.replaceStrings ["."] [""] version);
|
||||||
|
in
|
||||||
|
|
||||||
|
stdenv.mkDerivation rec {
|
||||||
|
pname = "moodle";
|
||||||
|
inherit version;
|
||||||
|
|
||||||
|
src = fetchurl {
|
||||||
|
url = "https://download.moodle.org/stable${stableVersion}/${pname}-${version}.tgz";
|
||||||
|
sha256 = "0xfriw0nfaf9hlcjviwg2acwpd192jf2ahw8sw3s6bj3pr1isxmd";
|
||||||
|
};
|
||||||
|
|
||||||
|
phpConfig = writeText "config.php" ''
|
||||||
|
<?php
|
||||||
|
return require(getenv('MOODLE_CONFIG'));
|
||||||
|
?>
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
mkdir -p $out/share/moodle
|
||||||
|
cp -r . $out/share/moodle
|
||||||
|
cp ${phpConfig} $out/share/moodle/config.php
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with stdenv.lib; {
|
||||||
|
description = "Free and open-source learning management system (LMS) written in PHP";
|
||||||
|
license = licenses.gpl3Plus;
|
||||||
|
homepage = "https://moodle.org/";
|
||||||
|
maintainers = with maintainers; [ aanderse ];
|
||||||
|
platforms = platforms.all;
|
||||||
|
};
|
||||||
|
}
|
@ -14725,6 +14725,8 @@ in
|
|||||||
|
|
||||||
mlmmj = callPackage ../servers/mail/mlmmj { };
|
mlmmj = callPackage ../servers/mail/mlmmj { };
|
||||||
|
|
||||||
|
moodle = callPackage ../servers/web-apps/moodle { };
|
||||||
|
|
||||||
morty = callPackage ../servers/web-apps/morty { };
|
morty = callPackage ../servers/web-apps/morty { };
|
||||||
|
|
||||||
mullvad-vpn = callPackage ../applications/networking/mullvad-vpn { };
|
mullvad-vpn = callPackage ../applications/networking/mullvad-vpn { };
|
||||||
|
Loading…
Reference in New Issue
Block a user