Skip to main content
    Installation

    How to Install an SSL Certificate on Apache (Ubuntu, Debian & Rocky Linux)

    Step-by-step guide to installing a commercial SSL certificate on Apache HTTP Server. Covers Ubuntu/Debian (apache2) and Rocky Linux/AlmaLinux (httpd), virtual host config, forced HTTPS, and renewal automation for 2026's 199-day certificate lifetimes.

    MS
    My-SSL Team
    ·
    20 min read
    ·Published May 28, 2026·Updated May 28, 2026

    What this guide covers

    Apache HTTP Server is the world's most widely deployed web server, powering millions of Linux hosts. This guide walks through installing a commercially issued SSL/TLS certificate on two major Linux families:

    • Ubuntu 22.04 / 24.04 and Debian 11/12 — which use the apache2 package and the a2enmod /a2ensite tooling
    • Rocky Linux 8/9 and AlmaLinux 8/9 — the recommended CentOS replacements, which use httpd and firewalld

    CentOS users: CentOS 7 reached end-of-life in June 2024 and CentOS 8 in December 2021. Neither receives security updates. Migrate to Rocky Linux or AlmaLinux — this guide's RHEL/Rocky section applies to both.

    If you haven't ordered your certificate yet, see My-SSL's SSL certificate options. DV certificates are typically issued within minutes; OV and EV take one to three business days. Have your issued .crt file and CA bundle ready before starting this guide.

    Prerequisites

    • Root or sudo access on the server
    • Apache 2.4.x installed and running (apache2 on Ubuntu/Debian, httpd on RHEL-family)
    • A domain name with a live A record pointing to the server's public IP
    • An SSL certificate issued by your CA — the .crt file plus the CA bundle
    • The private key (.key) generated when you created your CSR — keep this file secret
    • TCP port 443 open in your firewall (ufw on Ubuntu, firewalld on Rocky)

    Haven't generated a CSR yet? Our CSR generation guide walks through it step by step, or use the online CSR Generator to produce a CSR and matching private key in your browser.

    Certificate files you need

    Your CA delivers a zip archive. The three files Apache needs are:

    FileApache directiveNotes
    your_domain.crtSSLCertificateFileYour server certificate
    your_domain.keySSLCertificateKeyFilePrivate key — never share this
    ca_bundle.crtSSLCertificateFile (combined)Intermediate + root chain from your CA

    Apache 2.4.8+ (all modern distros): Instead of the deprecated SSLCertificateChainFile directive, combine your certificate and CA bundle into a single fullchain file and point SSLCertificateFile at it. This eliminates the "incomplete chain" browser warning.

    bash
    # Create a combined fullchain file (server cert first, then CA bundle)
    cat your_domain.crt ca_bundle.crt > your_domain_fullchain.crt

    Install Apache and mod_ssl — Ubuntu / Debian

    If Apache is already installed and running, skip to .

    Step 1 — Install apache2 and enable SSL modules

    bash
    sudo apt update
    sudo apt install -y apache2
    sudo a2enmod ssl
    sudo a2enmod headers
    sudo a2enmod rewrite
    sudo systemctl enable apache2
    sudo systemctl start apache2

    Step 2 — Open port 443 in UFW

    bash
    sudo ufw allow 'Apache Full'
    sudo ufw reload
    sudo ufw status

    "Apache Full" opens both port 80 (HTTP) and port 443 (HTTPS). If you use a different firewall or a cloud security group, open TCP 443 there instead.

    Install httpd and mod_ssl — Rocky Linux / AlmaLinux

    Step 1 — Install httpd and mod_ssl

    bash
    sudo dnf install -y httpd mod_ssl
    sudo systemctl enable --now httpd

    Installing mod_ssl drops a default TLS configuration at /etc/httpd/conf.d/ssl.conf. You will override the relevant parts with your own virtual host file.

    Step 2 — Open port 443 in firewalld

    bash
    sudo firewall-cmd --permanent --add-service=https
    sudo firewall-cmd --reload
    sudo firewall-cmd --list-services

    Upload your certificate files to the server

    Copy the fullchain file and private key to the server using SCP, SFTP, or your deployment tool. The conventional paths differ by distro:

    Ubuntu / Debian

    bash
    # Certificates
    sudo cp your_domain_fullchain.crt \
      /etc/ssl/certs/
    
    # Private key
    sudo cp your_domain.key \
      /etc/ssl/private/
    sudo chmod 600 \
      /etc/ssl/private/your_domain.key

    Rocky Linux / AlmaLinux

    bash
    # Certificates
    sudo cp your_domain_fullchain.crt \
      /etc/pki/tls/certs/
    
    # Private key
    sudo cp your_domain.key \
      /etc/pki/tls/private/
    sudo chmod 600 \
      /etc/pki/tls/private/your_domain.key

    Protect the private key. Set permissions to 600 (readable only by root). Never store it in a web-accessible directory or commit it to version control. If the key is ever exposed, revoke and reissue the certificate immediately.

    Configure the SSL virtual host — Ubuntu / Debian

    Create a dedicated virtual host file for HTTPS. Replace yourdomain.com and the file paths throughout:

    bash
    sudo nano /etc/apache2/sites-available/yourdomain.com-ssl.conf

    Paste this configuration:

    apacheconf
    <VirtualHost *:443>
        ServerName yourdomain.com
        ServerAlias www.yourdomain.com
        DocumentRoot /var/www/yourdomain.com/public_html
    
        # TLS configuration
        SSLEngine on
        SSLCertificateFile    /etc/ssl/certs/your_domain_fullchain.crt
        SSLCertificateKeyFile /etc/ssl/private/your_domain.key
    
        # Security headers
        Header always set Strict-Transport-Security         "max-age=31536000; includeSubDomains"
        Header always set X-Content-Type-Options "nosniff"
        Header always set X-Frame-Options "SAMEORIGIN"
        Header always set Referrer-Policy "strict-origin-when-cross-origin"
    
        ErrorLog  ${APACHE_LOG_DIR}/yourdomain.com-ssl-error.log
        CustomLog ${APACHE_LOG_DIR}/yourdomain.com-ssl-access.log combined
    </VirtualHost>

    Enable the site:

    bash
    sudo a2ensite yourdomain.com-ssl.conf

    Configure the SSL virtual host — Rocky Linux / AlmaLinux

    Create a new config file in /etc/httpd/conf.d/. Files in that directory are auto-included by httpd:

    bash
    sudo nano /etc/httpd/conf.d/yourdomain.com-ssl.conf
    apacheconf
    <VirtualHost *:443>
        ServerName yourdomain.com
        ServerAlias www.yourdomain.com
        DocumentRoot /var/www/yourdomain.com/public_html
    
        # TLS configuration
        SSLEngine on
        SSLCertificateFile    /etc/pki/tls/certs/your_domain_fullchain.crt
        SSLCertificateKeyFile /etc/pki/tls/private/your_domain.key
    
        # Security headers
        Header always set Strict-Transport-Security         "max-age=31536000; includeSubDomains"
        Header always set X-Content-Type-Options "nosniff"
        Header always set X-Frame-Options "SAMEORIGIN"
        Header always set Referrer-Policy "strict-origin-when-cross-origin"
    
        ErrorLog  /var/log/httpd/yourdomain.com-ssl-error.log
        CustomLog /var/log/httpd/yourdomain.com-ssl-access.log combined
    </VirtualHost>

    If the default /etc/httpd/conf.d/ssl.conf already contains a <VirtualHost *:443> block that conflicts, comment it out or delete it — only one virtual host should listen on port 443 per ServerName.

    Force HTTP → HTTPS

    Redirect all plain-HTTP traffic permanently to HTTPS with a port-80 virtual host.

    Ubuntu / Debian — add to /etc/apache2/sites-available/yourdomain.com.conf:

    apacheconf
    <VirtualHost *:80>
        ServerName yourdomain.com
        ServerAlias www.yourdomain.com
        # Permanent 301 redirect to HTTPS
        Redirect permanent / https://yourdomain.com/
    </VirtualHost>
    bash
    # Enable the HTTP site and disable the default placeholder
    sudo a2ensite yourdomain.com.conf
    sudo a2dissite 000-default.conf

    Rocky Linux / AlmaLinux — create or add to /etc/httpd/conf.d/yourdomain.com.conf:

    apacheconf
    <VirtualHost *:80>
        ServerName yourdomain.com
        ServerAlias www.yourdomain.com
        Redirect permanent / https://yourdomain.com/
    </VirtualHost>

    Harden TLS: protocols and cipher suite

    Add these directives inside your <VirtualHost *:443> block or globally in the mod_ssl config file:

    apacheconf
    # Allow TLS 1.2 and 1.3 only — disable SSLv3, TLS 1.0, TLS 1.1
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
    
    # Prefer server cipher order for TLS 1.2
    SSLHonorCipherOrder on
    
    # Strong cipher suite (TLS 1.3 uses its own built-in negotiation)
    SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
    
    # Disable TLS session tickets for better forward secrecy
    SSLSessionTickets off

    For an always-current, distro-aware configuration, use the Mozilla SSL Configuration Generator (select Apache and "Intermediate" for broad compatibility, or "Modern" if you don't need to support older browsers).

    Test the configuration and reload Apache

    Always test before reloading — a syntax error causes the reload to fail, and your site can go down if Apache was not already running with a valid config.

    Ubuntu / Debian

    bash
    sudo apache2ctl configtest
    # Expected: Syntax OK
    
    sudo systemctl reload apache2

    Rocky Linux / AlmaLinux

    bash
    sudo apachectl configtest
    # Expected: Syntax OK
    
    sudo systemctl reload httpd

    Verify the SSL installation

    Three ways to confirm everything is working:

    1. Browser check

    Open https://yourdomain.com in a browser. The padlock should appear with no warnings. Click the padlock to confirm the issuer, Subject, and validity dates match what your CA issued.

    2. OpenSSL command line

    bash
    openssl s_client -connect yourdomain.com:443 -showcerts
    
    # Look for:
    #   Verify return code: 0 (ok)
    # This means the full chain is present and the certificate is trusted.

    3. Online SSL Checker

    Use the My-SSL SSL Checker to verify chain completeness, expiry date, protocol support, and mixed-content status — all from an external vantage point.

    Automate renewals — critical with 199-day certificate lifetimes

    2026 change: The CA/Browser Forum reduced the maximum TLS certificate validity period to 199 days, effective March 15, 2026 (Ballot SC-081). The limit drops to 100 days in 2027 and 47 days by 2029. At 47 days you'll need approximately 8 renewals per year per domain — manual renewal is no longer practical.

    For commercial certificates purchased from a CA, automate the install step with a shell script triggered by cron:

    1. Set a calendar alert 30 days before expiry (your CA or My-SSL will email you)
    2. Generate a new CSR with a fresh private key
    3. Submit for reissuance and complete domain validation
    4. Download the new certificate and CA bundle
    5. Combine into a fullchain file, copy to the server, and reload Apache

    For Let's Encrypt / ACME (free DV certificates), Certbot with the Apache plugin handles the full renewal loop:

    bash
    # Ubuntu/Debian — install Certbot with Apache plugin
    sudo apt install -y certbot python3-certbot-apache
    
    # Obtain and install a Let's Encrypt certificate automatically
    sudo certbot --apache -d yourdomain.com -d www.yourdomain.com
    
    # Test the renewal process (dry run — no cert issued)
    sudo certbot renew --dry-run

    For the full Certbot setup covering DNS-01 wildcards, Docker, Kubernetes, and renewal hooks, see our Certbot & ACME automation guide. For context on why certificate lifetimes are shrinking, read 2026 SSL certificate lifetime changes. To understand the 199-day milestone specifically, see SSL certificates are now limited to 199 days.

    Troubleshooting common errors

    AH02572: No SSL Certificate set — not enabling HTTPS for VirtualHost

    SSLCertificateFile points to a missing or unreadable file. Run ls -la on the cert path. The file must be readable by the Apache process (www-data on Ubuntu, apache on Rocky). Check that SSLEngine on is present in the VirtualHost block.

    NET::ERR_CERT_AUTHORITY_INVALID / certificate verify failed

    Your certificate chain is incomplete. The fullchain file must contain the server certificate followed by all intermediate CA certificates. Run: openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt your_domain_fullchain.crt. If it fails, rebuild the file: cat your_domain.crt ca_bundle.crt > your_domain_fullchain.crt

    AH00526: Syntax error — SSLCertificateKeyFile does not exist

    Verify the exact path to the private key file. Ubuntu/Debian: /etc/ssl/private/. Rocky/AlmaLinux: /etc/pki/tls/private/. Run sudo apachectl configtest to see the full error message.

    Port 443 not accessible — connection refused or timeout

    Check the firewall: sudo ufw status verbose (Ubuntu) or sudo firewall-cmd --list-all (Rocky). Port 443 / service https must be allowed. Also check that Apache is listening: sudo ss -tlnp | grep 443

    Mixed content warnings in the browser

    The page loads some resources (images, scripts, fonts) over plain HTTP. Update those URLs to use relative paths or https:// absolute URLs. The browser DevTools console lists the offending resources.

    Other server installation guides

    FAQ