diff --git a/applications/pelican/nginx.nix b/applications/pelican/nginx.nix new file mode 100644 index 0000000..b1bb259 --- /dev/null +++ b/applications/pelican/nginx.nix @@ -0,0 +1,110 @@ +{ lib, config, pkgs, ... }: +with lib; +let + appUser = "nginx"; + name = "panel"; + module = "pelican-panel"; + cfg = config.modules.nginx.${name}; + serverName = "${name}."; + dataDir = "/var/www/pelican/public"; + port = 443; +in +{ + options.modules.nginx.${name} = { + enable = mkEnableOption "Enable ${name}"; + }; + + config = mkIf cfg.enable { + modules.${module}.enable = true; + networking.firewall.allowedTCPPorts = [ port ]; + + services.phpfpm.pools.${appUser} = { + user = appUser; + settings = { + "listen.owner" = appUser; + "listen.group" = appUser; + "listen.mode" = "0600"; + "pm" = "dynamic"; + "pm.max_children" = 75; + "pm.start_servers" = 10; + "pm.min_spare_servers" = 5; + "pm.max_spare_servers" = 20; + "pm.max_requests" = 500; + "catch_workers_output" = 1; + }; + }; + + services.nginx.virtualHosts."${serverName}" = { + root = "${dataDir}"; + listen = [{ inherit port; addr="0.0.0.0"; ssl=true; }]; + + forceSSL = true; + enableACME = true; + + extraConfig = '' + index index.html index.htm index.php; + charset utf-8; + + access_log off; + error_log /var/log/nginx/pelican.app-error.log error; + + client_max_body_size 100m; + client_body_timeout 120s; + + sendfile off; + + ssl_session_cache shared:SSL:10m; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; + ssl_prefer_server_ciphers on; + + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Robots-Tag none; + add_header Content-Security-Policy "frame-ancestors 'self'"; + add_header X-Frame-Options DENY; + add_header Referrer-Policy same-origin; + ''; + + locations = { + "/" = { + extraConfig = '' + try_files $uri $uri/ /index.php?$query_string; + ''; + }; + + "/favicon.ico".extraConfig = '' + access_log off; + log_not_found off; + ''; + + "/robots.txt".extraConfig = '' + access_log off; + log_not_found off; + ''; + + "~ \\.php$" = { + extraConfig = '' + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:${config.services.phpfpm.pools.${appUser}.socket}; + fastcgi_index index.php; + include ${config.services.nginx.package}/conf/fastcgi_params; + 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; + ''; + }; + + "~ /\\.ht".extraConfig = '' + deny all; + ''; + }; + }; + }; +} \ No newline at end of file diff --git a/applications/pelican/panel/panel.nix b/applications/pelican/panel/panel.nix new file mode 100644 index 0000000..c5bc198 --- /dev/null +++ b/applications/pelican/panel/panel.nix @@ -0,0 +1,64 @@ +{ inputs, pkgs, lib, config, ... }: + +with lib; let + cfg = config.modules.pelican-panel; + dir = "/var/www/pelican"; +in { + options = { + modules.pelican-panel = { + enable = mkEnableOption "Pelican Panel"; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ + pkgs.curl + pkgs.gnutar + pkgs.unzip + pkgs.php83 + pkgs.php83Packages.composer + pkgs.php83Extensions.gd + pkgs.php83Extensions.mysqli + pkgs.php83Extensions.mbstring + pkgs.php83Extensions.bcmath + pkgs.php83Extensions.xml + pkgs.php83Extensions.curl + pkgs.php83Extensions.zip + pkgs.php83Extensions.intl + pkgs.php83Extensions.sqlite3 + ( import ./pelican-install.nix { inherit pkgs; inherit dir; } ) + ( import ./pelican-update.nix { inherit pkgs; inherit dir; } ) + ]; + + systemd.timers."pelican-cron" = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnBootSec = "5m"; + OnUnitActiveSec = "1m"; + Unit = "pelican-cron.service"; + }; + }; + + systemd.services."pelican-cron" = { + script = '' + ${pkgs.php83}/bin/php ${dir}/artisan schedule:run >> /dev/null 2>&1 + ''; + serviceConfig = { + Type = "oneshot"; + }; + }; + + systemd.services.pelican-queue = { + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "nginx"; + Group = "nginx"; + Restart = "always"; + ExecStart = "${pkgs.php83}/bin/php ${dir}/artisan queue:work --tries=3"; + startLimitInterval = 180; + startLimitBurst = 30; + RestartSec = "5"; + }; + }; + }; +} \ No newline at end of file diff --git a/applications/pelican/panel/pelican-install.nix b/applications/pelican/panel/pelican-install.nix new file mode 100644 index 0000000..75e3f53 --- /dev/null +++ b/applications/pelican/panel/pelican-install.nix @@ -0,0 +1,28 @@ +{ pkgs, dir }: + +pkgs.writeShellScriptBin "pelican-install" '' + DIR=${dir} + + echo "Installing Pelican panel to $DIR ..." + if [ -d $DIR ]; then + echo "Directory $DIR already exists, exiting" + exit 1 + fi + echo "Creating directory ..." + mkdir -p $DIR + cd $DIR + + echo "Downloading Pelican panel ..." + curl -L https://github.com/pelican-dev/panel/releases/latest/download/panel.tar.gz | tar -xzv + echo "Installing Pelican panel using composer ..." + yes | composer install --no-dev --optimize-autoloader + + echo "Setting up the environment ..." + yes "" | php artisan p:environment:setup + + echo "Setting permissions ..." + chmod -R 755 storage/* bootstrap/cache/ + chown -R nginx:nginx $DIR + + echo "Pelican panel installed successfully" +'' \ No newline at end of file diff --git a/applications/pelican/panel/pelican-update.nix b/applications/pelican/panel/pelican-update.nix new file mode 100644 index 0000000..d359d44 --- /dev/null +++ b/applications/pelican/panel/pelican-update.nix @@ -0,0 +1,46 @@ +{ pkgs, dir }: + +pkgs.writeShellScriptBin "pelican-update" '' + DIR=${dir} + + echo "Updateing Pelican panel in $DIR ..." + if [ -d $DIR ]; then + echo "Directory $DIR found, entering maintenance mode ..." + else + echo "Directory $DIR does not exist, exiting" + exit 1 + fi + + cd $DIR + php artisan down + + echo "Downloading Pelican panel update ..." + curl -L https://github.com/pelican-dev/panel/releases/latest/download/panel.tar.gz | tar -xzv + + echo "Setting permissions ..." + chmod -R 755 storage/* bootstrap/cache + + echo "Updating Pelican panel using composer ..." + yes | composer install --no-dev --optimize-autoloader + + echo "Clearing compiled template cache ..." + php artisan view:clear + php artisan config:clear + + echo "Optimizing Pelican panel ..." + php artisan filament:optimize + + echo "Updating the database ..." + php artisan migrate --seed --force + + echo "Setting permissions ..." + chown -R nginx:nginx $DIR + + echo "Restart Pelican queue service ..." + systemctl restart pelican-queue.service + + echo "Exiting maintenance mode ..." + php artisan up + + echo "Pelican panel updated successfully" +'' \ No newline at end of file diff --git a/applications/pelican/wings/package.nix b/applications/pelican/wings/package.nix new file mode 100644 index 0000000..fa483e9 --- /dev/null +++ b/applications/pelican/wings/package.nix @@ -0,0 +1,19 @@ +{ stdenv, lib, fetchurl, docker, gnutar }: + +stdenv.mkDerivation rec { + pname = "pelican-wings"; + version = "v1.0.0-beta6"; + + src = fetchurl { + url = "https://github.com/pelican-dev/wings/releases/download/${version}/wings_linux_amd64"; + hash = "sha256-a2T4BjqS8Hy5YqwDEJpbvGqqsrVjdRhxvJLgk3MCXag="; + }; + + buildInputs = [ docker gnutar ]; + + phases = [ "installPhase" ]; + + installPhase = '' + install -D $src $out/bin/wings + ''; +} \ No newline at end of file diff --git a/applications/pelican/wings/wings.nix b/applications/pelican/wings/wings.nix new file mode 100644 index 0000000..0dd8b24 --- /dev/null +++ b/applications/pelican/wings/wings.nix @@ -0,0 +1,42 @@ +{ inputs, pkgs, lib, config, ... }: + +with lib; let + cfg = config.modules.pelican-wings; +in { + options = { + modules.pelican-wings = { + enable = mkEnableOption "Pelican Wings"; + }; + }; + + config = mkIf cfg.enable { + networking.firewall.allowedTCPPorts = [ 8080 8443 ]; + + virtualisation.docker.enable = true; + + environment.systemPackages = [ + ( pkgs.callPackage ./package.nix {} ) + ]; + + systemd.services.pelican-wings = { + description = "Wings Daemon"; + after = [ "docker.service" ]; + requires = [ "docker.service" ]; + partOf = [ "docker.service" ]; + + serviceConfig = { + User = "root"; + WorkingDirectory = "/etc/pelican"; + LimitNOFILE = 4096; + PIDFile = "/var/run/wings/daemon.pid"; + ExecStart = "/run/current-system/sw/bin/wings"; + Restart = "on-failure"; + startLimitInterval = 180; + startLimitBurst = 30; + RestartSec = "5"; + }; + + wantedBy = [ "multi-user.target" ]; + }; + }; +} \ No newline at end of file