0

I'm attempting to get an open-source webapp called pterodactyl (which is primarily php-fpm) running under Nginx however all files (except json files) are being served with the MIME type "text/html". This includes .css .js .png .ico files. I'm running this all under Nixos which is adding some complexity to finding a solution. I've found information here which involves adding lines to conf.d/php.conf but I don't believe that file exists on NixOS as the output of php --ini is:

Warning: Module "xml" is already loaded in Unknown on line 0
Configuration File (php.ini) Path: /nix/store/mga9xmf129kgs1167qlb7mib7rakl1mv-php-8.1.28/lib
Loaded Configuration File:         (none)
Scan for additional .ini files in: /nix/store/3cvc6xdxqd333fy3yh9ls02xf3r9mxgl-php-with-extensions-8.1.28/lib
Additional .ini files parsed:      /nix/store/3cvc6xdxqd333fy3yh9ls02xf3r9mxgl-php-with-extensions-8.1.28/lib/php.ini

which displays "none" for "Loaded Configuration File". I have no added configurations for php on build and the related section in my NixOS configs is:

let
  app = "nginx";
  domain = "my.url";
  dataDir = "/var/www/pterodactyl/public";
in {
  services.phpfpm.pools.${app} = {
    user = app;
    settings = {
      "listen.owner" = config.services.nginx.user;
      "pm" = "dynamic";
      "pm.max_children" = 32;
      "pm.max_requests" = 500;
      "pm.start_servers" = 2;
      "pm.min_spare_servers" = 2;
      "pm.max_spare_servers" = 5;
      "php_admin_value[error_log]" = "stderr";
      "php_admin_flag[log_errors]" = true;
      "catch_workers_output" = true;
      "security.limit_extensions" = ".php .js .png .svg .ico .css";
    };
    phpEnv."PATH" = lib.makeBinPath [ pkgs.php ];
    phpEnv."SCRIPT_FILENAME" = "index.php";
  };
  services.nginx = {
    enable = true;
    virtualHosts.${domain} = {
      forceSSL = true;
      enableACME = true;
      root = dataDir;
      locations."/".tryFiles = "$uri /index.php =404";
      locations."/".extraConfig = ''
        # Setting the absolute file location because I'm desperate
        fastcgi_param SCRIPT_FILENAME /var/www/pterodactyl/public/index.php;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:${config.services.phpfpm.pools.${app}.socket};
        include ${pkgs.nginx}/conf/fastcgi.conf;
      '';
      sslCertificate = "/path/to/cert.pem";
      sslCertificateKey = "/path/to/cert.pem";
     };
  };
  security.acme = {
    acceptTerms = true;
    defaults.email = "imposiblaa@gmail.com";
  };
  users.users.${app} = {
    isSystemUser = true;
    createHome = false;
    group  = app;
  };
  users.groups.${app} = {};
}

And this results in an Nginx config:

pid /run/nginx/nginx.pid;
error_log stderr;
daemon off;
events {
}
http {
        # Load mime types.
        include /nix/store/q2zhsbiy8v794s2d0vs38pjr1qfd9q33-mailcap-2.1.53/etc/nginx/mime.types;
        # When recommendedOptimisation is disabled nginx fails to start because the mailmap mime.types database
        # contains 1026 entries and the default is only 1024. Setting to a higher number to remove the need to
        # overwrite it because nginx does not allow duplicated settings.
        types_hash_max_size 4096;
        include /nix/store/3ab2m3d909950liid51g05ahqsm82hls-nginx-1.26.0/conf/fastcgi.conf;
        include /nix/store/3ab2m3d909950liid51g05ahqsm82hls-nginx-1.26.0/conf/uwsgi_params;
        default_type application/octet-stream;
        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:DHE-RSA-CHACHA20-POLY1305;
        # $connection_upgrade is used for websocket proxying
        map $http_upgrade $connection_upgrade {
                default upgrade;
                ''      close;
        }
        client_max_body_size 10m;
        server_tokens off;
        server {
                listen 0.0.0.0:80 ;
                listen [::0]:80 ;
                server_name my.url ;
                location / {
                        return 301 https://$host$request_uri;
                }
                location ^~ /.well-known/acme-challenge/ {
                        root /var/lib/acme/acme-challenge;
                        auth_basic off;
                        auth_request off;
                }
        }
        server {
                listen 0.0.0.0:443 ssl ;
                listen [::0]:443 ssl ;
                server_name my.url ;
                http2 on;
                ssl_certificate /path/to/fullchain.pem;
                ssl_certificate_key /path/to/key.pem;
                ssl_trusted_certificate /path/to/chain.pem;
                root /var/www/pterodactyl/public;
                location ^~ /.well-known/acme-challenge/ {
                        root /var/lib/acme/acme-challenge;
                        auth_basic off;
                        auth_request off;
                }
                location / {
                        try_files $uri /index.php =404;
                        fastcgi_param SCRIPT_FILENAME /var/www/pterodactyl/public/index.php;
                        fastcgi_split_path_info ^(.+\.php)(/.+)$;
                        fastcgi_pass unix:/run/phpfpm/nginx.sock;
                        include /nix/store/3ab2m3d909950liid51g05ahqsm82hls-nginx-1.26.0/conf/fastcgi.conf;
                }
        }
}

Any help getting this working would be greatly appreciated!

1 Answers1

0

Thanks to Alexey Ten I found the solution. I moved most of the original configuration for the "/" location to "~ \.php$".

     locations."~ \\.php$" = {
       extraConfig = ''
         fastcgi_split_path_info ^(.+\.php)(/.+)$;
         fastcgi_pass unix:${config.services.phpfpm.pools.${app}.socket};
         fastcgi_param SCRIPT_FILENAME /var/www/pterodactyl/public/index.php;
         fastcgi_index index.php;
         fastcgi_param HTTP_PROXY "";
         include ${pkgs.nginx}/conf/fastcgi.conf;
       '';
 };
  locations."/".tryFiles = "$uri $uri/ /index.php?$query_string";
  locations."/".index = "index.php";

The related section of the resulting nginx configuration is:

                location / {
                        index index.php;
                        try_files $uri $uri/ /index.php?$query_string;
                }
                location ~ \.php$ {
                        fastcgi_split_path_info ^(.+\.php)(/.+)$;
                        fastcgi_pass unix:/run/phpfpm/nginx.sock;
                        fastcgi_param SCRIPT_FILENAME /var/www/pterodactyl/public/index.php;
                        fastcgi_index index.php;
                        fastcgi_param HTTP_PROXY "";
                        include /nix/store/3ab2m3d909950liid51g05ahqsm82hls-nginx-1.26.0/conf/fastcgi.conf;
                }