Skip to main content
Being Idea Innovations
Install an SSL/TLS Certificate on Apache: Let's Encrypt and Manual .crt Files
Back to Blog

Install an SSL/TLS Certificate on Apache: Let's Encrypt and Manual .crt Files

25 September 20186 min readApache
Share:

HTTPS is no longer optional. Browsers mark plain HTTP as "Not secure", search engines rank it lower, and modern browser APIs — geolocation, service workers, the clipboard — simply refuse to run without it. Installing a certificate is the mechanism that turns it on.

This guide covers the way you should almost always do it now (Let's Encrypt, free and automatic), the manual process for a purchased certificate, and a self-signed certificate for local development.

SSL is dead; it is TLS now

A terminology note that matters, because the old names cause real confusion. "SSL" refers to a protocol whose last version, SSL 3.0, was broken by the POODLE attack in 2014 and is disabled everywhere. Its replacement is TLS, currently TLS 1.3.

Everyone still says "SSL certificate" out of habit, but the certificate itself is protocol-agnostic — the same .crt works with TLS. When you configure a server, make sure it offers only TLS 1.2 and 1.3 and nothing older.

How a certificate establishes trust

Chain of trust from a root CA through an intermediate certificate to your server certificate Root CA in the browser/OS store Intermediate you must install this Your certificate example.com signs signs Omit the intermediate and browsers cannot connect the chain — the top cause of "install worked, site still errors".
Browsers only trust root CAs directly. Your certificate chains up to a root through an intermediate — which is why you must install the intermediate, not just your own .crt.

The easy path: Let's Encrypt (free, automatic)

For any public-facing site, this is what you want. Let's Encrypt issues free, browser-trusted certificates, and Certbot installs and renews them for you.

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

# Issue and install in one step — Certbot edits your Apache config for you
sudo certbot --apache -d example.com -d www.example.com

Certbot asks for an email (for expiry warnings), obtains the certificate, writes the HTTPS virtual host, and offers to redirect HTTP to HTTPS. Say yes to the redirect.

Renewal — the part people forget

Let's Encrypt certificates last 90 days. That short window is deliberate — it forces automation, because a manual 90-day chore is one you will eventually miss. Certbot installs a renewal timer automatically. Confirm it works:

sudo certbot renew --dry-run

If that succeeds, you never think about certificates again. This alone is the reason to prefer Let's Encrypt over a purchased certificate for most sites.

Installing a purchased certificate manually

If you bought a certificate — for an extended-validation cert, or because a client requires a specific CA — you install the files by hand. You will have received:

  • your_domain.crt — your certificate
  • your_domain.key — the private key you generated with the CSR
  • intermediate.crt or a "CA bundle" — the intermediate chain

Step 1: generate the key and CSR

# 2048-bit RSA is the minimum; 4096 or an ECDSA key is stronger
openssl req -new -newkey rsa:2048 -nodes \
  -keyout example.com.key \
  -out example.com.csr

You will be prompted for details. The one that must be exact is Common Name — it has to match your domain precisely (www.example.com is different from example.com; use a SAN or wildcard cert if you need both).

Guard the .key file. It is the private key — anyone who has it can impersonate your site. Never email it, never commit it, and set its permissions to 600.

Send only the .csr to the certificate authority. Keep the .key.

Step 2: place the files

sudo mkdir -p /etc/ssl/example.com
sudo cp example.com.crt      /etc/ssl/example.com/
sudo cp intermediate.crt     /etc/ssl/example.com/
sudo cp example.com.key      /etc/ssl/example.com/
sudo chmod 600 /etc/ssl/example.com/example.com.key

Step 3: configure the Apache virtual host

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

    SSLEngine on
    SSLCertificateFile      /etc/ssl/example.com/example.com.crt
    SSLCertificateKeyFile   /etc/ssl/example.com/example.com.key
    SSLCertificateChainFile /etc/ssl/example.com/intermediate.crt

    # Offer only modern protocols. No SSLv3, no TLS 1.0/1.1.
    SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
    SSLHonorCipherOrder     off
</VirtualHost>

SSLCertificateChainFile is the line most manual installs miss. Without the intermediate, your certificate installs "successfully" and then some browsers — particularly on Android and older devices — refuse to connect because they cannot build the chain to a trusted root. On newer Apache (2.4.8+) you can instead concatenate your cert and the intermediate into one file and point SSLCertificateFile at it; order matters, your cert first.

Enable the module and test before reloading:

sudo a2enmod ssl
sudo apache2ctl configtest    # "Syntax OK" before you reload
sudo systemctl reload apache2

Redirect HTTP to HTTPS

Installing a certificate does not stop people reaching the insecure version. Force the redirect:

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

Then tell browsers to skip HTTP entirely on future visits with HSTS — but only once you are confident HTTPS is solid, because it is hard to undo:

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

A self-signed certificate for local development

For localhost you do not need a real CA — a self-signed certificate is fine, with the understanding that browsers will warn about it because no authority vouches for it.

openssl req -x509 -newkey rsa:2048 -nodes \
  -keyout localhost.key -out localhost.crt \
  -days 365 -subj "/CN=localhost"

Better, use mkcert, which creates a locally-trusted certificate so your browser shows no warning:

mkcert -install
mkcert localhost 127.0.0.1

Never use a self-signed certificate in production. Visitors get a full-page security warning, and training people to click through those is its own harm. Let's Encrypt is free — there is no reason to.

Verify the installation

# From the command line — shows the chain and expiry
openssl s_client -connect example.com:443 -servername example.com

# Check the expiry date directly
echo | openssl s_client -connect example.com:443 2>/dev/null \
  | openssl x509 -noout -dates

For a thorough external check, run the free SSL Labs test. Aim for an A. It flags a missing intermediate, weak protocols still enabled, and imminent expiry — the three most common real problems.

Common errors

SymptomCause
NET::ERR_CERT_AUTHORITY_INVALIDSelf-signed, or missing intermediate chain
ERR_CERT_COMMON_NAME_INVALIDCertificate domain does not match the URL
"Your connection is not private" after renewalApache not reloaded, or old cert still referenced
Mixed-content warningsPage loads images/scripts over http://
SSL_ERROR_NO_CYPHER_OVERLAPOnly old protocols enabled; add TLS 1.2/1.3

Mixed content is the one that surprises people after a migration: the certificate is perfect, but a single <img src="http://..."> makes the browser drop the padlock. Serve every asset over HTTPS, and add upgrade-insecure-requests to your Content-Security-Policy to catch stragglers.

Summary

  • Say "TLS"; SSL is a dead protocol. Serve only TLS 1.2 and 1.3.
  • For public sites, use Let's Encrypt with Certbot — free and auto-renewing.
  • Certificates expire; automate renewal and verify it with a dry run.
  • Installing a purchased cert means installing the intermediate chain too.
  • Protect the private key: chmod 600, never commit or email it.
  • Redirect HTTP to HTTPS, then add HSTS once stable.
  • Self-signed certs are for localhost only.
  • Test with SSL Labs and fix mixed content.
Share:

Written by

Amit Verma

Founder / Senior Software Engineer

Amit leads engineering at Being Idea. With 15+ years building scalable software products across global markets, he drives architecture decisions and engineering culture across every engagement.

More articles by Amit

Want to talk tech?

We ship software that scales. Let's work together.

No long-term contracts
Senior engineers only
US · AU · NZ timezone coverage
14-day trial on retainers