Skip to content

Instantly share code, notes, and snippets.

@blood72
Last active September 27, 2021 13:36
Show Gist options
  • Save blood72/dce243aed9a673aa42bd8b88e0c20dd2 to your computer and use it in GitHub Desktop.
Save blood72/dce243aed9a673aa42bd8b88e0c20dd2 to your computer and use it in GitHub Desktop.
Synology DSM 7 wildcard certificate renewal script without restarting (DS920+)
/bin/python - <<EOF
import os
from sys import exit
from json import load as parse
from filecmp import cmp, clear_cache
# env
DOMAIN = '__YOUR_DOMAIN__'
DEFAULT_CERT_KEY = '__YOUR_CA_DIR__'
ACME_DIR = '__YOUR_ACME_DIR__'
WORK_DIR = '/usr/syno/etc/certificate/_archive'
CERT_DIR = os.path.join(WORK_DIR, DEFAULT_CERT_KEY)
CERT_ORIGIN_PATH = [
'/usr/syno/etc/certificate',
'/usr/local/etc/certificate',
]
CERT_RUNNING_PATH = '/usr/syno/etc/www/certificate'
# copy file if it is different
def copy_file(file, target):
if cmp(file, target):
os.system('echo "already up-to-date: %s"' % target)
return
os.system('/bin/cp %s %s && echo "success to copy: %s"' % (file, target, target))
clear_cache()
# run acme.sh
os.system(' '.join([os.path.join(ACME_DIR, 'acme.sh'), '--cron', '--home', ACME_DIR, '--force']))
# copy renewed certificate
file_map = {
f'{DOMAIN}.key': 'privkey.pem',
f'{DOMAIN}.cer': 'cert.pem',
'ca.cer': 'chain.pem',
'fullchain.cer': 'fullchain.pem',
}
for new_file, old_file in file_map.items():
copy_file(os.path.join(ACME_DIR, DOMAIN, new_file), os.path.join(CERT_DIR, old_file))
# parse INFO
INFO_FILE = os.path.join(WORK_DIR, 'INFO')
if not os.path.isfile(INFO_FILE):
print(f"can't open {INFO_FILE}")
exit(-1)
with open(INFO_FILE) as f:
info = parse(f)
f.close()
if DEFAULT_CERT_KEY not in info:
print(f'{DEFAULT_CERT_KEY} was not found in your system. please check {INFO_FILE}')
exit(-1)
# check original certificate
def check_cert_origin(path):
for cert_dir in CERT_ORIGIN_PATH:
filepath = os.path.join(cert_dir, path)
if os.path.exists(filepath) is True:
return filepath
return False
# check running server certificate
def check_cert_running(path):
filepath = os.path.join(CERT_RUNNING_PATH, path, 'cert.conf')
if not os.path.isfile(filepath):
return []
with open(filepath) as f:
str = f.read()
f.close()
l = str.split()
if len(l) == 0:
return []
return dict(zip(l[::2], map(lambda x: x.rstrip(';'), l[1::2])))
# copy file if it is different
def copy_file(file, target):
if cmp(file, target):
os.system(f'echo "already up-to-date: {target}"')
return
os.system(f'/bin/cp {file} {target} && echo "success to copy: {target}"')
clear_cache()
# get services cert path
dirs = list(map(lambda x: [x['subscriber'], x['service']], info[DEFAULT_CERT_KEY]['services']))
# copy certificate to origin target
cert_files = file_map.values()
for path in map(lambda x: check_cert_origin(os.path.join(*x)), dirs):
for f in cert_files:
copy_file(os.path.join(CERT_DIR, f), os.path.join(path, f))
# copy certificate to running server target
for path in map(lambda x: check_cert_running('_'.join(x)), dirs):
if 'ssl_certificate_key' in path:
copy_file(os.path.join(CERT_DIR, 'privkey.pem'), path.pop('ssl_certificate_key'))
if 'ssl_certificate' in path:
copy_file(os.path.join(CERT_DIR, 'fullchain.pem'), path.pop('ssl_certificate'))
# reload server configuration
os.system('nginx -s reload')
EOF
/usr/syno/bin/synosystemctl reload nginx
@blood72
Copy link
Author

blood72 commented Sep 27, 2021

Basically, manual renewal does not even replace reverse proxy certificates.
/usr/syno/bin/synosystemctl restart nginx copies cert,
but there is a problem that the service is stopped for several minutes by unloading all applications.

I added a function to copy the certificate by searching the SSL certificate path applied to the reverse proxy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment