Securing Web Servers - KulbirJ/Protecting-the-Web- GitHub Wiki

Configuring Web Servers for Secure HTTPS with Security Headers: IIS, NGINX, and Apache

In today’s digital landscape, securing web servers is critical to protect sensitive data, mitigate vulnerabilities, and align with zero trust security principles like "never trust, always verify." This article provides detailed, step-by-step configurations for three popular web servers—Microsoft Internet Information Services (IIS), NGINX, and Apache—to enable HTTPS and implement all modern security headers. These setups are based on the latest stable versions as of February 25, 2025: IIS 10 (Windows Server 2022), NGINX 1.24.x/1.25.x, and Apache 2.4.58/2.4.59. Whether you’re securing a corporate website, an application, or a service, this guide ensures a robust, secure foundation. With these configurations in place your vulnerability scans against OWASP Top 10 will come clean.


Overview

Why HTTPS and Security Headers Matter

HTTPS encrypts traffic between clients and servers, preventing interception, while security headers mitigate common web vulnerabilities like cross-site scripting (XSS), clickjacking, and MIME-type sniffing. Together, they reduce attack surfaces and enforce strict access policies, key tenets of zero trust.

Assumptions

HTTPS: Requires a valid SSL/TLS certificate (e.g., from Let’s Encrypt or a trusted CA).

Security Headers: Includes HSTS, CSP, X-Content-Type-Options, and more, applied consistently across all servers.

Environment: Configurations assume modern OS platforms (Windows Server 2022 for IIS, Ubuntu 22.04/CentOS 9 for NGINX and Apache).


Microsoft IIS Configuration

Prerequisites

  • OS: Windows Server 2022 with IIS 10.
  • Certificate: Valid SSL/TSL certificate installed.
  • Access: Administrative privileges.

Step 1: Enable HTTPS

  1. Install IIS:

Open Server Manager > Add Roles and Features > Select Web Server(IIS) > Install with defaults plus HTTP Redirection.

  1. Install SSL Certificate:

In IIS Manager (inetmgr), select the server node > Server Certificates > Import or Create Certificate Request. Example: Use Certify The Web for Let’s Encrypt automation.

  1. Configure HTTPS Binding:

Right-click your site (e.g., "Default Web Site") > Edit Bindings > Add: Type: https Port: 443 Host name: yourdomain.com SSL Certificate: Select imported certificate.

  1. Redirect HTTP to HTTPS:

Select site > HTTP Redirect > Check Redirect requests > Set to https://yourdomain.com/$1 > Status code: 301.

Step 2: Add Security Headers

Edit or create web.config in your site’s root (e.g., C:\inetpub\wwwroot):

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="X-Content-Type-Options" value="nosniff" />
        <add name="X-Frame-Options" value="DENY" />
        <add name="Content-Security-Policy" value="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none';" />
        <add name="X-XSS-Protection" value="1; mode=block" />
        <remove name="X-Powered-By" />
        <add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains; preload" />
        <add name="Referrer-Policy" value="strict-origin-when-cross-origin" />
        <add name="Cache-Control" value="no-store, no-cache, must-revalidate" />
        <add name="Pragma" value="no-cache" />
        <add name="Permissions-Policy" value="geolocation=(), microphone=(), camera=()" />
      </customHeaders>
    </httpProtocol>
    <rewrite>
      <rules>
        <rule name="HTTP to HTTPS Redirect" stopProcessing="true">
          <match url="(.*)" />
          <conditions>
            <add input="{HTTPS}" pattern="off" />
          </conditions>
          <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
        </rule>
      </rules>
    </rewrite>
    <security>
      <requestFiltering removeServerHeader="true" />
    </security>
  </system.webServer>
</configuration>

Step 3: Additional Security

  • TLS Hardening: Use IIS Crypto to disable SSL 2.0/3.0, TLS 1.0/1.1, enable TLS 1.2/1.3, and prefer strong ciphers (e.g., AES-256-GCM).
  • Directory Browsing: Disable via Directory Browsing in IIS Manager.
  • Request Filtering: Deny unused file extensions (e.g., .config) and verbs (e.g., TRACE).

Step 4:Test


NGINX Configuration

  • OS: Ubuntu 22.04 or CentOS 9.
  • Certificate: Valid SSL/TSL certificate installed.
  • Access: Root or sudo privileges.

Step 1:Enable HTTPS

  1. Install NGINX:

Ubuntu: sudo apt install nginx

CentOS: sudo dnf install nginx

  1. Install SSL Certificate:

User Certbob: sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

  1. Configure Server Block: Edit /etc/nginx/sites-available/yourdomain.com(Ubuntu) or /etc/nginx/conf.d/yourdomain.com.conf(CentOS):
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.com/chain.pem;
    root /var/www/yourdomain.com/html;
    index index.html index.htm;
    location / {
        try_files $uri $uri/ =404;
    }
}

Enable (Ubuntu):sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/ Test: sudo nginx -t Reload: sudo systemctl reload nginx

Step 2: Add Security Headers

Update the HTTPS server block:

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.com/chain.pem;

    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none';" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Cache-Control "no-store, no-cache, must-revalidate";
    add_header Pragma "no-cache";
    add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
    server_tokens off;

    root /var/www/yourdomain.com/html;
    index index.html index.htm;
    location / {
        try_files $uri $uri/ =404;
    }
}

Step 3: Additional Security

  • TLS Hardening
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384";
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
  • Directory Listing: autoindex off;

  • Limit Methods:

location / {
    limit_except GET POST { deny all; }
}

Step 4: Test


Apache Configuration

Prerequisites

  • OS: Ubuntu 22.04 or CentOS 9.
  • Certificate: Valid SSL/TSL certificate installed.
  • Access: Root or sudo privileges.

Step 1: Enable HTTPS

  1. Install Apache

Ubuntu:sudo apt install apache2 CentOS: sudo dnf install httpd

  1. Enable Modules:

sudo a2enmod ssl headers rewrite

  1. Install SSL Certificate:

Use Certbot: sudo certbot --apache -d yourdomain.com -d www.yourdomain.com

  1. Configure Virtual Host: Edit /etc/apache2/sites-available/yourdomain.com.conf (Ubuntu) or /etc/httpd/conf.d/yourdomain.com.conf(CentOS):
<VirtualHost *:80>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com
    Redirect permanent / https://yourdomain.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com
    DocumentRoot /var/www/yourdomain.com/html
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/yourdomain.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/yourdomain.com/chain.pem
</VirtualHost>
  • Enable (Ubuntu): sudo a2ensite yourdomain.com.conf
  • Reload: sudo systemctl reload apache2 (Ubuntu) or httpd (CentOS)

Step 2:Add Security Headers

Update the HTTPS <virtualHost>:

<VirtualHost *:80>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com
    Redirect permanent / https://yourdomain.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com
    DocumentRoot /var/www/yourdomain.com/html
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/yourdomain.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/yourdomain.com/chain.pem

    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "DENY"
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none';"
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set Cache-Control "no-store, no-cache, must-revalidate"
    Header always set Pragma "no-cache"
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
    ServerSignature Off
    ServerTokens Prod
</VirtualHost>

Step 3: Additional Security

  • TLS Hardening
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder on
SSLSessionTickets off
  • Directory Listing
<Directory /var/www/yourdomain.com/html>
    Options -Indexes
</Directory>
  • Limit Methods:
RewriteEngine On
RewriteCond %{REQUEST_METHOD} !^(GET|POST)
RewriteRule .* - [R=405,L]

Step 4: Test

Reload: sudo systemctl reload apache2 (Ubuntu) or httpd (CentOS) Verify: https://yourdomain.com and SecurityHeaders.com. TLS Check: SSL Labs


Security Headers Explained

  • X-Content-Type-Options: nosniff - Prevents MIME-type sniffing.
  • X-Frame-Options: DENY - Blocks iframe embedding (clickjacking protection).
  • Content-Security-Policy (CSP) - Limits resource sources to mitigate XSS; customizable for app needs.
  • X-XSS-Protection: 1; mode=block - Legacy XSS filter for older browsers.
  • Strict-Transport-Security (HSTS) - Enforces HTTPS for 1 year with preload option.
  • Referrer-Policy - Controls referrer data for privacy.
  • Cache-Control/Pragma - Prevents caching of sensitive content.
  • Permissions-Policy - Restricts browser features (e.g., geolocation).
  • Server Hiding - Removes server version banners.

Conclusion

This guide equips IIS, NGINX, and Apache with HTTPS and comprehensive security headers, ensuring a secure web presence as of February, 2025. Each configuration is adaptable to static or dynamic sites, with room to customize based on specific needs. By implementing these setups, you align with zero trust principles, enhancing security in an increasingly distributed world.

⚠️ **GitHub.com Fallback** ⚠️