Nix migraines: NIX_SSL_CERT_FILE

Published 2025-02-28 on Farid Zakaria's Blog

This will be a self-post to describe nixpkgs#issue385955. I refused to just “copy code” from other packages and wanted to better understand what was going on.

If you’re on a “proper” operating system (i.e. Linux), Nix protects you from accidental impurities by enforcing a filesystem and network sandbox.

This is not the case in MacOS. You can optionally enable the sandbox but it does not include a network sandbox.

🤔 I have some pretty strong opinions here. Although I am using Nix on MacOS, I would advocate for Nix/Nixpkgs dropping MacOS (& eventual Windows/BSD) support. Constraints are when you can find simplicity and beauty.

I had packaged up my personal blog (this site right here! 📝) into a flake.nix that worked on Linux but was failing on MacOS.

Turns out that one of the jekyll plugins I am using, jekyll-github-metadata, tries to contact github.com to fetch a bunch of data I don’t even need 😤.

It would immediately fail with a cryptic SSL error.

SSL_connect SYSCALL returned=5 errno=0
peeraddr=140.82.116.5:443 state=error:
certificate verify failed
(unable to get local issuer certificate)
(Faraday::SSLError)

I was able to replicate this on NixOS with nix build --no-sandbox

Okay 🤔 it’s failing to verify the SSL certificate chain.

Let’s add curl to our derivation to debug and see what that says.

> curl: (77) error setting certificate file: /no-cert-file.crt

Okay, so we need to set the SSL certificate file which might not be present.

Searching some exmaples and the documentation of OpenSSL looks like we should set SSL_CERT_FILE.

env = {
  SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
};

Now curl passes, so it seems to successfully validate the TLS certificate chain but the jekyll build is still failing 🤦‍♂️.

Looking further online, there seems to be a second environment variable, NIX_SSL_CERT_FILE. Let’s set that one too.

env = rec {
  SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
  NIX_SSL_CERT_FILE = SSL_CERT_FILE
};

Okay great now everything builds 🎉.

Turns out that if you add the package cacert it includes a setup-hook that sets both of these environment variables.

nativeBuildInputs = with pkgs; [
  cacert
];

But, why are there 2 environment variables !?… 🤷

It’s not particularly clear which packages respect one rather than the other. If you have insight into this, please comment on nixpkgs#issue385955.

NIX_SSL_CERT_FILE is clear that it should work with OpenSSL via this patch in nixpkgs that leverages it.

curl and ruby both use OpenSSL so why are their behavior divergent.

Nix migraine 🤕.


Improve this page @ bc4b4d8
The content for this site is CC-BY-SA.