How to Configure Caddy with an External SSL Certificate Using Ansible


In this article, we’ll walk you through configuring Caddy (A powerful, easy-to-use web server that automatically handles SSL certificates and reverse proxying ) to use an external SSL/TLS certificate from a commercial Certificate Authority (CA).
While Caddy can handle automatic certificate management with Let’s Encrypt, there are situations where you may need to use a certificate provided by a third-party CA.
We’ll demonstrate how to deploy and configure this type of certificate with Caddy, including the necessary steps to ensure it works correctly.
We’ll automate the setup using Ansible ( A popular automation tool for configuring systems and deploying applications with simple, human-readable YAML files ) to simplify and streamline the process for production environments.
Prerequisites
Before you begin, ensure that you have:
A valid SSL/TLS certificate and corresponding private key from your CA.
Ansible installed for automation.
Root or sudo privileges on the server to install packages and modify system configurations.
Step 1: Preparing Your Certificate Files
When you receive an SSL certificate from a commercial Certificate Authority, it often consists of multiple files, such as:
The leaf certificate (your server’s certificate) — usually ends with .crt or .pem
The intermediate certificate (which bridges the trust between your leaf certificate and the root certificate) — ends with .crt or .pem
The private key associated with the leaf certificate — usually ends with .key
Sometimes these certificates are provided separately, and sometimes in a single file (full chain). In most cases, the leaf certificate needs to be combined with the intermediate certificate to form the full certificate chain. This ensures that browsers and other clients can validate the entire trust path, from the root CA to your leaf certificate.
Step 2: Setting Up Ansible to Automate the Configuration
For this guide, we’ll use Ansible to automate the deployment of your SSL certificate onto the Caddy server. The Ansible playbook will copy your certificate files, concatenate the leaf and intermediate certificates (if needed), and configure Caddy to use them.
Here is an example Ansible Playbook that automates the process of installing dependencies, configuring Caddy, and deploying the certificate:
- hosts: all
become: yes
tasks:
- name: Update apt packages
become: true
apt:
update_cache: yes
- name: Install Caddy and fail2ban
become: true
apt:
pkg:
- caddy
- fail2ban
- name: Copy server certificate file (example.com.crt)
copy:
src: ../templates/example.com.crt
dest: /etc/ssl/certs/example.com.crt
mode: ‘0644'
- name: Set correct ownership for the certificate file
file:
path: /etc/ssl/certs/example.com.crt
owner: caddy
group: caddy
mode: ‘0644'
- name: Copy intermediate certificate (DigiCertCA.crt)
copy:
src: ../templates/DigiCertCA.crt
dest: /etc/ssl/certs/DigiCertCA.crt
mode: ‘0644'
- name: Set correct ownership for the intermediate certificate
file:
path: /etc/ssl/certs/DigiCertCA.crt
owner: caddy
group: caddy
mode: ‘0644'
- name: Concatenate server certificate and intermediate certificate to form a full chain
shell: "cat /etc/ssl/certs/example.com.crt /etc/ssl/certs/DigiCertCA.crt > /etc/ssl/certs/example.com_fullchain.crt"
args:
creates: /etc/ssl/certs/example.com_fullchain.crt
- name: Copy private key file (example.com.key)
copy:
src: ../templates/example.com.key
dest: /etc/ssl/private/example.com.key
mode: ‘0600'
- name: Set correct ownership for the private key file
file:
path: /etc/ssl/private/example.com.key
owner: caddy
group: caddy
mode: ‘0600'
- name: Set correct permissions for the /etc/ssl/private directory
file:
path: /etc/ssl/private
owner: caddy
group: caddy
mode: ‘0750'
- name: Copy Caddy configuration file
template:
src: ../templates/Caddyfile
dest: /etc/caddy/Caddyfile
- name: Format Caddyfile
ansible.builtin.shell: /usr/bin/caddy fmt --overwrite /etc/caddy/Caddyfile
- name: Reload Caddy service to apply changes
systemd:
name: caddy
state: reloaded
Step 3: Explanation of Key Steps
1. Copying Certificate Files
After the installation, we begin by copying the necessary certificate files to their proper locations. These files typically include:
Leaf Certificate (example.com.crt): This is the public certificate issued for your domain.
Intermediate Certificate (DigiCertCA.crt): This bridges the trust between your leaf certificate and the root certificate.
Private Key (example.com.key): This is the private key that matches your leaf certificate.
These files are placed in the appropriate directories (/etc/ssl/certs and /etc/ssl/private) with correct file permissions to ensure proper access control. The playbook will set ownership to the caddy user, which is important for security.
2. Concatenating the Full Chain
In most cases, the leaf certificate needs to be combined with the intermediate certificate to form a full certificate chain. This ensures that clients can trace the certificate back to a trusted root authority.
Here’s the command used to concatenate the certificates:
cat /etc/ssl/certs/example.com.crt /etc/ssl/certs/DigiCertCA.crt > /etc/ssl/certs/example.com_fullchain.crt
The full chain includes the leaf certificate first, followed by the intermediate certificate. This order is important because it ensures the correct certificate trust path.
3. Configuring Caddy with the Certificates
Next, the template Caddyfile is configured to use the full certificate chain and the private key. The Caddyfile is a simple configuration file where we specify the certificate locations.
Here’s the relevant section in the Caddyfile:
example.com {
tls /etc/ssl/certs/example.com_fullchain.crt /etc/ssl/private/example.com.key
reverse_proxy localhost:8080
}
The tls directive tells Caddy to use the full chain certificate and the private key for SSL/TLS encryption. The reverse_proxy directive forwards traffic to your application running on localhost:8080.
4. Reloading Caddy
Finally, the playbook reloads the Caddy service using systemd to apply the new configuration and certificate changes:
- name: Reload Caddy service to apply changes
systemd:
name: caddy
state: reloaded
Step 4: Running the Playbook
To apply the changes, you’ll run the Ansible playbook on your server with the following command:
ansible-playbook -i your_inventory_file configure_caddy.yml
This will automate the entire process, including copying the certificate files, setting up Caddy, and reloading the service.
Step 5: Validation via Command Line
After deploying the certificate using Ansible, you can use the openssl command to validate the expiration of the SSL certificate from your local machine or a remote server:
1. Using openssl to Check SSL Expiration:
This command will connect to your server and display the expiration date of the SSL certificate:
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com </dev/null 2>/dev/null | openssl x509 -noout -enddate
Output: The command will return a line like this:
notAfter=Dec 31 23:59:59 2024 GMT
Conclusion
In this article, we’ve demonstrated how to configure Caddy with an external SSL/TLS certificate from a commercial Certificate Authority. Using Ansible, we’ve automated copying the certificate files, concatenating the full chain, and configuring Caddy to use the certificate for encrypted communication. By following this guide, you can ensure that your Caddy server is securely configured with external certificates, making it ready for production with minimal manual intervention.
By automating this process, you can easily scale and maintain secure configurations for multiple servers, saving you time and reducing the chance of errors.
Irene Ufia is a software engineer specializing in DevSecOps (Blockchain Infrastructure).
Follow me for insights and technical tips: LinkedIn | Github
Subscribe to my newsletter
Read articles from DevOps Insight with Irene directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

DevOps Insight with Irene
DevOps Insight with Irene
DevOps Insight shares practical tips on DevOps, Linux, automation, and cloud. You'll find actionable takeaways to build smarter and more reliable systems.