--- title: "Node.js SSL — System Trust Store Is Ignored" aliases: [nodejs-ssl, nodejs-trust-store, node-tls-reject, nodejs-self-signed] tags: [nodejs, ssl, tls, systemd, lxc, docker, homelab] sources: - "daily/2026-04-19.md" created: 2026-04-19 updated: 2026-04-19 --- # Node.js SSL — System Trust Store Is Ignored Node.js does not use the operating system's certificate trust store. Adding a self-signed certificate to `/etc/ssl/certs/` or running `update-ca-certificates` has no effect on Node.js TLS verification. The only reliable fix is to set `NODE_TLS_REJECT_UNAUTHORIZED=0` as an environment variable on the Node.js process itself — and for systemd-managed services, this must be in the unit file, not in a shell profile. ## Key Points - **Node.js bundles its own CA store** (Mozilla's root CAs compiled in) — it does not read `/etc/ssl/certs/` at runtime - `update-ca-certificates` and adding certs to the Linux trust store does not affect Node.js - `NODE_TLS_REJECT_UNAUTHORIZED=0` must be set in the **process environment**, not a login shell profile — for systemd services this means the unit file - Setting the env var via shell (`export NODE_TLS_REJECT_UNAUTHORIZED=0`) only affects that shell and its children — not a systemd service started separately - For self-signed or internal CA certificates, the proper long-term fix is `NODE_EXTRA_CA_CERTS=/path/to/ca.crt` — this tells Node.js to trust additional CAs without disabling verification entirely ## Details ### Why System Trust Store Doesn't Work Unlike Python (`certifi` or system certs), Go (uses system certs by default), or curl (uses system certs), Node.js compiles Mozilla's CA bundle at build time and uses it exclusively. This is a deliberate design decision for portability. Even in a Docker container or LXC where the system certs are managed by the distro, Node.js won't see them. The consequence: any application talking to an internal service with a self-signed or internal-CA-signed certificate will get `CERT_HAS_EXPIRED`, `UNABLE_TO_VERIFY_LEAF_SIGNATURE`, or `SELF_SIGNED_CERT_IN_CHAIN` errors even after you've properly configured the OS trust store. ### The systemd Fix For services managed by systemd, the env var must be in the unit file: ```ini # /etc/systemd/system/homepage.service [Service] Environment=NODE_TLS_REJECT_UNAUTHORIZED=0 ExecStart=/usr/bin/node /opt/homepage/server.js ``` After editing: ```bash systemctl daemon-reload systemctl restart homepage ``` A `drop-in` override is cleaner than editing the unit directly: ```bash mkdir -p /etc/systemd/system/homepage.service.d/ cat > /etc/systemd/system/homepage.service.d/tls.conf << 'EOF' [Service] Environment=NODE_TLS_REJECT_UNAUTHORIZED=0 EOF systemctl daemon-reload && systemctl restart homepage ``` ### The Proper Fix (NODE_EXTRA_CA_CERTS) `NODE_TLS_REJECT_UNAUTHORIZED=0` disables all certificate validation — dangerous on public-facing services. The correct approach for internal CAs: ```bash # Export Proxmox's self-signed certificate openssl s_client -connect 192.168.1.100:8006 -showcerts /dev/null \ | openssl x509 -outform PEM > /etc/ssl/private/proxmox-ca.crt # Tell Node.js to trust it Environment=NODE_EXTRA_CA_CERTS=/etc/ssl/private/proxmox-ca.crt ``` This adds the cert to Node.js's trusted set without disabling verification for other connections. ### Context: Homepage in LXC (2026-04-19) Homepage (a self-hosted dashboard) running in LXC 103 needed to call the Proxmox API at `https://192.168.1.100:8006`. Proxmox uses a self-signed certificate. The Proxmox cert was added to the system trust store inside LXC 103 — no effect. `NODE_TLS_REJECT_UNAUTHORIZED=0` was set in the shell — no effect (systemd started the service separately). Only adding it to the systemd unit file resolved the issue. ## Related Concepts - [[wiki/concepts/homepage-proxmox-widget-quirks]] — the Homepage dashboard context where this was discovered - [[wiki/concepts/lxc-arp-cache-api-failures]] — the other root cause of Homepage widget failures on that server - [[wiki/homelab/_index]] — Proxmox and LXC setup context ## Sources - [[daily/2026-04-19.md]] — Homepage LXC 103 calling Proxmox API; cert added to system trust store had no effect; `NODE_TLS_REJECT_UNAUTHORIZED=0` in systemd unit file was the only fix that worked