diff --git a/flake.nix b/flake.nix index 1377e87..b74252b 100644 --- a/flake.nix +++ b/flake.nix @@ -1,52 +1,19 @@ { - description = "A production ready configuration of the pterodactyl game server panel"; + description = "Nixos modules for the pterodactyl game server panel"; inputs = { nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; }; - outputs = { self, nixpkgs }: let - forAllSystems = nixpkgs.lib.genAttrs [ - "x86_64-linux" - ]; - in { - packages = forAllSystems (system: let - pkgs = nixpkgs.legacyPackages.${system}; - in { - - panel = let - version = ""; - in pkgs.fetchzip { - url = "https://github.com/pterodactyl/panel/releases/download/v${ version }/panel.tar.gz"; - hash = "sha256-0nOHtReVUVXYQY/glS4x0gkbhetoXSWg4rRwOJlkcM8="; - stripRoot = false; - }; - - php = pkgs.php81.buildEnv { - extensions = { enabled, all, }: enabled ++ (with all; [ - redis - ]); - }; - - wings = pkgs.buildGoModule rec { - pname = "pterodactyl-wings"; - version = "1.11.13"; - - src = pkgs.fetchFromGitHub { - owner = "pterodactyl"; - repo = "wings"; - rev = "v${version}"; - sha256 = "sha256-UpYUHWM2J8nH+srdKSpFQEaPx2Rj2+YdphV8jJXcoBU="; - }; - - vendorHash = "sha256-eWfQE9cQ7zIkITWwnVu9Sf9vVFjkQih/ZW77d6p/Iw0="; - subPackages = [ "." ]; - - ldflags = [ - "-X github.com/pterodactyl/wings/system.Version=${version}" - ]; - }; + outputs = { self, nixpkgs }: { + nixosModules = nixpkgs.lib.genAttrs [ "pterodactyl" ] ( + module: import ./modules/${module}.nix { flake = self; } + ); + packages = nixpkgs.lib.genAttrs [ "x86_64-linux" ] ( + system: nixpkgs.lib.genAttrs [ "pterodactyl" "php" "wings" ] ( + package: import ./packages/${package}.nix { pkgs = import nixpkgs { inherit system; }; }; + ) }); }; } diff --git a/modules/pterodactyl.nix b/modules/pterodactyl.nix new file mode 100644 index 0000000..7dfbc1c --- /dev/null +++ b/modules/pterodactyl.nix @@ -0,0 +1,165 @@ +{ flake }: +{ lib, config, pkgs, ... }: + +let + cfg = config.services.pterodactyl; + + flakePkgs = flake.outputs.packages.${pkgs.system}; + + defaultUser = "pterodactyl"; +in { + options.services.pterodactyl = { + enable = lib.mkEnableOption "Enable the pterodacytl game server panel"; + + proxy = { + enable = lib.mkEnableOption "Automatically configure Nginx to serve the panel"; + serverName = lib.mkOption { + type = lib.types.str; + description = "The canonical domain on which the panel will be hosted"; + default = "localhost"; + example = "pterodactyl.example.com"; + }; + + listenAddresses = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "The addresses the nginx server should listen on"; + default = [ "127.0.0.1" "[::1]" ]; + }; + }; + + user = lib.mkOption { + type = lib.types.str; + description = '' + The user that owns the files managed by the panel. + If you change this, make sure their files are accessible by your www user + (probably "nginx"). + ''; + default = defaultUser; + example = defaultUser; + }; + + pkg = lib.mkOption { + type = lib.types.package; + description = "The package in which to source the php files used by pterodactyl"; + default = flakePkgs.pterodactyl; + }; + + dataDir = lib.mkOption { + type = lib.types.str; + description = "The directory in which to store stateful data"; + default = "/var/lib/pterodactyl"; + }; + + redis = { + configureLocally = lib.mkEnableOption "Configure a local redis server for pterodactyl"; + + name = lib.mkOption { + type = lib.types.str; + description = "The Redis server name."; + default = "redis-pterodactyl"; + }; + + port = lib.mkOption { + type = lib.types.port; + description = "The port the redis server listens on"; + default = 6379; + }; + }; + }; + + config = lib.mkIf cfg.enable { + users = lib.mkIf (cfg.user == defaultUser) { + users.${cfg.user} = { + isSystemUser = true; + createHome = true; + home = cfg.dataDir; + group = cfg.user; + }; + + groups.${cfg.user} = { }; + + users.${config.services.nginx.user}.extraGroups = [ cfg.user ]; + }; + + services.redis.servers.${cfg.redis.name} = lib.mkIf cfg.redis.configureLocally { + enable = true; + port = cfg.redis.port; + }; + + services.nginx = lib.mkIf cfg.proxy.enable { + enable = true; + + virtualHosts."${cfg.serverName}" = { + root = "${config.services.pterodactyl.pkg}/public"; + + extraConfig = '' + index index.html index.htm index.php; + ''; + + locations = { + "~ \\.php$".extraConfig = '' + include ${pkgs.nginx}/conf/fastcgi_params; + + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:${config.services.phpfpm.pools.pterodactyl.socket}; + + fastcgi_index index.php; + + fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M"; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param HTTP_PROXY ""; + + fastcgi_intercept_errors off; + + fastcgi_buffer_size 16k; + fastcgi_buffers 4 16k; + + fastcgi_connect_timeout 300; + fastcgi_send_timeout 300; + fastcgi_read_timeout 300; + ''; + + "/" = { + tryFiles = "$uri $uri/ /index.php?$query_string"; + }; + }; + }; + }; + + services.phpfpm.pools.pterodactyl = { + user = cfg.user; + settings = { + "listen.owner" = config.services.nginx.user; + "pm" = "dynamic"; + "pm.start_servers" = 4; + "pm.min_spare_servers" = 4; + "pm.max_spare_servers" = 16; + "pm.max_children" = 64; + "pm.max_requests" = 256; + + "clear_env" = false; + "catch_workers_output" = true; + "decorate_workers_output" = false; + "php_admin_value[error_log]" = "stderr"; + "php_admin_flag[daemonize]" = "false"; + }; + }; + + systemd.services.pteroq = { + enable = true; + description = "Pterodactyl Queue Worker"; + after = [ "redis-${cfg.redis.name}.service" ]; + unitConfig = { StartLimitInterval = 180; }; + serviceConfig = { + User = cfg.user; + Group = cfg.user; + Restart = "always"; + ExecStart = + "${flakePkgs.php}/bin/php ${cfg.pkg}/artisan queue:work --queue=high,standard,low --sleep=3 --tries=3"; + StartLimitBurst = 30; + RestartSec = "5s"; + }; + wantedBy = [ "multi-user.target" ]; + }; + }; +} diff --git a/modules/wings.nix b/modules/wings.nix new file mode 100644 index 0000000..61590d8 --- /dev/null +++ b/modules/wings.nix @@ -0,0 +1,65 @@ +{ flake }: +{ lib, config, pkgs, ... }: + +with lib; +let + cfg = config.services.wings; + + flakePkgs = flake.outputs.packages.${pkgs.system}; + + wings = cfg.pkg; +in { + options.services.wings = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + }; + + configuration = lib.mkOption { + type = lib.types.attrs; + default = {}; + }; + + version = lib.mkOption { + type = lib.types.str; + default = "latest"; + }; + + pkg = lib.lib.mkOption { + type = lib.types.package; + description = "The package to use for the pterodactyl wings daemon"; + default = flakePkgs.wings; + }; + }; + + config = lib.mkIf cfg.enable { + virtualisation.docker.enable = true; + + systemd.services.wings = { + enable = cfg.enable; + description = "Pterodactyl Wings daemon"; + + after = [ "docker.service" ]; + partOf = [ "docker.service" ]; + requires = [ "docker.service" ]; + + startLimitIntervalSec = 180; + startLimitBurst = 30; + + serviceConfig = { + User = "root"; + # WorkingDirectory = "/run/wings"; + + LimitNOFILE = 4096; + PIDFile = "/var/run/wings/daemon.pid"; + + ExecStart = "${cfg.pkg}/bin/wings --config ${pkgs.writeText "config.yaml" (lib.strings.toJSON cfg.configuration)}"; + + Restart = "on-failure"; + RestartSec = "5s"; + }; + + wantedBy = [ "multi-user.target" ]; + }; + }; +} diff --git a/packages/php.nix b/packages/php.nix new file mode 100644 index 0000000..6a6affa --- /dev/null +++ b/packages/php.nix @@ -0,0 +1,12 @@ +{ pkgs }: + +pkgs.php83.buildEnv { + extensions = { enabled, all, }: enabled ++ (with all; [ + redis + # xdebug + ]); + + # extraConfig = '' + # xdebug.mode=debug + # ''; +} diff --git a/packages/pterodactyl.nix b/packages/pterodactyl.nix new file mode 100644 index 0000000..15a8a24 --- /dev/null +++ b/packages/pterodactyl.nix @@ -0,0 +1,9 @@ +{ pkgs }: + +let + version = "1.11.11"; +in pkgs.fetchzip { + url = "https://github.com/pterodactyl/panel/releases/download/v${ version }/panel.tar.gz"; + hash = "sha256-0nOHtReVUVXYQY/glS4x0gkbhetoXSWg4rRwOJlkcM8="; + stripRoot = false; +} diff --git a/packages/wings.nix b/packages/wings.nix new file mode 100644 index 0000000..9309948 --- /dev/null +++ b/packages/wings.nix @@ -0,0 +1,22 @@ +{ pkgs }: + +let + version = "1.11.13"; +in pkgs.buildGoModule rec { + pname = "pterodactyl-wings"; + version = "1.11.13"; + + src = pkgs.fetchFromGitHub { + owner = "pterodactyl"; + repo = "wings"; + rev = "v${version}"; + sha256 = "sha256-UpYUHWM2J8nH+srdKSpFQEaPx2Rj2+YdphV8jJXcoBU="; + }; + + vendorHash = "sha256-eWfQE9cQ7zIkITWwnVu9Sf9vVFjkQih/ZW77d6p/Iw0="; + subPackages = [ "." ]; + + ldflags = [ + "-X github.com/pterodactyl/wings/system.Version=${version}" + ]; +}