Skip to content

Web Server Hardening: Security Configuration Guide

DodaTech Updated 2026-06-23 9 min read

In this tutorial, you'll learn about Web Server Hardening: Security Configuration Guide. We cover key concepts, practical examples, and best practices.

Web server hardening is the practice of securing a web server by reducing its attack surface, disabling unnecessary services, configuring strong access controls, and implementing defense-in-depth security measures. A hardened server resists common attacks including injection, directory traversal, DDoS, and brute force attempts.

In this tutorial, you will learn to harden the OS layer (firewall, SSH, automatic updates), configure NGINX and Apache with security best practices, implement TLS hardening and security headers, set up fail2ban for brute force protection, configure file system permissions, integrate a Web Application Firewall (WAF), and audit your server for compliance. DodaTech applies these hardening measures to every production server serving Doda Browser, DodaZIP, and Durga Antivirus Pro.

What You'll Learn

By the end of this guide, you will harden a Linux web server from default installation to production-ready security posture, configure NGINX and Apache with security headers and rate limiting, set up fail2ban to block malicious IPs, implement file system access controls, and audit the server against the CIS benchmark.

Why Server Hardening Matters

Default server installations prioritize functionality over security. Unhardened servers are compromised within minutes of being exposed to the internet. Automated scanners constantly probe for open ports, default credentials, and known vulnerabilities. Hardening transforms a vulnerable default installation into a resilient production server. Every Web Servers administrator and Linux engineer must master hardening as a core competency.

Server Hardening Learning Path

flowchart LR
  A[OS Hardening] --> B[Web Server Config]
  B --> C[SSL/TLS Hardening]
  C --> D[Security Headers]
  D --> E[Fail2ban & WAF]
  E --> F{You Are Here}
  style F fill:#f90,color:#fff

OS-Level Hardening

Firewall configuration with UFW

# Default deny all incoming, allow all outgoing
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow essential services only
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Enable firewall
sudo ufw enable

# Verify
sudo ufw status verbose

Expected output

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing)

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
443/tcp                    ALLOW       Anywhere

SSH hardening

# /etc/ssh/sshd_config
sudo sed -i 's/#Port 22/Port 2222/' /etc/ssh/sshd_config
sudo sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/#MaxAuthTries 6/MaxAuthTries 3/' /etc/ssh/sshd_config
sudo sed -i 's/#AllowUsers/AllowUsers admin deployer/' /etc/ssh/sshd_config

# Apply changes
sudo systemctl restart sshd

Automatic security updates

# Install unattended-upgrades
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure --priority=low unattended-upgrades

# Configure auto-reboot for kernel updates
sudo sed -i 's/\/\/Unattended-Upgrade::Automatic-Reboot "false"/Unattended-Upgrade::Automatic-Reboot "true"/' /etc/apt/apt.conf.d/50unattended-upgrades
sudo sed -i 's/\/\/Unattended-Upgrade::Automatic-Reboot-Time "02:00"/Unattended-Upgrade::Automatic-Reboot-Time "03:00"/' /etc/apt/apt.conf.d/50unattended-upgrades

NGINX Security Configuration

# /etc/nginx/nginx.conf

# Hide NGINX version
server_tokens off;

# Limit request body size (prevents large upload DoS)
client_max_body_size 10M;

# Timeout settings to prevent slowloris attacks
client_body_timeout 12s;
client_header_timeout 12s;
send_timeout 10s;
keepalive_timeout 30s;

# Buffer size limits
client_body_buffer_size 128k;
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;
# Security headers in server block
server {
    listen 443 ssl http2;
    server_name dodatech.com;

    # Hide server version
    server_tokens off;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;

    # HSTS
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    # Block path traversal attacks
    location ~ \.(env|git|sql|log|bak|swp)$ {
        deny all;
    }

    # Restrict access to sensitive paths
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }

    # Rate limiting
    limit_req_zone $binary_remote_addr zone=general:10m rate=30r/s;
    location / {
        limit_req zone=general burst=50 nodelay;
        proxy_pass http://backend;
    }

    # Prevent hotlinking
    location ~ \.(jpg|jpeg|png|gif|webp)$ {
        valid_referers none blocked dodatech.com *.dodatech.com;
        if ($invalid_referer) {
            return 403;
        }
    }
}

Apache Security Configuration

# /etc/apache2/conf-enabled/security.conf

# Hide Apache version and OS
ServerTokens Prod
ServerSignature Off

# Disable directory listing globally
<Directory /var/www>
    Options -Indexes
</Directory>

# Limit HTTP methods
<LimitExcept GET POST HEAD>
    Require all denied
</LimitExcept>

# Disable server-side includes and CGI if not needed
<Directory /var/www/html>
    Options -ExecCGI -Includes
</Directory>

# Security headers
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
Header always set Content-Security-Policy "default-src 'self'"

# Block access to hidden files
<FilesMatch "^\.">
    Require all denied
</FilesMatch>

# Block sensitive file types
<FilesMatch "\.(env|git|sql|log|bak|swp|md)$">
    Require all denied
</FilesMatch>

TLS Hardening

# Generate a strong DH parameter (takes several minutes)
sudo openssl dhparam -out /etc/nginx/dhparam.pem 4096

# Expected output: no output, but file is created
# /etc/nginx/conf.d/tls.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;

# Use the generated DH param
ssl_dhparam /etc/nginx/dhparam.pem;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

Fail2ban Configuration

# Install fail2ban
sudo apt install fail2ban -y

# Create local jail configuration
cat << 'EOF' | sudo tee /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5

[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s

[nginx-http-auth]
enabled = true
port = http,https
logpath = %(nginx_error_log)s

[nginx-botsearch]
enabled = true
port = http,https
logpath = %(nginx_access_log)s

[apache-auth]
enabled = true
port = http,https
logpath = %(apache_error_log)s

# Custom: Rate limit web requests
[nginx-limit-req]
enabled = true
port = http,https
filter = nginx-limit-req
logpath = %(nginx_error_log)s
maxretry = 3
findtime = 60
bantime = 600
EOF

# Create custom filter for rate limit violations
cat << 'EOF' | sudo tee /etc/fail2ban/filter.d/nginx-limit-req.conf
[Definition]
failregex = ^.*limiting requests, excess:.* by zone.*client: <HOST>
ignoreregex =
EOF

sudo systemctl restart fail2ban
sudo fail2ban-client status

Expected output

Status
|- Number of jail:      4
`- Jail list:   sshd, nginx-http-auth, nginx-botsearch, nginx-limit-req

File System Permissions

# Web root permissions
sudo chown -R www-data:www-data /var/www/dodatech
sudo find /var/www/dodatech -type d -exec chmod 755 {} \;
sudo find /var/www/dodatech -type f -exec chmod 644 {} \;

# Sensitive files should not be world-readable
sudo chmod 640 /var/www/dodatech/.env
sudo chmod 640 /var/www/dodatech/config/database.php

# Restrict access to configuration files
sudo chown root:www-data /etc/nginx/nginx.conf
sudo chmod 640 /etc/nginx/nginx.conf
sudo chown root:www-data /etc/letsencrypt/ -R
sudo chmod 755 /etc/letsencrypt/
sudo chmod 600 /etc/letsencrypt/live/*/privkey.pem

# Audit setuid binaries (potential privilege escalation)
sudo find / -perm -4000 -type f 2>/dev/null

CVE and Vulnerability Scanning

# Install Lynis for security auditing
sudo apt install lynis -y
sudo lynis audit system

# Check for known vulnerabilities in installed packages
sudo apt install debsecan -y
sudo debsecan

# Run a quick web server scan with Nikto
sudo apt install nikto -y
nikto -h https://dodatech.com -ssl

Common Errors

1. Server Unreachable After Firewall Change

The firewall blocked SSH or web ports. Always keep a secondary SSH session open when changing firewall rules. Test with sudo ufw status numbered and allow the correct ports.

2. Security Headers Not Applied

Headers defined in an incorrect context or blocked by another directive. Use curl -I https://example.com to verify. Check that add_header directives are not overridden by inner blocks.

3. SSL Labs Rating Below A+

Weak ciphers, missing HSTS, or outdated protocols. Disable TLS 1.0/1.1, enable HSTS with a long max-age, and configure a modern cipher suite.

4. Fail2ban Not Banning IPs

The log path is incorrect or the filter regex does not match. Test with sudo fail2ban-regex /var/log/nginx/error.log /etc/fail2ban/filter.d/nginx-limit-req.conf.

5. Permission Denied After Chown

The web server user cannot read files. Ensure directories have execute permission (755) and files have read permission (644). The path to the document root must be traversable by the web server user at every level.

Practice Questions

1. What is the principle of least privilege and how does it apply to web server hardening? The principle of least privilege means giving users and processes only the minimum permissions needed. For web servers: run as a non-root user, restrict file permissions, disable unnecessary modules, and limit network access with a firewall.

2. How do security headers like X-Frame-Options and Content-Security-Policy protect users? X-Frame-Options prevents clickjacking by blocking the site from being loaded in iframes. Content-Security-Policy mitigates XSS attacks by restricting which resources can be loaded and executed.

3. What is fail2ban and how does it protect a web server? Fail2ban scans log files for malicious patterns (failed logins, scanning, brute force) and temporarily bans offending IP addresses using firewall rules. It reduces the attack surface without blocking legitimate traffic.

4. Challenge: Full server security audit

Perform a security audit on a web server:

  • Check all open ports and services
  • Verify SSL configuration against Mozilla SSL Configuration Generator
  • Audit all file permissions in the web root
  • Check for unused Apache/NGINX modules
  • Review fail2ban logs for blocked IPs
  • Generate a Lynis report and address all warnings

Mini Project: Production Server Hardening

Harden a fresh Linux web server from initial installation to production ready:

  1. Configure UFW firewall to allow only SSH, HTTP, and HTTPS
  2. Harden SSH (disable root login, key-based auth only, non-standard port)
  3. Harden NGINX with server_tokens off, request limits, security headers, and TLS hardening
  4. Generate strong DH parameters and configure OCSP stapling
  5. Install and configure fail2ban for SSH and NGINX jails
  6. Set proper file permissions on the web root and sensitive configuration files
  7. Run Lynis security audit and fix all critical and warning items
  8. Verify the setup with SSL Labs (target: A+ rating)
# Final verification commands
curl -sI https://dodatech.com | grep -E "Server|X-Frame|X-Content|Strict-Transport"
# Server: (no version)
# X-Frame-Options: SAMEORIGIN
# X-Content-Type-Options: nosniff
# Strict-Transport-Security: max-age=63072000; includeSubDomains

sudo fail2ban-client status nginx-limit-req
# Status for the jail: nginx-limit-req
# |- Currently banned: 12
# `- Total banned: 45

sudo lynis audit system --quick 2>/dev/null | grep -E " hardening"
# Hardening index : [66/100]  (improved from initial)

This hardening checklist is applied to every DodaTech production server handling Doda Browser updates, DodaZIP downloads, and Durga Antivirus Pro security services.

FAQ

How often should I update my web server?

Apply security patches immediately. Use unattended-upgrades for automatic critical updates. Perform full system updates monthly with a maintenance window.

What is the most important single hardening step?

Disabling root SSH login and using key-based authentication. Automated attacks constantly try root passwords. Without this step, all other hardening is undermined.

Do I need a Web Application Firewall (WAF)?

Yes for any public-facing application. A WAF blocks SQL injection, XSS, and other application-layer attacks that server-level hardening does not address. Consider ModSecurity with the OWASP Core Rule Set.

What is the difference between hardening and patching?

Hardening is proactive configuration to prevent attacks. Patching is reactive remediation of known vulnerabilities. Both are required for a complete security posture.

How do I monitor server security after hardening?

Set up log monitoring with fail2ban, review auth logs daily, use AIDE or Tripwire for file integrity monitoring, and subscribe to security advisories for your software stack.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro