Web server hardening lab: fix a weak nginx configuration and check it with curl
This lab gives each student a small website served by nginx with a configuration that is weak on purpose. It shows its version number, lists its folders, sends no security headers, and gives away a .git folder, a backup file and an open admin area. The student looks at it with curl, fixes the configuration inside the running container, reloads nginx and watches each check turn from FAIL to PASS.
It is designed by us from the public nginx image alone, so there is no vulnerable application to attack: only a server to make safer. The lab copy has no route to the internet and none to any other student.
What students learn
What a web server tells a visitor without being asked: its exact version, the files in a folder, files nobody meant to publish. They read response headers with curl -I, add the four common security headers, switch off the folder listing and the version number, refuse a .git folder and a backup file, and close an admin area to visitors. They also practise testing a configuration with nginx -t, loading it with nginx -s reload and checking the result with a tool. It suits secure configuration and system administration units; check your own awarding body’s unit for the exact wording.
Run it in your browser
The site is the service called web, and the lab’s terminal reaches it by that name. A docker command in the terminal can look at, enter, restart and read the logs of the lab’s service: it cannot create, pull or remove anything. The configuration folder is a named volume, so what the student saves is still there after the lab is stopped and started again.
- Open the Container page. Open Build on the bar and choose Run a container. Anybody may open it, and the Git lab and the SQL lab start with no account. Every other lab needs a free account: create one, sign in, then press Start.
- Find the lab. The Sample labs card lists every sample. Find Harden a web server (nginx).
- Press Start. Start runs it as it is, in one press. Edit the file first opens the compose file so you can change it before you start.
- Open it. On the lab’s page, open the terminal beside the lab. Run curl -I http://web to see the headers and docker exec web lab-check to see nine PASS or FAIL lines. Then docker exec -it web sh opens a shell in the server: edit /etc/nginx/conf.d/default.conf, test it with nginx -t and load it with nginx -s reload. The lab’s link, The bakery’s website, opens the site in a tab.
What to ask students to hand in
The output of curl -I http://web before and after, and of docker exec web lab-check at the end, so the change is visible in the student’s own terminal. For each fix, a sentence in their own words on what the weakness gave an attacker and what the setting does. The check says whether the server behaves as it should; only the explanation says whether it was understood. For stronger work ask for the whole configuration file.
The check is the lab’s own: lab-check asks the running server, so it reports what nginx does and not what a file says, and it exits with success only when all nine lines pass. The repository’s README also gives a one-line curl for each fix, for checking from anywhere. Nothing is marked automatically.
A basic lesson on this lab
Web Server Hardening Basics is a small lesson worked in this lab, with each step explained and a Run button that types its command into the student’s terminal. It looks at the headers and a folder listing, runs the check, fixes the version number with one command, reloads nginx and checks again. The other fixes are left to the student.
A free personal account is given it on the Basics module, which is on Home, every college can copy it from the Library’s Basics folder, and a new college opens with it in a module called Lab Basics (Sample). It is deliberately small: it shows a teacher what a lesson worked in a lab is, and the lab does the rest. Copy it into a module of your own to change it.
The code on GitHub
The compose file runs nginx’s own public image, pinned to a version, as the only service, and writes the site and the weak configuration when it starts. nginx is BSD-2-Clause licensed and is not distributed by us. The repository’s test plays a student through the lab, fix by fix, under the same limits the platform applies. Nothing the site links to outside itself can be fetched, because the lab has no way out to the internet.
Set it as work
Say in the task which fixes to make and what to hand in.
- Make the lab. In your module add a task and choose the Container lab card, then In a GitHub repository. Give https://github.com/mitsurutech/lab-harden-nginx with the branch main. The compose file is the default, compose.yaml. Fork the repository first if you want to change it.
- Publish and try it. Publish pins the commit you were shown, so a later change in the repository does not alter a lab you have already set. Start your own copy first.
- Hand it out. Assign it like any task, with a due date if you want one, and say in the task what to do and what to hand in.
- Mark what is handed in. Open a student’s copy and the work they handed in, mark it, and send it back with a reason if it needs more.
Questions people ask
- What if a student saves a mistake in the configuration?
- The lab still starts. A configuration that does not pass nginx -t when the lab starts is kept beside it as default.conf.broken and the weak one is written again. To start from the weak configuration on purpose, remove the file .seeded in /etc/nginx/conf.d and restart the service.
- Does the student need to install anything or reach the internet?
- No. nginx and curl are in the lab’s own image, the terminal is in the browser, and the lab copy has no way out to the internet.
- How do students check that their nginx hardening worked?
- They run docker exec web lab-check in the lab’s terminal, which prints nine PASS or FAIL lines and exits with success only when all nine pass. It asks the running server, so it reports what nginx does and not what a file says, and curl -I http://web shows the headers before and after.