diff --git a/configs/all-configurations.nix b/configs/all-configurations.nix index a6566344b..bd2f936c1 100644 --- a/configs/all-configurations.nix +++ b/configs/all-configurations.nix @@ -2,7 +2,9 @@ # LiberaForms is intentionally disabled. # Refer to . #liberaforms-container = import ./liberaforms/container.nix; - + flarum = { + imports = [./flarum]; + }; pretalx-postgresql = { imports = [ ./pretalx/pretalx.nix diff --git a/configs/flarum/default.nix b/configs/flarum/default.nix new file mode 100644 index 000000000..399d6ac29 --- /dev/null +++ b/configs/flarum/default.nix @@ -0,0 +1,14 @@ +{ + boot.isContainer = true; + networking.hostName = "test-flarum"; + + # Allow nginx through the firewall + networking.firewall.allowedTCPPorts = [80]; + + services.nginx.enable = true; + nixpkgs.hostPlatform = "x86_64-linux"; + services.flarum = { + enable = true; + domain = "10.233.2.2"; + }; +} diff --git a/flake.lock b/flake.lock index d22f9a36b..6c2c29a9d 100644 --- a/flake.lock +++ b/flake.lock @@ -42,15 +42,16 @@ "flake-parts": "flake-parts" }, "locked": { - "lastModified": 1693994164, - "narHash": "sha256-BtVCeCp5TInZ40bQtOAgT/0ghKWY+fW5EORFelFtcP4=", + "lastModified": 1691252882, + "narHash": "sha256-kCiFl72gV/OzDPCrw2CeHM6VEtVGFj57gaF8ZKD9LWI=", "owner": "loophp", "repo": "nix-php-composer-builder", - "rev": "600bc67c1adce95675d6c3487ba61ae5fab4dc25", + "rev": "0caf5a60753397cfa959a74fc9ea0562556573c1", "type": "github" }, "original": { "owner": "loophp", + "ref": "0caf5a60753397cfa959a74fc9ea0562556573c1", "repo": "nix-php-composer-builder", "type": "github" } diff --git a/flake.nix b/flake.nix index 6cfdbfccc..261e5d00a 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,7 @@ description = "NgiPkgs"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; - inputs.nix-php-composer-builder.url = "github:loophp/nix-php-composer-builder"; + inputs.nix-php-composer-builder.url = "github:loophp/nix-php-composer-builder?ref=0caf5a60753397cfa959a74fc9ea0562556573c1"; inputs.flake-utils.url = "github:numtide/flake-utils"; # Set default system to `x86_64-linux`, # as we currently only support Linux. @@ -25,14 +25,10 @@ }: with builtins; let importPackages = pkgs: - import ./all-packages.nix { - inherit (pkgs) newScope; - }; + import ./all-packages.nix {inherit (pkgs) newScope;}; importNixpkgs = system: overlays: - import nixpkgs { - inherit system overlays; - }; + import nixpkgs {inherit system overlays;}; importNixosConfigurations = import ./configs/all-configurations.nix; @@ -47,15 +43,13 @@ # Compute outputs that are invariant in the system architecture. allSystemsOutputs = system: let - pkgs = importNixpkgs system [ - nix-php-composer-builder.overlays.default - ]; + pkgs = + importNixpkgs system [nix-php-composer-builder.overlays.default]; treefmtEval = loadTreefmt pkgs; in { packages = importPackages pkgs; formatter = treefmtEval.config.build.wrapper; }; - in # We merge three attribute sets to construct all outputs: # 1. Outputs that are invariant in the system architecture # via `flake-utils.lib.eachDefaultSystem`. @@ -64,6 +58,7 @@ # 3. Outputs that are not tied to any system at all. # # 1. + in (flake-utils.lib.eachDefaultSystem allSystemsOutputs) # # 2. @@ -90,29 +85,28 @@ # `nixosTests` is a non-standard name for a flake output. # See . - nixosTests.${linuxSystem} = mapAttrs (_: pkgs.nixosTest) (import ./tests/all-tests.nix { - modules = extendedModules; - configurations = importNixosConfigurations; - }); + nixosTests.${linuxSystem} = + mapAttrs (_: pkgs.nixosTest) + (import ./tests/all-tests.nix { + modules = extendedModules; + configurations = importNixosConfigurations; + }); }) # # 3. // { - nixosConfigurations = - mapAttrs ( - _: config: - nixpkgs.lib.nixosSystem { - modules = [config] ++ nixpkgs.lib.attrValues extendedModules; - } - ) - importNixosConfigurations; + nixosConfigurations = mapAttrs (_: config: + nixpkgs.lib.nixosSystem { + modules = [config] ++ nixpkgs.lib.attrValues extendedModules; + }) + importNixosConfigurations; nixosModules = (import ./modules/all-modules.nix) // { # The default module adds the default overlay on top of nixpkgs. # This is so that `ngipkgs` can be used alongside `nixpkgs` in a configuration. - default.nixpkgs.overlays = [self.overlays.default]; + default.nixpkgs.overlays = [self.overlays.default nix-php-composer-builder.overlays.default]; }; # Overlays a package set (e.g. nixpkgs) with the packages defined in this flake. diff --git a/modules/all-modules.nix b/modules/all-modules.nix index 7847be27b..add3da330 100644 --- a/modules/all-modules.nix +++ b/modules/all-modules.nix @@ -3,4 +3,5 @@ # Refer to . #liberaforms = import ./liberaforms.nix; pretalx = import ./pretalx.nix; + flarum = import ./flarum.nix; } diff --git a/modules/flarum.nix b/modules/flarum.nix new file mode 100644 index 000000000..253144711 --- /dev/null +++ b/modules/flarum.nix @@ -0,0 +1,217 @@ +{ + config, + lib, + pkgs, + self, + utils, + ... +}: +with builtins; +with lib; let + cfg = config.services.flarum; + opt = options.services.flarum; + + flarumInstallConfig = pkgs.writeText "config.json" (builtins.toJSON { + debug = false; + offline = false; + + baseUrl = cfg.baseUrl; + databaseConfiguration = cfg.database; + adminUser = { + username = cfg.adminUser; + password = cfg.initialAdminPassword; + email = cfg.adminEmail; + }; + settings = {forum_title = cfg.forumTitle;}; + }); +in { + options = { + services.flarum = with types; { + enable = mkEnableOption "Flarum discussion platform"; + + package = mkPackageOption pkgs "flarum" {}; + + forumTitle = mkOption { + type = types.str; + default = "A Flarum Forum on NixOS"; + description = "Title of the forum."; + }; + + domain = mkOption { + type = types.str; + default = "localhost"; + example = "forum.example.com"; + description = "Domain to serve on."; + }; + + baseUrl = mkOption { + type = types.str; + default = "https://${cfg.domain}"; + example = "https://forum.example.com"; + description = "Change `domain` instead."; + }; + + adminUser = mkOption { + type = types.str; + default = "flarum"; + description = "Username for first web application administrator"; + }; + + adminEmail = mkOption { + type = types.str; + default = "admin@example.com"; + description = "Email for first web application administrator"; + }; + + initialAdminPassword = mkOption { + type = types.str; + default = "flarum"; + description = "Initial password for the adminUser"; + }; + + user = mkOption { + type = types.str; + default = "flarum"; + description = "System user to run Flarum"; + }; + + group = mkOption { + type = types.str; + default = "flarum"; + description = "System group to run Flarum"; + }; + + stateDir = mkOption { + type = types.path; + default = "/var/lib/flarum"; + description = "Home directory for writable storage"; + }; + + database = mkOption rec { + type = with types; attrsOf (oneOf [str bool int]); + description = "MySQL database parameters"; + default = { + # the database driver; i.e. MySQL; MariaDB... + driver = "mysql"; + # the host of the connection; localhost in most cases unless using an external service + host = "localhost"; + # the name of the database in the instance + database = "flarum"; + # database username + username = "flarum"; + # database password + password = ""; + # the prefix for the tables; useful if you are sharing the same database with another service + prefix = ""; + # the port of the connection; defaults to 3306 with MySQL + port = 3306; + strict = false; + }; + }; + + createDatabaseLocally = mkOption { + type = types.bool; + default = true; + description = "Create the database and database user locally, and run installation."; + }; + }; + }; + + config = mkIf cfg.enable { + users.users.${cfg.user} = { + isSystemUser = true; + home = cfg.stateDir; + createHome = true; + group = cfg.group; + }; + users.groups.${cfg.group} = {}; + + services.phpfpm.pools.flarum = { + user = cfg.user; + settings = { + "listen.owner" = config.services.nginx.user; + "listen.group" = config.services.nginx.group; + "listen.mode" = "0600"; + "pm" = mkDefault "dynamic"; + "pm.max_children" = mkDefault 10; + "pm.max_requests" = mkDefault 500; + "pm.start_servers" = mkDefault 2; + "pm.min_spare_servers" = mkDefault 1; + "pm.max_spare_servers" = mkDefault 3; + }; + phpOptions = '' + error_log = syslog + log_errors = on + ''; + }; + + services.nginx = { + enable = true; + virtualHosts."${cfg.domain}" = { + root = "${cfg.stateDir}/public"; + locations."~ \.php$".extraConfig = '' + fastcgi_pass unix:${config.services.phpfpm.pools.flarum.socket}; + fastcgi_index site.php; + ''; + extraConfig = '' + index index.php + include ${cfg.package}/build/.nginx.conf; + ''; + }; + }; + + services.mysql = mkIf cfg.enable { + enable = true; + package = pkgs.mysql; + ensureDatabases = [cfg.database.database]; + ensureUsers = [ + { + name = cfg.database.username; + ensurePermissions = { + "${cfg.database.database}.*" = "ALL PRIVILEGES"; + }; + } + ]; + }; + + assertions = [ + { + assertion = !cfg.createDatabaseLocally || cfg.database.driver == "mysql"; + message = "Flarum can only be automatically installed in MySQL/MariaDB."; + } + ]; + + systemd.services.flarum-install = { + description = "Flarum installation"; + requiredBy = ["phpfpm-flarum.service"]; + before = ["phpfpm-flarum.service"]; + requires = ["mysql.service"]; + after = ["mysql.service"]; + serviceConfig = { + Type = "oneshot"; + User = cfg.user; + Group = cfg.group; + }; + path = [config.services.phpfpm.phpPackage]; + script = + '' + mkdir -p ${cfg.stateDir}/{extensions,public/assets/avatars} + mkdir -p ${cfg.stateDir}/storage/{formatter,sessions,views} + cd ${cfg.stateDir} + cp -f ${cfg.package}/build/{extend.php,site.php,flarum} . + ln -sf ${cfg.package}/build/vendor . + ln -sf ${cfg.package}/build/public/index.php public/ + chmod a+x . public + chmod +x site.php extend.php flarum + '' + + lib.optionalString + (cfg.createDatabaseLocally && cfg.database.driver == "mysql") '' + if [ ! -f config.php ]; then + php flarum install --file=${flarumInstallConfig} + fi + php flarum migrate + # php flarum cache:clear + ''; + }; + }; +}