Skip to content

Instantly share code, notes, and snippets.

@davidbalbert
Last active February 29, 2024 16:12
Show Gist options
  • Star 80 You must be signed in to star a gist
  • Fork 13 You must be signed in to fork a gist
  • Save davidbalbert/6815258 to your computer and use it in GitHub Desktop.
Save davidbalbert/6815258 to your computer and use it in GitHub Desktop.
How to install custom SSL certificates on an ASUS RT-N66U running asuswrt-merlin
###########################################
# IMPORTANT NOTE:
#
# As of asuswrt-merlin 380.67 Beta, you
# can now configure SSL certificates from
# the Webui, making these instructions
# unnecessary.
###########################################
# First, enable SSH in the Administration->System tab.
# Then log in to the device.
# Verify that https_crt_save is off
admin@RT-N66U:/tmp/home/root# nvram get https_crt_save
0
# Enable https_crt_save and verify that it was set correctly
admin@RT-N66U:/tmp/home/root# nvram set https_crt_save=1
admin@RT-N66U:/tmp/home/root# nvram get https_crt_save
1
# Write your custom key and certificate to the ephemeral file system.
# Note that these files will not be preserved on restart.
admin@RT-N66U:/tmp/home/root# cat >/etc/key.pem
# paste in key
admin@RT-N66U:/tmp/home/root# cat >/etc/cert.pem
# paste in cert
# Verify https_crt_file is empty
admin@RT-N66U:/tmp/home/root# nvram get https_crt_file
admin@RT-N66U:/tmp/home/root#
# Restart httpd. When httpd starts up with https_crt_save enabled, it does the
# following: If /etc/cert.pem and /etc/key.pem exist, it tars them together and
# saves them in https_crt_file. If they do not exist (this would be the case
# on reboot) and https_crt_file exists, httpd will extract the contents of
# https_crt_file. You can see how this works in the start_ssl function here:
# https://github.com/RMerl/asuswrt-merlin/blob/master/release/src/router/httpd/httpd.c
admin@RT-N66U:/tmp/home/root# service restart_httpd
# Ensure https_crt_file is now full
admin@RT-N66U:/tmp/home/root# nvram get https_crt_file
# ...snip...
# Reboot AP to make sure cert is put back on boot
admin@RT-N66U:/tmp/home/root# reboot
@lmerega
Copy link

lmerega commented Nov 24, 2016

That's insane.
I'm on RT-N66U with 380.63_2 version.
I cannot install any certificate.
I tried to commit nvram too, but it looks like something is going wrong.
I use the crt file for Apache generated by startssl.com... I used it on Tomato happily, now I cannot install it on my router.
Any idea?
The process is entirely done. The file is generated... the cert is still the first one asus generated :-(
Any help appreciated

Luca

@lmerega
Copy link

lmerega commented Dec 4, 2016

C'mon... I do need an answer :-)

@lmerega
Copy link

lmerega commented Dec 5, 2016

Ok, I managed it. I do not know, what I was doing wrong. Now it works flawlessly.
Thx

Luca

@bigforo
Copy link

bigforo commented Dec 10, 2016

Thx

@PeterDaveHello
Copy link

It works on RT-AC58U / RT-AC1300G, thanks!

@cosmindidis
Copy link

Hi there,

I am trying to install a certificate using the above script and, for some reason, the last 'nvram get https_crt_file' command returns empty. I am running ver. 380.63.2 on an Asus RT-N66U. Any ideeas? The certificate is generated from Let's Encrypt, if it matters (I am using they private key and the full chain pem files).

Cosmin

@scorpiorooster
Copy link

scorpiorooster commented Nov 27, 2017

Found it!
Merlin won't accept the "my.server.cer" or "my.server.key" or "fullchain.cer" that are generated with acme.sh / Let's Encrypt.

I'm using an RT-N66W running 380.68.4.
*.pem format is required. Conversion is done with openssl.

Here's what worked for me:

SSH to Merlin. Go to dir that Let's Encrypt put your key and cer files.

openssl rsa -in my.server.key -text > private.pem
openssl x509 -inform PEM -in my.server.cer > public.pem

Go to Merlin web interface.
Upload them in the Asuswrt-Merlin web Administration / System menu. It will accept them if they will work or give you a wrong file message if they won't. The "Apply" button then restarts httpd and you will be back at login screen. A reboot is a good idea after that. I also flushed my dns and browser cache before opening the https Web interface ....and then I finally got to see the green lock and verified secure status...

@RiFi2k
Copy link

RiFi2k commented Dec 25, 2017

@scorpiorooster Your the man, exactly what I needed to make my local CA .crt and .key file I generated for the router work with Merlin. Saved me from pulling my hair out for another hour.

As an extra note for anyone else I didn't need to flush the cache just reboot and close the current tab and reopen it in a new one for the green lock.

@haraldinho2000
Copy link

@sasoiliev Did your suggestion make it into the codebase, in other words: should i be able to add a crt file with cert chain? For me it does not seem to work that way. I am using 384_4_2.
I solved it by simply going to /jffs/ssl and with nano edited the cert.pem file and pasted the content from my intermediate cert at the end of the file. After that a service restart_httpd and a new browser window and I was good to go.
However, just being able to upload the chain cert file through the UI would be much easier.

@sparky3387
Copy link

sparky3387 commented Jun 14, 2019

According to the code as long as https_crt_save is set to 1 and https_crt_file is unset it should save, but for some reason It was refusing to save the certs to the nvram, I was able to manually save the file by:

tar -czf cert.tgz --transform 's,^,etc/,' cert.pem key.pem
echo $(cat cert.tgz | base64 | tr -d '\n')

And then copying this and pasting it into the router without newlines or spaces at the end (I couldnt paste into the command prompt as it would truncate)

vi /tmp/https_crt_file
nvram set https_crt_file=$(cat /tmp/https_crt_file)
nvram commit

(Updated to add the commit, I also had to unplug power to stop it saving and overwriting the work I had done to create the correct nvram)
Also there is no need to save https certificates nvram set https_crt_save=0

@adorobis
Copy link

adorobis commented Feb 26, 2020

Great guide, unfortunately after recent Asus firmware update it stopped working. Apparently you have to create server.pem file as well, which is simply a concatenation of key.pem and cert.pem files. So running:

cat /etc/key.pem > /etc/server.pem
cat /etc/cert.pem >> /etc/server.pem

makes it work again.

@adorobis
Copy link

adorobis commented Feb 26, 2020

And below is my entire script that allows to automate the publishing SSL certificate on the router every time your letsencrypt (or other) certificates are renewed:

#!/bin/sh
rm ~/router.sh
#below section will create a single script named router.sh that will be executed remotely on the router via ssh
cat <<EOT >> router.sh
#!/bin/sh
cd /etc
ls *.pem
rm *.pem
nvram set https_crt_save=0
nvram unset https_crt_file
service restart_httpd
echo "httpd restarted"
nvram unset https_crt_file
service restart_httpd
echo "httpd restarted"
nvram get https_crt_file
#files are getting recreated after httpd restart
sleep 20
ls *.pem
rm *.pem
nvram set https_crt_save=1
#replace letsencrypt.crt and .key files with your respective files
cat <<EOT >> cert.pem
EOT
cat /etc/certificates/letsencrypt.crt >> router.sh
#for some reason my letsencrypt.crt file is not finishing with end of line character, might not be always the case
echo "" >> router.sh
echo "EOT" >> router.sh
cat <<EOT >> router.sh
cat <<EOT >> key.pem
EOT
cat /etc/certificates/letsencrypt.key >> router.sh
echo "EOT" >> router.sh
cat <<EOT >> router.sh
rm server.pem
#create the server.pem file from the certificate and key files
cat key.pem > server.pem
cat cert.pem >> server.pem
service restart_httpd
nvram get https_crt_file
EOT
#execute the script remotely on the router. Replace privatekey.pem with your private key you have
#created to access the router. Replace admin with correct user id and IP address with your router's IP address
cat router.sh | ssh -o StrictHostKeyChecking=no \
 -p 4092 -i privatekey.pem admin@10.144.1.1

@pkishino
Copy link

can't get this working on latest 384.17 FW on ac68u.. been trying around for ages above but it will always use the previous certificate that I uploaded.. I want to add a script to my certbot renew-hook to replace these..I had it working in the past but not with latest firmwares..

@adorobis
Copy link

I have it still running ok on AC-58U and firmware 3.0.0.4.382_51939. So far it works ok, I'll check when the certificate will allow renewal in a few weeks and with newer router firmware.
I would suggest to perform all the steps manually and see what is happening there on the router

@semsuddin
Copy link

semsuddin commented Jun 25, 2020

I'm running latest asusmerlin on 87U and all I had to do is to copy key and cert to jffs partition and then restart the httpd service.

Here's an example (I'm running it from NAS):

scp -i ./sshPrivKeyToConnectToRouter.pem /localLocationOfCertificates/*.mydomain.com.cer username@router.mydomain.com:/jffs/.cert/cert.pem

scp -i ./sshPrivKeyToConnectToRouter.pem /localLocationOfCertificates/*.mydomain.com.key username@router.mydomain.com:/jffs/.cert/key.pem

ssh -i ./sshPrivKeyToConnectToRouter.pem username@router.mydomain.com service restart_httpd

So in short:

  1. Copy cert files to:
    /jffs/.cert/cert.pem
    /jffs/.cert/key.pem
  2. Restart the service
    service restart_httpd

@adorobis
Copy link

@semsuddin
My routers are not supported by the Merlin project, should this behave the same on original Asuswrt firmware?

@semsuddin
Copy link

@adorobis
I'm really not sure, but you can always try to SSH to router and check it out. If you currently have any certificate imported then do check that it is in the jffs partition once connected. If it is then it should behave the same way as I described as well.

@adorobis
Copy link

OK, thanks, just checked and certificates are not in the jffs directory. The are in /etc directory. Anyway so far it work

@semsuddin
Copy link

semsuddin commented Jun 26, 2020

Ok. In my case they get copied from /jffs to /etc/tmp after the service restarts.

@adorobis
Copy link

ah, that's interesting, I'll give it a try in a free moment...

@miqrogroove
Copy link

Seems to get more complicated every year. This time the magical combination was:

nvram set https_crt_save=0
cd /tmp/etc
cat > key.pem [paste the key, Enter, Ctrl+C]
cat > cert.pem [paste the cert, Enter, Ctrl+C]
rm server.pem
cd /jffs
cp /tmp/etc/key.pem ./
cp /tmp/etc/crt.pem ./
service restart_httpd
nvram set https_crt_save=1

Tried many other combinations and this was the only thing that would survive the reboot.

@tomdaley92
Copy link

I'm running latest asusmerlin on 87U and all I had to do is to copy key and cert to jffs partition and then restart the httpd service.

Here's an example (I'm running it from NAS):

scp -i ./sshPrivKeyToConnectToRouter.pem /localLocationOfCertificates/*.mydomain.com.cer username@router.mydomain.com:/jffs/.cert/cert.pem

scp -i ./sshPrivKeyToConnectToRouter.pem /localLocationOfCertificates/*.mydomain.com.key username@router.mydomain.com:/jffs/.cert/key.pem

ssh -i ./sshPrivKeyToConnectToRouter.pem username@router.mydomain.com service restart_httpd

So in short:

  1. Copy cert files to:
    /jffs/.cert/cert.pem
    /jffs/.cert/key.pem
  2. Restart the service
    service restart_httpd

Hey thanks man, I was having trouble finding the location of the certificates that persists 👍
Here's the Ansible version: https://github.com/tomdaley92/rt-ax88u

@parmstro
Copy link

parmstro commented Jul 27, 2021

After fooling around with all the responses here. I stumbled upon the simple fact, when using the UI on
WAN >> DDNS >> Import Your Own Certificate >> Upload
For the key file and certificate file, you MUST supply files named key.pem and cert.pem
This ensures that the files are accepted and persisted to your configuration. My files were initially named differently.

[RFE] - Please include a statement as to the proper naming of the files, OR simply rename the files when they are saved to the router. I would consider this a bug. A user should not have to name the files specifically unless they are provided with a prompt to do so or warning/error when the provided files are not named appropriately.

@jebeaudet
Copy link

Just struggled too long on this. Make sure you can first upload the key/cert through the UI and that's it's accepted. If it keeps going back to the auto generated asus one, it means that the firmware did not accept your certificate. The "Server Certificate" section needs to show your own certificate info!

From this thread it seems EC certificates are not accepted so only RSA. I've used RSA2048. Also, make sure you don't concatene intermediate certificate, the certificate uploaded should be the one given by acme, nothing more nothing less.

Once that done and clear, you can copy your cert/key to /jffs/.cert and you should be good to go.

Relevant source code and this

@bsmojver
Copy link

Yeah, the DDNS page hack by @parmstro worked for me as well with the current official Asus firmware (3.0.0.4.386_46065). The only thing is that in AP mode, which I am using, this page is not linked in menus, so one has to hit it directly, For example:

https://:8443/Advanced_ASUSDDNS_Content.asp

I then pretended to enable the DDNS client (will not work, but that's not relevant) and uploaded key/cert in PEM format and hit Apply.

PS. I later disabled the non-working DDNS setup and the uploaded key/cert were left alone (i.e. still survived a reboot).

@jmontleon
Copy link

On the latest stock firmware (3.0.0.4.386_49703):

mkdir -p tmp/etc
cd tmp

cat << EOF > etc/cert.pem
...
EOF
cat << EOF > etc/key.pem
...
EOF

tar zcvf cert.tgz etc/cert.pem etc/key.pem
mv /jffs/cert.tgz /jffs/cert.tgz.bak
mv cert.tgz /jffs/
service restart_httpd

Test, if satisfied, reboot and it should persist.

@Matssa56
Copy link

Matssa56 commented Nov 6, 2022

On the latest stock firmware (3.0.0.4.386_49703):

mkdir -p tmp/etc
cd tmp

cat << EOF > etc/cert.pem
...
EOF
cat << EOF > etc/key.pem
...
EOF

tar zcvf cert.tgz etc/cert.pem etc/key.pem
mv /jffs/cert.tgz /jffs/cert.tgz.bak
mv cert.tgz /jffs/
service restart_httpd

Test, if satisfied, reboot and it should persist.

Hey thanks for the script, I tried using it and apparently my ax88 doesn't use the new updated certs, still using the old ones. Is there a file that I need to remove or something? I didn't do the nvram stuff though, not sure if it will help.

Thanks 🙏

@adorobis
Copy link

adorobis commented Nov 7, 2022

I didn't do the nvram stuff though, not sure if it will help.

Yes, the "nvram stuff" is required. It clears the old cert before saving the new one.

@Matssa56
Copy link

Matssa56 commented Nov 7, 2022

Just checked and the nvram was already at 1.
I managed to make it work, apparently I didn't put the certs in the good area : I was putting them in /etc instead of /jffs/.cert

So my script is :

  • copy from my NAS the cert.pem and key.pem to /jffs/.cert/
  • tar the two
  • remove old tar backup and create new one under /jffs/
  • move tar
  • reboot httpd

Since my certfs expire in 80 days, we'll see if my script works or not :)

Thanks!

@adorobis
Copy link

adorobis commented Nov 8, 2022

And have you kept the nvram commands?

@Matssa56
Copy link

Matssa56 commented Nov 8, 2022

And have you kept the nvram commands?

Nope, i only activated the nvram once and for all, I don't deactivate it to clean it and activate it after. I'm on the latest Merlin firmware for the ax88u (388 is in beta, I'm on the one just before)

@cristit
Copy link

cristit commented Jan 15, 2023

According to the code as long as https_crt_save is set to 1 and https_crt_file is unset it should save, but for some reason It was refusing to save the certs to the nvram, I was able to manually save the file by:

tar -czf cert.tgz --transform 's,^,etc/,' cert.pem key.pem
echo $(cat cert.tgz | base64 | tr -d '\n')

And then copying this and pasting it into the router without newlines or spaces at the end (I couldnt paste into the command prompt as it would truncate)

vi /tmp/https_crt_file
nvram set https_crt_file=$(cat /tmp/https_crt_file)
nvram commit

(Updated to add the commit, I also had to unplug power to stop it saving and overwriting the work I had done to create the correct nvram) Also there is no need to save https certificates nvram set https_crt_save=0

I tried this method, but following error occurred:

nvramhttps_crt_file value length is bigger than allowed max length:1024

I'm using the last firmware version, but on ASUS GT-AX11000.

When I try to load the https page, the browser says the certificate is empty. Running command:

nvram get https_crt_file

The output is empty.

Is anybody still able to use his own certificate?

@jebeaudet
Copy link

jebeaudet commented Jan 15, 2023

@cristit try with the Web ui first to confirm your key+cert is working., ref https://gist.github.com/davidbalbert/6815258?permalink_comment_id=4047785#gistcomment-4047785

I'm guessing you're hitting a length limit, were you trying to concatenate intermediate certificates into your leaf maybe?

@cristit
Copy link

cristit commented Jan 15, 2023

thanks @jebeaudet!

https://router.mydomain.abc says the certificate is empty.

what is the size of the file, when you try to read it the https_crt_file using:

nvram get https_crt_file

@vincentkoevoets
Copy link

vincentkoevoets commented Mar 16, 2023

From this thread it seems EC certificates are not accepted so only RSA. I've used RSA2048. Also, make sure you don't concatene intermediate certificate, the certificate uploaded should be the one given by acme, nothing more nothing less.

This! This turned out to be the problem for me, on stock firmware at least. When I generated my certificates with "--key-type rsa" with certbot, the below commands worked without any problems. I used the exact same commands before on Asusmerlin, and that worked with EC certificates. But I had to revert back to stock firmware, and tried to import my own certificates again, but it did not work. So I think that Merlin has implemented them, but Asus hasn't (yet). Could that be the case?
I am on the ZenWifi XT-8, but I imagine this also goes for the RT-N66U.

So in short:
Copy cert files to:
/jffs/.cert/cert.pem
/jffs/.cert/key.pem
Restart the service
service restart_httpd

@sparky3387
Copy link

sparky3387 commented Aug 21, 2023

Its been a while since I have been in the gist, but for anyone using a Lets Encrypt certificate this script below combined with the following acme.sh command gets a working internal certificate
acme.sh --home /jffs/acme.sh --issue -d example.com --dns dns_cf --debug --fullchain-file /etc/cert.pem --key-file /etc/key.pem --reloadcmd "/jffs/acme.sh/installcertificate.sh"

/jffs/acme.sh/installcertificate.sh

#!/bin/sh
tar -C / -czf /jffs/cert.tgz etc/cert.pem etc/key.pem
nvram set https_crt_save=1
service restart_httpd

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