Skip to content


Subversion checkout URL

You can clone with
Download ZIP
An OCSP responder written in Ruby. Uses r509 and Sinatra.
branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.

r509-ocsp-responder Build Status Coverage Status

r509-ocsp-responder is an OCSP responder written using r509 and Sinatra to conform to RFC 2560 and 5019.


r509-ocsp-responder depends on r509, redis, r509-validity-redis (or another library that implements R509::Validity such as r509-validity-crl), sinatra, and dependo. These must be installed as gems.

Basic Usage


If you have cloned the repo you can build the gem with rake gem:build and install with rake gem:install . Alternately you can use a prebuilt gem by typing gem install r509-ocsp-responder .

Set Up

Save the below into a file

require "r509"
require "dependo"
require 'r509/ocsp/responder/server'

Dependo::Registry[:log] =

require "r509/validity/redis"
require 'redis'
  gem "hiredis"
  Dependo::Registry[:log].warn "Loading redis with hiredis driver"
  redis = => :hiredis)
rescue Gem::LoadError
  Dependo::Registry[:log].warn "Loading redis with standard ruby driver"
  redis =
Dependo::Registry[:validity_checker] =



responder = R509::OCSP::Responder::Server
run responder

Configure config.yaml

The config.yaml contains certificate authority nodes as well as options like copy_nonce (documented below). Each CA node has an arbitrary name like test_ca and contains a ca_cert and (optional) ocsp_cert node. If you want to sign OCSP responses directly from your root you'll set your config up like this:

copy_nonce: true
cache_headers: true
max_cache_age: 60
      cert: spec/fixtures/second_ca.cer
      key: spec/fixtures/second_ca.key

If you want to use an OCSP delegate

copy_nonce: true
cache_headers: true
max_cache_age: 60
      cert: spec/fixtures/test_ca.cer
      cert: spec/fixtures/test_ca_ocsp.cer
      key: spec/fixtures/test_ca_ocsp.key

Finally, if you're responding for multiple roots you specify them like so:

copy_nonce: true
cache_headers: true
max_cache_age: 60
      cert: spec/fixtures/test_ca.cer
      cert: spec/fixtures/test_ca_ocsp.cer
      key: spec/fixtures/test_ca_ocsp.key
      cert: spec/fixtures/second_ca.cer
      key: spec/fixtures/second_ca.key

Configure Thin & nginx

The example below is an example yaml config for thin. You will want to have as many servers as you have cores.

chdir: /var/www/r509-ocsp-responder
rackup: /var/www/r509-ocsp-responder/
socket: /var/run/r509-ocsp-responder.sock
pid: /var/run/
servers: 2
daemonize: true
log: /var/log/r509-ocsp-responder.log

Since this config is just using sockets let's set up nginx as a reverse proxy for the thin instances. We can also use this as a caching layer if we choose to enable cache_headers.

proxy_cache_path  /var/www/cache levels=1:2 keys_zone=ocsp:8m max_size=16m inactive=64m;
proxy_temp_path /var/www/cache/tmp;

upstream thin_ocsp_responder{
  server unix:/var/run/r509-ocsp-responder.0.sock fail_timeout=0;
  server unix:/var/run/r509-ocsp-responder.1.sock fail_timeout=0;
server {
  listen     80;

  location / {
    proxy_pass http://thin_ocsp_responder;
    proxy_cache ocsp;
    proxy_cache_use_stale updating;

Within the location block you may also choose to add these directives:

proxy_cache_methods GET POST;
proxy_cache_valid  200 302  1m;

If present, these lines will cause 200 and 302 responses to POST and GET to be cached for 1 minute. This allows you to cache POST requests (Note: Per the HTTP RFC POST requests should not be cached) in addition to the GET requests normally supported by the ruby layer. NOTE: The proxy_cache_valid values are lower priority than caching headers sent by the thin instances so if you do not keep the value here in sync with the max_cache_age config (or turn off cache_headers entirely and solely control it through nginx) you will have mismatched cache times. Additionally, this will cache nonced responses, which wastes RAM since they will not be re-used.

If you would like to track the cache utilization you can also modify the nginx logging to track cache hits. There are a variety of ways this can be accomplisehd, but one of the simplest is simply to alter your log_format line to add $upstream_cache_status.


This OCSP responder supports several optional flags (in addition to supporting an arbitrary number of responder certificates).

  • copy_nonce - (true/false) Sets whether to copy the nonce from request to response (if present)

  • cache_headers - (true/false) Sets whether to set HTTP headers for caching GET responses. Coupled with a reverse proxy you can cache responses for a finite period and vastly speed up the response time of your server (at the cost of response freshness). Nonced requests will not be cached. The performance benefit of caching can vary drastically depending on the mix of clients connecting to the OCSP responder.

  • max_cache_age - (integer) Sets the maximum age in seconds a response can be cached. At this time r509-ocsp-responder does not support cache invalidation so it is recommended to set this to a low value to reduce the time you may serve stale responses in the event of a revocation.


You can send a kill -USR2 signal to any running r509-ocsp-responder process to cause it to reload and print its config to the logs (provided your app server isn't trapping USR2 first).


You can file bugs on GitHub or join the #r509 channel on to ask questions.

Running Tests

You'll need rspec, rake, and rack-test to run the tests. With these gems in place run rake spec

Something went wrong with that request. Please try again.