User Tools

Site Tools


Synology: Import wildcard certificate from pfSense plus certificate renewal automation with Tux

Hey, my name is "Tux"! Did you ever wonder how you can import pfSense's wilcard certificate into your Synology NAS and set up an automated certificate renewal process?

Hey, my name is "Tux" and this tutorial will show you how you can avoid using Synology's limited wildacrd certificate service and how to take advantage of a centralized, fully automated wildcard certificate renewal management when using the acme package within pfSense.

First thoughts


This tutorial is based on:
  • Synology DSM 6.2.3
  • Netgate pfSense 2.4.5 with ACME 0.6.8 package

Important note!

This tutorial assumes you have already set up a wildcard certificate including automated renewal process by using pfSense's acme package. If you don't know how to do this from scratch I would strongly recommend this german or english tutorials, both of them do provide great informations about how to start creating certificates by using pfSense's acme package from scratch.

Please be aware that a default wildcard certificate *, created by Let's Encrypt certificate service (which pfSense's acme package is using) does only cover the domain including its prefixes such as

and so on, but not the main domain itself such as

If you want to cover all domain prefixes including the main domain itself (which I'd highly recommend!), you have to add just both entries on the according certificate inside pfSense's acme package as shown below:

pfSense wildcard settings

In addition please be aware that no matter which official CA you are using, in most cases * also does not cover multiple domain prefixes exceeding a domain's 3rd-level-label such as

Additionally this tutorial assumes you have set up SSH root-access with public authentication key from pfSense to your Synology NAS for automated and unattended access. If you have not set up this already, please do it by referring to this tutorial first and then to this tutorial.

Please note that this tutorial also assumes you have your Synology NAS up and running 24/7. Otherwise a reliable automated certificate renewal process cannot be guaranteed.

Start of tutorial

As you are aware of the information box above we move to practice now.

Let's begin!

Step 1: Initial certificate export/import

First, login into your pfSense web interface and navigate to:

SystemCert. ManagerCertificates

From here, as shown on the screenshot below, you have to export your certificate file (1) and the according public key file (2) temporarly onto your local computer:

Export pfSense certificate file (1) and private key file (2)

Now you should have the following two files stored on your local computer:

  1. <myDomain>.cer
  2. <myDomain>.key
Exported certificate files

Now login into your Synology NAS' web interface. From there do the following steps to import the exported certificate files:

Control PanelSecurityCertificateAdd → Choose Add a new certificateNext → Choose Import certificate and add a proper short description (important, do not leave the description empty (explanation later on)!) such as <myDomain>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

Add a description!
Choose the according files

Your certificate should now show up similar to this:

Import succeeded!

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

Now open a terminal on your local computer and SSH with root user into your Synology NAS by executing:

$ ssh -p "<mySynologySSHPort>" root@<mySynologyIPAddress>

From there, execute the following command to navigate to the directory where Synology DSM stores all its certificates:

$ cd /usr/syno/etc/certificate/_archive/

Now execute:

$ ls -l

Any certificate installed on your Synology NAS holds its own directory named by a string containing six random characters similar to H6QDpY. So if you have multiple certificates installed on your Synology NAS, therefore multiple directories will show up. To check which one holds the recent imported certificate, just check the according creation date which matches the time you have imported the certificate:

Date check

Now cd into that specific certificate directory…

$ cd <myCertificateDirectory>/

..and execute a list command again:

$ ls -l

As you can see there are the following three files stored inside the directory:

  • cert.pem
  • fullchain.pem
  • privkey.pem

Note that the original files were fully renamed to static names (yes, the files were just renamed and not converted as the original files were already formatted as ASCII code), the file type changed to .pem and there is even an additional file called fullchain.pem being created automatically by Synology DSM's certificate import process.

Now the initial certificate import/export process has finished. You already have a working wildcard certificate on your Synology NAS now but unfortunately, unlike your pfSense's automated certificate renewal process, there is none existing on your Synology NAS yet.
We'll change that.

Step 2: Synology scripts and configuration

To accomplish an automated certificate renewal process on your Synology NAS you now have to create the accoring environment on your Synology NAS by command line interface.

Unfortunately it is not enough to just replace the updated certificate files on your Synology NAS after a certificate renewal process has been executed on your pfSense system. Therefore, to just copy over the new certificate files would not be a solution that would work. If you'd dive a little deeper into looking for a reason, you'll notice the following INFO file which its content holds the answer you are looking for:

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

You can see now that Synology DSM is using this file to store its information about which certificate is assigned to which application(s). Of course you could adjust every single entry manually but thanks to this guy you can just use a script for that (we'll get to that in a minute). The script is searching/replacing the according certificate by using the description tag desc inside the INFO file, so this was the reason why it was so important to set a proper short description previously and to not leave it empty.

Now let's move on and follow further steps.

Create a script file called

$ vi /usr/syno/etc/certificate/_archive/

…and paste the following content (don't change anything, just copy and paste!):


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

CERT_FILES=(cert.pem fullchain.pem privkey.pem)

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


for CERT_TARGET_DIR in $(python $CERT_NAME $2); do
  for CERT_FILE in ${CERT_FILES[@]}; do
	eval "chown root:root ${CERT_TARGET_DIR}/$CERT_FILE"
	eval "chmod 600 ${CERT_TARGET_DIR}/$CERT_FILE"

Save the file and quit the editor.

Now create a script file called

$ vi /usr/syno/etc/certificate/_archive/

…and paste the following content (don't change anything, just copy and paste!):

#!/usr/bin/env python

usage = "./ 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
        if cert_id is None:
            return None
        cert_id = cert_name
        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'])

    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)
    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))

Save the file and quit the editor.

Now make both scripts executable:

$ chmod +x /usr/syno/etc/certificate/_archive/
$ chmod +x /usr/syno/etc/certificate/_archive/

Now create the according directory, needed for the scripts.
Note: It is important to replace <myCertificateDescription> with the description text you have set on the certificate import process. The description text has to match the according directory name and is case sensitive!)

$ mkdir -p /usr/syno/etc/certificate/_archive/certs/<myCertificateDescription>

Step 3: pfSense script and configuration

Now, from your local computer, SSH with admin user into your pfSense system. From there, create the following directory:

$ mkdir ~/scripts

Now, inside that directory, you have to create a script file, which will copy the required certificate files unattended and immediately whenever they are being updated automatically by pfSense's acme package. Just create the script and give it a proper custom name <mySciptFile>.sh (I called mine copy<myDomain>

$ vi ~/scripts/<mySciptFile>.sh

Now paste the following content and adjust the according place holders (please note, as already mentioned previously, the following script does not have to convert any of the files before copying over because the original files are already coded as ASCII, therefore some simple file renaming commands will do the job right):

scp -P <mySynologySSHPort> /conf/acme/<myCertificate>.crt root@<mySynologyIPAddress>:/usr/syno/etc/certificate/_archive/<myCertificateDirectory>/cert.pem
scp -P <mySynologySSHPort> /conf/acme/<myCertificate>.key root@<mySynologyIPAddress>:/usr/syno/etc/certificate/_archive/<myCertificateDirectory>/privkey.pem
scp -P <mySynologySSHPort> /conf/acme/<myCertificate>.fullchain root@<mySynologyIPAddress>:/usr/syno/etc/certificate/_archive/<myCertificateDirectory>/fullchain.pem
scp -P <mySynologySSHPort> /conf/acme/<myCertificate>.crt root@<mySynologyIPAddress>:/usr/syno/etc/certificate/_archive/certs/<myCertificateDescription>/cert.pem
scp -P <mySynologySSHPort> /conf/acme/<myCertificate>.key root@<mySynologyIPAddress>:/usr/syno/etc/certificate/_archive/certs/<myCertificateDescription>/privkey.pem
scp -P <mySynologySSHPort> /conf/acme/<myCertificate>.fullchain root@<mySynologyIPAddress>:/usr/syno/etc/certificate/_archive/certs/<myCertificateDescription>/fullchain.pem
ssh -p <mySynologySSHPort> root@<mySynologyIPAddress> "sudo /usr/syno/etc/certificate/_archive/update-cert '<myCertificateDescription>'"
ssh -p <mySynologySSHPort> root@<mySynologyIPAddress> "sudo reboot now"

Important notes!

Restarting services

Be aware that the last script line will reboot your Synology NAS immediately. This will make sure all of your applications are being reliably restarted after every certificate renewal process which is necessary to get the new certificate applied to the application(s). Instead of rebooting the whole Synology DSM system you could also restart every according application service. You can find out all installed application services by executing the following command on your Synology NAS:

$ synoservicecfg -list

So instead of

ssh -p <mySynologySSHPort> root@<mySynologyIPAddress> "sudo reboot now"

your last script line(s) could look similiar to:

ssh -p <mySynologySSHPort> root@<mySynologyIPAddress> "sudo /usr/syno/sbin/synoservice --restart nginx"
ssh -p <mySynologySSHPort> root@<mySynologyIPAddress> "sudo /usr/syno/sbin/synoservice --restart pkgctl-Apache2.4"
ssh -p <mySynologySSHPort> root@<mySynologyIPAddress> "sudo /usr/syno/sbin/synoservice --restart pkgctl-CardDAVServer"

Setting a reboot timer

Certificates are not being renewed a second before they exceed. Therefore it is not necessary to reboot your Synology NAS or restart the according service(s) immediately after the files have been copied over to your Synology NAS because the old ones would still be valid for a while. So if you want to wait until a specific time of day to reboot your Synology NAS or to restart the according service(s) (in my case 23:59) you are free to add the following script code right before the reboot command:

while [ $(date +%H:%M) != "<myRebootTime>" ];
	do sleep 1;


while [ $(date +%H:%M) != "23:59" ];
	do sleep 1;
ssh -p <mySynologySSHPort> root@<mySynologyIPAddress> "sudo reboot now"

In general please feel free to adjust the script according to your requirements!

Save the file and quit the editor.

Now make the script executable:

$ chmod +x ~/scripts/<mySciptFile>.sh

Almost finished now! The very good news is on pfSense's acme package which allows you to execute any desired script immediately after an acme certificate renewal process. On pfSense's web interface do:

SystemCert. ManagerCertificates → Click the edit button on <myCertificate> → Scroll down to Actions list, click + Add and enter the path to your script as shown below:

Activate script automation!

Click onSave and you're done! To test the functionality you want to start a certifiacte renewal process manually:
On pfSense's web interface navigate to:

ServicesAcme certificates → Click on Renew by the according certificate

Final notes!

  • If you have multiple domains for which you want to automate the certificate renewal process just use a script per domain. You should avoid puttig all together in one script which makes management easier in my personal opinion.
  • Please remember to backup all of your customized scripts in case you need so set up this environment again for whatever reason!

End of tutorial

synologyimportcertfrompfsense.txt · Last modified: 2020/11/03