How to Configure Apache to Use SSL (HTTPS)

How to configure Apache to use SSL (HTTPS)

I stopped treating HTTPS as optional a long time ago. Browsers flag plain HTTP sites as “Not Secure,” search engines factor it into rankings, and any site of mine handling logins or personal data has a basic obligation to encrypt traffic. Apache’s mod_ssl makes this straightforward, and Let’s Encrypt removed the cost excuse entirely.

Here’s exactly how I set up HTTPS on Apache — getting a certificate, configuring TLS, redirecting HTTP, and hardening the result.

How HTTPS Works (Briefly)

HTTPS wraps HTTP traffic in TLS encryption, using a certificate issued by a trusted Certificate Authority to prove the server’s identity and establish an encrypted channel between browser and server. The certificate has a public certificate file and a private key that has to stay secret.

Prerequisites

  • Apache installed with a registered domain pointing to the server’s public IP
  • Root or sudo access
  • Port 443 open in the firewall (see my firewall configuration post)
  • mod_ssl installed
# Debian/Ubuntu
sudo apt install openssl

# RHEL/CentOS
sudo dnf install mod_ssl openssl

Step 1: Enable mod_ssl

Debian/Ubuntu:

sudo a2enmod ssl
sudo systemctl restart apache2

RHEL/CentOS: mod_ssl is typically enabled automatically after dnf install mod_ssl.

Step 2: Get a Free Certificate with Let’s Encrypt (Certbot)

Certbot has automated this for me on every server I’ve set up in the last few years.

# Debian/Ubuntu
sudo apt install certbot python3-certbot-apache

# RHEL/CentOS
sudo dnf install certbot python3-certbot-apache

I run Certbot in Apache mode — it detects my virtual hosts automatically:

sudo certbot --apache -d example.com -d www.example.com

Certbot then:

  1. Verifies domain ownership via an HTTP challenge.
  2. Obtains the certificate from Let’s Encrypt.
  3. Updates my Apache virtual host with SSL configuration automatically.
  4. Offers to set up an HTTP → HTTPS redirect, which I always accept.

Step 3: Verify Automatic Renewal

Let’s Encrypt certificates expire every 90 days. Certbot installs a renewal timer automatically:

sudo systemctl status certbot.timer
sudo certbot renew --dry-run

The dry run confirms renewal works without actually renewing anything.

Manual SSL Configuration (Without Certbot)

If I’m using a certificate from another CA, here’s the configuration underneath what Certbot generates:

<VirtualHost *:443>
    ServerName example.com
    DocumentRoot /var/www/html

    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/example.com.crt
    SSLCertificateKeyFile /etc/ssl/private/example.com.key
    SSLCertificateChainFile /etc/ssl/certs/example.com-chain.crt

    <Directory /var/www/html>
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/ssl-error.log
    CustomLog ${APACHE_LOG_DIR}/ssl-access.log combined
</VirtualHost>

On modern Apache/OpenSSL, SSLCertificateFile can often include the full chain, making a separate SSLCertificateChainFile unnecessary — I check my CA’s specific instructions to be sure.

Step 4: Redirect HTTP to HTTPS

I add this to the port 80 virtual host so everything gets forced to HTTPS:

<VirtualHost *:80>
    ServerName example.com
    Redirect permanent / https://example.com/
</VirtualHost>

Or with mod_rewrite when I want more control:

<VirtualHost *:80>
    ServerName example.com
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>

Step 5: Test and Reload

sudo apachectl configtest
sudo systemctl reload apache2

I confirm HTTPS is working:

curl -I https://example.com/

Then I run it through SSL Labs (https://www.ssllabs.com/ssltest/) for a full grade on the configuration.

Hardening TLS Configuration

Default mod_ssl settings on older distros can still allow outdated, weak protocol versions. I update /etc/apache2/mods-available/ssl.conf (Debian) or the equivalent httpd-ssl.conf (RHEL):

SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
SSLSessionTickets off

I add HSTS to tell browsers to always use HTTPS for this domain going forward:

Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"

For a configuration tailored to my exact Apache/OpenSSL versions, I lean on the Mozilla SSL Configuration Generator, since recommended cipher suites evolve over time and I’d rather not hand-maintain that list myself.

Enabling HTTP/2

HTTP/2 needs TLS in practice, and I’ve seen real performance improvements from multiplexing once it’s on.

sudo a2enmod http2
<VirtualHost *:443>
    Protocols h2 http/1.1
    ...
</VirtualHost>

Real-World Use Cases

  • Any site handling logins, payments, or personal data — non-negotiable in my book.
  • SEO-sensitive sites, since HTTPS is a confirmed ranking factor.
  • API endpoints serving mobile apps or third-party integrations that need encrypted transport.
  • Multi-domain hosting using SNI to serve different certificates per virtual host on the same IP.

Mistakes I’ve Made

  • Forgetting to open port 443 in the firewall right after installing a certificate.
  • Mixing HTTP and HTTPS resources on the same page, which browsers block as “mixed content.”
  • Letting a certificate expire because an auto-renewal failed silently and I didn’t notice — I monitor renewal timers now.
  • Sticking with outdated TLS versions or weak cipher suites, which fail modern security audits.
  • Not redirecting HTTP to HTTPS, leaving both accessible and diluting SEO signals.

Security Best Practices

  • I enforce TLS 1.2+ only, disabling TLS 1.0/1.1 and all SSL versions entirely.
  • I enable HSTS with a long max-age once I’m confident HTTPS is fully and permanently working.
  • Private keys stay readable only by root and the Apache process: sudo chmod 600 /etc/ssl/private/example.com.key
  • I automate renewal and monitor certificate expiry proactively.
  • I re-test TLS configuration with SSL Labs periodically, since recommendations shift over time.

Performance Optimization

  • OCSP stapling reduces the latency of certificate revocation checks for clients: SSLUseStapling onSSLStaplingCache "shmcb:/var/run/ocsp(128000)"
  • I enable HTTP/2 for multiplexed connections.
  • SSL session reuse (SSLSessionCache) cuts the cost of repeated TLS handshakes for returning visitors.
  • In my experience, TLS termination itself has modest CPU overhead on modern hardware and is rarely the actual bottleneck for typical traffic levels.

Troubleshooting

“Your connection is not private” browser warning I check certificate validity dates and that the certificate matches the requested domain exactly:

openssl x509 -in /etc/ssl/certs/example.com.crt -noout -dates -subject

Certbot renewal fails I check /var/log/letsencrypt/letsencrypt.log for the specific error; common causes are DNS changes, firewall blocking the HTTP challenge, or an expired DNS record for a subdomain.

Mixed content warnings in the browser console I search the site’s HTML/CSS/JS for hardcoded http:// references and update them to https://.

500 error immediately after enabling SSL apachectl configtest — usually a typo’d certificate/key file path or mismatched cert and key.

FAQs

Do I need a paid certificate, or is Let’s Encrypt sufficient? Let’s Encrypt gives the same encryption strength as paid certificates for standard use cases in my experience. Paid certs sometimes add extended validation branding or warranty coverage, but no meaningful technical security advantage.

How often do I need to renew my certificate? Every 90 days for Let’s Encrypt; Certbot’s automatic renewal handles it, usually attempting around day 60.

Can I run HTTP and HTTPS simultaneously? Yes, and I keep port 80 open specifically to redirect to HTTPS rather than closing it, since some clients still attempt an initial HTTP connection.

Summary and Key Takeaways

  • mod_ssl plus Certbot/Let’s Encrypt gives me a fast, free path to a fully working HTTPS setup.
  • I always redirect HTTP to HTTPS and enable HSTS once things are stable.
  • I harden TLS configuration by disabling outdated protocols and weak ciphers.
  • I automate certificate renewal and watch for renewal failures.
  • SSL Labs is my go-to check-in to make sure the configuration hasn’t drifted from current best practices.

References

  • Apache mod_ssl Documentation: https://httpd.apache.org/docs/current/mod/mod_ssl.html
  • Let’s Encrypt / Certbot: https://certbot.eff.org/
  • Mozilla SSL Configuration Generator: https://ssl-config.mozilla.org/
  • Qualys SSL Labs Server Test: https://www.ssllabs.com/ssltest/
Total
1
Shares

Leave a Reply

Previous Post
How to configure Apache to use a different port

How to Configure Apache to Use a Different Port

Next Post
How to set up password protection for a directory

How to Set Up Password Protection for a Directory in Apache

Related Posts