16. Live Project: Building a Reels App with EC2, S3 and RDS
16.10 Deployment: Nginx, PHP Settings and Going Live
Code tayar aahe – aata Nginx aani PHP-FPM la sangu. Upload size teen thikani jultat, lakshat theva.
deploy/reels.conf
# /etc/nginx/conf.d/reels.conf (Ubuntu: /etc/nginx/sites-available/reels + symlink)
server {
listen 80;
server_name reels.yourdomain.com;
root /var/www/reels/public; # ONLY public/ is reachable from the web
index index.php;
client_max_body_size 60M; # must be >= PHP post_max_size
server_tokens off;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; media-src 'self' https://ravindra-reels-media-pune.s3.ap-south-1.amazonaws.com; img-src 'self' data:; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" always;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/run/php-fpm/www.sock; # Ubuntu: unix:/run/php/php-fpm.sock
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_read_timeout 120s;
}
location ~ /\. { deny all; } # .git, .env and other hidden files
}
deploy/99-reels.ini
; /etc/php.d/99-reels.ini (Ubuntu: /etc/php/8.3/fpm/conf.d/99-reels.ini)
upload_max_filesize = 55M
post_max_size = 58M
max_execution_time = 120
memory_limit = 256M
expose_php = Off
display_errors = Off
log_errors = On
session.use_strict_mode = 1
cd /var/www/reels
# 1. syntax-check EVERY PHP file before going live
find . -path ./vendor -prune -o -name '*.php' -print -exec php -l {} \;
# 2. PHP settings
sudo cp deploy/99-reels.ini /etc/php.d/99-reels.ini # Ubuntu: /etc/php/8.3/fpm/conf.d/
sudo service php-fpm restart # Ubuntu: php8.3-fpm
# 3. Nginx site
sudo cp deploy/reels.conf /etc/nginx/conf.d/reels.conf # Ubuntu: sites-available + ln -s
sudo nginx -t && sudo service nginx reload
# 4. permissions: code read-only for the web server
sudo chown -R ec2-user:ec2-user /var/www/reels
sudo chown root:apache /var/www/reels/config.php && sudo chmod 640 /var/www/reels/config.php
# 5. smoke test
curl -I http://localhost/login.php -H "Host: reels.yourdomain.com" # expect 200
curl -s http://localhost/config.php -H "Host: reels.yourdomain.com" -o /dev/null -w "%{http_code}\n" # expect 404
Expected php -l output:
./src/bootstrap.php
No syntax errors detected in ./src/bootstrap.php
./public/upload.php
No syntax errors detected in ./public/upload.php
./public/feed.php
No syntax errors detected in ./public/feed.php
...
Why this matters for security
Pointing root at public/ (not the project folder) is what keeps config.php, vendor/ and schema.sql out of reach. server_tokens off and expose_php = Off hide version numbers that scanners use to pick exploits, and location ~ /\. blocks .git and .env – a very common finding in real penetration tests.
Ravindra Bagale's Tip
Students write /var/www/reels as the Nginx root, not /var/www/reels/public – and then https://site/config.php... Nginx runs the PHP, so the password isn't shown, but schema.sql and composer.json can be downloaded. After deploying, always do the curl test from step 5 – it must return 404.
Ravindra Bagale's Tip – मराठी
Nginx root मध्ये students /var/www/reels लिहितात, /var/www/reels/public नाही – आणि https://site/config.php... Nginx PHP run करतो म्हणून password दिसत नाही, पण schema.sql आणि composer.json download होतात. Deploy नंतर step 5 चा curl test नेहमी करा – 404 आलाच पाहिजे.
Ravindra Bagale's Tip – हिंदी
Nginx root में students /var/www/reels लिखते हैं, /var/www/reels/public नहीं – और https://site/config.php... Nginx PHP run करता है इसलिए password नहीं दिखता, पर schema.sql और composer.json download हो जाते हैं. Deploy के बाद step 5 वाला curl test हमेशा करो – 404 ही आना चाहिए.
Lab
Deploy the app, run the php -l loop until every file reports no syntax errors, and complete the smoke tests. Then register, post a video and see it in the feed using http://<Elastic-IP> with cookie_secure temporarily false.