DISCLAIMER: Written by ChatGPT because I’m just too tired. But everything in here is based on what I actually did to make it finally work, and I’m sharing this in the hopes that it saves you some of the frustration I went through.

Introduction

So you’re self-hosting Joplin Server behind a Caddy reverse proxy and thought “Hey, I’ll just use tls internal, and it’ll all be fine.”

Spoiler: it won’t. Not right away, anyway.

This guide walks through exactly how to get Joplin Desktop to stop throwing cert errors (UNABLE_TO_GET_ISSUER_CERT_LOCALLY) and finally sync with your Joplin Server instance over HTTPS, using Caddy’s tls internal feature.


My Setup

  • OS: Linux (Proxmox LXC running Docker)
  • Reverse Proxy: Caddy with tls internal
  • Joplin Server: Docker container (joplin/server:latest)
  • Joplin Desktop: Windows client
  • Domain: joplin.YOUR_DOMAIN.com (local-only via internal DNS)

The Problem

Joplin Desktop does not trust certificates generated by Caddy’s internal CA out of the box. Even if:

  • You’ve installed the root cert into Windows
  • You’ve set the NODE_EXTRA_CA_CERTS environment variable
  • You’ve tried --ignore-certificate-errors
  • You’ve tested with curl or openssl and everything seems fine

…Joplin will still throw:

UNABLE_TO_GET_ISSUER_CERT_LOCALLY

Why? Because the Joplin client does not use your system’s CA trust store for internal requests.


The Solution

You have to explicitly point the Joplin Desktop app to the root certificate under:

Tools → Options → Synchronization → Show Advanced Settings → Custom TLS certificates

Yes, this setting is collapsed by default. Yes, it will drive you mad. Yes, it’s the only thing that works.


Step-by-Step Guide

1. Use tls internal in your Caddyfile

joplin.YOUR_DOMAIN.com {
    reverse_proxy YOUR_IP_ADDRESS:YOUR_PORT
    encode gzip
    tls internal
    log {
        output file /var/log/caddy/notes.log
    }
}

2. Find the Caddy root certificate

The Caddy root cert lives here:

/var/lib/caddy/.local/share/caddy/pki/authorities/local/root.crt

3. Copy the root certificate to your Windows machine

Save it somewhere easy to find, like:

C:\certs\caddy.crt

(If you’re using Notepad++ or similar, make sure line endings are preserved and the file isn’t mangled.)

4. Configure Joplin Desktop to trust the cert

  1. Open Joplin Desktop
  2. Go to Tools → Options → Synchronization
  3. Choose Joplin Server (Beta)
  4. Enter your server URL and credentials
  5. Click Show Advanced Settings
  6. Set Custom TLS certificates to:
C:\certs\caddy.crt
  1. Click Check synchronization configuration

If everything is working, you should get:

Success! Synchronization configuration appears to be correct.

5. Profit 🎉

Now you can sync across devices without needing to use http://, disable TLS, or punch holes in security you actually want.


Troubleshooting

Q: I already installed the cert in Windows. Why didn’t it work?

A: Joplin doesn’t use the Windows CA store for API calls. It only affects the embedded Chromium engine (UI stuff).

Q: What about NODE_EXTRA_CA_CERTS?

A: Joplin uses Electron/Node in a way that bypasses that setting for its sync requests.

Q: Why didn’t you mention this earlier?

A: Because I didn’t know. Now I do, and so do you.


Conclusion

Don’t trust the default. Don’t assume the CA store is enough. Don’t assume that just because curl says it’s good, Joplin will agree.

And above all, don’t skip over the hidden “Advanced Settings” button. It’s hiding the only thing that matters.

Stay sane out there.


If you got here because of a desperate late-night search — welcome. You’re not alone. Hopefully this helped.