Fix for "Certificate has expired" error with Joplin Cloud and self-hosted sync targets

Updates:

  • The issue has been resolved in Joplin Cloud, so if you had the "Ignore TLS certificate errors" option enabled, don't forget to switch it off as it is not secure.

  • If you are self hosting and are having troubles with this bug, please give a try to the latest pre-release, which includes a permanent fix: Pre-release v2.5 is now available (Updated 2 Oct)


Some of you might be experiencing an error "Certificate has expired" when synchronising with Joplin Cloud (and possibly other services) when using the desktop application.

This is due to Let's Encrypt root certificate that expired on 30 September, and the new method they are using is not compatible with the Joplin desktop application.

This actually affects thousands of applications, not just Joplin, so various solutions are being considered right now and hopefully a fix will be available relatively soon.

For now, as a workaround, you can simply check " Ignore TLS certificate errors " in Configuration > Synchronisation > Advanced Options

I will let you know as soon as a fix is available so that you can clear that option.

More info:

11 Likes

And for those of you using Joplin CLI as well, disable it there too. :wink:

joplin config net.ignoreTlsErrors true

2 Likes

Update: I have implemented a temporary fix on Joplin Cloud which should solve the issue for now. If you're having still some issues please let me know. An updated desktop app will be available later on with a more permanent fix.

I am having issues with Nextcloud sync. I self-host the nextcloud and it shows a valid cert when I check from the web interface.

This worked for Joplin Cloud, and the same method could be applied on your server probably:

[Bug]: Let's Encrypt root CA isn't working properly · Issue #31212 · electron/electron · GitHub

1 Like

The workaround works, but does it present a security issue? Thank you.

No it doesn't, it's still a valid certificate.

1 Like

Thank you, thank you!!! Invaluable help. I was tearing my hair out with Joplin desktop having the certificate error and I kept thinking it was the cert on my nextcloud.

For those running their own Joplin Server using apache and certbot to manage the certificate generation, the following fixes the issue:

sudo certbot certonly --preferred-chain "ISRG Root X1" --apache

(Note this is a suggested reply in the link posted above by @laurent)

The joplin server setup I'm using is is based off of this thread Guide for Joplin-Server on Raspberry Pi (thanks to @MrKanister)

1 Like

In case others are having issues with --preferred-chain not being a recognized flag on Ubuntu 18.04 LTS, following this comment worked for me: [Bug]: Let's Encrypt root CA isn't working properly · Issue #31212 · electron/electron · GitHub

Thanks laurent! This fixed my desktop issue on desktop.

The option is called "Ignore TLS certificate errors".
So, now anyone could self-sign a certificate for your synchronization target and pretend to be them. How is that not a security issue?

There is another option, "Custom TLS certificates", isn't it better to download the certificate of your sync target and import it here?

1 Like

It is. This is a temporary, stopgap solution.

1 Like

If anyone uses an automated update service (like /usr/bin/certbot renew) and wants to apply the option for preferred chain only to a particular domain, then the right place is in the config file at /etc/letsencrypt/renewal/your.domain.name.conf with this syntax:

... cut on purpose

[renewalparams]
account = ...obfuscated...
authenticator = webroot
preferred_chain = ISRG Root X1
webroot_path = /...obfuscated...,
server = https://acme-v02.api.letsencrypt.org/directory

... cut on purpose

And the renewal be forced with /usr/bin/certbot renew --force-renewal.

1 Like

Yes as mentioned it was just a workaround and it is indeed not secure. Thanks for the reminder anyway - I've updated the top post with more info about it.

unfortunately, adding a line did not help
preferred_chain = ISRG Root X1

letsencrypt certificate has been refreshed as you can see by date, but joplin desktop still won't sync with error.

Only Ignore TLS certificate errors helps :frowning:

I've resolved the issue on my self-hosted Joplin cloud. The "preferred chain" solution does actually work, however simply telling certbot/traefik/whatever where to get new certificates doesn't cause it to replace old ones, so you actually need to delete your certificate store to have them get refreshed.

To verify that you're seeing the "correct" error, run a command like this one:

$ openssl s_client -connect joplin.example.com:443 -servername joplin.example.com
CONNECTED(00000005)
depth=1 O = Digital Signature Trust Co., CN = DST Root CA X3
verify error:num=10:certificate has expired
notAfter=Sep 30 14:01:15 2021 GMT
verify return:0
depth=1 O = Digital Signature Trust Co., CN = DST Root CA X3
verify error:num=10:certificate has expired
notAfter=Sep 30 14:01:15 2021 GMT
verify return:0
depth=3 O = Digital Signature Trust Co., CN = DST Root CA X3
verify error:num=10:certificate has expired
notAfter=Sep 30 14:01:15 2021 GMT
verify return:0
---
Certificate chain
 0 s:/CN=joplin.example.com
   i:/C=US/O=Let's Encrypt/CN=R3
 1 s:/C=US/O=Let's Encrypt/CN=R3
   i:/C=US/O=Internet Security Research Group/CN=ISRG Root X1
 2 s:/C=US/O=Internet Security Research Group/CN=ISRG Root X1
   i:/O=Digital Signature Trust Co./CN=DST Root CA X3
---
# Lines omitted...

    Start Time: 1633452339
    Timeout   : 7200 (sec)
    Verify return code: 10 (certificate has expired)
---
^C

Note that you see "certificate has expired" as the error message, note that "ISRG Root X1" is listed as a signer but so is "DST Root CA X3". The DST certificate is the expired one.

Steps to resolve

  1. Update your preferred chain to "ISRG Root X1".
  2. Delete the currently-valid certificate.
  3. Restart your services.

I use traefik, so the following config snippet suits step 1:

[certificatesResolvers.le.acme]
preferredChain = "ISRG Root X1"

To accomplish step 2 using my setup, I deleted the configured acme.json file (certificatesResolvers.le.acme.storage file).

To confirm that everything is working, rerun the same command from before and see the new output:

$ openssl s_client -connect joplin.example.com:443 -servername joplin.example.com
CONNECTED(00000005)
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = joplin.example.com
verify return:1
---
Certificate chain
 0 s:/CN=joplin.example.com
   i:/C=US/O=Let's Encrypt/CN=R3
 1 s:/C=US/O=Let's Encrypt/CN=R3
   i:/C=US/O=Internet Security Research Group/CN=ISRG Root X1
---
# Lines omitted...

    Start Time: 1633453694
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
^C

I ran these tests using LibreSSL 2.6.5.

sorry I am a bit late but I have alse experienced the certificate error. I self host with nextcloud.

It appears that this error only affects the windows client. Both the android and linux (manjaro in my case) clients work without the Ignore TLS Certificate errors in the settings.

I'm afraid the Windows client only assertion isn't the case @luciandf. I have experienced the issue using the AppImage on Debian Linux Buster, with self-host Nextcloud secured with LetsEncrypt.