LEGO Deployment Step-by-Step Guide — Acme Tool For SSL Certificate Management

Mar 26, 2026

What Is This Guide About?

This guide explains, in plain English, how to use a tool called Lego to get, install, and automatically renew SSL certificates for your website or application. Think of an SSL certificate like a security padlock for your website — it tells visitors that your site is safe and that no one is secretly reading the data sent between them and your server.

Lego is a powerful, lightweight program (a single file — no extra software needed!) that runs on Windows, Mac, and Linux. It works with more than 100 DNS providers and handles everything for you: getting the certificate, installing it, and renewing it automatically before it expires.

? PREREQUISITE

Before following this guide, make sure you have completed the Lego Installation Guide and have your ACME server credentials (Email, EAB Key ID, and HMAC Key) ready.


Key Terms You Need to Know

Before we get started, here is a quick plain-English glossary of the technical words you will see:

Term What It Means (Plain English)
SSL Certificate A digital file that proves your website is authentic and encrypts all data sent to/from it. Like a passport for your website.
ACME Server The online service that issues (creates and approves) your certificate. Lego talks to this behind the scenes.
EAB Credentials Your unique login key pair for the ACME server. Think of it as a username and password, but more secure.
DNS Provider The company that manages your domain name records (e.g. Cloudflare, Route53). Lego uses it to prove you own the domain.
DNS Challenge A security check where Lego adds a temporary record to your DNS to prove you control the domain.
Run Hook A script that runs automatically after a certificate is issued or renewed — for example, to restart your web server.
Cron Job A scheduled task on Linux/Mac that runs at set times automatically (e.g. every night at 2 AM).
Task Scheduler The Windows equivalent of a cron job — runs scripts on a schedule.
SAN Certificate A certificate that covers multiple domain names at once (e.g. example.com AND www.example.com).
Wildcard Certificate A certificate that covers ALL sub-domains under a domain (e.g. *.example.com covers api.example.com, mail.example.com, etc.).

Part 1 — Getting Your SSL Certificate (Issuance)

This section explains how to ask Lego to request a brand-new certificate from the ACME server. This is the very first step — like applying for a new passport.

Step 1.1 — Understanding the Issuance Timeout

By default, Lego waits up to 30 seconds for the ACME server to create your certificate once all security checks pass. Some ACME servers take longer — if yours does, Lego will stop waiting and show an error before your certificate is ready.

To fix this, you can tell Lego to wait longer by adding --cert.timeout followed by the number of seconds. This option is available from Lego version 4.7.0 and above.

? RECOMMENDED

Always set --cert.timeout 300 (5 minutes) when getting a new certificate. This prevents timeout errors on slower ACME servers.

Common timeout values:

  • 300 — Wait up to 5 minutes (recommended for most setups)
  • 600 — Wait up to 10 minutes (for very slow or asynchronous ACME servers)

Step 1.2 — Get a Certificate for One Domain (Single Domain)

Use this if you need a certificate for exactly one website address (e.g. demo.example.com only).

???? Linux / macOS
source ~/.lego/config/acme-server.env

lego --email "$EMAIL" \
--server "$ACME_SERVER" \
--eab --kid "$EAB_KEY_ID" \
--hmac "$EAB_HMAC_KEY" \
--dns cloudflare \
--domains demo.example.com \
--cert.timeout 300 \
run
???? Windows (PowerShell)
. "$env:USERPROFILE\.lego\config\acme-server.ps1"

lego --email "$env:EMAIL" `
--server "$env:ACME_SERVER" `
--eab --kid "$env:EAB_KEY_ID" `
--hmac "$env:EAB_HMAC_KEY" `
--dns cloudflare `
--domains demo.example.com `
--cert.timeout 300 `
run

What you should see when it works:

[INFO] [demo.example.com] acme: Obtaining certificate
[INFO] [demo.example.com] acme: Validating domain
[INFO] [demo.example.com] The server validated our request
[INFO] [demo.example.com] acme: Requesting certificate
[INFO] [demo.example.com] Server responded with a certificate.

???? TIP

To see extra detail about what Lego is doing, add --dns.resolvers 8.8.8.8:53 to the command. This also forces Lego to use Google's public DNS for checking, which can help avoid false errors.

Step 1.3 — Get a Certificate for Multiple Domains (SAN Certificate)

A SAN (Subject Alternative Name) certificate covers several domain names at once — very useful if you have multiple addresses pointing to the same server. Just repeat --domains for each address you want to cover.

???? Linux / macOS
lego --email "$EMAIL" \
--server "$ACME_SERVER" \
--eab --kid "$EAB_KEY_ID" \
--hmac "$EAB_HMAC_KEY" \
--dns cloudflare \
--domains example.com \
--domains www.example.com \
--domains mail.example.com \
--domains api.example.com \
--cert.timeout 300 \
run
???? Windows (PowerShell)
lego --email "$env:EMAIL" `
--server "$env:ACME_SERVER" `
--eab --kid "$env:EAB_KEY_ID" `
--hmac "$env:EAB_HMAC_KEY" `
--dns cloudflare `
--domains example.com `
--domains www.example.com `
--domains mail.example.com `
--domains api.example.com `
--cert.timeout 300 `
run

Step 1.4 — Get a Wildcard Certificate

A wildcard certificate covers your main domain and ALL its sub-domains. For example, *.example.com covers api.example.com, mail.example.com, app.example.com, and any others. It is best to include the root domain (example.com) alongside the wildcard to cover everything.

???? Linux / macOS
lego --email "$EMAIL" \
--server "$ACME_SERVER" \
--eab --kid "$EAB_KEY_ID" \
--hmac "$EAB_HMAC_KEY" \
--dns cloudflare \
--domains "*.example.com" \
--domains example.com \
--cert.timeout 300 \
run
???? Windows (PowerShell)
lego --email "$env:EMAIL" `
--server "$env:ACME_SERVER" `
--eab --kid "$env:EAB_KEY_ID" `
--hmac "$env:EAB_HMAC_KEY" `
--dns cloudflare `
--domains "*.example.com" `
--domains example.com `
--cert.timeout 300 `
run

Step 1.5 — Get a Wildcard + Multi-Domain Certificate

You can combine both wildcards and specific extra domains in a single certificate. This is the most flexible option for complex setups.

lego --email "$EMAIL" \
--server "$ACME_SERVER" \
--eab --kid "$EAB_KEY_ID" --hmac "$EAB_HMAC_KEY" \
--dns cloudflare \
--domains "*.example.com" \
--domains example.com \
--domains www.example.com \
--domains mail.example.com \
--cert.timeout 300 \
run

Step 1.6 — Choosing a Certificate Key Type

A key type is the mathematical algorithm used to protect your certificate. Different types offer different trade-offs between compatibility and speed.

Key Type Flag What It Means When to Use
RSA 4096 --key-type rsa4096 Most compatible with older systems. Slightly slower. Default choice for maximum compatibility.
RSA 2048 --key-type rsa2048 Compatible, slightly faster than RSA 4096. Use for older systems or performance-sensitive setups.
ECDSA P-256 --key-type ec256 Modern, fast, and small. Best performance. Recommended for new setups on modern servers.
ECDSA P-384 --key-type ec384 More secure than P-256, slightly slower. Use for high-security environments.

Example — ECDSA P-256 (recommended for performance):

lego --email "$EMAIL" \
--server "$ACME_SERVER" \
--eab --kid "$EAB_KEY_ID" --hmac "$EAB_HMAC_KEY" \
--dns cloudflare \
--domains demo.example.com \
--key-type ec256 \
run

Part 2 — Where Are My Certificates Stored?

After Lego successfully gets your certificate, it saves it on your computer. Here is exactly where to find each file.

???? Linux / macOS
~/.lego/certificates/

??? demo.example.com.crt
? (Certificate + chain)
??? demo.example.com.key
? (Private key — KEEP SAFE)
??? demo.example.com.issuer.crt
? (Intermediate cert only)
??? demo.example.com.json
(Metadata: expiry, URLs)
???? Windows
C:\Users\Username\.lego\certificates\

??? demo.example.com.crt
? (Certificate + chain)
??? demo.example.com.key
? (Private key — KEEP SAFE)
??? demo.example.com.issuer.crt
? (Intermediate cert only)
??? demo.example.com.json
(Metadata: expiry, URLs)

What each file is for:

File Purpose
.crt The full certificate chain (certificate + intermediates). This is what you give to Apache, Nginx, IIS, etc.
.key NEVER share this file, upload it publicly, or commit it to version control (like Git).
.issuer.crt Just the intermediate certificate. Some older applications need this file separately.
.json Metadata about your certificate: expiry date, covered domains, and the certificate's URL on the ACME server.

???? IMPORTANT SECURITY NOTE

The .key file is like the master password to your certificate. Anyone who has it can impersonate your website. Store it securely, restrict access to it, and never put it in a public place.


Part 3 — Installing the Certificate on Your Web Server

Getting the certificate is only half the job. You also need to install it on your web server so that your website actually uses it. Lego can do this automatically using "run hooks" — small scripts that run right after a certificate is issued or renewed.

Step 3.1 — What Are Run Hooks?

A run hook is a command or script that Lego automatically runs every time it successfully gets or renews a certificate. This is how you tell Lego: "After you get the certificate, please copy it to the right folder and restart my web server."

Simple example — restart Nginx automatically after getting a certificate:

lego --email "$EMAIL" \
--server "$ACME_SERVER" \
--eab --kid "$EAB_KEY_ID" --hmac "$EAB_HMAC_KEY" \
--dns cloudflare \
--domains demo.example.com \
--run-hook "systemctl reload nginx" \
run

You can chain multiple hooks (they run in order):

--run-hook "/path/to/deploy-script.sh" \
--run-hook "systemctl reload nginx" \
--run-hook "docker restart web-app" \

Step 3.2 — Installing on Apache Web Server (Linux)

Follow these steps to automatically deploy your certificate to an Apache web server every time it is issued or renewed.

Step A — Create the deployment script:

sudo nano /usr/local/bin/lego-deploy-apache.sh

Copy and paste the following into the file:

#!/bin/bash

DOMAIN="demo.example.com"
CERT_SRC="$HOME/.lego/certificates"
CERT_DEST="/etc/apache2/ssl"

mkdir -p "$CERT_DEST"

cp "$CERT_SRC/$DOMAIN.crt" "$CERT_DEST/$DOMAIN.crt"
cp "$CERT_SRC/$DOMAIN.key" "$CERT_DEST/$DOMAIN.key"
cp "$CERT_SRC/$DOMAIN.issuer.crt" "$CERT_DEST/$DOMAIN.issuer.crt"

chmod 644 "$CERT_DEST/$DOMAIN.crt"
chmod 644 "$CERT_DEST/$DOMAIN.issuer.crt"
chmod 600 "$CERT_DEST/$DOMAIN.key"

systemctl reload apache2

echo "$(date): Apache certificates deployed for $DOMAIN" >> /var/log/lego-deploy.log

Step B — Make the script executable (so the system can run it):

sudo chmod +x /usr/local/bin/lego-deploy-apache.sh

Step C — Get your certificate and run the deploy hook:

lego --email "$EMAIL" \
--server "$ACME_SERVER" \
--eab --kid "$EAB_KEY_ID" --hmac "$EAB_HMAC_KEY" \
--dns cloudflare \
--domains demo.example.com \
--run-hook "/usr/local/bin/lego-deploy-apache.sh" \
run

Step D — Configure Apache to use the certificate:

sudo tee /etc/apache2/sites-available/demo.example.com-ssl.conf > /dev/null << 'EOF'
<VirtualHost *:443>
ServerName demo.example.com
DocumentRoot /var/www/demo.example.com

SSLEngine on
SSLCertificateFile /etc/apache2/ssl/demo.example.com.crt
SSLCertificateKeyFile /etc/apache2/ssl/demo.example.com.key

SSLProtocol -all +TLSv1.2 +TLSv1.3
Header always set Strict-Transport-Security "max-age=63072000"
</VirtualHost>
EOF

sudo a2enmod ssl headers
sudo a2ensite demo.example.com-ssl
sudo systemctl reload apache2

Step 3.3 — Installing on Nginx Web Server (Linux)

Follow these steps to automatically deploy your certificate to an Nginx web server.

Step A — Create the deployment script:

sudo nano /usr/local/bin/lego-deploy-nginx.sh

Script content:

#!/bin/bash

DOMAIN="demo.example.com"
CERT_SRC="$HOME/.lego/certificates"
CERT_DEST="/etc/nginx/ssl"

mkdir -p "$CERT_DEST"

cp "$CERT_SRC/$DOMAIN.crt" "$CERT_DEST/$DOMAIN.crt"
cp "$CERT_SRC/$DOMAIN.key" "$CERT_DEST/$DOMAIN.key"

chmod 644 "$CERT_DEST/$DOMAIN.crt"
chmod 600 "$CERT_DEST/$DOMAIN.key"

nginx -t && systemctl reload nginx

echo "$(date): Nginx certificates deployed for $DOMAIN" >> /var/log/lego-deploy.log

Step B — Make the script executable:

sudo chmod +x /usr/local/bin/lego-deploy-nginx.sh

Step C — Get your certificate with the deploy hook:

lego --email "$EMAIL" \
--server "$ACME_SERVER" \
--eab --kid "$EAB_KEY_ID" --hmac "$EAB_HMAC_KEY" \
--dns cloudflare \
--domains demo.example.com \
--run-hook "/usr/local/bin/lego-deploy-nginx.sh" \
run

Step D — Configure Nginx to use SSL:

server {
listen 443 ssl http2;
server_name demo.example.com;
root /var/www/demo.example.com;

ssl_certificate /etc/nginx/ssl/demo.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/demo.example.com.key;

ssl_protocols TLSv1.2 TLSv1.3;
add_header Strict-Transport-Security "max-age=63072000" always;
}

server {
listen 80;
server_name demo.example.com;
return 301 https://$host$request_uri; # Redirect HTTP to HTTPS
}

sudo nginx -t # Test config first — check for errors
sudo systemctl reload nginx # Apply changes

Step 3.4 — Installing on Windows IIS

On Windows, IIS uses the Windows Certificate Store rather than plain files. The script below handles the conversion and import for you.

Step A — Save this script as C:\Scripts\lego-deploy-iis.ps1:

$Domain      = "demo.example.com"
$CertSrc = "$env:USERPROFILE\.lego\certificates"
$CertPath = "$CertSrc\$Domain.crt"
$KeyPath = "$CertSrc\$Domain.key"
$PfxPath = "$env:TEMP\$Domain.pfx"
$PfxPassword = ConvertTo-SecureString -String "TempPassword123!" -Force -AsPlainText

# Convert certificate files to PFX format (required by Windows)
& "C:\Program Files\Git\usr\bin\openssl.exe" pkcs12 -export `
-out $PfxPath -inkey $KeyPath -in $CertPath -password pass:TempPassword123!

# Import into Windows Certificate Store
$Cert = Import-PfxCertificate -FilePath $PfxPath `
-CertStoreLocation Cert:\LocalMachine\My -Password $PfxPassword

# Bind to IIS site
Import-Module WebAdministration
$Binding = Get-WebBinding -Name "Default Web Site" -Protocol https
if ($Binding) { $Binding.AddSslCertificate($Cert.Thumbprint, "My") }

Remove-Item $PfxPath -Force # Clean up temporary file

Add-Content -Path "C:\Scripts\lego-deploy.log" `
-Value "$(Get-Date): IIS certificate deployed for $Domain"

Step B — Issue certificate with the IIS deploy hook:

lego --email "$env:EMAIL" `
--server "$env:ACME_SERVER" `
--eab --kid "$env:EAB_KEY_ID" --hmac "$env:EAB_HMAC_KEY" `
--dns cloudflare `
--domains demo.example.com `
--run-hook "powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\lego-deploy-iis.ps1" `
run

Step 3.5 — Advanced: Custom Deployment Hook (for Multiple Services)

If you need to deploy to multiple folders, multiple web servers, or even remote servers all at once, use this advanced script. It includes error checking and logging.

Save as /usr/local/bin/lego-deploy-custom.sh:

#!/bin/bash

set -e # Stop immediately if anything fails

DOMAIN="$LEGO_CERT_DOMAIN" # Lego provides this automatically
CERT_PATH="$LEGO_CERT_PATH"
KEY_PATH="$LEGO_CERT_KEY_PATH"
LOG_FILE="/var/log/lego-deploy.log"

log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"; }

log "Starting deployment for: $DOMAIN"

# Check files exist before proceeding
if [[ ! -f "$CERT_PATH" ]] || [[ ! -f "$KEY_PATH" ]]; then
log "ERROR: Certificate or key file not found"; exit 1
fi

# Deploy to multiple local directories
for location in "/etc/nginx/ssl" "/etc/apache2/ssl" "/opt/custom-app/ssl"; do
if [[ -d "$location" ]]; then
cp "$CERT_PATH" "$location/$DOMAIN.crt"
cp "$KEY_PATH" "$location/$DOMAIN.key"
chmod 644 "$location/$DOMAIN.crt"
chmod 600 "$location/$DOMAIN.key"
log "Deployed to $location"
fi
done

# Reload all running web services
for service in nginx apache2 custom-app; do
if systemctl is-active --quiet "$service"; then
systemctl reload "$service"; log "Reloaded $service"
fi
done

# Copy to remote servers (requires SSH key access)
for server in server1.local server2.local; do
scp "$CERT_PATH" "root@$server:/etc/ssl/certs/$DOMAIN.crt"
scp "$KEY_PATH" "root@$server:/etc/ssl/private/$DOMAIN.key"
ssh "root@$server" "systemctl reload nginx"
log "Deployed to remote $server"
done

log "Deployment completed for $DOMAIN"
sudo chmod +x /usr/local/bin/lego-deploy-custom.sh

lego --email "$EMAIL" \
--server "$ACME_SERVER" \
--eab --kid "$EAB_KEY_ID" --hmac "$EAB_HMAC_KEY" \
--dns cloudflare \
--domains demo.example.com \
--run-hook "/usr/local/bin/lego-deploy-custom.sh" \
run

Part 4 — Setting Up Automatic Certificate Renewal

SSL certificates expire — they have a "use by" date. Lego can check your certificates automatically and renew them before they run out, so you never get a scary "Certificate Expired" warning on your website. By default, Lego renews when there are 30 days left.

Step 4.1 — The Basic Renewal Command

The renew command checks if your certificate needs renewing. If it does, it renews it and runs any deploy hooks. If it doesn't need renewing yet, it does nothing — safe to run any time.

???? Linux / macOS
source ~/.lego/config/acme-server.env

lego --email "$EMAIL" \
--server "$ACME_SERVER" \
--dns cloudflare \
--domains demo.example.com \
--run-hook "/usr/local/bin/lego-deploy-nginx.sh" \
renew --days 30
???? Windows (PowerShell)
. "$env:USERPROFILE\.lego\config\acme-server.ps1"

lego --email "$env:EMAIL" `
--server "$env:ACME_SERVER" `
--dns cloudflare `
--domains demo.example.com `
--run-hook "powershell.exe -File C:\Scripts\lego-deploy-iis.ps1" `
renew --days 30

???? HOW IT WORKS

The --days 30 flag means: "Only renew if the certificate expires within the next 30 days." This means you can safely run this command every day — it will only take action when needed.

Step 4.2 — Automatic Renewal on Linux / macOS (Cron Job or Systemd)

A cron job is a scheduled task that runs a command at set times. We will set one up to run every day at 2 AM to check and renew your certificates.

Step A — Create the renewal script:

sudo nano /usr/local/bin/lego-renew.sh

Paste this content into the file:

#!/bin/bash

source "$HOME/.lego/config/acme-server.env"

DOMAINS=("demo.example.com" "example.com" "*.wildcard-example.com")
LOG_FILE="/var/log/lego-renewal.log"

log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"; }

log "Starting renewal check"

for domain in "${DOMAINS[@]}"; do
log "Checking: $domain"
lego --email "$EMAIL" \
--server "$ACME_SERVER" \
--dns cloudflare \
--domains "$domain" \
--run-hook "/usr/local/bin/lego-deploy-nginx.sh" \
renew --days 30 >> "$LOG_FILE" 2>&1
[ $? -eq 0 ] && log "Done: $domain" || log "ERROR: $domain"
done

log "Renewal check finished"

Step B — Make the script executable:

sudo chmod +x /usr/local/bin/lego-renew.sh

Option 1 — Add a Cron Job (runs daily at 2 AM):

sudo crontab -e

# Add this line inside the editor:
0 2 * * * /usr/local/bin/lego-renew.sh >> /var/log/lego-cron.log 2>&1

Option 2 — Use Systemd Timer (recommended on modern Linux):

Systemd timers are more reliable than cron jobs on modern Linux systems.

Create a service file at /etc/systemd/system/lego-renewal.service:

[Unit]
Description=Lego Certificate Renewal
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/lego-renew.sh
User=root

Create a timer file at /etc/systemd/system/lego-renewal.timer:

[Unit]
Description=Lego Certificate Renewal Timer
Requires=lego-renewal.service

[Timer]
OnCalendar=daily
RandomizedDelaySec=1h # Runs at a random time within 1 hour to avoid server overload
Persistent=true # Re-runs missed jobs if the machine was off

[Install]
WantedBy=timers.target

Enable and start the timer:

sudo systemctl daemon-reload
sudo systemctl enable lego-renewal.timer
sudo systemctl start lego-renewal.timer

# Check that it is active:
sudo systemctl list-timers lego-renewal.timer

Step 4.3 — Automatic Renewal on Windows (Task Scheduler)

On Windows, we use Task Scheduler to run the renewal script automatically every day.

Step A — Create the PowerShell renewal script at C:\Scripts\lego-renew.ps1:

. "$env:USERPROFILE\.lego\config\acme-server.ps1"

$Domains = @("demo.example.com", "example.com", "*.wildcard-example.com")
$LogFile = "C:\Scripts\lego-renewal.log"

function Write-Log { param($Message)
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - $Message" |
Tee-Object -FilePath $LogFile -Append
}

Write-Log "Starting renewal check"

foreach ($Domain in $Domains) {
Write-Log "Checking: $Domain"
lego --email "$env:EMAIL" `
--server "$env:ACME_SERVER" `
--dns cloudflare `
--domains $Domain `
--run-hook "powershell.exe -File C:\Scripts\lego-deploy-iis.ps1" `
renew --days 30 2>&1 | Tee-Object -FilePath $LogFile -Append
if ($LASTEXITCODE -eq 0) { Write-Log "Done: $Domain" }
else { Write-Log "ERROR: $Domain" }
}

Write-Log "Renewal check finished"

Step B — Register the Task Scheduler task (run PowerShell as Administrator):

$Action    = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-ExecutionPolicy Bypass -File C:\Scripts\lego-renew.ps1"

$Trigger = New-ScheduledTaskTrigger -Daily -At 2AM

$Principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" `
-LogonType ServiceAccount -RunLevel Highest

$Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries `
-DontStopIfGoingOnBatteries -StartWhenAvailable

Register-ScheduledTask -TaskName "Lego Certificate Renewal" `
-Action $Action -Trigger $Trigger -Principal $Principal `
-Settings $Settings `
-Description "Daily renewal check for Lego SSL certificates"

# Confirm it was created:
Get-ScheduledTask -TaskName "Lego Certificate Renewal"

Part 5 — Advanced Deployment Scenarios

This section covers more advanced situations: deploying to multiple servers, Docker containers, Kubernetes, and Azure Key Vault.

Step 5.1 — Deploying to Multiple Servers at Once

If you run multiple web servers and want all of them to get the new certificate automatically, use this script. It copies the certificate to each server using SSH.

?? PREREQUISITE

SSH key-based authentication must be set up between your main server and the remote servers. The remote servers must be accessible via SSH without a password prompt.

Save as /usr/local/bin/lego-deploy-multi.sh:

#!/bin/bash

DOMAIN="$LEGO_CERT_DOMAIN"
CERT_PATH="$LEGO_CERT_PATH"
KEY_PATH="$LEGO_CERT_KEY_PATH"
REMOTE_SERVERS=("server1.local" "server2.local" "server3.local")
LOG_FILE="/var/log/lego-multi-deploy.log"

log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"; }

log "Multi-server deployment for: $DOMAIN"

for server in "${REMOTE_SERVERS[@]}"; do
log "Deploying to $server"
scp "$CERT_PATH" "root@$server:/etc/ssl/certs/$DOMAIN.crt"
scp "$KEY_PATH" "root@$server:/etc/ssl/private/$DOMAIN.key"
ssh "root@$server" "chmod 644 /etc/ssl/certs/$DOMAIN.crt"
ssh "root@$server" "chmod 600 /etc/ssl/private/$DOMAIN.key"
ssh "root@$server" "systemctl reload nginx"
log "Done: $server"
done

log "Multi-server deployment complete"

Step 5.2 — Deploying to Docker Containers

If your web server runs inside a Docker container, use this script to copy certificates to the Docker volume directory and restart the containers.

Save as /usr/local/bin/lego-deploy-docker.sh:

#!/bin/bash

DOMAIN="$LEGO_CERT_DOMAIN"
CERT_PATH="$LEGO_CERT_PATH"
KEY_PATH="$LEGO_CERT_KEY_PATH"
DOCKER_VOL="/var/docker/ssl"

mkdir -p "$DOCKER_VOL"

cp "$CERT_PATH" "$DOCKER_VOL/$DOMAIN.crt"
cp "$KEY_PATH" "$DOCKER_VOL/$DOMAIN.key"

chmod 644 "$DOCKER_VOL/$DOMAIN.crt"
chmod 600 "$DOCKER_VOL/$DOMAIN.key"

# Restart the containers so they pick up the new certificate
docker restart nginx-proxy
docker restart web-app

echo "$(date): Docker containers updated for $DOMAIN" >> /var/log/lego-docker.log

Step 5.3 — Deploying to Kubernetes

Kubernetes stores certificates as "Secrets". This script creates or updates a TLS Secret in your cluster whenever a certificate is renewed.

Save as /usr/local/bin/lego-deploy-k8s.sh:

#!/bin/bash

DOMAIN="$LEGO_CERT_DOMAIN"
CERT_PATH="$LEGO_CERT_PATH"
KEY_PATH="$LEGO_CERT_KEY_PATH"
NAMESPACE="production"
SECRET_NAME="tls-secret-$(echo $DOMAIN | tr '.' '-')"

# Create or update the TLS Secret in Kubernetes
kubectl create secret tls "$SECRET_NAME" \
--cert="$CERT_PATH" \
--key="$KEY_PATH" \
--namespace="$NAMESPACE" \
--dry-run=client -o yaml | kubectl apply -f -

# Restart the ingress controller to pick up the new certificate
kubectl rollout restart deployment/nginx-ingress-controller -n ingress-nginx

echo "$(date): Kubernetes secret updated for $DOMAIN" >> /var/log/lego-k8s.log

Step 5.4 — Deploying to Azure Key Vault

Azure Key Vault is a secure cloud storage service for secrets and certificates. This script converts your certificate to PFX format (required by Azure) and uploads it directly.

Save as /usr/local/bin/lego-deploy-azure-keyvault.sh:

#!/bin/bash

DOMAIN="$LEGO_CERT_DOMAIN"
CERT_PATH="$LEGO_CERT_PATH"
KEY_PATH="$LEGO_CERT_KEY_PATH"
VAULT_NAME="mykeyvault"
CERT_NAME=$(echo "$DOMAIN" | tr '.' '-') # Azure names cannot contain dots
PFX_PASSWORD="SecurePassword123!"

# Step 1: Convert to PFX format (required by Azure Key Vault)
PFX_FILE="/tmp/$CERT_NAME.pfx"
openssl pkcs12 -export \
-out "$PFX_FILE" \
-inkey "$KEY_PATH" \
-in "$CERT_PATH" \
-password "pass:$PFX_PASSWORD"

# Step 2: Upload to Azure Key Vault
az keyvault certificate import \
--vault-name "$VAULT_NAME" \
--name "$CERT_NAME" \
--file "$PFX_FILE" \
--password "$PFX_PASSWORD"

# Step 3: Delete the temporary PFX file (keep it secure)
rm -f "$PFX_FILE"

echo "$(date): Certificate uploaded to Azure Key Vault for $DOMAIN" >> /var/log/lego-azure.log

Part 6 — Monitoring and Maintenance

After everything is set up, you need to keep an eye on your certificates to make sure renewals are working and to catch any issues early.

Step 6.1 — List and View Your Certificates

List all certificate files:

???? Linux / macOS ???? Windows (PowerShell)
ls -la ~/.lego/certificates/ dir "$env:USERPROFILE\.lego\certificates\"

View full certificate details (domains, dates, issuer):

???? Linux / macOS
openssl x509 \
-in ~/.lego/certificates/demo.example.com.crt \
-noout -text
???? Windows (PowerShell)
& "C:\Program Files\Git\usr\bin\openssl.exe" x509 `
-in "$env:USERPROFILE\.lego\certificates\demo.example.com.crt" `
-noout -text

View certificate metadata (expiry date, covered domains):

???? Linux / macOS ???? Windows (PowerShell)
cat ~/.lego/certificates/demo.example.com.json | jq Get-Content "$env:USERPROFILE\.lego\certificates\demo.example.com.json" | ConvertFrom-Json

Step 6.2 — Check When Your Certificate Expires

???? Linux / macOS
# Check expiry date:
echo | openssl s_client \
-connect demo.example.com:443 \
-servername demo.example.com 2>/dev/null \
| openssl x509 -noout -dates

# Check how many days are left:
echo $(( ($(date -d "$(echo | openssl s_client \
-connect demo.example.com:443 \
| openssl x509 -noout -enddate \
| cut -d= -f2)" +%s) - $(date +%s)) / 86400 )) days

Have any Questions

Call HTTPS

If you have any questions, feel free to call us

© 2025 https.in. All rights reserved.