Provide manageable Let's Encrypt Certificate for Rails.
- Rails 6.1+
- Ruby 2.7+
Puts this in your Gemfile:
gem 'rails-letsencrypt'Run install migrations
rails generate lets_encrypt:install
rake db:migrateSetup private key for Let's Encrypt API, and create an account at letsencrypt.org associated with that key
rails generate lets_encrypt:registerAdd acme-challenge mounts in config/routes.rb
mount LetsEncrypt::Engine => '/.well-known'Add a file to config/initializers/letsencrypt.rb and put below config you need.
LetsEncrypt.config do |config|
  # Using Let's Encrypt staging server or not
  # Default only `Rails.env.production? == true` will use Let's Encrypt production server.
  config.use_staging = true
  # Set the private key path
  # Default is locate at config/letsencrypt.key
  config.private_key_path = Rails.root.join('config', 'letsencrypt.key')
  # Use environment variable to set private key
  # If enable, the API Client will use `LETSENCRYPT_PRIVATE_KEY` as private key
  # Default is false
  config.use_env_key = false
  # Should sync certificate into redis
  # When using ngx_mruby to dynamic load certificate, this will be helpful
  # Default is false
  config.save_to_redis = false
  # The redis server url
  # Default is nil
  config.redis_url = 'redis://localhost:6379/1'
  # Enable it if you want to customize the model
  # Default is LetsEncrypt::Certificate
  #config.certificate_model = 'MyCertificate'
endThe SSL certificate setup depends on the web server, this gem can work with ngx_mruby or kong.
Add a new domain into the database.
cert = LetsEncrypt::Certificate.create(domain: 'example.com')
cert.get # alias  `verify && issue`Makes a request to Let's Encrypt and verify domain
cert = LetsEncrypt::Certificate.find_by(domain: 'example.com')
cert.verifyAsk Let's Encrypt to issue a new certificate.
cert = LetsEncrypt::Certificate.find_by(domain: 'example.com')
cert.issuecert = LetsEncrypt::Certificate.find_by(domain: 'example.com')
cert.renewCheck a certificate is verified and issued.
cert = LetsEncrypt::Certificate.find_by(domain: 'example.com')
cert.active? # => trueCheck a certificate is expired.
cert = LetsEncrypt::Certificate.find_by(domain: 'example.com')
cert.expired? # => falseTo renew a certificate, you can run renew task to renew coming expires certificates.
rake letsencrypt:renewIf you are using Sidekiq or others, you can enqueue renew task daily.
LetsEncrypt::RenewCertificatesJob.perform_later
When the certificate is trying to issue a new one, you can subscribe it for logging or error handling.
ActiveSupport::Notifications.subscribe('letsencrypt.issue') do |name, start, finish, id, payload|
  Rails.logger.info("Certificate for #{payload[:domain]} is issued")
endThe setup is following this Article
Add config/initializers/letsencrypt.rb to add config to sync certificate.
LetsEncrypt.config do |config|
  config.redis_url = 'redis://localhost:6379/1'
  config.save_to_redis = true
endConnect Redis when Nginx worker start
http {
  # ...
  mruby_init_worker_code '
    userdata = Userdata.new
    userdata.redis = Redis.new "127.0.0.1", 6379
    # If your redis database is not 0, please select a correct one
    userdata.redis.select 1
  ';
}
Setup SSL using mruby
server {
  listen 443 ssl;
  server_name _;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers HIGH:!aNULL:!MD5;
  ssl_certificate certs/dummy.crt;
  ssl_certificate_key certs/dummy.key;
  mruby_ssl_handshake_handler_code '
    ssl = Nginx::SSL.new
    domain = ssl.servername
    redis = Userdata.new.redis
    unless redis["#{domain}.crt"].nil? and redis["#{domain}.key"].nil?
      ssl.certificate_data = redis["#{domain}.crt"]
      ssl.certificate_key_data = redis["#{domain}.key"]
    end
  ';
}
Coming soon.
The gem is available as open source under the terms of the MIT License.