Prerequisites:
Port 80 and 443 open – but if you’re already self-hosting a website, you should already have these ports open for Let’s Encrypt to work. In this guide, you don’t need to open these ports on your NAS.
Ubuntu with certbot and Let’s Encrypt and wildcard SSL configuration.

I assume you already know how to log in to Synology NAS and Ubuntu using SSH.

One off SSL setup.

First, in Ubuntu, copy the certificate files from /etc/letsencrypt/live/grischke.pro and the files you will need are cert.pem (domain certificate), chain.pem (intermediate certificate (optional)) and privkey.pem (private key) to your computer. The .pem extension shouldn’t matter. At the end of the day it’s just a text file. Now, add this certificate manually to DSM manually:

Control Panel → Security → Certificate → Add → Choose Add a certificate → Next → Choose Import certificate → Next → On Private Key: click on Browse and choose the <myPrivateKey>.key file from your local computer. On Certificate: click on Browse and choose the <myCertficate>.cer file from your local computer. Leave Intermedia Certificate: empty. → OK

Your certificate should now look similar to this:

Now click on SettingsConfigure → Select the certificate you just uploaded for every application you need, for example System default → press OK.

and select the according imported certificate for every single application as required from the according dropdown menu.
Then click on OK.

Now SSH to your Synology NAS. (I highly recommend MobaXterm app).

First, change and enable root login and password

sudo synouser -setpw root 'strong_password'

Check current ssh config and optionally allow Root Password Login using the following script. Alternatively, you can manually edit the config file and change “no” to “yes”.

sudo vi /etc/ssh/sshd_config

What the script below does is it checks and adjusts the option accordingly:

If the line #PermitRootLogin no exists, it will uncomment and change it to PermitRootLogin yes.

If the line PermitRootLogin no exists, it will change it to PermitRootLogin yes.

If the line #PermitRootLogin yes exists, it will uncomment it.

sudo sed -i 's/^#PermitRootLogin no/PermitRootLogin yes/; s/^PermitRootLogin no/PermitRootLogin yes/; s/^#PermitRootLogin prohibit-password/PermitRootLogin yes/; s/^PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

Restart ssh service

sudo systemctl restart sshd

Now, go to where certificates are kept on Synology NAS.

cd /usr/syno/etc/certificate/_archive/
ls -l

Each certificate installed on a Synology NAS is stored in a unique directory named with a string of six random characters, such as ZWP80f. If there are multiple certificates installed, you will see several directories. To identify the directory containing the recently imported certificate, verify the creation date that corresponds with the time the certificate was imported.

Identify which certificate is active and if you don’t have any active add it.

An important step is to add the cryptic directory name to your certificate manager’s description within the Synology DSM GUI. This action simplifies future management and ensures you can easily identify which cryptic certificate directory name corresponds to each of your domain certificates, a particularly useful practice when managing multiple certificates on your Synology DSM system.

Control Panel → Security → Certificate → Right click the according certificate → Edit → Within the Description: input mask enter the according cryptic folder name → OK

Now your certificate description entry should be made and should look similar to this:

cd into that specific directory and run ls -l, you will see the same .pem files. If you were to upload certificates from other SSL provider, they would be renamed to cert.pem etc. and since we’re importing them from Ubuntu, they simply get uploaded to your NAS.

You already possess a functioning wildcard certificate on your Synology NAS; however, unlike the automated certificate renewal process on your Ubuntu, your Synology NAS lacks such a feature. Let’s address this issue.

Go back to DSM:

 

 and change the SSL description to the name of the folder. Make sure the description is exactly the same as the directory name with six random characters.The directory will contain the following four files:

cert.pem
fullchain.pem
chain.pem
privkey.pem

To achieve an automated certificate renewal process on your Synology NAS, you must establish the corresponding environment via the command line interface.

Regrettably, merely replacing the updated certificate files on your Synology NAS following a certificate renewal process executed on your Ubuntu system is insufficient. Thus, simply copying over the new certificate files would not work. If you investigate further for a reason, you will find the following INFO file, the content of which contains the answer you seek:

cat /usr/syno/etc/certificate/_archive/INFO

It is evident that Synology DSM utilises this file to keep track of the certificate assigned to each application. While it’s possible to manually edit each entry, a script can automate this process (more on that shortly). The script operates by searching for and replacing the relevant certificate, utilising the desc description tag within the INFO file—this corresponds to the description previously established for the certificate in question.

Now, let’s proceed and follow the subsequent steps.

Create a script file called update-cert.sh… using the vi text editor (to save and exit, press Escape key and then type :wq and press enter)

vi /usr/syno/etc/certificate/_archive/update-cert.sh
Paste the following script:
!/bin/bash

UPDCERT_USAGE="Usage: ./update-cert CERT_NAME [--by-id]"

CERTS_ROOTDIR=/usr/syno/etc/certificate/_archive/certs
CERT_NAME=$1
CERT_FILES=(cert.pem fullchain.pem privkey.pem)

if [ -z $CERT_NAME ]; then
echo $UPDCERT_USAGE
exit -1
fi
if [[ ( -n $2 ) && ( $2 != --by-id ) ]]; then
echo $UPDCERT_USAGE
exit -1
fi

CERT_DIR=${CERTS_ROOTDIR}/$CERT_NAME

for CERT_TARGET_DIR in $(python get-cert-dirs.py $CERT_NAME $2); do
for CERT_FILE in ${CERT_FILES[@]}; do
eval "cp ${CERT_DIR}/$CERT_FILE ${CERT_TARGET_DIR}/$CERT_FILE"
eval "chown root:root ${CERT_TARGET_DIR}/$CERT_FILE"
eval "chmod 600 ${CERT_TARGET_DIR}/$CERT_FILE"
done
echo
done

Create a second python script

vi /usr/syno/etc/certificate/_archive/get-cert-dirs.py
Paste the following script
#!/usr/bin/env python

usage = "./get-cert-dirs.py CERT_NAME [--by-id]"

system_dir = "/usr/syno/etc/certificate"
pkg_dir = "/usr/local/etc/certificate"
archive_dir = system_dir+"/_archive"
info_path = archive_dir+"/INFO"

import sys
import json

def parse_info(cert_name, by_description=False):
    certs = json.loads(open(info_path).read())
    if by_description is True:
        cert_id = None
        for key in certs.keys():
            if certs[key]['desc'] == cert_name:
                cert_id = key
                break
        if cert_id is None:
            return None
    else:
        cert_id = cert_name
    try:
        cert_info = certs[cert_id]
    except KeyError:
        return None

    paths = ["\"{}/{}\"".format(archive_dir, cert_id)]
    for service in cert_info['services']:
        root_dir = pkg_dir if service['isPkg'] is True else system_dir
        path = "\"{}/{}/{}\"".format(root_dir, service['subscriber'], service['service'])
        paths.append(path)

    return paths

if __name__ == "__main__":
    wrong_usage = False
    args_num = len(sys.argv) - 1
    if args_num < 1:
        wrong_usage = True
    elif args_num == 2 and sys.argv[2] != "--by-id":
        wrong_usage = True
    elif args_num > 2:
        wrong_usage = True
    if wrong_usage is True:
        print("Usage: "+usage)
        sys.exit(-1)
    cert_name = sys.argv[1]
    by_description = True if args_num == 1 else False
    dirs = parse_info(cert_name, by_description)
    if dirs is not None:
        print(" ".join(dirs))

Now make both scripts executable:

chmod +x /usr/syno/etc/certificate/_archive/update-cert.sh
chmod +x /usr/syno/etc/certificate/_archive/get-cert-dirs.py

Now, create the corresponding directory required for the scripts. Note: It is crucial to replace <myCertificateDescription> with the description text you provided during the certificate import process. The description text must match the corresponding directory name and is case-sensitive.

mkdir -p /usr/syno/etc/certificate/_archive/certs/<myCertificateDescription>
Now, connect to your Linux (in my case, Ubuntu) using SSH.
Create the script in Ubuntu:
# create script directory
mkdir ~/scripts
# create script file vi ~/scripts/renewNASSSH.sh
Copy the following and paste it in the “renewNASSSH.sh”, save and quit (Escape > :wq > Enter).
#!/bin/sh
#
# Copy certificate files to temporary directory on Synology NAS:
#NAS
scp -O /etc/letsencrypt/live/grischke.pro/fullchain.pem [email protected]:/usr/syno/etc/certificate/_archive/certs/ZWP80f/fullchain.pem
scp -O /etc/letsencrypt/live/grischke.pro/privkey.pem [email protected]:/usr/syno/etc/certificate/_archive/certs/ZWP80f/privkey.pem
scp -O /etc/letsencrypt/live/grischke.pro/chain.pem [email protected]:/usr/syno/etc/certificate/_archive/certs/ZWP80f/chain.pem
scp -O /etc/letsencrypt/live/grischke.pro/cert.pem [email protected]:/usr/syno/etc/certificate/_archive/certs/ZWP80f/cert.pem
#NASS
scp -O /etc/letsencrypt/live/grischke.pro/fullchain.pem [email protected]:/usr/syno/etc/certificate/_archive/certs/163sba/fullchain.pem
scp -O /etc/letsencrypt/live/grischke.pro/privkey.pem [email protected]:/usr/syno/etc/certificate/_archive/certs/163sba/privkey.pem
scp -O /etc/letsencrypt/live/grischke.pro/chain.pem [email protected]:/usr/syno/etc/certificate/_archive/certs/163sba/chain.pem
scp -O /etc/letsencrypt/live/grischke.pro/cert.pem [email protected]:/usr/syno/etc/certificate/_archive/certs/163sba/cert.pem
#NASSS
scp -O /etc/letsencrypt/live/grischke.pro/fullchain.pem [email protected]:/usr/syno/etc/certificate/_archive/certs/z0QRrE/fullchain.pem
scp -O /etc/letsencrypt/live/grischke.pro/privkey.pem [email protected]:/usr/syno/etc/certificate/_archive/certs/z0QRrE/privkey.pem
scp -O /etc/letsencrypt/live/grischke.pro/chain.pem [email protected]:/usr/syno/etc/certificate/_archive/certs/z0QRrE/chain.pem
scp -O /etc/letsencrypt/live/grischke.pro/cert.pem [email protected]:/usr/syno/etc/certificate/_archive/certs/z0QRrE/cert.pem
#
# Update certificate on Synology NAS remotely:
ssh [email protected] "sudo /usr/syno/etc/certificate/_archive/update-cert.sh 'ZWP80f'"
ssh [email protected] "sudo /usr/syno/etc/certificate/_archive/update-cert.sh '163sba'"
ssh [email protected] "sudo /usr/syno/etc/certificate/_archive/update-cert.sh 'z0QRrE'"
#
# Delete temporary certificate files:
ssh [email protected] "rm -rf /usr/syno/etc/certificate/_archive/certs/ZWP80f/*"
ssh [email protected] "rm -rf /usr/syno/etc/certificate/_archive/certs/163sba/*"
ssh [email protected] "rm -rf /usr/syno/etc/certificate/_archive/certs/z0QRrE/*"
#
# Reboot Synology NAS:
# ssh [email protected] "systemctl restart nginx"
# ssh [email protected] "systemctl restart nginx"
# ssh [email protected] "systemctl restart nginx"
#
# Optional # ssh [email protected] "sudo reboot now" # ssh [email protected] "sudo reboot now" # ssh [email protected] "sudo reboot now"

With the above script, the last section is commented out. If you want to restart DSM, uncomment restart nginx section, if you have more services, it’s safer to reboot the NAS – for this, uncomment the last three lines instead.