Web server hardening & HTTPS
Your website is the one door you want everyone to walk through. That makes it the part of the server strangers look at most. Out of the box, Apache is friendly: it tells visitors its version, lists folders that have no index page, and talks in plain text anyone on the network can read. Let's make it polite but tight-lipped, and encrypted.
You will learn
- Reading what your server gives away with
curl -I ServerTokens,ServerSignatureand turning off folder listings- Security headers, and where Apache's config lives on each family
- HTTPS: a test certificate now, a free real one from Let's Encrypt later
Where the config lives
You set up Apache in Linux Basics, lesson 14. The two families split its config up differently:
| What | Rocky / RHEL (httpd) | Ubuntu / Debian (apache2) |
|---|---|---|
| Main file | /etc/httpd/conf/httpd.conf | /etc/apache2/apache2.conf |
| Your own settings | a new file in /etc/httpd/conf.d/ | /etc/apache2/conf-available/ + a2enconf |
| Turn a module on | install it (dnf install mod_ssl) | sudo a2enmod NAME |
| Sites | <VirtualHost> blocks in conf.d/*.conf | sites-available/ + a2ensite |
| Check before reloading | sudo apachectl configtest | sudo apache2ctl configtest |
Say less: version numbers and folder listings
Ask your own server what it tells visitors: curl -I http://localhost. The Server: line shows Apache's exact version, and often the OS. Like the nmap -sV result in lesson 4, that saves an attacker a step. Two settings fix it:
ServerTokens Prod # Server: header just says "Apache"
ServerSignature Off # no version line at the bottom of error pages
Next, folder listings. Both families ship Options Indexes for the web folder. That means a folder with no index.html shows a list of every file in it, including ones you never linked to. Take Indexes out of the Options line and Apache answers "403 Forbidden" instead.
Just like changing the SSH port, hiding the version is a small extra, not protection. Bots try their tricks on every server whatever it says. Updating Apache is what actually closes holes (Linux Basics 2, lesson 6).
Security headers
Headers are little notes your server sends with every page, telling the browser how to behave. A few cost nothing and block whole kinds of attacks:
| Header | What it tells the browser |
|---|---|
X-Content-Type-Options: nosniff | Trust the file type I send; don't guess (stops some sneaky script tricks) |
X-Frame-Options: SAMEORIGIN | Don't let other sites show my pages inside a frame (stops "clickjacking") |
Strict-Transport-Security | Only ever talk to this site over HTTPS, for the next year (HSTS) |
Content-Security-Policy | Exactly which places scripts, styles and images may come from. Powerful, so test it carefully |
They're set with Header always set NAME "value". On Rocky, mod_headers is already on. On Ubuntu, turn it on first with sudo a2enmod headers, or the config check fails with "Invalid command 'Header'".
HTTPS
Without HTTPS, everything between the browser and your server (passwords, form data, cookies) travels as plain text. HTTPS encrypts it and proves the visitor is talking to the real server. That proof is a certificate.
| Task | Rocky / RHEL | Ubuntu / Debian |
|---|---|---|
| HTTPS with a test certificate | sudo dnf install mod_ssl (makes localhost.crt) | sudo a2enmod ssl + sudo a2ensite default-ssl (the "snakeoil" cert) |
| Open the firewall | sudo firewall-cmd --permanent --add-service=httpssudo firewall-cmd --reload | sudo ufw allow 'Apache Full' |
| A real certificate (needs a domain name) | sudo dnf install certbot python3-certbot-apache (EPEL) | sudo apt install certbot python3-certbot-apache |
| Get it and set it up | sudo certbot --apache -d club.example.org same on both | |
| Renewals (every 90 days, automatic) | sudo certbot renew --dry-run same on both | |
A self-signed certificate encrypts just as well, but nobody vouches for it, so browsers warn and curl refuses unless you add -k. That's fine for a lab. Let's Encrypt gives real, trusted certificates for free, but it has to reach your server by its domain name from the internet, which a home lab can't do. Use certbot when your site has a real name.
Once HTTPS works, send plain-HTTP visitors over to it with a redirect in the port-80 site:
<VirtualHost *:80>
Redirect permanent / https://192.168.1.50/
</VirtualHost>
Try it: lock up the club website 🔐
The club site runs on the server with the factory settings. Work through it the way you would on a real server: look, change one thing, test, reload.
Quick check
1. curl http://localhost/files/ shows "Index of /files" and a list of files. What's wrong?
✓ Remove Indexes, and keep private files out of the web folder altogether.
2. On Ubuntu, you add Header always set X-Frame-Options "SAMEORIGIN" and configtest says "Invalid command 'Header'". Why?
✓ A directive only exists once the module that provides it is loaded.
3. Your lab site uses a self-signed certificate. Is the traffic encrypted?
✓ Encryption and trust are two different jobs. A certificate from a trusted authority does both.