Created
August 11, 2025 08:05
-
-
Save theoparis/5a4306f2bbf534ee15b8db28b74bbcaf to your computer and use it in GitHub Desktop.
pyrodactyl nixos setup (WIP)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
pkgs, | |
... | |
}: { | |
virtualisation.docker.enable = true; | |
virtualisation.docker.storageDriver = "btrfs"; | |
services.pyrodactyl.enable = true; | |
services.pyrodactyl.url = "https://pyro.example.com"; | |
services.mysql.enable = true; | |
services.mysql.package = pkgs.mariadb; | |
services.redis.enable = true; | |
services.caddy = { | |
enable = true; | |
virtualHosts = { | |
"pyro.example.com".extraConfig = '' | |
reverse_proxy http://localhost:8080 | |
''; | |
}; | |
}; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
config, | |
lib, | |
pkgs, | |
... | |
}: | |
let | |
cfg = config.services.pyrodactyl; | |
php = ( | |
pkgs.php.withExtensions ( | |
{ | |
enabled, | |
all, | |
}: | |
enabled | |
++ (with all; [ | |
openssl | |
gd | |
pdo_mysql | |
pdo | |
mbstring | |
tokenizer | |
bcmath | |
xml | |
dom | |
curl | |
zip | |
]) | |
) | |
); | |
in | |
{ | |
options = { | |
services.pyrodactyl = { | |
enable = lib.mkEnableOption "Enable Pyrodactyl panel"; | |
url = lib.mkOption { | |
type = lib.types.str; | |
description = "The url where pyrodactyl is accessible"; | |
}; | |
databasePassword = lib.mkOption { | |
type = lib.types.str; | |
description = "Database password"; | |
}; | |
listenAddress = lib.mkOption { | |
type = lib.types.str; | |
default = "localhost"; | |
description = "Address for the built-in Laravel server to bind."; | |
}; | |
listenPort = lib.mkOption { | |
type = lib.types.int; | |
default = 8080; | |
description = "Port for the built-in Laravel server."; | |
}; | |
adminUser = { | |
email = lib.mkOption { | |
type = lib.types.str; | |
default = "[email protected]"; | |
}; | |
username = lib.mkOption { | |
type = lib.types.str; | |
default = "admin"; | |
}; | |
firstName = lib.mkOption { | |
type = lib.types.str; | |
default = "Admin"; | |
}; | |
lastName = lib.mkOption { | |
type = lib.types.str; | |
default = "User"; | |
}; | |
password = lib.mkOption { | |
type = lib.types.str; | |
description = "Admin user password."; | |
default = "admin"; | |
}; | |
}; | |
package = lib.mkOption { | |
type = lib.types.package; | |
default = | |
with pkgs; | |
pkgs.php.buildComposerProject2 (finalAttrs: { | |
pname = "pyrodactyl"; | |
version = "4.0.0-dev"; | |
# src = self; | |
src = fetchFromGitHub { | |
owner = "pyrohost"; | |
repo = "pyrodactyl"; | |
rev = "4c3bccf1d5533f7fc55bdbcf4a371219818d41c4"; | |
hash = "sha256-SBiRdG8NuK9uccX+qZ9IFpcK1YEPksm8iPBXLoUMO4w="; | |
}; | |
nativeBuildInputs = [ | |
nodejs_latest | |
gitMinimal | |
pnpm.configHook | |
]; | |
buildInputs = [ | |
php | |
]; | |
vendorHash = "sha256-gomWp2zyD+OFbyuD8NqjTaJChTsle5/tvqcDkPXqM64="; | |
pnpmDeps = pnpm.fetchDeps { | |
inherit (finalAttrs) pname version src; | |
fetcherVersion = 2; | |
hash = "sha256-1wcKqnHHTcfBM39h5K1PaDLUwR3cAxYRbngvtU95FZc="; | |
}; | |
buildPhase = '' | |
pnpm run build | |
''; | |
# postInstall = '' | |
# cp .env.example ${placeholder "out"}/ | |
# ''; | |
}); | |
}; | |
}; | |
}; | |
config = lib.mkIf cfg.enable { | |
users.users.pyrodactyl = { | |
isSystemUser = true; | |
home = "/var/lib/pyrodactyl"; | |
createHome = true; | |
group = "pyrodactyl"; | |
}; | |
users.groups.pyrodactyl = { }; | |
environment.systemPackages = [ cfg.package ]; | |
systemd.services.pyrodactyl-copy = { | |
description = "Copy pyrodactyl files to /var/lib/pyrodactyl"; | |
before = [ | |
"pyrodactyl-db-init.service" | |
"pyrodactyl.service" | |
]; | |
wantedBy = [ "multi-user.target" ]; | |
serviceConfig = { | |
Type = "oneshot"; | |
User = "root"; # Needs permission to copy from Nix store and chown | |
}; | |
script = '' | |
set -eu | |
if [ -z "$(ls -A /var/lib/pyrodactyl)" ]; then | |
cp -ar ${cfg.package}/share/php/pyrodactyl/{*,.*} /var/lib/pyrodactyl/ | |
chown -R pyrodactyl:pyrodactyl /var/lib/pyrodactyl | |
chmod -R 0755 /var/lib/pyrodactyl | |
fi | |
''; | |
}; | |
systemd.services.mariadb-user-setup = { | |
description = "Ensure MariaDB pyrodactyl user, database, and permissions"; | |
wants = [ "mysql.service" ]; | |
after = [ "mysql.service" ]; | |
serviceConfig = { | |
Type = "oneshot"; | |
}; | |
script = '' | |
set -eu | |
# Use socket auth to connect as root, no password needed | |
${pkgs.mariadb}/bin/mysql -u root <<SQL | |
CREATE DATABASE IF NOT EXISTS pyrodactyl; | |
CREATE USER IF NOT EXISTS 'pyro'@'localhost' IDENTIFIED BY 'supersecret'; | |
GRANT ALL PRIVILEGES ON pyrodactyl.* TO 'pyro'@'localhost'; | |
FLUSH PRIVILEGES; | |
SQL | |
''; | |
wantedBy = [ "multi-user.target" ]; | |
}; | |
# Initial DB + .env setup | |
systemd.services.pyrodactyl-db-init = { | |
description = "Initialise Pyrodactyl database"; | |
after = [ | |
"mysql.service" | |
"mariadb-user-setup.service" | |
"pyrodactyl-copy.service" | |
]; | |
wants = [ | |
"mysql.service" | |
"mariadb-user-setup.service" | |
"pyrodactyl-copy.service" | |
]; | |
before = [ "pyrodactyl.service" ]; | |
serviceConfig = { | |
Type = "oneshot"; | |
User = "pyrodactyl"; | |
Group = "pyrodactyl"; | |
WorkingDirectory = "/var/lib/pyrodactyl"; | |
}; | |
script = '' | |
set -eu | |
export PATH="${pkgs.mariadb}/bin:$PATH" | |
sleep 5 | |
# Generate .env only if missing | |
if [ ! -f .env ]; then | |
cp .env.example .env | |
${php}/bin/php artisan key:generate --force | |
${php}/bin/php artisan p:environment:database \ | |
--host=localhost \ | |
--port=3306 \ | |
--database=pyrodactyl \ | |
--username=pyro \ | |
--password=supersecret \ | |
--no-interaction | |
sed -i \ | |
-e "s|^APP_URL=.*|APP_URL=${cfg.url}|" \ | |
-e "s|^REDIS_HOST=.*|REDIS_HOST=localhost|" \ | |
.env | |
fi | |
# Run migrations | |
${php}/bin/php artisan migrate --seed --force | |
if ! ${pkgs.php}/bin/php artisan tinker --execute="exit(App\Models\User::where('email', '${cfg.adminUser.email}')->exists() ? 0 : 1)"; then | |
${pkgs.php}/bin/php artisan p:user:make \ | |
--email="${cfg.adminUser.email}" \ | |
--name-first="${cfg.adminUser.firstName}" \ | |
--name-last="${cfg.adminUser.lastName}" \ | |
--password="${cfg.adminUser.password}" \ | |
--admin | |
mysql -u pyro -psupersecret -h localhost -e "USE pyrodactyl; UPDATE users SET root_admin = 1;" | |
fi | |
''; | |
wantedBy = [ "multi-user.target" ]; | |
}; | |
systemd.services.pyrodactyl = { | |
description = "Pyrodactyl Panel"; | |
after = [ | |
"network.target" | |
"pyodactyl-db-init.service" | |
"pyrodactyl-copy.service" | |
]; | |
requires = [ | |
"pyrodactyl-db-init.service" | |
"pyrodactyl-copy.service" | |
]; | |
serviceConfig = { | |
User = "pyrodactyl"; | |
Group = "pyrodactyl"; | |
WorkingDirectory = "/var/lib/pyrodactyl"; | |
ExecStart = '' | |
${php}/bin/php artisan serve \ | |
--host=${cfg.listenAddress} \ | |
--port=${toString cfg.listenPort} | |
''; | |
Restart = "always"; | |
}; | |
wantedBy = [ "multi-user.target" ]; | |
}; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
sandcats