You get an SSL error on an internal service
You spin up an internal API server and sign it with your company's private certificate authority. You run curl https://internal-api.example.com from your Fedora workstation and the terminal immediately rejects the connection. The error says SSL certificate problem: unable to get local issuer certificate. Your browser shows a red warning triangle. The server is fine. Your certificate chain is valid. Fedora just does not know who to trust.
How the trust store actually works
Linux distributions do not trust certificates by default. They ship with a curated list of public certificate authorities that major browsers and operating systems recognize. Fedora centralizes this list in a single directory tree and compiles it into library-specific bundles. When you install a new certificate, you are not editing a single configuration file. You are dropping a PEM file into a staging directory and running a compiler that rebuilds the trust bundles for OpenSSL, NSS, and GnuTLS.
Think of the trust store like a corporate security desk. The desk keeps a master list of approved vendors. When a new vendor arrives, you hand them a badge template to the desk. The desk prints copies for the parking garage, the server room, and the cafeteria. You never hand the badge directly to the security guards at each door. You update the master list, and the desk distributes the changes.
Fedora implements this with the /etc/pki/ca-trust/ directory and the update-ca-trust command. The ca-certificates package owns the directory structure. Every application that relies on system cryptography reads from the compiled bundles, not the raw source files. The source/ directory holds your additions. The extracted/ directory holds the compiled output. Package updates touch source/ but never overwrite your files. The system rebuilds extracted/ automatically after relevant package installations, but you must trigger it manually for custom certificates.
Trust the package manager. Manual file edits drift, snapshots stay.
Adding a custom CA certificate
You need to add your internal CA to the system trust store. The process requires two steps. You place the certificate in the correct staging directory. You run the extraction command.
First, ensure your certificate is in PEM format. PEM files are Base64-encoded ASCII text that start with -----BEGIN CERTIFICATE-----. If your certificate arrives as a .crt or .cer file in DER format, convert it before proceeding. The trust compiler silently ignores binary files.
Here is how to stage the certificate and rebuild the trust store.
# Copy the PEM certificate to the anchors directory.
# The anchors directory is the staging area for new trusted CAs.
sudo cp internal-ca.pem /etc/pki/ca-trust/source/anchors/
# Rebuild the consolidated trust bundles for all crypto libraries.
# This command reads the source directory and writes to /etc/pki/ca-trust/extracted/
sudo update-ca-trust extract
The extract step is mandatory. Dropping a file into anchors does nothing until you run extract. The command reads every file in the source/ tree, applies the blocklist rules, and writes compiled bundles to extracted/. Applications read from extracted/. If you skip extract, your applications will continue to reject the certificate.
Fedora convention keeps user modifications in /etc/pki/ca-trust/source/. The package manager never overwrites files in source/. It only manages the default public CAs. Your custom certificates survive system updates.
Run update-ca-trust extract after every anchor change. The compiler does not watch the directory for changes.
Verifying the certificate was added
Run a quick check to confirm the trust store recognized the new authority. The trust command reads the compiled NSS database directly and prints human-readable entries.
# Query the trust database for your certificate's subject or issuer name.
# The trust command reads the compiled NSS database directly.
trust list | grep -i "internal-ca"
# Test a live TLS handshake against your internal service.
# The -v flag prints the certificate chain and verification steps.
curl -v https://internal-api.example.com 2>&1 | grep -i "issuer"
You will see output similar to this in your terminal.
text
issuer: CN = Internal Root CA, O = MyCompany, C = US
SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
server certificate verification OK
If trust list returns your certificate and curl completes without an SSL error, the system trusts the CA. Reboot before you debug. Half the time the symptom is gone once the bundle is compiled.
Removing and blocking certificates
You do not delete certificates from the trust store. You move them to the blocklist directory. This preserves an audit trail and prevents accidental re-addition.
Here is how to distrust a CA that you previously added.
# Move the certificate from anchors to the blocklist directory.
# The blocklist directory tells the compiler to exclude this CA from all bundles.
sudo mv /etc/pki/ca-trust/source/anchors/internal-ca.pem \
/etc/pki/ca-trust/source/blocklist/
# Rebuild the trust bundles to apply the exclusion rule.
sudo update-ca-trust extract
The blocklist/ directory takes precedence over anchors/. If a certificate exists in both locations, the compiler ignores it. This design prevents race conditions during package updates. You can safely delete the file from blocklist/ once you are certain it will never be needed again.
Move to blocklist before deleting. Future-you will thank you.
Common pitfalls and what the error looks like
The most common failure is providing a DER-encoded certificate instead of PEM. The update-ca-trust tool silently ignores files it cannot parse. You will run extract, see no errors, and still get connection failures. Check the file header. If it starts with -----BEGIN CERTIFICATE-----, it is PEM. If it looks like random binary text, convert it with openssl x509 -inform DER -in cert.der -outform PEM -out cert.pem.
Another frequent mistake is editing the wrong directory. Users sometimes copy certificates directly into /etc/pki/ca-trust/extracted/ or /etc/ssl/certs/. Those directories are generated outputs. The next time a package updates or you run extract, your manual edits vanish. Always stage files in source/anchors/.
You may also encounter applications that ignore the system trust store entirely. Firefox and Thunderbird maintain their own NSS databases. Chrome and Chromium use their bundled root store. Electron apps follow the same pattern. System-wide trust does not automatically propagate to applications that ship their own certificate bundles.
If you see [FAILED] Failed to start myservice.service during boot because a systemd unit relies on TLS, check the unit's environment. Some services require an explicit SSL_CERT_FILE or REQUESTS_CA_BUNDLE environment variable. Fedora's default systemd units usually inherit the system trust store, but custom services sometimes override it.
Run journalctl -xeu myservice.service first. Read the actual error before guessing.
Managing per-application NSS databases
When an application uses its own NSS database, you must manage certificates at the application level. The certutil tool handles this. It ships in the nss-tools package.
Here is how to add a certificate to a standalone NSS database.
# Install the NSS command-line utilities if they are missing.
sudo dnf install nss-tools
# List existing certificates in the target database directory.
# The -d flag points to the database path. The -L flag lists entries.
certutil -L -d /path/to/app/nssdb
# Import the certificate and mark it as a trusted CA.
# The -t flag sets trust attributes. CT,," means trusted CA for SSL, email, and object signing.
certutil -A -d /path/to/app/nssdb -n "Internal CA" -t "CT,," -i internal-ca.pem
NSS databases store certificates in SQLite files named cert9.db. The certutil command modifies the database directly. You do not need to restart the application if it reloads the database on demand. Most desktop applications require a full restart to pick up NSS changes.
Check the application documentation for its database path. Guessing the path breaks the database.
Generating and inspecting certificates
You sometimes need to create a temporary certificate for local testing. The openssl tool handles generation and inspection.
Here is how to create a self-signed certificate and verify its contents.
# Generate a 4096-bit RSA key and a self-signed certificate valid for one year.
# The -nodes flag skips password encryption for automated service use.
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
# Inspect the certificate details without printing the raw Base64 block.
# The -text flag decodes the ASN.1 structure. The -noout flag suppresses the PEM dump.
openssl x509 -in cert.pem -text -noout
Self-signed certificates are fine for internal testing and development environments. They will trigger warnings in every browser and terminal client. Production environments require a certificate signed by a recognized public CA or an internal CA that you have already added to the trust store.
For production environments, consider using Certbot with Let's Encrypt to obtain free, automatically renewed certificates for public-facing services.
Inspect the Subject and Issuer fields before deploying. Mismatched names cause handshake failures.
When to use each approach
Use the system trust store when you need every terminal tool and system service to trust a certificate automatically. Use certutil when you are managing a legacy application that maintains its own NSS database. Use application-specific configuration when the software ships a bundled root store and ignores system paths. Use Certbot with Let's Encrypt when you are running a public-facing web server and need automated certificate renewal. Stay on the default public trust store if you only connect to widely recognized internet services.