A while back, I published a blog post over at my Broadpin blog on how to integrate Let's Encrypt free SSL certificates with the Oracle Cloud Infrastructure (OCI) Load Balancer.
That approach works great, but in real-world project scenarios, we often hit a specific roadblock: What happens when you need multi-domain (SAN) certificates, but you don't have the access or ability to use a DNS Challenge?
If you can't touch the DNS records, you have to pivot. Here is a slightly modified, highly automated approach using the HTTP-01 challenge, OCI Object Storage, and dynamic Security Lists. The script allows to do a validation of multiple domain names for one certificate. The old scripts didn't work here.
The Core Differences: Old vs. New Approach
- Validation Method: Instead of relying on DNS records (DNS-01), we are using the HTTP-01 challenge.
- Token Hosting: We route Let's Encrypt's validation requests directly through the OCI Load Balancer to a public OCI Object Storage Bucket (acting as our webroot), rather than a compute instance web server. Routing everything under /.well-known allows to have multiple challenges available. Furthermore, this approach is faster since it doesn't require load balancer changes
- Dynamic Security: To keep things tight, we use an empty OCI Security List. The Certbot script uses the OCI CLI to dynamically open Port 80 only during the validation process, and immediately closes it afterward. This allows having restricted access otherwise or especially don't having to open port 80 at all normally.
- Zero-Touch Deployment: The deployment hook pushes the renewed certificate directly into OCI Certificates Management using the OCI CLI, keeping the Load Balancer updated automatically.
The Architecture at a Glance
If you want to replicate this, here is the high-level setup:
1. OCI Infrastructure Prep
- Create a public Object Storage bucket named acme in your root compartment (set a lifecycle rule to delete objects after 2 days).

Public Bucket

Policy to clean up old challenges
- On your Load Balancer, create a routing rule (ACME) that forwards anything starting with /.well-known/acme-challenge/ to your new bucket.

Rule to forward to object storage
- If you're typically not leveraging HTTP, set up a listener on Port 80 using this rule, pointing to a "None" backend set.
- Create an empty Security List (letsencrypt_temp_allowed_only) and assign it to your public Load Balancer subnet.
2. The Certbot Automation Machine
On a management instance, set up a Python virtual environment with Certbot installed. You will need to write three custom bash scripts to act as Certbot hooks:
- oci-authenticator.sh: Grabs the $CERTBOT_TOKEN, uses the OCI CLI to temporarily open Port 80 on your Security List, and uploads the token to your acme bucket.
- oci-closefirewall.sh: The cleanup hook. It instantly wipes the ingress rules on the Security List, locking Port 80 back down.
- oci-deploy.sh: Takes the newly generated $RENEWED_LINEAGE files and uses oci certs-mgmt certificate update-certificate-by-importing-config-details to push the new cert directly into OCI. This script should be able to handle multiple domains in RENEWED_DOMAINS. I did this as follows:
FIRST_DOMAIN="${RENEWED_DOMAINS%% *}"
OCI_CERT_OCID=$(oci certs-mgmt certificate list --all --compartment-id $COMPARTMENT_ID --query "data.items[?subject.\"common-name\"=='${FIRST_DOMAIN}'&& \"lifecycle-state\"=='ACTIVE'].id|join(',',@)"| tr -d '\""')
CERT_PATH=$(cat $RENEWED_LINEAGE/cert.pem)
CERT_CHAIN=$(cat $RENEWED_LINEAGE/chain.pem)
CERT_KEY=$(cat $RENEWED_LINEAGE/privkey.pem)
oci certs-mgmt certificate update-certificate-by-importing-config-details --certificate-id=$OCI_CERT_OCID --cert-chain-pem="$CERT_CHAIN" --certificate-pem="$CERT_PATH" --private-key-pem="$CERT_KEY"
Wrap it all in an autorenew.sh script, stick it in your crontab, and you have a fully automated, multi-domain SSL renewal system that completely bypasses the need for DNS administration!


