How to Install an SSL Certificate on Apache
Install an SSL certificate on Apache with the right PEM files, virtual host directives, permissions, verification steps, renewal, and fixes for common errors.
Direct answer: Apache HTTPS requires mod_ssl, a virtual host listening on port 443, SSLEngine on, a certificate file, and its matching private key. For a Certbot certificate on Apache 2.4.8 or newer, point Apache at /etc/letsencrypt/live/<domain>/fullchain.pem and /etc/letsencrypt/live/<domain>/privkey.pem, test the configuration, then reload or restart Apache.
What you need before installation
- An Apache 2.4 server with
mod_ssland OpenSSL support. Apache’s SSL/TLS How-To documents the required directives. - DNS for the hostname pointing to this server.
- TCP port 443 reachable from clients.
- A certificate and matching private key in PEM format, issued by a commercial certificate authority or an ACME client such as Certbot.
- If you are issuing through ACME HTTP validation, an HTTP challenge path that remains reachable during issuance.
For Certbot, the current files are normally in /etc/letsencrypt/live/<domain>:
| File | Use | Security note |
|---|---|---|
fullchain.pem |
Server certificate followed by intermediate certificates; use as SSLCertificateFile on Apache 2.4.8+. |
Public certificate chain. |
privkey.pem |
Private key; use as SSLCertificateKeyFile. |
Keep secret. Never place it in the web root or source control. |
cert.pem |
Leaf/server certificate by itself. | Used with a separate chain file on older arrangements. |
chain.pem |
Intermediate certificates. | Pair with cert.pem when your Apache version or configuration requires separate files. |
Install and configure the certificate
1. Locate the HTTPS virtual-host file
Debian and Ubuntu commonly keep site files under sites-available; Red Hat-family systems commonly use conf.d. Edit the virtual host that serves the hostname, or create one if no HTTPS host exists.
2. Add the TLS virtual host
LoadModule ssl_module modules/mod_ssl.so
Listen 443
<VirtualHost *:443>
ServerName www.example.com
SSLEngine on
SSLCertificateFile "/etc/letsencrypt/live/www.example.com/fullchain.pem"
SSLCertificateKeyFile "/etc/letsencrypt/live/www.example.com/privkey.pem"
DocumentRoot "/var/www/www.example.com"
</VirtualHost>
Replace the hostname, certificate directory, and document root. The ServerName must match a name covered by the certificate. Add any required ServerAlias values to the same virtual host.
3. Enable the module and site
Use your distribution’s Apache tooling to enable ssl and the site, then ensure Apache is configured to listen on 443. The exact helper command differs between distributions, so verify the resulting configuration rather than copying a command intended for another operating system.
4. Protect the private key
privkey.pem is a secret. Certbot explicitly says it must be kept secret. Apache reads it when starting, so the service must have the minimum read access required by your platform’s privilege model. Do not make the key world-readable, serve its directory as web content, or commit it to a repository.
5. Test before applying
apachectl configtest
# Debian/Ubuntu alternative:
apache2ctl configtest
Continue only when the result reports a valid configuration. Fix every syntax, missing-file, certificate, and permission error first.
6. Reload or restart Apache
Reload Apache after a certificate replacement when your service manager supports a graceful reload. A full restart may be required when enabling modules or when reload fails. Apache reads certificate files at startup; its mod_ssl reference notes that a restart is required for changes to take effect.
Verify that HTTPS is serving the right certificate
Browser check
- Open
https://www.example.com. - Inspect the certificate details and confirm the hostname appears in the subject alternative names.
- Check that the issuer chain is trusted and that the browser is not reporting a missing intermediate.
- Test every hostname you placed in
ServerNameorServerAlias.
OpenSSL verification
openssl s_client \
-connect www.example.com:443 \
-servername www.example.com \
-showcerts
The -servername option sends SNI, which matters when several HTTPS virtual hosts share one address. Inspect the served certificate, intermediates, expiry, and verification result. To inspect OCSP stapling when it is enabled:
openssl s_client \
-connect www.example.com:443 \
-servername www.example.com \
-status
HTTP client checks
curl -I https://www.example.com
import requests
response = requests.get("https://www.example.com", timeout=30)
print(response.status_code)
print(response.url)
const response = await fetch('https://www.example.com');
console.log(response.status, response.url);
These clients validate the certificate using their normal trust stores. A failure usually indicates a hostname mismatch, an incomplete chain, an expired certificate, or a server that is not reachable on 443.
Certificate renewal with Certbot
Certbot updates the live directory with the newest certificate files during renewal. Keep Apache pointed directly at the live paths instead of copying certificates to a second directory. After renewal, reload Apache so the running process reads the new files. Use your environment’s normal Certbot renewal test and configure a deploy or post-renewal hook to perform that reload.
# Example hook action; adapt the service command to your system
systemctl reload apache2
# or
systemctl reload httpd
Confirm the hook’s service name and permissions on your distribution. If a reload is not supported or fails, schedule a controlled restart.
Choosing a certificate source
| Choice | Best fit | Operational work |
|---|---|---|
| Commercial CA | Organizations that need the CA’s issuance process or certificate policy. | Install the supplied leaf, intermediate chain, and private key; renew manually unless the CA supplies automation. |
| ACME client such as Certbot | Automated issuance and renewal for domains you control. | Keep validation reachable, preserve the live paths, and reload Apache after renewal. |
| Managed hosting | Teams that do not administer Apache directly. | Use the host’s certificate workflow; the provider controls the virtual host and reload. |
The Apache directives are the same once the PEM material is available.
Troubleshooting common Apache SSL errors
| Symptom | Likely cause | Fix |
|---|---|---|
| Apache will not start and asks for a pass phrase | The private key is encrypted. | Provide the pass phrase through an approved startup mechanism or install a key arrangement your operational policy supports. Apache must be able to read the key when starting. |
| Browser reports an incomplete or untrusted chain | Only the leaf certificate was configured. | Use fullchain.pem on Apache 2.4.8+, or configure both the leaf certificate and intermediate chain where separate files are required. |
Permission denied reading privkey.pem |
The Apache service account cannot read the key. | Keep restrictive ownership and mode, then grant only the minimum controlled access required by the service’s privilege model. |
| The old certificate is still served | Apache has not reread the files. | Reload or restart Apache, then verify again with openssl s_client. |
| The wrong certificate appears | The request is selecting another *:443 virtual host. |
Check ServerName, ServerAlias, SNI, and virtual-host ordering. Test with the correct -servername value. |
| Connection refused or times out | Apache is not listening on 443, a firewall blocks TCP 443, or DNS points elsewhere. | Confirm Listen 443, the active service configuration, firewall rules, and DNS records. |
| Certificate file not found | The path is mistyped or the renewal directory is unavailable. | Check the exact filename and permissions under /etc/letsencrypt/live/<domain>, then rerun apachectl configtest. |
| HTTP validation fails during issuance | The ACME challenge path is blocked, redirected incorrectly, or unreachable. | Keep the required HTTP challenge path reachable while issuing or renewing the certificate. |
Performance, reliability, and cost considerations
- Performance: TLS adds connection setup work, so keep Apache’s certificate configuration stable and use graceful reloads where appropriate. Certificate installation itself does not change your application’s response time after the connection is established.
- Reliability: Renewal is only complete when the renewed files are loaded by the running Apache process. Monitor expiry and verify the live endpoint after a renewal hook runs.
- Security: Restrict access to
privkey.pem, avoid copying it into application directories, and do not expose directory listings for certificate storage. - Operations: Keep the virtual host pointed at Certbot’s
livesymlinks so future renewals do not require editing Apache configuration. - Cost: Commercial certificates may involve a purchase; ACME issuance can automate certificate management. Your infrastructure, hosting, and operational labor remain separate costs.
Or skip the browser setup
If your goal is to capture the finished HTTPS page rather than operate a browser yourself, ScreenshotNeo provides a website screenshot API. It accepts a URL and returns PNG, JPEG, WebP, or PDF. Cookie and consent banners, newsletter popups, and chat widgets are removed before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.
See the ScreenshotNeo API documentation for all options.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://www.example.com \
-o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://www.example.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://www.example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo also includes an MCP server so Claude, Cursor, and other MCP clients can take screenshots, inspect pages, and capture PDFs. The Free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
FAQ
Which file belongs in SSLCertificateFile?
Use fullchain.pem for Certbot certificates on Apache 2.4.8 and newer. It contains the leaf certificate followed by the intermediate certificates.
Do I need SSLCertificateChainFile?
Not for the usual Apache 2.4.8+ Certbot setup using fullchain.pem. Older arrangements may require separate leaf and chain files.
Can I use the certificate’s IP address instead of its hostname?
Only if the certificate’s subject alternative names include that IP address. Test the exact hostname clients will request.
Why does Apache need a restart after a certificate change?
Apache reads the certificate and key at startup. Reload or restart the service so the running process consumes the new files.
Should I copy renewed Certbot files elsewhere?
No. Keep the virtual host pointed at the files in /etc/letsencrypt/live/<domain> and reload Apache after renewal.


