-
|
Hello, new to all this and struggling at a certain point :) I managed my setup to issue certificates using acme.sh (docker), duckdns and let´s encrypt. Unfortunately i get no pem stuff, but instead i get "myDomain.cer", "myDomain.key", "ca.cer", "myDomain.csr" and "fullchain.cer". So at that point i have some trouble going on with mosquitto tls config. So some help is very appreciated at that point, thank you! :) |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
|
As i was struggling on that point, here was my solution for the certs, using acme.sh for the dns challenge with renew. As i have no real clue, i created with chatgpt :) This one gives me certs, downloads the root, which acme did not and checks if update is needed. duckdns_acmerenew.sh: #!/bin/bash
set -euo pipefail
CONFIG_FILE="/etc/duckdns_acme.conf"
if [ ! -f "$CONFIG_FILE" ]; then
echo "❌ Fehler: Config-Datei $CONFIG_FILE nicht gefunden!"
exit 1
fi
source "$CONFIG_FILE"
log() {
echo -e "$1"
if [ -n "${LOGFILE:-}" ]; then
echo -e "$(date +'%Y-%m-%d %H:%M:%S') $1" >> "$LOGFILE"
fi
}
error_exit() {
log "❌ Fehler: $1"
exit 1
}
for cmd in docker openssl curl date; do
if ! command -v "$cmd" &>/dev/null; then
error_exit "Befehl '$cmd' fehlt."
fi
done
ACME_CONTAINER="acme.sh"
ACME_EXEC="docker exec $ACME_CONTAINER"
ACME_INTERNAL_DIR="/out/_data/${DOMAIN}_ecc"
ROOT_CERT_URL_PRIMARY="https://letsencrypt.org/certs/isrgrootx2.pem"
ROOT_CERT_URL_FALLBACK="https://letsencrypt.org/certs/isrgrootx1.pem"
ROOT_CERT_FILE="$CERT_DIR/root.pem"
ROOT_CERT_TEMP="$CERT_DIR/root_temp.pem"
if [ ! -d "$CERT_DIR" ]; then
error_exit "Zertifikatsverzeichnis $CERT_DIR existiert nicht (bitte manuell anlegen)."
fi
CERT_FILE="$CERT_DIR/cert.pem"
# Ablaufprüfung
if [ -f "$CERT_FILE" ]; then
EXPIRY_DATE=$(openssl x509 -enddate -noout -in "$CERT_FILE" | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s)
NOW_EPOCH=$(date +%s)
REMAINING_DAYS=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
if [ "$REMAINING_DAYS" -gt "$RENEW_THRESHOLD_DAYS" ]; then
log "ℹ️ Zertifikat noch $REMAINING_DAYS Tage gültig – keine Erneuerung nötig laut Ablaufdatum."
else
log "🔄 Zertifikat läuft in $REMAINING_DAYS Tagen ab – acme.sh wird zur Erneuerung aufgerufen."
fi
else
log "📄 Kein bestehendes Zertifikat – acme.sh wird zur Ausstellung aufgerufen."
fi
# acme.sh aufrufen
ACME_CMD="$ACME_EXEC env DuckDNS_Token=$DUCKDNS_TOKEN /root/.acme.sh/acme.sh"
if $ACME_CMD --renew -d "$DOMAIN" --ecc --standalone --dns dns_duckdns --days "$RENEW_THRESHOLD_DAYS"; then
log "✅ acme.sh hat Zertifikat erneuert oder bestätigt."
else
log "ℹ️ acme.sh hat keine Erneuerung durchgeführt (noch gültig) – fahre fort."
fi
log "📦 Kopiere Zertifikate aus dem Container ($ACME_INTERNAL_DIR)..."
cp "$CERT2_DIR/$DOMAIN.cer" "$CERT_DIR/cert.pem" || error_exit "Fehler beim Kopieren von cert.pem"
cp "$CERT2_DIR/$DOMAIN.key" "$CERT_DIR/key.pem" || error_exit "Fehler beim Kopieren von key.pem"
cp "$CERT2_DIR/fullchain.cer" "$CERT_DIR/fullchain.pem" || error_exit "Fehler beim Kopieren von fullchain.pem"
cp "$CERT2_DIR/ca.cer" "$CERT_DIR/ca.pem" || error_exit "Fehler beim Kopieren von ca.pem"
cp "$CERT2_DIR/$DOMAIN.cer" "$CERT3_DIR/cert.pem" || error_exit "Fehler beim Kopieren von cert.pem"
cp "$CERT2_DIR/$DOMAIN.key" "$CERT3_DIR/key.pem" || error_exit "Fehler beim Kopieren von key.pem"
cp "$CERT2_DIR/fullchain.cer" "$CERT3_DIR/fullchain.pem" || error_exit "Fehler beim Kopieren von fullchain.pem"
cp "$CERT2_DIR/ca.cer" "$CERT3_DIR/ca.pem" || error_exit "Fehler beim Kopieren von ca.pem"
log "🌐 Lade Root-Zertifikat (ISRG Root X2 bevorzugt)..."
if curl -sf -o "$ROOT_CERT_TEMP" "$ROOT_CERT_URL_PRIMARY" && [ -s "$ROOT_CERT_TEMP" ]; then
log "✅ ISRG Root X2 heruntergeladen."
else
log "⚠️ X2 fehlgeschlagen, versuche X1..."
if curl -sf -o "$ROOT_CERT_TEMP" "$ROOT_CERT_URL_FALLBACK" && [ -s "$ROOT_CERT_TEMP" ]; then
log "✅ ISRG Root X1 heruntergeladen."
else
rm -f "$ROOT_CERT_TEMP"
error_exit "Root-Zertifikat konnte nicht heruntergeladen werden."
fi
fi
mv "$ROOT_CERT_TEMP" "$ROOT_CERT_FILE"
chmod 644 "$ROOT_CERT_FILE"
cat "$CERT_DIR/fullchain.pem" "$ROOT_CERT_FILE" > "$CERT_DIR/fullchain-with-root.pem"
log "🔍 Validiere Zertifikatkette..."
if ! openssl verify -CAfile "$CERT_DIR/fullchain.pem" "$CERT_DIR/cert.pem" >/dev/null 2>&1; then
log "⚠️ Warnung: Zertifikatkette möglicherweise nicht vollständig valide."
else
log "✅ Zertifikatkette ist gültig."
fi
chmod 600 "$CERT_DIR/key.pem"
chmod 644 "$CERT_DIR/"*.pem
log "🎉 Fertig: Zertifikat aktualisiert oder geprüft."
log "📁 Dateien:"
log " - cert.pem"
log " - key.pem"
log " - ca.pem"
log " - fullchain.pem"
log " - root.pem"
log " - fullchain-with-root.pem"
*********************************************************************************************************************************
duckdns_acme.conf:
# /etc/duckdns_acme.conf
# Your DuckDns-token
DUCKDNS_TOKEN="your-token-id"
# Your DuckDNS Domain (z.B. your.duckdns.org)
DOMAIN="your.duckdns.org"
# Destination Dir (has to exist, create manually)
CERT_DIR="/xyz/mosquitto-tls/certs"
# Another Destination folder (has to exist, create manually)
CERT3_DIR="/xyz/xyz/certs"
# Days before renewal
RENEW_THRESHOLD_DAYS=10
# Optional: Path zu Logfile (leave empty for no logging)
LOGFILE="/var/log/duckdns_acme_renew.log"
# Source Dir for Certifikate (has to excist, create manually)
CERT2_DIR="/var/lib/docker/volumes/out/_data/grobro.duckdns.org_ecc" |
Beta Was this translation helpful? Give feedback.
-
|
To answer your original question, cat /mypath/acme.sh/mydomain.duckdns.org_ecc/fullchain.cer /mypath/root-ca/isrgrootx1.pem > /mypath/mosquitto/fullchain.pem && cp /mypath/acme.sh/mydomain.duckdns.org_ecc/mydomain.duckdns.org.key /mypath/mosquitto/privkey.pemI didn't take a long look at the code you posted, but I think it can be simplified a lot. What might be missing though is a way to trigger the mosquitto instance to reload the certificates after they are renewed. By the way, you should put the code into a code block, otherwise Github will render it as markdown like making the comments headlines. Issueing the certificate can be done manually, since it only has to be done once. Using your setup with Duck DNS and the acme.sh docker container it can be done like this: docker run --rm --name acme-issue --tty --env DuckDNS_Token="mytoken" --volume "/mypath/acme.sh":/acme.sh neilpang/acme.sh --issue --server letsencrypt --dns dns_duckdns -d mydomain.duckdns.orgAfter the root certificate is downloaded, the command I posted at the beginning can be used to put the fullchain certificate together with the root. Something like the following commands should be run automatically weekly (or daily) to check, if the certificate should be renewed, to copy the certificate files, and to reload them in Mosquitto. docker run --rm --name acme-renew-cert --volume "/mypath/acme.sh":/acme.sh neilpang/acme.sh acme.sh --renew -d mydomain.duckdns.org
cat /mypath/acme.sh/mydomain.duckdns.org_ecc/fullchain.cer /mypath/root-ca/isrgrootx1.pem > /mypath/mosquitto/fullchain.pem
cp /mypath/acme.sh/mydomain.duckdns.org_ecc/mydomain.duckdns.org.key /mypath/mosquitto/privkey.pem
docker kill --signal=SIGHUP mosquittoHere the command Note: If acme.sh is not as docker run commands like this, but as a native daemon like intended, it schedules the renewal commands of the certificates automatically and you don't have to run/schedule those renewal commands manually. |
Beta Was this translation helpful? Give feedback.
As i was struggling on that point, here was my solution for the certs, using acme.sh for the dns challenge with renew. As i have no real clue, i created with chatgpt :) This one gives me certs, downloads the root, which acme did not and checks if update is needed.
Then copy to destination dirs, in the format mosquitto is accepting it.
There is a daily cronjob running my script (conf file needed too, see below script):
duckdns_acmerenew.sh: