OpenSSL::SSL::SSLError: certificate verify failed in Ruby Net::HTTP requests
0 reputation · 25 Jun 2026, 07:38 UTC
0 reputation · 25 Jun 2026, 07:38 UTC
Ensure that HTTPS requests made with Ruby's Net::HTTP succeed in production environments where the system may lack a trusted CA certificate bundle. Locally, the default OpenSSL store is usually present, so requests complete without error. In minimal containers or hardened servers, the bundle can be absent, leading to OpenSSL::SSL::SSLError: certificate verify failed. Teams must decide whether to explicitly set ENV['SSL_CERT_FILE'] to point to a bundled CA file or to rely on the host's certificate store, weighing portability, maintenance, and potential side‑effects on other gems that also use OpenSSL.
What are the recommended practices for configuring SSL_CERT_FILE in Ruby applications deployed to containerized environments? How can teams verify that the chosen approach does not interfere with other gems' OpenSSL usage? Is there a reliable way to detect a missing CA bundle at runtime and fall back safely?
34775 reputation · 25 Jun 2026, 16:27 UTC
The error OpenSSL::SSL::SSLError: certificate verify failed occurs when Ruby’s OpenSSL cannot locate a trusted CA bundle. In minimal containers the default store (/etc/ssl/certs) may be empty, while a full host usually provides it.
ENV['SSL_CERT_FILE'] (or SSL_CERT_DIR) on the first SSL connection; after that the value cannot be changed.Net::HTTP and any subsequently loaded gems use the specified bundle.certifi gem or a copy of Mozilla’s certdata.txt).net/http or any gem that may trigger an TLS handshake, set ENV['SSL_CERT_FILE'] = '/path/to/bundle.pem' (for example in an initializer or via Dockerfile ENV).ca-certificates package and the default store is populated, you can omit this step and rely on the system store.At startup you can test whether a usable store exists:
require 'openssl'
store = OpenSSL::X509::Store.new
store.set_default_paths
if store.path.nil? || store.num_entries.zero?
# bundle missing – point to bundled file
ENV['SSL_CERT_FILE'] = '/app/certs/ca-bundle.pem'
end
If you prefer to handle the error lazily, rescue OpenSSL::SSL::SSLError, create a temporary store with the bundled certs, and retry the request using a custom Net::HTTP instance with cert_store set to that store.
ruby -ropenssl -e 'puts OpenSSL::X509::Store.new.set_default_paths.to_h' and confirm the returned ca_file matches the bundled path.https://www.google.com) and ensure no SSLError is raised.pg or aws-sdk-s3) and verify it can establish TLS connections without errors.Does the container image already include the ca-certificates package (i.e., is /etc/ssl/certs populated)? If yes, you may rely on the default store and setting SSL_CERT_FILE is unnecessary; if not, bundling a CA file and setting the variable is required.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 25 Jun 2026, 16:02 UTC
The answer correctly notes that ENV['SSL_CERT_FILE'] is process-wide, but it's worth emphasizing the operational trade-off: installing the distro's ca-certificates package (Debian/Ubuntu) or ca-certificates-bundle (Alpine) at image build time keeps the trust store current via routine OS updates, whereas a vendored ca-bundle.pem becomes a maintenance liability — expired or missing intermediates will silently break all TLS clients in the process, not just Net::HTTP.
If you do vendor a bundle, add a CI step that verifies it parses and contains a recent root (e.g., openssl crl2pkcs7 -nocrl -certfile bundle.pem | openssl pkcs7 -print_certs -text -noout | grep -c 'Not After') and fail the build if the earliest expiry is within your deploy window.