← Back to Apache Course | Chapter 4: Security | Lesson 2 of 4

SSL/TLS Setup

Getting HTTPS actually working end-to-end means more than the mod_ssl directives alone -- it means obtaining a real certificate, keeping it renewed, and configuring TLS itself securely.

"SSL" vs. TLS

"SSL" is the name everyone still uses out of habit, but the actual protocol in use today is TLS -- SSL's modern successor. Apache's module is still called mod_ssl for historical reasons, and its directives (SSLEngine, SSLProtocol) keep the old name even though they configure TLS.

Getting a Certificate with Certbot

Let's Encrypt (via the certbot tool) is the standard way to get a free, trusted certificate. sudo certbot --apache -d example.com -d www.example.com obtains a certificate, edits the matching VirtualHost automatically to add the SSL directives, and sets up a redirect from HTTP to HTTPS -- much less manual than editing SSLCertificateFile by hand.

Automatic Renewal

Let's Encrypt certificates last only 90 days by design, so certbot installs a systemd timer (or cron job) that runs certbot renew automatically. It's still worth checking renewal actually works with sudo certbot renew --dry-run, since a silently broken renewal job means the certificate expires without warning months later.

Note: Run certbot renew --dry-run right after setup, and again periodically -- it simulates the renewal process without touching the live certificate, so you can confirm it works before you actually need it to.

Restricting Weak Protocols and Ciphers

SSLProtocol and SSLCipherSuite control which TLS versions and encryption algorithms Apache will accept. Modern practice is to disable old, insecure protocol versions explicitly: SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 leaves only TLS 1.2 and 1.3 available, since the older versions have known weaknesses.

Example: Restricting to modern TLS versions

apacheconf
<VirtualHost *:443>
    ServerName example.com
    SSLEngine On
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
</VirtualHost>
{# Flagged by hand after confirming a runner can't handle this example (a shell command / go.mod file stored as a TopicExample, a language feature the configured runner version doesn't support, or output that blows a runner's sandbox limit) -- see TopicExample.norun. Never render the run button for these, regardless of language, since it would just fail at execute_code (or worse, hang the Judge0 queue on a submission that can never finish cleanly). #}

⚠️ This example can't run in the browser editor. Try it in your own local environment instead.

{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Setting up a certificate once and never verifying auto-renewal actually works, then having the site go down months later when it silently expires.
  2. Leaving old TLS versions (SSLv3, TLS 1.0/1.1) enabled by not setting SSLProtocol explicitly, which some security scanners and compliance checks will flag.
  3. Confusing the certificate's domain name with the VirtualHost's ServerName -- a certificate only validates for the exact domains it was issued for.
🔒

Chapter Quiz — Complete all 4 topics to unlock

0/4 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.