Labs · Cyber Security
Lab: Set Up LEMP with PHP-FPM on Your Server and Switch Off PHP Error Display on the Live Site
Course: Cyber Security · Chapter 9: PHP, LAMP and LEMP Step by Step
Chapter 9 builds LAMP and LEMP step by step; this lab makes the PHP part safe for a live site.
Chala mitrano! A PHP error message on a live website is a free gift to an attacker: it shows folder paths, file names and sometimes database details. Today we see that leak with our own eyes on our own server, then close it the right way: hide errors from visitors, keep them in a log for us. Chala!
चला मित्रांनो! Live website वरचा PHP error message म्हणजे attacker ला मोफत gift: त्यात folder paths, file names आणि कधी कधी database details दिसतात. आज आपण तो leak आपल्याच server वर स्वतःच्या डोळ्यांनी बघणार, मग तो योग्य पद्धतीने बंद करणार: visitors पासून errors लपवायचे, आपल्यासाठी log मध्ये ठेवायचे. चला!
चलो दोस्तों! Live website पर PHP error message attacker के लिए मुफ्त gift है: उसमें folder paths, file names और कभी-कभी database details दिखती हैं। आज हम वो leak अपने ही server पर अपनी आँखों से देखेंगे, फिर उसे सही तरीके से बंद करेंगे: visitors से errors छुपाओ, अपने लिए log में रखो। चलो!
Suppose we are…
Suppose we are a PHP developer at a small agency that builds order pages for restaurants listed on Zomato. On the first day live, a typo shows Warning: Undefined variable $total in /usr/share/nginx/html/order.php on line 12 to every customer. Now strangers know our folder structure. Good teams set display_errors = Off on live servers and read errors from a log file instead.
Goal of this lab
By the end you will have:
- A working LEMP stack part: Linux + Nginx + PHP-FPM (FastCGI Process Manager, the program that runs PHP for Nginx).
- Seen a PHP warning leak a file path, then hidden it.
display_errors = Off,log_errors = Onandexpose_php = Off, and the error written to a log only you can read.
What you need (all free)
- Your free-tier EC2 Amazon Linux 2023 server with Nginx (Lab 7), HTTP 80 open to My IP.
- 35–40 minutes.
Safety and ethics
Never leave phpinfo() or test pages on a real website; delete them after the lab. Practise on your own server only.
Part 1: add PHP-FPM
-
SSH to the server and install PHP-FPM:
sudo dnf install -y php-fpm php-cli sudo systemctl enable --now php-fpm sudo nginx -t && sudo systemctl restart nginxOn Amazon Linux 2023 the php-fpm package already adds the Nginx config that sends
.phpfiles to PHP-FPM. -
Create a test page:
echo '<?php echo "PHP works: " . PHP_VERSION; ?>' | sudo tee /usr/share/nginx/html/hello.php curl http://localhost/hello.phpWhat you should see:
PHP works: 8.x.x.
Part 2: see the leak
-
Check the current settings:
php -i | grep -E "^display_errors|^log_errors|^expose_php" -
To see the danger, switch errors on for a moment, the way a developer might on a test box:
sudo sed -i 's/^display_errors = .*/display_errors = On/' /etc/php.ini sudo systemctl restart php-fpm echo '<?php echo "Total: " . $total; ?>' | sudo tee /usr/share/nginx/html/order.php curl -i http://localhost/order.phpWhat you should see:
Warning: Undefined variable $total in /usr/share/nginx/html/order.php on line 1, and a headerX-Powered-By: PHP/8.x.x. The path and the PHP version are both leaks.
Part 3: close it the right way
-
Back up the config, then set the safe values:
sudo cp /etc/php.ini /etc/php.ini.bak sudo sed -i 's/^display_errors = .*/display_errors = Off/' /etc/php.ini sudo sed -i 's/^log_errors = .*/log_errors = On/' /etc/php.ini sudo sed -i 's/^expose_php = .*/expose_php = Off/' /etc/php.ini sudo systemctl restart php-fpm -
Test again:
curl -i http://localhost/order.phpWhat you should see:
HTTP/1.1 200 OK, the textTotal:with no warning, and noX-Powered-Byheader. -
Find where the error went. PHP-FPM on Amazon Linux 2023 writes the site's errors to its pool log:
sudo tail -n 5 /var/log/php-fpm/www-error.logWhat you should see:
PHP Warning: Undefined variable $total in /usr/share/nginx/html/order.php on line 1. Only you, with sudo, can read it. -
Delete the test pages:
sudo rm /usr/share/nginx/html/hello.php /usr/share/nginx/html/order.php.
Ravindra Bagale's Tip
Display errors on your laptop or test server, never on live. On live, log errors and read the log. One more habit: when you are done with a test page, rm it the same minute. Old info.php pages are found on real servers every day!
Ravindra Bagale's Tip – मराठी
Errors laptop वर किंवा test server वर दाखवा, live वर कधीच नाही. Live वर errors log करा आणि log वाचा. अजून एक सवय: test page चं काम झालं की त्याच मिनिटाला rm करा. जुन्या info.php pages खऱ्या servers वर रोज सापडतात!
Ravindra Bagale's Tip – हिंदी
Errors laptop या test server पर दिखाओ, live पर कभी नहीं। Live पर errors log करो और log पढ़ो। एक और आदत: test page का काम खत्म होते ही उसी मिनट rm करो। पुराने info.php pages असली servers पर रोज़ मिलते हैं!
Common mistakes
| Mistake | What happens | Fix |
|---|---|---|
Editing php.ini but not restarting PHP-FPM |
Old settings stay active | sudo systemctl restart php-fpm |
| Restarting only Nginx | PHP settings do not change | PHP-FPM reads php.ini, not Nginx |
display_errors = Off and log_errors = Off |
Errors disappear completely and bugs are hard to find | Keep log_errors = On |
Leaving phpinfo() or test files online |
Full server details for anyone | Delete test files right after use |
502 Bad Gateway after install |
PHP-FPM is not running | sudo systemctl status php-fpm, then start it |
Self-check checklist
0 of 5 done
Try-at-home challenge
PHP-FPM can force a setting for one pool so that a developer cannot switch it back on from code. Find the line in /etc/php-fpm.d/www.conf that does this for display_errors and turn it on.
Check your answer
Run grep -n "display_errors" /etc/php-fpm.d/www.conf. You will find a commented line ;php_flag[display_errors] = off. Change it to php_admin_flag[display_errors] = off (the admin version cannot be changed with ini_set() in code), save, and run sudo systemctl restart php-fpm.
Clean up to avoid charges
Keep the server for Lab 10 if you continue today. Otherwise: EC2 → Instances → Instance state → Terminate (delete) instance.
Samjla ka? Errors on screen for you, in the log for live. Aata pudhe jaauya: Chapter 10 adds MySQL, and we give it a least-privilege user.