-
-
Save catchdave/69854624a21ac75194706ec20ca61327 to your computer and use it in GitHub Desktop.
#!/bin/bash | |
# | |
# *** For DSM v7.x *** | |
# | |
# How to use this script: | |
# 1. Get your 3 PEM files ready to copy over from your local machine/update server (privkey.pem, fullchain.pem, cert.pem) | |
# and put into a directory (this will be $CERT_DIRECTORY). | |
# Personally, I use this script (https://gist.github.com/catchdave/3f6f412bbf0f0cec32469fb0c9747295) to automate steps 1 & 4. | |
# 2. Ensure you have a user setup on synology that has ssh access (and ssh access is setup). | |
# This user will need to be able to sudo as root (i.e. add this line to sudoers, <USER> is the user you create): | |
# <USER> ALL=(ALL) NOPASSWD: /var/services/homes/<USER>/replace_certs.sh | |
# 3. Copy this script to Synology: sudo scp replace_synology_ssl_certs.sh $USER@$SYNOLOGY_SERVER:~/ | |
# 4. Call this script as follows: | |
# sudo bash -c scp ${CERT_DIRECTORY}/{privkey,fullchain,cert}.pem $USER@$SYNOLOGY_SERVER:/tmp/ \ | |
# && ssh $USER@$SYNOLOGY_SERVER 'sudo ./replace_synology_ssl_certs.sh' | |
# Script start. | |
DEBUG= # Set to any non-empty value to turn on debug mode | |
error_exit() { echo "[ERROR] $1"; exit 1; } | |
warn() { echo "[WARN ] $1"; } | |
info() { echo "[INFO ] $1"; } | |
debug() { [[ "${DEBUG}" ]] && echo "[DEBUG ] $1"; } | |
# 1. Initialization | |
# ================= | |
[[ "$EUID" -ne 0 ]] && error_exit "Please run as root" # Script only works as root | |
certs_src_dir="/usr/syno/etc/certificate/system/default" | |
services_to_restart=("nmbd" "avahi" "ldap-server") | |
packages_to_restart=("ScsiTarget" "SynologyDrive" "WebDAVServer" "ActiveBackup") | |
target_cert_dirs=( | |
"/usr/syno/etc/certificate/system/FQDN" | |
"/usr/local/etc/certificate/ScsiTarget/pkg-scsi-plugin-server/" | |
"/usr/local/etc/certificate/SynologyDrive/SynologyDrive/" | |
"/usr/local/etc/certificate/WebDAVServer/webdav/" | |
"/usr/local/etc/certificate/ActiveBackup/ActiveBackup/" | |
"/usr/syno/etc/certificate/smbftpd/ftpd/") | |
# Add the default directory | |
default_dir_name=$(</usr/syno/etc/certificate/_archive/DEFAULT) | |
if [[ -n "$default_dir_name" ]]; then | |
target_cert_dirs+=("/usr/syno/etc/certificate/_archive/${default_dir_name}") | |
debug "Default cert directory found: '/usr/syno/etc/certificate/_archive/${default_dir_name}'" | |
else | |
warn "No default directory found. Probably unusual? Check: 'cat /usr/syno/etc/certificate/_archive/DEFAULT'" | |
fi | |
# Add reverse proxy app directories | |
for proxy in /usr/syno/etc/certificate/ReverseProxy/*/; do | |
debug "Found proxy dir: ${proxy}" | |
target_cert_dirs+=("${proxy}") | |
done | |
[[ "${DEBUG}" ]] && set -x | |
# 2. Move and chown certificates from /tmp to default directory | |
# ============================================================= | |
mv /tmp/{privkey,fullchain,cert}.pem "${certs_src_dir}/" || error_exit "Halting because of error moving files" | |
chown root:root "${certs_src_dir}/"{privkey,fullchain,cert}.pem || error_exit "Halting because of error chowning files" | |
info "Certs moved from /tmp & chowned." | |
# 3. Copy certificates to target directories if they exist | |
# ======================================================== | |
for target_dir in "${target_cert_dirs[@]}"; do | |
if [[ ! -d "$target_dir" ]]; then | |
debug "Target cert directory '$target_dir' not found, skipping..." | |
continue | |
fi | |
info "Copying certificates to '$target_dir'" | |
if ! (cp "${certs_src_dir}/"{privkey,fullchain,cert}.pem "$target_dir/" && \ | |
chown root:root "$target_dir/"{privkey,fullchain,cert}.pem); then | |
warn "Error copying or chowning certs to ${target_dir}" | |
fi | |
done | |
# 4. Restart services & packages | |
# ============================== | |
info "Rebooting all the things..." | |
for service in "${services_to_restart[@]}"; do | |
/usr/syno/bin/synosystemctl restart "$service" | |
done | |
for package in "${packages_to_restart[@]}"; do # Restart packages that are installed & turned on | |
/usr/syno/bin/synopkg is_onoff "$package" 1>/dev/null && /usr/syno/bin/synopkg restart "$package" | |
done | |
# Faster ngnix restart (if certs don't appear to be refreshing, change to synosystemctl | |
if ! (/usr/syno/bin/synow3tool --gen-all && sudo systemctl reload nginx); then | |
warn "nginx failed to restart" | |
fi | |
info "Completed" |
Do you think this is important restart that package once the certificate is changed?
I'm not convinced that those apps need to be restarted; As a check, I'd recommend you try the scripts with service_to_restart
and packages_to_restart
empty, as well as emptying target_cert_dirs
and then run this script once everything is done. It will identify the folders you need to add back to target_cert_dirs
that weren't handled by the synology OS and then you'll be able to populate the target folders and the packages / services to restart based only on those that it finds. Then you can test those apps you depend on to ensure they're working properly.
regarding your SSH login, you should be able to use import your public SSH key from the host you're copying FROM into the ~/.ssh/authorized_keys
file on your synology (whichever user you're logging in as) and use key authentication which won't require a password prompt.
For example, if you're copying the files from linuxhost
as user bob
:
login to linuxhost
as bob
and copy the contents of the file ~/.ssh/id_rsa.pub
If you're logging INTO the admin
user of the synology:
login to synology as admin
and edit the file ~/.ssh/authorized_keys
paste the contents from bob
's public key into the bottom of the authorized_keys
file (should be a single line, don't add any additional line breaks etc)
then when you attempt to ssh into the synology from linuxhost
it should use the key instead of a password prompt. Do it manually the first time for a prompt to add the machine to known_hosts
and then once it's done, you won't have to use a password any more.
I added the script I use to renew my ssl and copy the cert everywhere here: https://gist.github.com/catchdave/3f6f412bbf0f0cec32469fb0c9747295
Could be a useful starting place for folks to create their own (won't be usable out of the box, since you will have different combinations services & servers). This specific one is controlled by a cronjob on the server that plex runs on.
Do you think this is important restart that package once the certificate is changed?
I'm not convinced that those apps need to be restarted; As a check, I'd recommend you try the scripts with
service_to_restart
andpackages_to_restart
empty, as well as emptyingtarget_cert_dirs
and then run this script once everything is done. It will identify the folders you need to add back totarget_cert_dirs
that weren't handled by the synology OS and then you'll be able to populate the target folders and the packages / services to restart based only on those that it finds. Then you can test those apps you depend on to ensure they're working properly.regarding your SSH login, you should be able to use import your public SSH key from the host you're copying FROM into the
~/.ssh/authorized_keys
file on your synology (whichever user you're logging in as) and use key authentication which won't require a password prompt.For example, if you're copying the files from
linuxhost
as userbob
: login tolinuxhost
asbob
and copy the contents of the file~/.ssh/id_rsa.pub
If you're logging INTO theadmin
user of the synology: login to synology asadmin
and edit the file~/.ssh/authorized_keys
paste the contents frombob
's public key into the bottom of theauthorized_keys
file (should be a single line, don't add any additional line breaks etc)then when you attempt to ssh into the synology from
linuxhost
it should use the key instead of a password prompt. Do it manually the first time for a prompt to add the machine toknown_hosts
and then once it's done, you won't have to use a password any more.
Thank you very much for the quality of your answer telnetdoogie!
I managed to make passwordless work very well and I finally did my own script to replace the certificate on the synology because my need was not to replace the default certificate for everything, but just to replace the one I use only for synology drive because the port 6690 used by drive cannot be proxied by nginx since it is not a https protocol. So for this port, I do a port forwarding while all the rest is going through my nginx server which has the certbot certificate automatically renewed. This explain why I needed a script to send the certificate to the NAS each time it is renewed on the nginx.
So my need was just to use this certificate for drive and let the default one for all the rest.
I do the same with my firewall which is also used for the SSL vpn. I used a script that use the API of the firewall to send and update the certificate to it each time it is renewed on the nginx.
Thank you for the great job that has been made here. It helped me a lot!
Here is my script if it can help anyone.
So first I have manually uploaded a certificate in to the synology so that it creates the cert folder name which is using random characters. I also configure "Synology Drive Server" to use this certificate so that the link is made on the system.
Then, I just update the script to use that folder name and the script just update the cert and restart the "Synology Drive" service.
I made another script on the nginx that do the action of copying and executing that script into the synology NAS.
In my case too it was enough to run the synow3tool and do an nginx restart, thanks for the hints.
My script to find the correct folder and an opportunity to check nginx config before restarting the server:
cp ~/certs/* /usr/syno/etc/certificate/_archive/$(cat /usr/syno/etc/certificate/_archive/DEFAULT)
/usr/syno/bin/synow3tool --gen-all
nginx -t
read -p "nginx config ok?"
systemctl restart nginx
Hi Catchdave,
I'm looking for a solution for my DS1010+ with DSM 5.2-5967 Update 9.
I found many article on the net but nothing help me until yet.
Maybe you have already an idee.
Best Regards
DJG.
Hi Catchdave,
I'm looking for a solution for my DS1010+ with DSM 5.2-5967 Update 9. I found many article on the net but nothing help me until yet.
@DJGauthier : I have never had a system with 5.x OS so I simply don't know what it looks like. Fundamentally, you simply need to find where the SSL certs are stored and then find out the right way to restart associated services to use the new certs when you upload them. Perhaps the locations are similar to the 6.x version of this (look at the gist's history). You can probably easily find certs using a find
command once you SSH in.
I don't know where you are getting that error from, or what the context is. So I can't really work off just that error (is it on the browser, on the synology box, elsewhere). You could also consider upgrading your OS. version 5.x is a 8 years old.
@DJGauthier It appears you're running into a port forwarding issue. Have you been able to renew certs successfully using the Synology UI? The address you're using - [mysyno].synology.me
will point to your public WAN IP, so you're unlikely to be able to test that locally unless you're doing some hairpin NAT rules on your router. I'd start with validating that LetsEncrypt certificates can be generated via the UI on the Synology NAS before you try to use scripts to do the same.
Alternatively you could switch to certbot using DNS-01 challenge instead of HTTP-01 to avoid the need to have ports open and forwarded. More info here:
Hi,
Is it necessary to reboot all the services? As the script restarts all the services, docker and virtual machines that are running on the synology are affected.
I guess, some of Step 4. "Rebooting all the things..." can be disabled by default ?
I am not sure—this was the easiest method to make sure everything works. Feel free to experiment :)
You definitely need to restart any web servers serving the cert (so nginx at least).
Is it necessary to reboot all the services?
It's not, unless you have a service specifically that seems to need it.
For me, simply running:
/usr/syno/bin/synow3tool --gen-all
/usr/syno/bin/synow3tool --nginx=reload
and /usr/syno/bin/synow3tool --restart-dsm-service
...refreshes certs for DSM and Reverse Proxy setups with no need to bounce apps (like docker, which takes a long time and is disruptive if runnning network services in containers)
I use Caddy Web Server as my reverse proxy running inside Container Manager (Docker) on my Synology DSM. Caddy is also great as a certificate manager.
Inspired by you and your code (all of you here), I wrote my own script synology-cert-deploy.sh which takes only the private key and full certificate chain files as input, since those are the only two TLS files coming from Caddy, and deploys them to Synology DSM. As long as it has the new private key and full chain, it can extract all the remaining files from these two files.
On DSM 7.2-64570 Update 1, the script will update the certificates (as verified by the Certificate tab of the Security applet in the Control Panel), but fail to restart the DSM webserver which runs on port 5001 for me.
Manually issuing the /usr/syno/bin/synow3tool --nginx=reload
command seemed to do the trick, though.
Hi,
I installed this script and when running it everything seems fine.
The certificate in the control panel is updated. But when browsing to the DSM webserver on port 5001 it keeps showing the old certificate.
I already rebooted the device, but keeps showing the old certificate.
What am I missing?
Thanks.
@Daermegil check in the Certificates pane in DSM and see if you have one certificate set up, and make sure it's this one. It is possible to have multiples and assign a different one to DSM.
@telnetdoogie thank you for your quick reply.
I do have 2 certificates, one is my actual certificate. The other one is for quickconnect, but I can't delete that one. I also don't think it is the one causing problems.
But I think I see the problem. The certificate I'm using is RSA, but the old one from synology is RSA/ECC. The webserver is probally using ECC I guess, because the file ECC-cert.pem is still my old certificate. I'm just going to reset the certificates and readd them. But I have reached my request limit so I'll have to wait a bit.
@Daermegil RSA is fine; that's what I'm using too... I did see in my notes that I needed to manually import the LE certificates into DSM before the automation worked reliably.
When you're prompted for Private Key that's the privkey.pem
file. When you're prompted for the Certificate that's cert.pem
. When prompted for the Intermediate Certificate that's fullchain.pem
.
DSM does accept certs without adding the intermediate cert, but it causes some things to fail.
Try manually adding those and see if that works for you. Once the manual add works, the automation should also work.
I think from my memory, if you upload the wrong files (and it'll still appear to work sometimes) in the wrong inputs, it will actually rename things on the filesystem but when the automation works, it's now updating the wrong files. I'm not stating that right but I definitely had some weirdness early on because I wasn't providing the Intermediate cert; instead I was using fullchain.pem
as the Certificate file, which gave me issues with VPN, for example.
@telnetdoogie I added a RSA only certificate and replaced it using the script, everything seems to work brilliantly now!
Thanks for the help!
This appears to miss all "WebStation" pages for me.
I added
# Add WebStation directories
for webstation in /usr/local/etc/certificate/WebStation/*/; do
debug "Found WebStation dir: ${webstation}"
target_cert_dirs+=("${webstation}")
done
But those then weren't re"compiled" into the correct folders nginx uses, so I wrote
# somehow WebStation ends up not getting applied later, so lets manually do it (if it works later it will simply get overwritten)
for ws in /usr/syno/etc/www/certificate/WebStation_*/; do
info "Copying WebStation certificates to '$ws'"
ws_crt=$( grep -o "$ws"cert.conf -Pe '(?<=ssl_certificate\s)\s*.*(?=;$)' | xargs )
ws_key=$( grep -o "$ws"cert.conf -Pe '(?<=ssl_certificate_key\s)\s*.*(?=;$)' | xargs )
ln -f "${certs_src_dir}/"fullchain.pem "$ws_crt"
ln -f "${certs_src_dir}/"privkey.pem "$ws_key"
done
which appears to be sufficient. I still had to add nginx -s reload
to get changes to show up.
Is this really the only way to do this?
In the process I grepped through my /usr
and also saw my cert ended up in /usr/local/etc/certificate/LogCenter/pkg-LogCenter/
somehow, so it might be good to add that path as
target_cert_dirs=(
[...]
"/usr/local/etc/certificate/LogCenter/pkg-LogCenter/")
# Faster ngnix restart (if certs don't appear to be refreshing, change to synosystemctl
if ! /usr/syno/bin/synow3tool --gen-all && sudo systemctl reload nginx; then
warn "nginx failed to restart"
fi
The above lines should change to
if ! /usr/syno/bin/synow3tool --gen-all; then
warn "nginx failed to generate config"
fi
info "Restart nginx"
# Faster ngnix restart (if certs don't appear to be refreshing, change to systemctl restart)
systemctl reload nginx
Otherwise, systemctl reload nginx
will not be executed.
Otherwise,
systemctl reload nginx
will not be executed.
@xiaozhuai: I'm not sure I understand how the above is true (or why you want to separate out the two commands). The intent is that we do not restart if the certs did not generate correctly and instead issue a warning.
systemctl reload nginx
will be executed if and only if the synow3tool --gen-all
command is executed correctly, which is the intent of the original code.
Could you provide an example where this does not work as intended?
Could you provide an example where this does not work as intended?
@catchdave
That's odd.
I try this script on my machine last time and foud the second command never exec.
And I'm sure the /usr/syno/bin/synow3tool --gen-all
is ok.
Confirmed, the script is wrong. You can try below.
#!/usr/bin/env bash
if ! true && echo "Good"; then
echo "Not good"
fi
It prints nothing.
It should be
#!/usr/bin/env bash
if ! (true && echo "Good"); then
echo "Not good"
fi
And it prints Good
.
So the script should change to
# Faster ngnix restart (if certs don't appear to be refreshing, change to systemctl restart)
if ! (/usr/syno/bin/synow3tool --gen-all && systemctl reload nginx); then
warn "nginx failed to restart"
fi
Thanks --you are right, it should have parenthesis! I updated the script. Appreciate the suggestion, @xiaozhuai
Hello @catchdave. Nice script! I want to test it. But I have DS218+ where in all certs directories are not just 3 files which is copied by your script.
There are these structure:
cert.pem chain.pem fullchain.pem info privkey.pem root.pem short-chain.pem
I can create cert.pem chain.pem fullchain.pem privkey.pem
But I haven't idea about root.pem short-chain.pem.
Do you have same structure? Or is it something new? How to solve it? Thx for info.
@raven2cz my advice is to initially manually add your LE cert and make it default. Through the DSM interface, the mapping of LE generated files is:
Private Key ---------------> privkey.pem
Certificate ---------------> cert.pem
Intermediate Certificate --> fullchain.pem
Once that's done and the LE cert is now your default certificate, the script should work fine.
It was too beautiful to be real... When I execute the script, it reset (hard reboot) all my VMs running on VMM which is a big problem for me :(
I see that footswitch is mentioning using "reload" for nginx but this is already implemented on the script provided by catchdave.
I any case, I tried commenting this on the script but it still resetting all VMs.
I found out that this is the restart of the package ScsiTarget that do it...
Do you think this is important restart that package once the certificate is changed?
If you have any idea , I would be very grateful since this issue is blocking me to use this amazing script.