Page 1 of 1

[HowTo] Embedded N4F auto renew SSL certs + web UI + syncthing UI

Posted: 04 Oct 2017 19:28
by faust
I wanted to use ( to generate my internal SSL certificates with Let's Encrypt using the ACME protocol. I also wanted to automate the renewal said certs and use them with the web UI (lighttpd) and with the syncthing UI on my embedded N4F system. I've summarized my method below. The rough procedure is as follows:

- Installing packages on embedded system
- Meeting prereqs for
- Running and scheduling with cron
- Importing the certs for the web UI and syncthing

Firstly, requires wget or curl so making packages persistent on an embedded system is required. Several tutorials describe using unionfs to manage this process which I've followed. I have an encrypted UFS partition called "sysdata" which holds this kind of files. So on the sysdata partition, I created empty /usr/local and /var/db/pkg paths so, once sysdata is mounted, the paths are:

Code: Select all


Note that there are some reported issues in other threads when using unionfs in this way. From what I've read, these problems are caused by mounting on /var only (rather than the full /var/db/pkg path). Apparently all that is needed in /var is the pkg databases (as /var/db/pkg/local.sqlite appears to maintain information about installed packages). I do have similar concerns about mounting all of /usr/local as, for instance, /usr/local/www is the lighttpd document root and thus contains all of the files for the web UI. So a fair caution is given to the reader on this point.

The unionfs paths are mounted with a postinit script:

Code: Select all


mount_unionfs -o w /mnt/sysdata/unionfs/usr/local /usr/local
mount_unionfs -o w /mnt/sysdata/unionfs/var/db/pkg /var/db/pkg
mount_unionfs -o w /mnt/sysdata/unionfs/acme /home/acme

This runs immediately after my postinit script which mounts my encrypted volumes (further details: viewtopic.php?f=67&t=11930). Note that I also use unionfs to mount an acme home directory (more on that shortly).

After mounting the /usr/local and /var/db/pkg paths with unionfs as per the postinit script, I installed wget with the following commands:

Code: Select all

pkg update
pkg search wget
pkg install wget-1.19.1

I created an unprivileged user, acme, to run which does all of its work in the users home directory. Since I keep such system data on encrypted volumes, I once again used unionfs to mount the acme users home directory. This allows me to keep these files encrypted without changing how I use/partition sysdata and provides some logical consistency with how I manage persistence of certain files.

After that, I logged in with the acme user, ran using wget (as per the instructions on the github page) and generated certs according to my specification. Since supports the DNS API of my (crappy) registrar, that's how I generate my certs. As per the following script:

Code: Select all



$ACME_WD/ --issue --dns dns_gd -d $CERT_HN --force

I set this script to run with cron (web UI: System > Advanced > Cron), as the acme user every 2 months (Let's Encrypt certs expire after 90 days).

The only thing that remains is copying the cert/key over so that they're used by services of interest. In this case, by lighttpd (for the web UI), and syncthing (for its own web UI).

After some digging through the guts of the web UI, I found that /etc/inc/ and /etc/inc/ had what I needed to deploy the cert. This next PHP script reads the cert and key generated by, checks their validity and, if new, saves them to the config file and over the syncthing https cert and key. It then restarts lighttpd and syncthing.

Code: Select all



require_once '';

# Paths to acme files
$acme_path = "/home/acme/";
$acme_domain = "hostname.domain.tld";
$acme_cert_path = "{$acme_path}{$acme_domain}/{$acme_domain}.cer";
$acme_key_path = "{$acme_path}{$acme_domain}/{$acme_domain}.key";

# Read the acme cert
$acme_file = fopen($acme_cert_path, "r");
$acme_cert = fread($acme_file, filesize($acme_cert_path));

# Read the acme key
$acme_file = fopen($acme_key_path, "r");
$acme_key = fread($acme_file, filesize($acme_key_path));

# Check validity of cert and key
$valid_cert = is_valid_certificate($acme_cert);
$valid_key = is_valid_privatekey($acme_key,"RSA");

# Check if cert and key are new
$isnew_cert = (base64_encode($acme_cert) != $config['system']['webgui']['certificate']);

# Import cert if cert/key are valid and cert is new
if ($valid_cert && $valid_key && $isnew_cert):

	echo "PHP acme cert import: Importing new certificate..." . PHP_EOL;
	echo " - $acme_cert_path" . PHP_EOL;

	# Write cert to config
	$config['system']['webgui']['certificate'] = base64_encode($acme_cert);
	echo " - $acme_key_path" . PHP_EOL;

	# Write key to config
	$config['system']['webgui']['privatekey'] = base64_encode($acme_key);
	echo " - Writing to config.xml" . PHP_EOL;

	# Commit to config file

	# Syncthing: copy certs and restart
	echo " - Copying cert/key to syncthing directory" . PHP_EOL;
	exec("cp {$acme_path}{$acme_domain}/{$acme_domain}.cer {$syncthing_dir}https-cert.pem");
	exec("cp {$acme_path}{$acme_domain}/{$acme_domain}.key {$syncthing_dir}https-key.pem");
	exec("chown syncthing:syncthing {$syncthing_dir}https-cert.pem");
	exec("chown syncthing:syncthing {$syncthing_dir}https-key.pem");
	echo " - Restarting syncthing" . PHP_EOL;
	exec("service syncthing stop");
	exec("service syncthing onestart");

	# Restart lighttpd
	echo " - Restarting lighttpd" . PHP_EOL;
	exec("/etc/rc.d/lighttpd restart");

# Don't import cert if invalid or isn't new
	echo "PHP acme cert import: Not importing cert/key." . PHP_EOL;
	if (!$valid_cert): echo " - Invalid certificate : $acme_cert_path" . PHP_EOL; endif;
	if (!$valid_key): echo " - Invalid private key : $acme_key_path" . PHP_EOL; endif;
	if (!$isnew_cert): echo " - Certificate already in use : $acme_cert_path" . PHP_EOL; endif;


I set this script up with cron to run as root every week. This means that roughly 90% of the time, it just looks at the same old certs, notes that they haven't changed, and does nothing.

When lighttpd is started, the rc.d script copies the SSL cert and key (if applicable) directly from the config file and saves them to /var/etc/cert.pem. This means that the cert/key can't simply be copied to the correct location followed by a restart of lighttpd. Also, if the cert/key is entered in the web UI manually and saved, the new cert is not loaded and the user is prompted that a restart is required (in order to restart lighttpd). This avoids the need for a restart.

Note that syncthing is started with the "onestart" argument instead of "start" because I don't have syncthing enabled in the config file. Since my syncthing system files are stored on an encrypted UFS partition, I start syncthing manually with a postinit script after all encrypted partitions (and unionfs directories) are mounted and stop it manually with a shutdown script before unmounting all such systems.

Re: [HowTo] Embedded N4F auto renew SSL certs + web UI + syncthing UI

Posted: 08 Oct 2017 15:07
by tony1
you could probably set the cert location using the "Additional Parameters" section of the webserver.
just an idea?

Re: [HowTo] Embedded N4F auto renew SSL certs + web UI + syncthing UI

Posted: 17 Dec 2017 14:27
by jerryone
hmm, it is possible to make a video tutorial of what is in here? i have tray to do this in a virtual machines and the result was not what i have expected. may i have jump steps, but i have tray two times and nothing happend with this SSL cert install. i am quite a new to this kind off line write and freebsd servers!!! thanks ! or i don't know may by click on this after u see this click and copy this... for the stupid guys that are tray to do and understand! many thanks !

Re: [HowTo] Embedded N4F auto renew SSL certs + web UI + syncthing UI

Posted: 17 Dec 2017 18:06
by raulfg3
ideally, this procedure must be installed by OBI to share it with all users.

any volunteers?.

Re: [HowTo] Embedded N4F auto renew SSL certs + web UI + syncthing UI

Posted: 14 Mar 2018 10:38
by sherman
Let's Encrypt is such a great additon to the world of the Internet.
But I wonder why there is so less enthusiam here in the forum about it. Rarely thread or tutorial like this one.
Is Nas4free more or less a dead project and only for nerds?
It would be so nice if normal dads coudl benefit from Nas4Free and an easy way to use auto updating SSL certs.
Obi ?

Re: [HowTo] Embedded N4F auto renew SSL certs + web UI + syncthing UI

Posted: 14 Mar 2018 11:18
by raulfg3
+1 to add to OBI.

But actually there are a few developers and are focused on other things.

Re: [HowTo] Embedded N4F auto renew SSL certs + web UI + syncthing UI

Posted: 14 Mar 2018 16:37
by hc221
Hey Guys, I made a setup with virtualbox and a Ubuntu nginx Server in there. On this way it was easy to implement letsencrypt to a dedicated Server which has no impact on local nas4free setup. Could be a solution.

Re: [HowTo] Embedded N4F auto renew SSL certs + web UI + syncthing UI

Posted: 01 Feb 2019 16:27
by HenriM

It would be nice that you can 'just' configure a file-location to the Certificate and Private Key. This way you would only need to update this file-location for e.g. the Let's Encrypt certificates. In case XigmaNAS detects a difference it knows that it should restart the web-server (without need of completely restarting the whole server).

Small side-note. Just found out that for private key you need next header/footer:


Mind the RSA part which is normally not present in the private key of Let's Encrypt. This should thus also be taken into account.