Jump to content

QNAP T-133 QTS 5.2.10+ Porkbun DDNS 2026


Recommended Posts

trycatchthis
Posted

Emby SSL on QNAP QTS Using Porkbun, Let's Encrypt, and AI-Generated Scripts

Goal

Configure secure remote access to Emby over HTTPS using an SSL certificate, with a residential internet connection where the public IP address changes frequently.

The setup uses:

  • Domain and DNS: A domain such as yourdomainname.top, registered with Porkbun.

  • Dynamic DNS (DDNS): Porkbun's API to update DNS records when your public IP address changes.

  • SSL certificate: A free Let's Encrypt certificate obtained using DNS-01 validation.

  • Certificate format: PKCS#12 (.pfx), compatible with Emby Server.

  • Automation: Shell scripts to update DNS records, obtain and renew the SSL certificate, and update Emby's certificate configuration using its API.

The scripts are generated with the assistance of an AI of your choice and adapted to work with your particular NAS and setup.

Requirements

1. Porkbun account

  • A Porkbun account with a valid payment method (PayPal, credit card, etc.).

  • A registered domain name.

  • An API key and secret API key, with access restricted to the domain where possible.

At the time of writing, .top domains are an inexpensive option. The prices I found were approximately US$1.63 for the first year, with renewals at US$4.63 per year. Three years would cost approximately US$10.27 at those prices. Check the current pricing before registering, as domain prices can change.

Website: https://porkbun.com/

2. QNAP NAS

  • QNAP NAS running QTS.

  • My setup uses a QNAP TS-133 running QTS 5.2.10 or later.

  • SSH access to the NAS.

I connected to the NAS shell from Windows using PowerShell and SSH. You can use any SSH client you prefer.

Example:

ssh adminuser@qnapnashostnameorip

The scripts may require administrative privileges, depending on your QTS configuration and the operations being performed. A regular user account may not have sufficient permissions.

3. Emby Server

  • Emby Server must already be installed and configured on the NAS.

  • I used the native QPKG installation rather than Docker, as I wanted to keep the setup as lightweight as possible on my NAS.

  • I used the ARMv8 package listed for the TS-x28 and TS-x32 series. https://emby.media/qnap-server.html

Emby Community: https://emby.media/community/

Credits

Configuration Variables

The scripts use the following variables. Replace the empty values with your own details where required.

DOMAIN=""                 # The domain registered with Porkbun
PORKBUN_API_KEY=""        # Your Porkbun API key
PORKBUN_SECRET_API_KEY="" # Your Porkbun secret API key
PFX_PASSWORD=""           # Password used to protect the .pfx file
EMBY_API_KEY=""           # Your Emby API key

Important: Keep your API keys and certificate password private. Do not publish scripts containing your actual credentials on the forums.

Steps

1. Register a domain and configure Porkbun

Register an inexpensive domain at Porkbun. A .top domain is one option, although you can choose another extension if you find a better price.

Generate a Porkbun API key and secret API key. Restrict API access to the domain you intend to use, where supported.

2. Check the required dependencies

The first script checks whether the NAS has the commands and tools required by the subsequent scripts.

This helps identify missing dependencies before attempting to configure DDNS or install the SSL certificate.

This script checks for required and optional commands, verifies that persistent storage is available, checks free disk space, and tests whether the existing acme.sh client can run.

Usage: Copy and paste the entire block into your QNAP SSH shell.

cat > /share/CACHEDEV1_DATA/porkbun_ddns_dependency_check.sh <<'SCRIPT'
#!/bin/sh

# ============================================================
# Porkbun DDNS Dependency Check
# Platform: QNAP QTS
# ============================================================

GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
NC='\033[0m'

ERRORS=0
WARNINGS=0

pass() {
    printf "${GREEN}[PASS]${NC} %s\n" "$1"
}

warn() {
    printf "${YELLOW}[WARN]${NC} %s\n" "$1"
    WARNINGS=$((WARNINGS + 1))
}

error() {
    printf "${RED}[ERROR]${NC} %s\n" "$1"
    ERRORS=$((ERRORS + 1))
}

# ------------------------------------------------------------
# Check dependencies
# ------------------------------------------------------------
for cmd in curl openssl git crontab python3 opkg; do
    if command -v "$cmd" >/dev/null 2>&1; then
        pass "$cmd found: $(command -v "$cmd")"
    else
        case "$cmd" in
            curl|openssl|crontab)
                error "$cmd not found (required)"
                ;;
            *)
                warn "$cmd not found (optional)"
                ;;
        esac
    fi
done

# ------------------------------------------------------------
# Check persistent storage
# ------------------------------------------------------------
STORAGE="/share/CACHEDEV1_DATA"

if [ -d "$STORAGE" ]; then
    pass "Persistent storage exists: $STORAGE"

    DISK_INFO=$(df -h "$STORAGE" 2>/dev/null |
        awk 'NR==2 {
            printf "Size: %s | Used: %s | Available: %s | Use: %s",
            $2, $3, $4, $5
        }')

    if [ -n "$DISK_INFO" ]; then
        pass "Storage status: $DISK_INFO"
    else
        warn "Unable to determine storage usage"
    fi

    AVAILABLE=$(df -Pk "$STORAGE" 2>/dev/null |
        awk 'NR==2 {print $4}')

    case "$AVAILABLE" in
        ''|*[!0-9]*)
            error "Unable to determine available storage space"
            ;;
        *)
            if [ "$AVAILABLE" -gt 0 ]; then
                pass "Storage has free space"
            else
                error "Storage has no free space"
            fi
            ;;
    esac
else
    error "Persistent storage not found: $STORAGE"
fi

# ------------------------------------------------------------
# Check existing ACME client
# ------------------------------------------------------------
ACME="/share/CACHEDEV1_DATA/.acme.sh/acme.sh"

if [ -x "$ACME" ]; then
    pass "ACME client is executable: $ACME"

    ACME_VERSION=$("$ACME" --version 2>&1)
    ACME_STATUS=$?

    if [ "$ACME_STATUS" -eq 0 ]; then
        printf '%s\n' "$ACME_VERSION" |
            while IFS= read -r line; do
                printf "${GREEN}[PASS]${NC} ACME version: %s\n" "$line"
            done
    else
        error "ACME client failed to run: $ACME_VERSION"
    fi
else
    warn "ACME client missing or not executable: $ACME"
fi

# ------------------------------------------------------------
# Summary
# ------------------------------------------------------------
printf "\n${GREEN}Checks completed${NC}\n"
printf "${YELLOW}WARNINGS: %s${NC}\n" "$WARNINGS"
printf "${RED}ERRORS: %s${NC}\n" "$ERRORS"

# Return a failure status if any required check failed.
if [ "$ERRORS" -gt 0 ]; then
    exit 1
fi

exit 0

# ============================================================
SCRIPT

chmod 700 /share/CACHEDEV1_DATA/porkbun_ddns_dependency_check.sh &&
/share/CACHEDEV1_DATA/porkbun_ddns_dependency_check.sh

Expected result: The script reports which dependencies are present or missing, displays storage usage, checks the ACME client, and prints a final warning/error summary.

3. Configure Dynamic DNS (DDNS)

The next script creates a DDNS updater that uses the Porkbun API to update your domain's DNS A record when your public IPv4 address changes.

Porkbun's API can also be used to manage AAAA records for IPv6, if required. You can ask your AI assistant to modify the script to support this.

An A record maps a domain name to an IPv4 address. An AAAA record maps a domain name to an IPv6 address.

This shell script checks your public IPv4 address and updates the root-domain DNS A record through the Porkbun API when the address changes.

Before running the script, configure these three variables:

  • DOMAIN — your registered domain name.

  • PORKBUN_API_KEY — your Porkbun API key.

  • PORKBUN_API_SECRET — your Porkbun secret API key.

Usage: Copy and paste the entire block into your QNAP SSH shell.

# Create the DDNS updater script.
cat > /share/CACHEDEV1_DATA/porkbun-ddns.sh <<'SCRIPT'
#!/bin/sh
set -eu
umask 077

# ===== CONFIGURATION: EDIT THESE THREE VALUES =====
DOMAIN=""
PORKBUN_API_KEY=""
PORKBUN_API_SECRET=""
# ==================================================

# Files and directories
STATE_DIR="/share/CACHEDEV1_DATA/.porkbun-ddns"
STATE_FILE="$STATE_DIR/last_ip"
LOG_FILE="$STATE_DIR/update.log"

# Porkbun DNS TTL (minimum 600 seconds)
TTL="600"

mkdir -p "$STATE_DIR"
chmod 700 "$STATE_DIR"

log() {
    printf '%s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >> "$LOG_FILE"
}

# Prevent overlapping executions
LOCK_DIR="$STATE_DIR/lock"

if ! mkdir "$LOCK_DIR" 2>/dev/null; then
    exit 0
fi

trap 'rmdir "$LOCK_DIR" 2>/dev/null || true' EXIT HUP INT TERM

# Obtain the public IPv4 address
IP=""

for URL in \
    "https://api.ipify.org" \
    "https://checkip.amazonaws.com"
do
    IP="$(curl -4 -fsS --connect-timeout 10 --max-time 20 "$URL" 2>/dev/null |
        tr -d '[:space:]' || true)"

    if printf '%s\n' "$IP" |
        grep -Eq '^([0-9]{1,3}\.){3}[0-9]{1,3}$'; then
        break
    fi

    IP=""
done

if [ -z "$IP" ]; then
    log "ERROR: Could not obtain public IPv4 address."
    exit 1
fi

# Validate IPv4 octets
OLD_IFS="$IFS"
IFS=.
set -- $IP
IFS="$OLD_IFS"

for OCTET in "$@"; do
    case "$OCTET" in
        ''|*[!0-9]*)
            log "ERROR: Invalid public IP."
            exit 1
            ;;
    esac

    [ "$OCTET" -le 255 ] || {
        log "ERROR: Invalid public IP."
        exit 1
    }
done

# Skip the API request if the IP has not changed
if [ -f "$STATE_FILE" ] &&
    [ "$(cat "$STATE_FILE")" = "$IP" ]; then
    exit 0
fi

# Update the root-domain A record
RESPONSE="$(curl -fsS --connect-timeout 10 --max-time 30 \
    -H 'Content-Type: application/json' \
    -X POST \
    "https://api.porkbun.com/api/json/v3/dns/editByNameType/$DOMAIN/A/" \
    -d "{\"apikey\":\"$PORKBUN_API_KEY\",\"secretapikey\":\"$PORKBUN_API_SECRET\",\"content\":\"$IP\",\"ttl\":\"$TTL\"}" \
    2>&1)" || {
        log "ERROR: Porkbun API request failed: $RESPONSE"
        exit 1
    }

# Require explicit API success before saving the new IP
if ! printf '%s' "$RESPONSE" |
    grep -q '"status"[[:space:]]*:[[:space:]]*"SUCCESS"'; then
    log "ERROR: Porkbun API did not confirm success: $RESPONSE"
    exit 1
fi

# Save the successfully updated IP
printf '%s\n' "$IP" > "$STATE_FILE"
chmod 600 "$STATE_FILE"

log "SUCCESS: $DOMAIN A record updated to $IP"
SCRIPT

# Set permissions and run the script
chmod 700 /share/CACHEDEV1_DATA/porkbun-ddns.sh &&
/share/CACHEDEV1_DATA/porkbun-ddns.sh

4. Install the SSL certificate

The next script obtains a free SSL/TLS certificate from Let's Encrypt using DNS-01 validation through Porkbun's API.

The certificate and private key are packaged into a password-protected PKCS#12 (.pfx) file for use with Emby Server.

DNS-01 validation is particularly useful when the server is behind a residential internet connection, as it does not require Let's Encrypt to connect directly to the NAS over HTTP.

This script installs acme.sh if it is not already installed, obtains a free Let's Encrypt certificate using Porkbun DNS-01 validation, and exports the certificate and private key into a password-protected PKCS#12 (.pfx) file for Emby Server.

Configuration required:

  • PORKBUN_API_KEY, PORKBUN_SECRET_API_KEY, PFX_PASSWORD, DOMAIN

Usage: Copy and paste the entire block into your QNAP SSH shell.

cat > /share/CACHEDEV1_DATA/setup-emby-ssl.sh <<'SCRIPT'
#!/bin/sh
set -eu
umask 077

# ============================================================
# CONFIGURATION — EDIT THESE VALUES
# ============================================================
PORKBUN_API_KEY=""
PORKBUN_SECRET_API_KEY=""
PFX_PASSWORD=""

DOMAIN=""
BASE="/share/CACHEDEV1_DATA"
ACME="$BASE/.acme.sh"
CERTDIR="$BASE/EmbySSL"
# ============================================================

# Validate configuration
[ -n "$DOMAIN" ] || {
    echo "ERROR: Set DOMAIN at the top of the script."
    exit 1
}

[ -n "$PORKBUN_API_KEY" ] || {
    echo "ERROR: Set PORKBUN_API_KEY at the top of the script."
    exit 1
}

[ -n "$PORKBUN_SECRET_API_KEY" ] || {
    echo "ERROR: Set PORKBUN_SECRET_API_KEY at the top of the script."
    exit 1
}

[ -n "$PFX_PASSWORD" ] || {
    echo "ERROR: Set a strong PFX_PASSWORD at the top of the script."
    exit 1
}

export PORKBUN_API_KEY PORKBUN_SECRET_API_KEY

echo "=== Emby SSL setup: $DOMAIN ==="

mkdir -p "$ACME" "$CERTDIR"
chmod 700 "$ACME" "$CERTDIR"

# ------------------------------------------------------------
# Install acme.sh if missing
# ------------------------------------------------------------
if [ ! -x "$ACME/acme.sh" ]; then
    cd /tmp

    if [ ! -f acme.sh.tar.gz ]; then
        curl -fL \
            https://github.com/acmesh-official/acme.sh/archive/refs/heads/master.tar.gz \
            -o acme.sh.tar.gz
    fi

    tar -xzf acme.sh.tar.gz
    cd acme.sh-master

    ./acme.sh --install \
        --home "$ACME" \
        --config-home "$ACME" \
        --nocron
fi

# ------------------------------------------------------------
# Use Let's Encrypt and issue the certificate
# ------------------------------------------------------------
"$ACME/acme.sh" --set-default-ca --server letsencrypt

"$ACME/acme.sh" --issue \
    --server letsencrypt \
    --dns dns_porkbun \
    -d "$DOMAIN" \
    --keylength ec-256

# ------------------------------------------------------------
# Export certificate and private key
# ------------------------------------------------------------
"$ACME/acme.sh" --install-cert \
    -d "$DOMAIN" \
    --ecc \
    --key-file "$CERTDIR/privkey.pem" \
    --fullchain-file "$CERTDIR/fullchain.pem"

# ------------------------------------------------------------
# Generate Emby-compatible PFX
# ------------------------------------------------------------
openssl pkcs12 -export \
    -out "$CERTDIR/emby.pfx" \
    -inkey "$CERTDIR/privkey.pem" \
    -in "$CERTDIR/fullchain.pem" \
    -passout "pass:$PFX_PASSWORD"

chmod 600 "$CERTDIR"/*

unset PORKBUN_API_KEY PORKBUN_SECRET_API_KEY PFX_PASSWORD

echo
echo "SUCCESS: $CERTDIR/emby.pfx"
echo "Configure this certificate path and PFX password in Emby."
echo "Automatic renewal scheduling and Emby reload are not configured yet."
SCRIPT

chmod 700 /share/CACHEDEV1_DATA/setup-emby-ssl.sh

echo "Script created. Edit the configuration variables, then run:"
echo "/share/CACHEDEV1_DATA/setup-emby-ssl.sh"

Important: This script obtains and exports the certificate, but it does not configure Emby automatically or set up renewal scheduling. Those steps must be completed separately.

5. Configure Emby to use the .pfx certificate

Configure Emby Server to use the generated .pfx file and its password.

Restart Emby if required, then test HTTPS access from another device. Test from outside your home network as well to confirm that remote access works.

6. Automate SSL certificate renewal

The final script automates certificate renewal and updates Emby's certificate configuration using the Emby API.

A cron job is configured on the NAS to run the renewal script periodically, so the certificate can be renewed without manual intervention.

The renewal process should also handle updating Emby with the renewed certificate and reloading or restarting Emby as necessary.

Configuration required: Porkbun API key, Porkbun secret API key, PFX password, Emby API key, and domain name.

Usage: Copy and paste the entire block into your QNAP SSH shell.

# ============================================================
# Renew Emby SSL certificate
# ============================================================
cat > /share/CACHEDEV1_DATA/renew-emby-ssl.sh <<'SCRIPT'
#!/bin/sh
set -eu
umask 077

# ============================================================
# Emby SSL renewal using acme.sh + Porkbun DNS + Emby API
# Manual run: forces renewal
# Scheduled run: checks after 85 days
# ============================================================

# EDIT THESE FIVE VALUES
PORKBUN_API_KEY=""
PORKBUN_SECRET_API_KEY=""
PFX_PASSWORD=""
EMBY_API_KEY=""
DOMAIN=""

# Configuration
ACME='/share/CACHEDEV1_DATA/.acme.sh/acme.sh'
CERT_DIR='/share/CACHEDEV1_DATA/EmbySSL'
CERT_FILE="$CERT_DIR/emby.cer"
KEY_FILE="$CERT_DIR/emby.key"
FULLCHAIN_FILE="$CERT_DIR/fullchain.cer"
PFX_FILE="$CERT_DIR/emby.pfx"

EMBY_IP='127.0.0.1'
EMBY_PORT='8096'

BASE='/share/CACHEDEV1_DATA'
LOG="$BASE/renew-emby-ssl.log"
STATE="$BASE/.emby-ssl-last-renewal"
LOCK="$BASE/.renew-emby-ssl-lock"

# Scheduled runs wait 85 days between successful renewals.
RENEW_AFTER_DAYS=85

# ------------------------------------------------------------
# Validate configuration
# ------------------------------------------------------------
[ -n "$DOMAIN" ] || {
    echo "ERROR: Set DOMAIN."
    exit 1
}

[ -n "$PORKBUN_API_KEY" ] || {
    echo "ERROR: Set PORKBUN_API_KEY."
    exit 1
}

[ -n "$PORKBUN_SECRET_API_KEY" ] || {
    echo "ERROR: Set PORKBUN_SECRET_API_KEY."
    exit 1
}

[ -n "$PFX_PASSWORD" ] || {
    echo "ERROR: Set PFX_PASSWORD."
    exit 1
}

[ -n "$EMBY_API_KEY" ] || {
    echo "ERROR: Set EMBY_API_KEY."
    exit 1
}

# Log messages with timestamps.
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> "$LOG"
}

fail() {
    log "ERROR: $*"
    exit 1
}

# Prevent overlapping runs.
if ! mkdir "$LOCK" 2>/dev/null; then
    log "Another renewal process appears to be running; exiting."
    exit 1
fi

trap 'rm -rf "$LOCK"' EXIT HUP INT TERM

# Verify required programs and paths.
[ -x "$ACME" ] || fail "acme.sh not found or not executable: $ACME"
command -v openssl >/dev/null 2>&1 || fail "openssl not found."
command -v curl >/dev/null 2>&1 || fail "curl not found."

mkdir -p "$CERT_DIR" || fail "Cannot create certificate directory."

# Supply DNS credentials to acme.sh.
export PORKBUN_API_KEY
export PORKBUN_SECRET_API_KEY

MODE="${1:-manual}"
NOW="$(date +%s)"

if [ "$MODE" = "--scheduled" ]; then
    if [ -f "$STATE" ]; then
        LAST="$(cat "$STATE" 2>/dev/null)"
        case "$LAST" in
            ''|*[!0-9]*) LAST=0 ;;
        esac
    else
        LAST=0
    fi

    ELAPSED=$((NOW - LAST))
    REQUIRED=$((RENEW_AFTER_DAYS * 86400))

    if [ "$LAST" -gt 0 ] && [ "$ELAPSED" -lt "$REQUIRED" ]; then
        log "Scheduled check: last successful renewal was less than $RENEW_AFTER_DAYS days ago; skipping."
        exit 0
    fi
elif [ "$MODE" != "manual" ]; then
    fail "Unknown argument: $MODE. Use --scheduled or no argument."
fi

log "Starting $MODE renewal for $DOMAIN."

# Force renewal when manually run or when the scheduled check is due.
if ! "$ACME" --renew -d "$DOMAIN" --ecc --force >> "$LOG" 2>&1; then
    fail "acme.sh renewal failed."
fi

# Export the renewed certificate files to stable paths.
if ! "$ACME" --install-cert -d "$DOMAIN" --ecc \
    --cert-file "$CERT_FILE" \
    --key-file "$KEY_FILE" \
    --fullchain-file "$FULLCHAIN_FILE" >> "$LOG" 2>&1; then
    fail "acme.sh certificate installation/export failed."
fi

[ -s "$KEY_FILE" ] || fail "Private key is missing or empty."
[ -s "$FULLCHAIN_FILE" ] || fail "Full-chain certificate is missing or empty."

# Build the PFX in a temporary file, then replace the old one.
TMP_PFX="$CERT_DIR/emby.pfx.tmp.$$"
trap 'rm -f "$TMP_PFX"; rm -rf "$LOCK"' EXIT HUP INT TERM

if ! openssl pkcs12 -export \
    -out "$TMP_PFX" \
    -inkey "$KEY_FILE" \
    -in "$FULLCHAIN_FILE" \
    -passout "pass:$PFX_PASSWORD" >> "$LOG" 2>&1; then
    rm -f "$TMP_PFX"
    fail "OpenSSL failed to create the PFX."
fi

chmod 600 "$TMP_PFX" || fail "Could not secure temporary PFX."
mv -f "$TMP_PFX" "$PFX_FILE" || fail "Could not replace PFX file."
chmod 600 "$PFX_FILE" || fail "Could not secure PFX file."

log "Created updated PFX: $PFX_FILE"

# Escape backslashes and double quotes for valid JSON.
JSON_PASSWORD="$(printf '%s' "$PFX_PASSWORD" | sed 's/\\/\\\\/g; s/"/\\"/g')"

# Tell Emby to use the renewed certificate.
HTTP_CODE="$(curl --connect-timeout 10 --max-time 30 \
    --write-out '%{http_code}' \
    --output /dev/null \
    --silent \
    --show-error \
    -X POST "http://${EMBY_IP}:${EMBY_PORT}/emby/System/Configuration/Partial" \
    -H "X-Emby-Token: ${EMBY_API_KEY}" \
    -H 'Content-Type: text/plain' \
    --data-binary "{\"CertificatePath\":\"$PFX_FILE\",\"CertificatePassword\":\"$JSON_PASSWORD\"}" \
    2>> "$LOG")" || fail "Could not contact Emby API. Check that Emby is running."

case "$HTTP_CODE" in
    200|204)
        log "Emby API accepted the certificate configuration (HTTP $HTTP_CODE)."
        ;;
    *)
        fail "Emby API returned HTTP $HTTP_CODE. Check the API key, endpoint, and Emby logs."
        ;;
esac

# Mark success only after certificate creation and Emby API update.
date +%s > "$STATE" || fail "Could not update renewal timestamp."
log "SUCCESS: certificate renewed, PFX created, and Emby notified."

unset PORKBUN_API_KEY PORKBUN_SECRET_API_KEY PFX_PASSWORD EMBY_API_KEY
exit 0
SCRIPT

chmod 700 /share/CACHEDEV1_DATA/renew-emby-ssl.sh

# Install/update the daily 03:17 scheduled check without duplicating it.
CRON_FILE='/etc/config/crontab'
CRON_TMP='/share/CACHEDEV1_DATA/.emby-crontab.tmp'
CRON_LINE='17 3 * * * /bin/sh /share/CACHEDEV1_DATA/renew-emby-ssl.sh --scheduled'

if [ -f "$CRON_FILE" ]; then
    grep -F -v '/share/CACHEDEV1_DATA/renew-emby-ssl.sh' "$CRON_FILE" > "$CRON_TMP"
else
    : > "$CRON_TMP"
fi

echo "$CRON_LINE >> /share/CACHEDEV1_DATA/renew-emby-ssl.log 2>&1" >> "$CRON_TMP"
cat "$CRON_TMP" > "$CRON_FILE"
rm -f "$CRON_TMP"

crontab "$CRON_FILE" && /etc/init.d/crond.sh restart

echo
echo 'Script created and permissions set.'
echo 'Daily cron installation attempted.'
echo 'Edit the configuration values before running the script.'
# ============================================================

Usage

  • Manual renewal: /share/CACHEDEV1_DATA/renew-emby-ssl.sh

  • Scheduled check: /share/CACHEDEV1_DATA/renew-emby-ssl.sh --scheduled

The scheduled check skips renewal until 85 days have elapsed since the last successful run. The manual command forces renewal.

Security: Keep your API keys and PFX password private. Do not post real credentials or unredacted logs on the forum.

 

 


Note: These instructions describe my setup. Paths, package compatibility, permissions, and service-restart requirements may differ between QNAP models and QTS versions. Test each stage before relying on the automation.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...