Improving TLS Security Configurations in Apache

                
                Improving TLS Security Configurations in Apache
This article shows how to turn a regular Apache HTTPS virtual host into a tightly secured gateway for your project. We take a standard VirtualHost for a production server and harden it step by step: from selecting TLS protocols to filtering user-uploaded media files. Everything is presented in a practical “why it matters, how it’s broken without it, what to do” format.

1. Switch to Encrypted Port

 

Listen only on 443 for secure traffic. This removes the temptation to keep functionality on unencrypted HTTP and reduces the attack surface for MitM.

How it’s broken without this: traffic interception and substitution, cookie/session theft, downgrade to HTTP.

 

Listen 443

 

Basic hygiene — all sensitive data only over TLS.

 

2. Isolated Default Virtual Host

 

_default_:443 ensures that any host hitting 443 without an explicit VirtualHost lands in a safe profile.

 

<VirtualHost _default_:443>
    ServerAdmin admin@example.com
    ServerName  example.com
    DocumentRoot "C:/Apache24/htdocs"
    
    
#</VirtualHost> will be at the end

 

3. Enable TLS and Correct Certificates

 

Enable TLS and specify the chain/key. Correct files and permissions are the basis of trust.

How it’s broken without this: self-signed/broken chains → phishing via warnings; private key leak → total compromise.

 

	SSLEngine on
	SSLCertificateFile     "C:/Apache24/conf/ssl/domain.cert.pem"
	SSLCertificateKeyFile  "C:/Apache24/conf/ssl/private.key.pem"

 

Keep keys outside the web-root, readable only by the service user.

 

4. Protocol and Cipher Policy

 

Disable outdated protocols and weak ciphers, enforce server cipher order.

How it’s broken without this: downgrade to TLS 1.0/1.1, attacks on CBC/3DES/RC4/MD5, BEAST/Lucky13, etc.

 

	SSLProtocol             -all +TLSv1.2 +TLSv1.3
	SSLCipherSuite          HIGH:!aNULL:!MD5:!3DES
	SSLHonorCipherOrder     On
	SSLCompression          Off

 

Bottom line: Minimum — TLS 1.2/1.3, disable compression (CRIME) and trash ciphers.

 

5. Certificate Status Check (OCSP stapling)

 

The server attaches a fresh certificate status. Clients don’t need to contact the OCSP server.

Without this, privacy is worse (leaked OCSP queries), unstable checks ⇒ users ignore warnings.

 

	SSLUseStapling On

 

Stapling improves both privacy and performance.

 

6. Enforce HSTS

 

Force browsers to use only HTTPS, including subdomains, and allow preload.

How it’s broken without this: downgrade to HTTP, cookie interception, mixed content.

 

    <IfModule headers_module>
        Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    </IfModule>

 

Note: enable HSTS only after the entire domain is really ready to live on HTTPS.

7. WSGI Entry Point with Minimal Rights

 

Explicitly map the root to the WSGI app and forbid directory listing.

How it’s broken without this: random static/service files exposed, routing bypass to files.

 

    WSGIScriptAlias / "C:/Apache24/htdocs/our_project/our_project/wsgi.py"
<Directory "C:/Apache24/htdocs/our_project/our_project/">
    <Files wsgi.py>
        Require all granted
        Options -Indexes
    </Files>
</Directory>

 

8. Static Files: Open but No Indexes

 

Serve static files without auto-listing to avoid exposing project structure.

 

    Alias /static "C:/Apache24/htdocs/our_project/staticfiles/"
    <Directory "C:/Apache24/htdocs/our_project/staticfiles/">
        Require all granted
        Options -Indexes
    </Directory>

 

Result: only what’s explicitly addressed is visible.

 

9. Media: Block Dangerous Extensions + Cache

 

Serve user files but block anything executable.

How it’s broken without this: upload and execution of .py/.exe/.ps1, etc. → RCE/privilege escalation, payload hosting.

 

    Alias /media/ "C:/Apache24/htdocs/our_project/media/"
    <Directory "C:/Apache24/htdocs/our_project/media/">
        Require all granted
        Options -Indexes
        <FilesMatch "\.(py|pyc|pyo|sh|bat|cmd|ps1|exe)$">
            Require all denied
        </FilesMatch>
        <IfModule mod_expires.c>
            ExpiresActive On
            ExpiresDefault "access plus 7 days"
        </IfModule>
    </Directory>

 

Media are data, not code. Deny executable formats and set a safe TTL.

 

10. Limit Request Body Size

 

Set a limit to protect the backend and prevent abuse of uploads.

Prevents DoS with huge bodies, massive archives/dictionary attacks via upload.

 

    LimitRequestBody 26214400  # 25 MiB

 

Adjust the limit to real needs; better smaller than “maybe later.”

 

11. Separate Logs for TLS Virtual Host

 

Separate error/access logs simplify incident investigation over HTTPS.

How it’s broken without this: noisy shared rotation hides anomalies, context lost.

 

    ErrorLog  "logs/ssl_error.log"
    CustomLog "logs/ssl_access.log" combined
</VirtualHost>

 

Personally I feed logs to AI for analysis. As in the previous article, I admit it’s a crutch. But apparently until I get hacked, I won’t automate.

 

Summary

 

+- Here’s how it should look:

 

Listen 443

ServerAdmin admin@example.com
ServerName  example.com

DocumentRoot "C:/Apache24/htdocs"

SSLEngine on
SSLCertificateFile     "C:/Apache24/conf/ssl/domain.cert.pem"
SSLCertificateKeyFile  "C:/Apache24/conf/ssl/private.key.pem"
SSLProtocol             -all +TLSv1.2 +TLSv1.3
SSLCipherSuite          HIGH:!aNULL:!MD5:!3DES
SSLHonorCipherOrder     On
SSLCompression          Off
SSLUseStapling On

<IfModule headers_module>
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
</IfModule>

WSGIScriptAlias / "C:/Apache24/htdocs/our_project/our_project/wsgi.py"

<Directory "C:/Apache24/htdocs/our_project/our_project/">
    <Files wsgi.py>
        Require all granted
        Options -Indexes
    </Files>
</Directory>

Alias /static "C:/Apache24/htdocs/our_project/staticfiles/"

<Directory "C:/Apache24/htdocs/our_project/staticfiles/">
    Require all granted
    Options -Indexes
</Directory>

Alias /media/ "C:/Apache24/htdocs/our_project/media/"

<Directory "C:/Apache24/htdocs/our_project/media/">
    Require all granted
    Options -Indexes
    <FilesMatch "\.(py|pyc|pyo|sh|bat|cmd|ps1|exe)$">
        Require all denied
    </FilesMatch>
    <IfModule mod_expires.c>
        ExpiresActive On
        ExpiresDefault "access plus 7 days"
    </IfModule>
</Directory>

LimitRequestBody 26214400

ErrorLog  "logs/ssl_error.log"
CustomLog "logs/ssl_access.log" combined