The Apache equivalent of a from-scratch Nginx setup: enabling the SSL module, configuring a VirtualHost for HTTPS, and adding the redirect — with Apache's own specific directive names and a couple of Apache-specific gotchas.

1. Enable the SSL module
sudo a2enmod ssl
sudo systemctl restart apache2
On Debian/Ubuntu-based systems, Apache's modules are enabled individually this way; other distributions may have mod_ssl compiled in by default or require a different enabling mechanism — check your specific distribution's Apache documentation if a2enmod isn't available.
2. The HTTPS VirtualHost
<VirtualHost *:443>
ServerName yourdomain.com
ServerAlias www.yourdomain.com
DocumentRoot /var/www/yourdomain
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/cert.pem
SSLCertificateKeyFile /etc/apache2/ssl/privkey.pem
SSLCertificateChainFile /etc/apache2/ssl/chain.pem
</VirtualHost>
Unlike Nginx (which typically expects a single concatenated full-chain file), Apache traditionally uses a separate SSLCertificateChainFile directive for the intermediate bundle — though newer Apache/mod_ssl versions also support a combined file via SSLCertificateFile alone. Check your specific Apache version's documentation, since using the wrong pattern for your version is a common source of chain-related trust errors.
3. The HTTP redirect VirtualHost
<VirtualHost *:80>
ServerName yourdomain.com
ServerAlias www.yourdomain.com
Redirect permanent / https://yourdomain.com/
</VirtualHost>
As with Nginx, this needs to be a separate VirtualHost bound to port 80 — Apache selects which VirtualHost handles a request partly based on the port it's listening on, so redirect logic belongs in the port-80 block exactly.
4. Enable the site and reload
sudo a2ensite yourdomain-ssl.conf
sudo apachectl configtest && sudo systemctl reload apache2
As with Nginx's -t flag, apachectl configtest validates syntax before reloading — always run this first, since a broken configuration can otherwise take the site down on reload rather than being caught beforehand.
5. Confirm listening ports
Check that Apache's ports.conf (or equivalent) includes Listen 443 — a surprisingly common oversight when adding HTTPS to a server that was previously HTTP-only, since Apache won't automatically start listening on a new port just because a VirtualHost references it.
6. Basic hardening
SSLProtocol -all +TLSv1.2 +TLSv1.3
Header always set Strict-Transport-Security "max-age=31536000"
The Header directive requires mod_headers to be enabled (a2enmod headers) if it isn't already — another module-enabling step specific to Apache's architecture that Nginx doesn't require for the equivalent functionality.
Common first-time mistakes to check for
- Forgetting to enable
mod_sslormod_headersbefore referencing directives that depend on them, which produces a startup error rather than a silent failure - Using
SSLCertificateChainFileon a newer Apache version that expects the chain concatenated intoSSLCertificateFileinstead, or vice versa on an older version - A VirtualHost with no matching
Listendirective for its port, meaning Apache never in practice opens that port at all
What mod_ssl version differences mean for available configuration directives
Newer mod_ssl versions support additional directives and consolidated certificate file handling (a single SSLCertificateFile rather than requiring a separate SSLCertificateChainFile) — checking your specific Apache and mod_ssl version against current documentation avoids using outdated directive patterns from an older tutorial.
Confirm the full chain with OpenSSL, not just a green padlock
Run openssl s_client -connect yourdomain.com:443 -showcerts after installing — it shows every certificate Apache is actually sending, in order. A missing intermediate here is often invisible in a browser (which frequently patches the gap itself via AIA fetching) but breaks curl, most programming-language HTTP clients, and older devices outright.
Working versus production-ready, on Apache specifically
A working Apache config successfully serves HTTPS. A production-ready one also has OCSP stapling active — confirm the module's loaded with apachectl -M | grep ssl, then check stapling itself with the same -status flag on the command above — plus a current cipher suite list and HSTS. An SSL scan tool's overall grade is the fastest way to see the gap between the two.
Testing before DNS has fully propagated
For a brand-new domain, point curl at your server's IP directly with curl --resolve yourdomain.com:443:1.2.3.4 https://yourdomain.com — this exercises your actual VirtualHost match and certificate, including Apache's ServerName/ServerAlias matching, without waiting on DNS at all.
One annotated VirtualHost block as your reference
Keep a single, commented VirtualHost block — redirect, HTTPS block, certificate paths, cipher configuration, OCSP stapling, HSTS — as the template every future Apache site starts from, rather than reassembling the pieces from memory each time.
Validate before every reload, not just the first one
apachectl configtest takes a few seconds and catches a syntax error before it can take down an otherwise-working site — worth running before every reload for the life of the server, not just while you're actively debugging something.
A quick closing checklist for a from-scratch Apache install
Before calling it done: the certificate and full chain check out under openssl s_client -showcerts, HTTP redirects to HTTPS with a 301, apachectl -M shows ssl_module and stapling active, and an SSL scan tool reports a strong grade.
Adding HTTP/2 alongside your new setup
Enable mod_http2 and add Protocols h2 h2c http/1.1 to the relevant VirtualHost — a meaningful free performance upgrade for multi-resource pages, available the moment HTTPS itself is working, since every major browser requires HTTPS for HTTP/2.
Supporting a lingering TLS 1.0 client, temporarily
If you have specific, confirmed evidence some portion of your audience still needs TLS 1.0 or 1.1, Mozilla's SSL Configuration Generator has an "old" preset for exactly this — treat it as a deliberate, temporary SSLProtocol override with a plan to remove it, not a permanent default.
Test on a subdomain before touching your primary domain
Apply the complete configuration to a lower-stakes subdomain's VirtualHost first. A mistake there costs you nothing important; the same mistake applied directly to your primary domain costs you your highest-traffic property's uptime.
Loading comments…