# Ruby OpenSSL::SSL::SSLError certificate verify failed: fixes

> Ruby's "certificate verify failed" means OpenSSL could not verify the server chain. Point Ruby at a valid CA bundle or fix the chain; avoid VERIFY_NONE.

Source: https://ssl.sh/errors/ruby-certificate-verify-failed/
Last updated: 2026-11-10

**`OpenSSL::SSL::SSLError ... certificate verify failed` means Ruby's OpenSSL connected to the server but could not verify the certificate chain against the CA certificates it loads.** Usually Ruby is looking at a CA file that does not exist or is outdated, or the remote server is not sending its intermediate certificate.

## Quick fix

Pointing Ruby at a valid CA bundle fixes most cases.

Find out which OpenSSL and which CA paths your Ruby uses:

```bash
ruby -ropenssl -e 'puts OpenSSL::OPENSSL_LIBRARY_VERSION, OpenSSL::X509::DEFAULT_CERT_FILE, OpenSSL::X509::DEFAULT_CERT_DIR'
ls -l "$(ruby -ropenssl -e 'print OpenSSL::X509::DEFAULT_CERT_FILE')"
```

If the file is missing, point Ruby at a valid bundle:

```bash
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt   # Debian/Ubuntu path
```

For gem and bundle problems, run `bundle doctor ssl` (recent Bundler) and `gem update --system`. If only one host fails, check its chain with the [SSL checker](https://ssl.sh/tools/ssl-checker/).

## Causes

### 1. Ruby's OpenSSL cannot find its CA file

Rubies built with rbenv/ruby-build, asdf or rvm link to a particular OpenSSL (often Homebrew's on macOS). If that OpenSSL has no certificate file, or it was removed during an upgrade, every verification fails.

- **Confirm:** `DEFAULT_CERT_FILE` points to a path that does not exist or is empty.
- **Fix:** install or update that OpenSSL's CA package, set `SSL_CERT_FILE`, or reinstall the Ruby version so it links to a current OpenSSL.

### 2. Outdated CA certificates or RubyGems

Old systems and old RubyGems releases lack newer roots.

- **Confirm:** the failing host chains to a root that is newer than your OS or RubyGems version.
- **Fix:** update the OS `ca-certificates` package and run `gem update --system` and `bundle update --bundler`.

### 3. Wrong system clock

The RubyGems guide lists a wrong clock as one of the two main causes; a date in the past or future makes valid certificates look expired or not yet valid.

- **Fix:** correct the time and enable NTP synchronisation.

### 4. The remote server sends an incomplete chain

- **Confirm:** `openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts` lists only one certificate.
- **Fix:** the server must send its intermediates; see [missing intermediate certificate](https://ssl.sh/errors/missing-intermediate-certificate/) and the [chain builder](https://ssl.sh/tools/chain-builder/).

### 5. A corporate proxy or internal CA

Roots that are not in the public bundle need to be added explicitly:

```ruby
require "net/http"
require "openssl"

store = OpenSSL::X509::Store.new
store.set_default_paths
store.add_file("/etc/ssl/certs/company-root.pem")

http = Net::HTTP.new("intranet.example.com", 443)
http.use_ssl = true
http.cert_store = store
puts http.get("/").code
```

For a whole machine, add the root to the OS trust store instead. If the message reads `self-signed certificate in certificate chain`, see [that page](https://ssl.sh/errors/self-signed-certificate-in-certificate-chain/).

## Fixes by environment

Every fix points Ruby's OpenSSL at a current CA file; on macOS that often means relinking Ruby to the current Homebrew OpenSSL.

**macOS with Homebrew and rbenv/asdf:** `brew upgrade openssl@3 ca-certificates`, then reinstall the affected Ruby with ruby-build so it links to the current OpenSSL. As a stopgap, `export SSL_CERT_FILE="$(brew --prefix)/etc/ca-certificates/cert.pem"`.

**Debian / Ubuntu:**

```bash
sudo apt-get install --reinstall ca-certificates
sudo cp company-root.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates
```

**RHEL family:** place roots in `/etc/pki/ca-trust/source/anchors/` and run `update-ca-trust`.

**Windows (RubyInstaller):** run the check command above to see where Ruby looks, and set `SSL_CERT_FILE` to a bundle that includes any corporate root.

**Docker:** install `ca-certificates` in the image and copy private roots in before `bundle install`.

**Faraday / HTTParty:** both accept a CA file or store (`ssl: { ca_file: ... }` in Faraday, `ssl_ca_file:` in HTTParty).

## Don't do this

- **`http.verify_mode = OpenSSL::SSL::VERIFY_NONE`.** It accepts any certificate from anyone; credentials and API responses can be intercepted.
- **Redefining `OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE`.** This old snippet turns verification off for every library in the process.
- **`:ssl_verify_mode: 0` in `.gemrc`, or switching gem sources to `http://`.** Gems are code you execute; downloading them without authentication invites tampering.
