Self-signed certs for internal network devices

I have enough crap on my home network that clicking through the warnings on webpages is a fuss. Of course, so is installing a private root cert on all my servers but doing so has a few advantages.

  1. It’s neater than not doing
  2. I can choose which devices I install the root cert on. Those should be the machines from which I expect to actually interact with home network decives. So any work machines should not get the cert. Personal machines should.
  3. Which has the added advantage of reminding me that I’m not using the right machine when I get alerts.

The point here isn’t to increase security in any dramatic way. In practice, having a root cert installed on machines is something of a liability as it could be used to sign other things and any certificate signed with this key would be accepted by my browser so someone could use it to fool me into visiting faked sites. It actually is important that it’s kept secure. So, offline on a USB key. This is more about keeping things in my home network neat and tidy. All my externally facing machines get LetsEncrypt certs.

So here’s the process:

1. Create a certificate authority

This will have to be installed to the certificate store on any machine I want to not pop errors 1. create a private key 2. self-sign 3. install root CA on machines

2. Create client certificates (CSR)

3. Sign CSR with root CA key

4. Install CSRs to servers

Creating the root certificate

I followed this guide. This only has to be done once.

Create the root key

On a machine with OpenSSL / LibreSSL etc.:

openssl genrsa -aes256 -out [domain.tld].rootCA.key 2048

This will create a key prompting for a password to encrypt it with aes256.

Create root certificate signed with the root key

openssl req -x509 -new -nodes -key [domain.tld].rootCA.key -sha256 -days 1024 -out [domain.tld].rootCA.pem

This creates a certificate, signed by itself (or the root key at least), valid for 1024 days. This will act as our root certificate.

Install the new root certificate to relevant machines


Open Keychain and use the import items menu option to import the certificate. It will be imported as a login item which should be sufficient most of the time. To add the certificate to the system store (so that all users will receive it) change the destination store using the options button in the import dialogue. Once installed, double click the certificate and in the trust section, set it to trusted.

Create device certificates

openssl genrsa -out [device.fqdn.tld].key 2048
openssl req -new -key [device.fqdn.tld].key -out [device.fqdn.tld].csr
openssl x509 -req -in [device.fqdn.tld].csr -CA [device.fqdn.tld].rootCA.pem -CAkey [device.fqdn.tld].rootCA.key -CAcreateserial -out [device.fqdn.tld].crt -days 728 -sha256

Depending on the device, it will require the key and the CRT to be uploaded or for them to be combined in a pem file. If the combination is required, the two can simply be concatenated:

cat hostname_example_com.key hostname_example_com.crt > server.pem

Installing device certificates

EdgeRouter PoE

This device is straightforward (the Cloudkey is less so). Create a server.pem file by concatenating the device key and crt as above. this file should be copied to /etc/lighttpd on the router. Kill and restart the lighttpd service with the following:

kill -SIGINT $(cat /var/run/
/usr/sbin/lighttpd -f /etc/lighttpd/lighttpd.conf


This is a little tougher as you need to obtain the certificate signing request (CSR) from the device before using it to create the certificate (step three in create device certificates, above). There are a bunch of guides around that talk to different aspects of the process using a mix of real certificates and self-signed but there’s not one that’s particularly clear on how to implement a self-signed certificate. The process I ended up using was to create the device key and crt on the device itself as per this instruction. I’m not sure I can see any good reason to create the certificate on the device though. It just adds a degree of copy/pasta. That instruction did point me at the directory where the certificates are stored howerver.

  1. SSH to the cloudkey (unnecessary I thinK) cd /tmp openssl genrsa -out /etc/ssl/private/cloudkey.key 2048 openssl req -new -batch -subj “/C=UK/ST=Netherlands/L=Amsterdam/O=[domain.tld]/OU=kyomu/CN=[device.fqdn.tld]” -key /etc/ssl/private/cloudkey.key -out /etc/ssl/private/cloudkey.csr
  2. Backup the existing SSL configuration sftp mjpadmin@[device.fqdn.tld]:/etc/ssl/private/backup/* ./
  3. On the device with the root cert (the signing machine) Copy the cloudkey.key and cloudkey.csr to the signing machine cd ~/Projects/tls/devices/cloudkey Create the device certificate openssl x509 -req -in cloudkey.csr -CA ../../root/[domain.tld].rootCA.pem -CAkey ../../root/[domain.tld].rootCA.key -CAcreateserial -out cloudkey.crt -days 728 -sha256 Create a pkcs12 file - note that the password is important. It’s required for the import process to work on the CloudKey.* openssl pkcs12 -export -in cloudkey.crt -inkey cloudkey.key -out cloudkey.p12 -name cloudkey -CAfile cloudkey.crt -caname root -password pass:aircontrolenterprise
  4. Ship the crt and p12 files to the cloudkey (I believe that only the p12 is actually required). sftp [user]@[device]:/etc/ssl/private put [device].p12 exit
  5. SSH into the cloudkey cd /etc/ssl/private keytool -importkeystore -deststorepass aircontrolenterprise -destkeypass aircontrolenterprise -destkeystore /usr/lib/unifi/data/keystore -srckeystore /etc/ssl/private/cloudkey.p12 -srcstoretype PKCS12 -srcstorepass aircontrolenterprise -alias cloudkey

This shoud give output as follows:

“‘ Importing keystore /etc/ssl/private/cloudkey.p12 to /usr/lib/unifi/data/keystore…

Warning: The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore /usr/lib/unifi/data/keystore -destkeystore /usr/lib/unifi/data/keystore -deststoretype pkcs12”. “’

  1. Test that the configuration has taken ”‘ root@Cloudkey:/etc/ssl/private# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful “’
  2. Apply the changes ”‘ root@Cloudkey:/etc/ssl/private# /etc/init.d/nginx restart [ ok ] Restarting nginx (via systemctl): nginx.service. root@Cloudkey:/etc/ssl/private# /etc/init.d/unifi restart “’