Skip to content

Commit

Permalink
[PHP Provider] Ensure that PHP-FPM workers output is streamed to Nginx (
Browse files Browse the repository at this point in the history
#1168)

* PHP: Ensure workers output is streamed to Nginx

This allows errors and warnings to be streamed in Nginx output. This is critical to be able to get access to the application log, which is usually streamed on `php://stderr` in production.

* Update tests
  • Loading branch information
lolautruche authored Aug 30, 2024
1 parent d2dcbbf commit da969c0
Show file tree
Hide file tree
Showing 7 changed files with 7 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/providers/php/php-fpm.conf
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ pm.min_spare_servers = 4
pm.max_spare_servers = 32
pm.start_servers = 18
clear_env = no
catch_workers_output = yes
2 changes: 1 addition & 1 deletion tests/snapshots/generate_plan_tests__php_api.snap
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ expression: plan
},
"staticAssets": {
"nginx.template.conf": "worker_processes 5;\ndaemon off;\n\nworker_rlimit_nofile 8192;\n\nevents {\n worker_connections 4096; # Default: 1024\n}\n\nhttp {\n include $!{nginx}/conf/mime.types;\n index index.html index.htm index.php;\n\n default_type application/octet-stream;\n log_format main '$remote_addr - $remote_user [$time_local] $status '\n '\"$request\" $body_bytes_sent \"$http_referer\" '\n '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n access_log /dev/stdout;\n error_log /dev/stdout;\n sendfile on;\n tcp_nopush on;\n server_names_hash_bucket_size 128; # this seems to be required for some vhosts\n\n server {\n listen ${PORT};\n listen [::]:${PORT};\n server_name localhost;\n\n $if(NIXPACKS_PHP_ROOT_DIR) (\n root ${NIXPACKS_PHP_ROOT_DIR};\n ) else (\n root /app;\n )\n \n add_header X-Frame-Options \"SAMEORIGIN\";\n add_header X-Content-Type-Options \"nosniff\";\n \n index index.php;\n \n charset utf-8;\n \n $if(IS_LARAVEL) (\n location / {\n try_files $uri $uri/ /index.php?$query_string;\n }\n ) else ()\n \n $if(NIXPACKS_PHP_FALLBACK_PATH) (\n location / {\n try_files $uri $uri/ ${NIXPACKS_PHP_FALLBACK_PATH}?$query_string;\n }\n ) else ()\n \n location = /favicon.ico { access_log off; log_not_found off; }\n location = /robots.txt { access_log off; log_not_found off; }\n \n $if(IS_LARAVEL) (\n error_page 404 /index.php;\n ) else ()\n \n location ~ \\.php$ {\n fastcgi_pass 127.0.0.1:9000;\n fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;\n include $!{nginx}/conf/fastcgi_params;\n include $!{nginx}/conf/fastcgi.conf;\n }\n \n location ~ /\\.(?!well-known).* {\n deny all;\n }\n }\n}",
"php-fpm.conf": "[www]\nlisten = 127.0.0.1:9000\nuser = nobody\npm = dynamic\npm.max_children = 50\npm.min_spare_servers = 4\npm.max_spare_servers = 32\npm.start_servers = 18\nclear_env = no\n",
"php-fpm.conf": "[www]\nlisten = 127.0.0.1:9000\nuser = nobody\npm = dynamic\npm.max_children = 50\npm.min_spare_servers = 4\npm.max_spare_servers = 32\npm.start_servers = 18\nclear_env = no\ncatch_workers_output = yes\n",
"scripts/config/template.mjs": "import { readFile, writeFile } from \"fs/promises\";\nimport { getNixPath } from \"../util/nix.mjs\";\n\nconst replaceStr = input =>\n input\n // If statements\n .replaceAll(/\\$if\\s*\\((\\w+)\\)\\s*\\(([^]*?)\\)\\s*else\\s*\\(([^]*?)\\)/gm,\n (_all, condition, value, otherwise) =>\n process.env[condition] ? replaceStr(value) : replaceStr(otherwise)\n )\n // Variables\n .replaceAll(/\\${(\\w+)}/g,\n (_all, name) => process.env[name]\n )\n // Nix paths\n .replaceAll(/\\$!{(\\w+)}/g,\n (_all, exe) => getNixPath(exe)\n )\n\nexport async function compileTemplate(infile, outfile) {\n await writeFile(outfile,\n replaceStr(await readFile(infile, { encoding: 'utf8' })),\n { encoding: 'utf8' })\n}\n",
"scripts/prestart.mjs": "#!/usr/bin/env node\nimport { compileTemplate } from \"./config/template.mjs\";\nimport { e } from \"./util/cmd.mjs\";\nimport { checkEnvErrors, isLaravel } from \"./util/laravel.mjs\";\nimport Logger from \"./util/logger.mjs\";\nimport { access, constants } from 'node:fs/promises'\n\nconst prestartLogger = new Logger('prestart');\nconst serverLogger = new Logger('server');\n\nif (process.argv.length != 4) {\n prestartLogger.error(`Usage: ${process.argv[1]} <config-file> <output-file>`)\n process.exit(1);\n}\n\nawait Promise.all([\n isLaravel() ? checkEnvErrors('/app') : Promise.resolve(),\n access('/app/storage', constants.R_OK)\n .then(() => e('chmod -R ugo+rw /app/storage'))\n .catch(() => {}),\n compileTemplate(process.argv[2], process.argv[3])\n]).catch(err => prestartLogger.error(err));\n\nserverLogger.info(`Server starting on port ${process.env.PORT}`)\n",
"scripts/util/cmd.mjs": "import { execSync } from \"child_process\";\n\nexport const e = cmd => execSync(cmd).toString().replace('\\n', '');",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ expression: plan
},
"staticAssets": {
"nginx.template.conf": "worker_processes 5;\ndaemon off;\n\nworker_rlimit_nofile 8192;\n\nevents {\n worker_connections 4096; # Default: 1024\n}\n\nhttp {\n include $!{nginx}/conf/mime.types;\n index index.html index.htm index.php;\n\n default_type application/octet-stream;\n log_format main '$remote_addr - $remote_user [$time_local] $status '\n '\"$request\" $body_bytes_sent \"$http_referer\" '\n '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n access_log /dev/stdout;\n error_log /dev/stdout;\n sendfile on;\n tcp_nopush on;\n server_names_hash_bucket_size 128; # this seems to be required for some vhosts\n\n server {\n listen ${PORT};\n listen [::]:${PORT};\n server_name localhost;\n\n $if(NIXPACKS_PHP_ROOT_DIR) (\n root ${NIXPACKS_PHP_ROOT_DIR};\n ) else (\n root /app;\n )\n \n add_header X-Frame-Options \"SAMEORIGIN\";\n add_header X-Content-Type-Options \"nosniff\";\n \n index index.php;\n \n charset utf-8;\n \n $if(IS_LARAVEL) (\n location / {\n try_files $uri $uri/ /index.php?$query_string;\n }\n ) else ()\n \n $if(NIXPACKS_PHP_FALLBACK_PATH) (\n location / {\n try_files $uri $uri/ ${NIXPACKS_PHP_FALLBACK_PATH}?$query_string;\n }\n ) else ()\n \n location = /favicon.ico { access_log off; log_not_found off; }\n location = /robots.txt { access_log off; log_not_found off; }\n \n $if(IS_LARAVEL) (\n error_page 404 /index.php;\n ) else ()\n \n location ~ \\.php$ {\n fastcgi_pass 127.0.0.1:9000;\n fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;\n include $!{nginx}/conf/fastcgi_params;\n include $!{nginx}/conf/fastcgi.conf;\n }\n \n location ~ /\\.(?!well-known).* {\n deny all;\n }\n }\n}",
"php-fpm.conf": "[www]\nlisten = 127.0.0.1:9000\nuser = nobody\npm = dynamic\npm.max_children = 50\npm.min_spare_servers = 4\npm.max_spare_servers = 32\npm.start_servers = 18\nclear_env = no\n",
"php-fpm.conf": "[www]\nlisten = 127.0.0.1:9000\nuser = nobody\npm = dynamic\npm.max_children = 50\npm.min_spare_servers = 4\npm.max_spare_servers = 32\npm.start_servers = 18\nclear_env = no\ncatch_workers_output = yes\n",
"scripts/config/template.mjs": "import { readFile, writeFile } from \"fs/promises\";\nimport { getNixPath } from \"../util/nix.mjs\";\n\nconst replaceStr = input =>\n input\n // If statements\n .replaceAll(/\\$if\\s*\\((\\w+)\\)\\s*\\(([^]*?)\\)\\s*else\\s*\\(([^]*?)\\)/gm,\n (_all, condition, value, otherwise) =>\n process.env[condition] ? replaceStr(value) : replaceStr(otherwise)\n )\n // Variables\n .replaceAll(/\\${(\\w+)}/g,\n (_all, name) => process.env[name]\n )\n // Nix paths\n .replaceAll(/\\$!{(\\w+)}/g,\n (_all, exe) => getNixPath(exe)\n )\n\nexport async function compileTemplate(infile, outfile) {\n await writeFile(outfile,\n replaceStr(await readFile(infile, { encoding: 'utf8' })),\n { encoding: 'utf8' })\n}\n",
"scripts/prestart.mjs": "#!/usr/bin/env node\nimport { compileTemplate } from \"./config/template.mjs\";\nimport { e } from \"./util/cmd.mjs\";\nimport { checkEnvErrors, isLaravel } from \"./util/laravel.mjs\";\nimport Logger from \"./util/logger.mjs\";\nimport { access, constants } from 'node:fs/promises'\n\nconst prestartLogger = new Logger('prestart');\nconst serverLogger = new Logger('server');\n\nif (process.argv.length != 4) {\n prestartLogger.error(`Usage: ${process.argv[1]} <config-file> <output-file>`)\n process.exit(1);\n}\n\nawait Promise.all([\n isLaravel() ? checkEnvErrors('/app') : Promise.resolve(),\n access('/app/storage', constants.R_OK)\n .then(() => e('chmod -R ugo+rw /app/storage'))\n .catch(() => {}),\n compileTemplate(process.argv[2], process.argv[3])\n]).catch(err => prestartLogger.error(err));\n\nserverLogger.info(`Server starting on port ${process.env.PORT}`)\n",
"scripts/util/cmd.mjs": "import { execSync } from \"child_process\";\n\nexport const e = cmd => execSync(cmd).toString().replace('\\n', '');",
Expand Down
2 changes: 1 addition & 1 deletion tests/snapshots/generate_plan_tests__php_laravel.snap
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ expression: plan
},
"staticAssets": {
"nginx.template.conf": "worker_processes 5;\ndaemon off;\n\nworker_rlimit_nofile 8192;\n\nevents {\n worker_connections 4096; # Default: 1024\n}\n\nhttp {\n include $!{nginx}/conf/mime.types;\n index index.html index.htm index.php;\n\n default_type application/octet-stream;\n log_format main '$remote_addr - $remote_user [$time_local] $status '\n '\"$request\" $body_bytes_sent \"$http_referer\" '\n '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n access_log /dev/stdout;\n error_log /dev/stdout;\n sendfile on;\n tcp_nopush on;\n server_names_hash_bucket_size 128; # this seems to be required for some vhosts\n\n server {\n listen ${PORT};\n listen [::]:${PORT};\n server_name localhost;\n\n $if(NIXPACKS_PHP_ROOT_DIR) (\n root ${NIXPACKS_PHP_ROOT_DIR};\n ) else (\n root /app;\n )\n \n add_header X-Frame-Options \"SAMEORIGIN\";\n add_header X-Content-Type-Options \"nosniff\";\n \n index index.php;\n \n charset utf-8;\n \n $if(IS_LARAVEL) (\n location / {\n try_files $uri $uri/ /index.php?$query_string;\n }\n ) else ()\n \n $if(NIXPACKS_PHP_FALLBACK_PATH) (\n location / {\n try_files $uri $uri/ ${NIXPACKS_PHP_FALLBACK_PATH}?$query_string;\n }\n ) else ()\n \n location = /favicon.ico { access_log off; log_not_found off; }\n location = /robots.txt { access_log off; log_not_found off; }\n \n $if(IS_LARAVEL) (\n error_page 404 /index.php;\n ) else ()\n \n location ~ \\.php$ {\n fastcgi_pass 127.0.0.1:9000;\n fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;\n include $!{nginx}/conf/fastcgi_params;\n include $!{nginx}/conf/fastcgi.conf;\n }\n \n location ~ /\\.(?!well-known).* {\n deny all;\n }\n }\n}",
"php-fpm.conf": "[www]\nlisten = 127.0.0.1:9000\nuser = nobody\npm = dynamic\npm.max_children = 50\npm.min_spare_servers = 4\npm.max_spare_servers = 32\npm.start_servers = 18\nclear_env = no\n",
"php-fpm.conf": "[www]\nlisten = 127.0.0.1:9000\nuser = nobody\npm = dynamic\npm.max_children = 50\npm.min_spare_servers = 4\npm.max_spare_servers = 32\npm.start_servers = 18\nclear_env = no\ncatch_workers_output = yes\n",
"scripts/config/template.mjs": "import { readFile, writeFile } from \"fs/promises\";\nimport { getNixPath } from \"../util/nix.mjs\";\n\nconst replaceStr = input =>\n input\n // If statements\n .replaceAll(/\\$if\\s*\\((\\w+)\\)\\s*\\(([^]*?)\\)\\s*else\\s*\\(([^]*?)\\)/gm,\n (_all, condition, value, otherwise) =>\n process.env[condition] ? replaceStr(value) : replaceStr(otherwise)\n )\n // Variables\n .replaceAll(/\\${(\\w+)}/g,\n (_all, name) => process.env[name]\n )\n // Nix paths\n .replaceAll(/\\$!{(\\w+)}/g,\n (_all, exe) => getNixPath(exe)\n )\n\nexport async function compileTemplate(infile, outfile) {\n await writeFile(outfile,\n replaceStr(await readFile(infile, { encoding: 'utf8' })),\n { encoding: 'utf8' })\n}\n",
"scripts/prestart.mjs": "#!/usr/bin/env node\nimport { compileTemplate } from \"./config/template.mjs\";\nimport { e } from \"./util/cmd.mjs\";\nimport { checkEnvErrors, isLaravel } from \"./util/laravel.mjs\";\nimport Logger from \"./util/logger.mjs\";\nimport { access, constants } from 'node:fs/promises'\n\nconst prestartLogger = new Logger('prestart');\nconst serverLogger = new Logger('server');\n\nif (process.argv.length != 4) {\n prestartLogger.error(`Usage: ${process.argv[1]} <config-file> <output-file>`)\n process.exit(1);\n}\n\nawait Promise.all([\n isLaravel() ? checkEnvErrors('/app') : Promise.resolve(),\n access('/app/storage', constants.R_OK)\n .then(() => e('chmod -R ugo+rw /app/storage'))\n .catch(() => {}),\n compileTemplate(process.argv[2], process.argv[3])\n]).catch(err => prestartLogger.error(err));\n\nserverLogger.info(`Server starting on port ${process.env.PORT}`)\n",
"scripts/util/cmd.mjs": "import { execSync } from \"child_process\";\n\nexport const e = cmd => execSync(cmd).toString().replace('\\n', '');",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ expression: plan
},
"staticAssets": {
"nginx.template.conf": "worker_processes 5;\ndaemon off;\n\nworker_rlimit_nofile 8192;\n\nevents {\n worker_connections 4096; # Default: 1024\n}\n\nhttp {\n include $!{nginx}/conf/mime.types;\n index index.html index.htm index.php;\n\n default_type application/octet-stream;\n log_format main '$remote_addr - $remote_user [$time_local] $status '\n '\"$request\" $body_bytes_sent \"$http_referer\" '\n '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n access_log /dev/stdout;\n error_log /dev/stdout;\n sendfile on;\n tcp_nopush on;\n server_names_hash_bucket_size 128; # this seems to be required for some vhosts\n\n server {\n listen ${PORT};\n listen [::]:${PORT};\n server_name localhost;\n\n $if(NIXPACKS_PHP_ROOT_DIR) (\n root ${NIXPACKS_PHP_ROOT_DIR};\n ) else (\n root /app;\n )\n \n add_header X-Frame-Options \"SAMEORIGIN\";\n add_header X-Content-Type-Options \"nosniff\";\n \n index index.php;\n \n charset utf-8;\n \n $if(IS_LARAVEL) (\n location / {\n try_files $uri $uri/ /index.php?$query_string;\n }\n ) else ()\n \n $if(NIXPACKS_PHP_FALLBACK_PATH) (\n location / {\n try_files $uri $uri/ ${NIXPACKS_PHP_FALLBACK_PATH}?$query_string;\n }\n ) else ()\n \n location = /favicon.ico { access_log off; log_not_found off; }\n location = /robots.txt { access_log off; log_not_found off; }\n \n $if(IS_LARAVEL) (\n error_page 404 /index.php;\n ) else ()\n \n location ~ \\.php$ {\n fastcgi_pass 127.0.0.1:9000;\n fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;\n include $!{nginx}/conf/fastcgi_params;\n include $!{nginx}/conf/fastcgi.conf;\n }\n \n location ~ /\\.(?!well-known).* {\n deny all;\n }\n }\n}",
"php-fpm.conf": "[www]\nlisten = 127.0.0.1:9000\nuser = nobody\npm = dynamic\npm.max_children = 50\npm.min_spare_servers = 4\npm.max_spare_servers = 32\npm.start_servers = 18\nclear_env = no\n",
"php-fpm.conf": "[www]\nlisten = 127.0.0.1:9000\nuser = nobody\npm = dynamic\npm.max_children = 50\npm.min_spare_servers = 4\npm.max_spare_servers = 32\npm.start_servers = 18\nclear_env = no\ncatch_workers_output = yes\n",
"scripts/config/template.mjs": "import { readFile, writeFile } from \"fs/promises\";\nimport { getNixPath } from \"../util/nix.mjs\";\n\nconst replaceStr = input =>\n input\n // If statements\n .replaceAll(/\\$if\\s*\\((\\w+)\\)\\s*\\(([^]*?)\\)\\s*else\\s*\\(([^]*?)\\)/gm,\n (_all, condition, value, otherwise) =>\n process.env[condition] ? replaceStr(value) : replaceStr(otherwise)\n )\n // Variables\n .replaceAll(/\\${(\\w+)}/g,\n (_all, name) => process.env[name]\n )\n // Nix paths\n .replaceAll(/\\$!{(\\w+)}/g,\n (_all, exe) => getNixPath(exe)\n )\n\nexport async function compileTemplate(infile, outfile) {\n await writeFile(outfile,\n replaceStr(await readFile(infile, { encoding: 'utf8' })),\n { encoding: 'utf8' })\n}\n",
"scripts/prestart.mjs": "#!/usr/bin/env node\nimport { compileTemplate } from \"./config/template.mjs\";\nimport { e } from \"./util/cmd.mjs\";\nimport { checkEnvErrors, isLaravel } from \"./util/laravel.mjs\";\nimport Logger from \"./util/logger.mjs\";\nimport { access, constants } from 'node:fs/promises'\n\nconst prestartLogger = new Logger('prestart');\nconst serverLogger = new Logger('server');\n\nif (process.argv.length != 4) {\n prestartLogger.error(`Usage: ${process.argv[1]} <config-file> <output-file>`)\n process.exit(1);\n}\n\nawait Promise.all([\n isLaravel() ? checkEnvErrors('/app') : Promise.resolve(),\n access('/app/storage', constants.R_OK)\n .then(() => e('chmod -R ugo+rw /app/storage'))\n .catch(() => {}),\n compileTemplate(process.argv[2], process.argv[3])\n]).catch(err => prestartLogger.error(err));\n\nserverLogger.info(`Server starting on port ${process.env.PORT}`)\n",
"scripts/util/cmd.mjs": "import { execSync } from \"child_process\";\n\nexport const e = cmd => execSync(cmd).toString().replace('\\n', '');",
Expand Down
Loading

0 comments on commit da969c0

Please sign in to comment.