This guide is for developers, system administrators, and technical managers responsible for running web servers in production. Whether you use Apache, Nginx, or another server, a default installation leaves many security gaps open. Follow these steps to systematically close them — hardening your server against common attacks, information leakage, and misconfiguration exploits. Sensagraph can automatically verify many of these controls on a continuous basis.
Disable Unnecessary Modules and Services
Every enabled module or service that you do not actively use is a potential entry point for attackers. Default installations of Apache and Nginx often include modules for WebDAV, status pages, autoindex, and server-side scripting engines that may not be required. Audit and remove anything that is not essential.
- List all enabled modules: run
apache2ctl -M(Apache) or review yournginx.confcompiled modules. - Disable WebDAV modules (
mod_dav,mod_dav_fs) unless your application explicitly requires them. - Disable server status and info endpoints (
mod_status,mod_info) or restrict them to localhost only. - Remove autoindex / directory listing modules if not needed (see Step 04 for full directory listing hardening).
- Disable unused scripting language handlers (e.g., Perl, CGI) at the server level.
- Stop and disable any OS-level services not required by the web server (FTP, Telnet, unused databases).
- After disabling, restart the server and verify functionality is not affected.
Enforce HTTPS and Configure TLS Properly
Serving content over unencrypted HTTP exposes users to eavesdropping and man-in-the-middle attacks. Enforcing HTTPS and correctly configuring TLS is one of the highest-impact hardening steps you can take. Sensagraph checks your TLS configuration and certificate validity automatically.
- Obtain a valid TLS certificate from a trusted CA (Let's Encrypt is free and widely supported).
- Configure a permanent redirect (HTTP 301) from all HTTP traffic to HTTPS at the server level.
- Disable TLS 1.0 and TLS 1.1 — support only TLS 1.2 and TLS 1.3.
- Use strong cipher suites; a recommended starting point for Nginx:
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; - Set
ssl_prefer_server_ciphers on;(Nginx) orSSLHonorCipherOrder On(Apache) to enforce your cipher preference. - Enable OCSP Stapling to speed up certificate validation:
ssl_stapling on; ssl_stapling_verify on;(Nginx). - Set a secure Diffie-Hellman parameter: generate with
openssl dhparam -out /etc/ssl/dhparam.pem 4096and reference it in your config. - Verify your TLS configuration using an independent scanner after every change.
Set Secure HTTP Response Headers
HTTP security headers instruct browsers how to handle your content, protecting users from clickjacking, cross-site scripting, MIME sniffing, and other attacks. Missing or misconfigured headers are one of the most common findings in web security assessments. Sensagraph automatically checks for the presence and correctness of these headers.
- Strict-Transport-Security (HSTS): Add
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadto enforce HTTPS for at least one year. - Content-Security-Policy (CSP): Define a policy that restricts script, style, and resource sources. Start restrictive and widen only as needed, e.g.
default-src 'self';. - X-Frame-Options: Set to
DENYorSAMEORIGINto prevent clickjacking. - X-Content-Type-Options: Set to
nosniffto prevent MIME-type sniffing. - Referrer-Policy: Set to
strict-origin-when-cross-originor stricter to limit referrer leakage. - Permissions-Policy: Restrict access to browser features (camera, microphone, geolocation) that your app does not use.
- Remove the
X-Powered-Byheader entirely (reveals technology stack). - Test all headers after deployment using your browser's developer tools or an automated scan.
Restrict Directory Listing and Sensitive File Access
Directory listing allows anyone to browse your server's file structure, potentially exposing source code, backups, and configuration files. Sensitive files accidentally placed in the web root compound this risk enormously.
- Disable directory listing globally in Apache: set
Options -Indexesin your main config or.htaccess. - Disable autoindex in Nginx: ensure
autoindex off;is set (it is the default, but confirm it explicitly). - Block direct access to hidden files and directories (dot files): in Nginx, add
location ~ /\. { deny all; }; in Apache, useRedirectMatch 404 /\..*$. - Block access to common sensitive file extensions:
.env,.bak,.sql,.log,.conf,.gitdirectories. - Move all configuration and secrets files outside the web root where possible.
- Verify that
/.git/,/.env,/wp-config.php.bak, and similar paths return 403 or 404 — never 200. - Audit your web root regularly for files that should not be publicly accessible.
Hide Server Version and Technology Information
By default, web servers broadcast their software name and version in response headers and error pages. Attackers use this information to quickly identify vulnerable server versions and target known CVEs. Suppress this information to raise the cost of reconnaissance.
- Nginx: Set
server_tokens off;in thehttpblock ofnginx.conf. - Apache: Set
ServerTokens ProdandServerSignature Offinhttpd.conforapache2.conf. - Remove or rewrite the
Serverresponse header using a header manipulation module if you require further obfuscation. - Remove the
X-Powered-Byheader (PHP, Express, and others add this by default); in PHP setexpose_php = Offinphp.ini. - Customise default error pages (404, 403, 500) so they do not reveal stack traces, software versions, or file paths.
- Confirm suppression by inspecting response headers in your browser or via an automated scan — Sensagraph checks for exposed server banners.
Limit Allowed HTTP Methods
Web servers often accept HTTP methods — such as TRACE, PUT, DELETE, and OPTIONS — that are not required by most applications. Leaving these enabled provides attackers with additional vectors, including cross-site tracing (XST) attacks via TRACE.
- Identify the HTTP methods your application actually uses (typically GET, POST, and possibly OPTIONS for CORS pre-flight).
- Nginx: Restrict methods with a block such as:
if ($request_method !~ ^(GET|POST|HEAD)$) { return 405; } - Apache: Use a
<LimitExcept>directive to deny all methods except those explicitly required. - Always disable the TRACE method — it is rarely needed and enables cross-site tracing attacks.
- Test that disallowed methods return 405 Method Not Allowed or 403 Forbidden and not a 200 OK.
Implement Rate Limiting and Request Controls
Without rate limiting, your server is vulnerable to brute-force login attempts, credential stuffing, and volumetric denial-of-service attacks. Controlling request rates and payload sizes significantly reduces your exposure.
- Nginx rate limiting: Use
limit_req_zoneandlimit_reqdirectives to cap requests per IP, e.g. 10 requests/second with a burst allowance. - Apache: Use
mod_ratelimitormod_evasiveto limit connection rates and block abusive IPs. - Set a maximum request body size appropriate for your application:
client_max_body_size 10m;(Nginx) orLimitRequestBody 10485760(Apache). - Set timeouts for slow clients: configure
client_body_timeout,client_header_timeout, andkeepalive_timeout(Nginx) or their Apache equivalents. - Apply stricter rate limits specifically to authentication endpoints (
/login,/api/auth) and password reset flows. - Consider integrating a Web Application Firewall (WAF) in front of your server for deeper request inspection.
- Log and alert on repeated 429 (Too Many Requests) or 403 responses to detect active attacks.
Harden File and Directory Permissions
Overly permissive file and directory permissions allow attackers — or other users on a shared system — to read configuration files, modify application code, or write malicious files. Apply the principle of least privilege rigorously.
- Run the web server process as a dedicated, non-privileged user (e.g.,
www-dataon Debian/Ubuntu,nginxon RHEL/CentOS) — never as root. - Set web root directory permissions to
755(owner read/write/execute, group and others read/execute). - Set static file permissions to
644(owner read/write, group and others read-only). - Set configuration file permissions to
640or600so only the owner (and optionally the web server group) can read them. - Ensure
.envand secrets files are600and owned by the application user only. - Deny write access to the web server process on all directories except designated upload folders.
- Restrict upload directories from executing scripts: configure
php_admin_value engine Offor equivalent for upload paths. - Audit permissions recursively:
find /var/www -type f -perm /o+wto identify world-writable files.
Keep Software Updated and Monitor Continuously
Hardening is not a one-time task. New vulnerabilities in web server software, TLS libraries, and server-side frameworks are discovered regularly. A robust update and monitoring process ensures your hardening remains effective over time. Sensagraph continuously scans your web server configuration and alerts you when new issues are detected.
- Subscribe to security advisories for your web server software (Apache, Nginx) and OS distribution.
- Apply security patches within 72 hours of release for critical vulnerabilities; within 30 days for lower severity.
- Use your OS package manager's automatic security update feature (
unattended-upgradeson Debian/Ubuntu,dnf-automaticon RHEL/CentOS) for OS-level patches. - Keep TLS libraries (OpenSSL, LibreSSL) up to date — many critical TLS vulnerabilities are in the underlying library.
- Enable and review server access and error logs; ship them to a centralised log management system.
- Set up alerting for anomalous patterns: high 4xx/5xx rates, unexpected 200 responses on sensitive paths, traffic spikes.
- Schedule regular automated security scans of your web server to catch configuration drift and new exposures.
- After any significant configuration change or software upgrade, re-run your full hardening checklist.