Ravindra BagaleCourses & study guides Track your progress

Labs · Cyber Security

Lab: Host a Static Page on Nginx, Add Basic Security Headers and Verify Them with curl -I

Beginner35 minYour EC2 server with Nginx (Lab 7) · curl · Browser DevTools

Course: Cyber Security · Chapter 8: Hosting a Static Website and Changing the Configuration

Chapter 8 hosts a static website and changes the configuration; this lab adds security headers to it.

Chala mitrano! Security headers are small instructions that our server sends to the browser: "don't guess file types", "don't show me inside another site's frame", "load scripts only from me". Five lines of Nginx config, big protection. Aaj aapan te lavuya.

Suppose we are…

Suppose we are building the landing page for a BookMyShow college fest campaign on our own Nginx server. A security reviewer runs curl -I on the page and says: "No security headers. Someone could put your page inside an invisible frame on their site and trick users into clicking (clickjacking)." We fix it with a few add_header lines and prove it with curl.

Goal of this lab

By the end you will have:

  • Your own index.html served by Nginx.
  • Five security headers added in one separate file: X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy and Content-Security-Policy.
  • Proof from curl -I and the browser's DevTools.

What you need (all free)

  • Your EC2 server with Nginx from Lab 7 (HTTP 80 open to My IP only).
  • 30–35 minutes.

Safety and ethics

Test headers on your own server. Online header checkers are fine for your own site; do not use them to collect information about other companies' sites for attacks.

Steps

  1. SSH to the server. Replace the default page with your own:

    echo '<!doctype html><html><head><meta charset="utf-8"><title>Fest 2026</title></head><body><h1>College Fest 2026</h1><p>Hosted on my own Nginx.</p></body></html>' | sudo tee /usr/share/nginx/html/index.html
    
  2. Open http://<your-server-ip> in your browser.

    What you should see: the heading College Fest 2026.

  3. Check the headers before the change:

    curl -I http://localhost
    

    What you should see: Server, Date, Content-Type, Content-Length, Last-Modified, ETag and nothing about security.

  4. Create a separate file for the headers. Files in /etc/nginx/conf.d/ ending in .conf are loaded inside the http block:

    sudo nano /etc/nginx/conf.d/security-headers.conf
    
  5. Paste these lines, then save (Ctrl + O, Enter, Ctrl + X):

    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
    add_header Content-Security-Policy "default-src 'self'" always;
    

    nosniff stops the browser from guessing file types, SAMEORIGIN blocks other sites from framing your page, Referrer-Policy limits what address is shared when users click away, Permissions-Policy switches off camera, mic and location, and the CSP (Content Security Policy) allows content only from your own site. always adds them to error pages too.

  6. Test and reload:

    sudo nginx -t && sudo systemctl reload nginx
    
  7. Check the headers again:

    curl -I http://localhost
    

    What you should see: all five new headers in the response, for example X-Frame-Options: SAMEORIGIN.

  8. Check an error page too: curl -I http://localhost/nope.

    What you should see: HTTP/1.1 404 Not Found and the same five headers, thanks to always.

  9. In your browser, press F12 → Network tab → reload the page → click the first request (/ or your IP) → Headers → Response Headers. Find the five headers.

  10. Still in DevTools, open the Console tab and run document.title. It works, because it is your own page; the CSP only blocks content from other sites.

Ravindra Bagale's Tip

Careful: if you write add_header inside a location block, Nginx forgets the headers from the http level for that location. Students then wonder why headers disappear on one page. Keep them in one place, or repeat all of them in that location. He trap khup common aahe!

Common mistakes

Mistake What happens Fix
Forgetting always Headers missing on 404 and 500 pages Add always at the end of each line
add_header inside a location that has its own headers The http-level headers vanish for that location Keep headers in one place or repeat all of them
CSP too strict for a real site with Google Fonts or analytics Fonts or scripts stop loading Add only the domains you need, for example font-​src 'self' https://​fonts.​gstatic.​com
Adding Strict-​Transport-​Security on plain HTTP Browsers ignore it; can cause trouble later Add HSTS only after HTTPS works (Lab 13)
File saved as security-​headers.​txt Nginx ignores it The name must end in .conf

Self-check checklist

0 of 5 done

Try-at-home challenge

Create test-frame.html on your own laptop with <iframe src="http://<your-server-ip>/"></iframe> and open it in the browser. What happens, and which header caused it? Then look in the DevTools console for the message.

Check your answer

The frame stays empty or shows a "refused to connect" box. The Console says the page refused to be framed because X-Frame-Options is sameorigin. (The modern CSP way is frame-ancestors 'self'; note that default-src does not cover framing, so add frame-ancestors separately if you rely on CSP.) Your local file is a different origin, so framing is blocked: that is clickjacking protection working.

Clean up to avoid charges

Keep the server for Lab 9 if you are continuing today. Otherwise terminate it: EC2 → Instances → Instance state → Terminate (delete) instance.

Samjla ka? Five headers, one file, always, then curl -I to prove it. Aata pudhe jaauya: Chapter 9 adds PHP and a database.