Does anyone know of a way to run the ruby debugger and SSL at the same time with Thin?
I've been using Thin successfully with Rails 3.0.10.
I start it using rails server --debugger, and I can debug my code.
Recently, I have also needed to add SSL support to my application, and I'd like to be able to test it locally with a self-signed certificate.
Unfortunately, I have not found a way to start Thin with SSL support when using rails server.
I can successfully start Thin with SSL support by using:
thin start --ssl --ssl-verify --ssl-key-file ssllocal/server.key
--ssl-cert-file ssllocal/server.crt
However, I have not found a way to activate the debugger using thin start.
So it seems like I have the choice of running the debugger (rails server) or SSL (thin start), but not both.
It seems possible to get Webrick to run SSL using rails server by modifying the rails/script file (see here). I experimented with this approach, but I have not had success. Here's one of the attempts:
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 3
# gems installed from the root of your application.
APP_PATH = File.expand_path('../../config/application', __FILE__)
require File.expand_path('../../config/boot', __FILE__)
# THIS IS NEW:
require "rails/commands/server"
require 'rack'
require 'thin'
module Rails
class Server
def default_options
super.merge({
:Port => 3000,
:environment => (ENV['RAILS_ENV'] || "development").dup,
:daemonize => false,
:debugger => false,
:pid => File.expand_path("tmp/pids/server.pid"),
:config => File.expand_path("config.ru"),
:SSLEnable => true
:ssl => true,
"ssl-verify" => true,
"ssl-key-file" => File.expand_path("ssllocal/server.key"),
"ssl-cert-file" => File.expand_path("ssllocal/server.crt")
})
end
end
end
require 'rails/commands'
Note: for those who might be wondering, I created an 'ssllocal' directory off my root application directory, and that's where I store the ssl keys and certs.
You could try just requiring the debugger yourself in your development environment.
In your Gemfile:
if RUBY_VERSION =~ /^1.9/
gem "ruby-debug19", :group => :development
else
gem "ruby-debug", :group => :development
end
And within the config block of your config/environments/development.rb:
require 'ruby-debug'
Debugger.start
This permits you to place the debugger statement anywhere in your code.
Here's my solution - I hacked the Thin TcpServer to load my self-signed SSL certs, only in the development environment. My script/rails looks like this:
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
APP_PATH = File.expand_path('../../config/application', __FILE__)
require File.expand_path('../../config/boot', __FILE__)
# Hack our SSL certs into Thin TcpServer, only in development environment
require 'thin'
module Thin
module Backends
TcpServer.class_eval do
def initialize_with_SSL(host, port)
if Rails.env.development?
Rails.logger.info "Loading SSL certs from ./ssl_dev..."
#ssl = true
#ssl_options = {
:private_key_file => File.expand_path("../../ssl_dev/server.key", __FILE__),
:cert_chain_file => File.expand_path("../../ssl_dev/server.crt", __FILE__),
:verify_peer => nil
}
end
initialize_without_SSL(host, port)
end
alias_method :initialize_without_SSL, :initialize
alias_method :initialize, :initialize_with_SSL
end
end
end
# Must load 'rails/commands' after Thin SSL hack
require 'rails/commands'
Here's how I got it to finally work on production using Thin:
rvmsudo thin start -p 443 --ssl --ssl-key-file ssl/server.key --ssl-cert-file ssl/server.crt
If you are having issues with your KEY file, make sure you validate the CSR by using a site like:
https://ssl-tools.verisign.com
If your CSR fails, then the certificate you receive from your signing authority will fail too.
My site would refuse to load with the SSL certs, only to find out that I abbreviated my State name to "TX" instead of "Texas" while creating my private key. That was the reason it wasn't working all along! SSL certs are a pain in the ass!
I was able to successfully get the debugging working with ssl enabled thin, using the solution suggested by nathan. Though I had to do one small change of deferring initialization of #ssl after the call of initialize_without_ssl (an alias method for the original TcpServer's initialize)
require 'thin'
module Thin
module Backends
TcpServer.class_eval do
def initialize_with_SSL(host, port)
if Rails.env.development?
Rails.logger.info "Loading SSL certs from ./ssl_dev..."
#ssl_options = {
:private_key_file => File.expand_path("../../ssl_dev/server.key", __FILE__),
:cert_chain_file => File.expand_path("../../ssl_dev/server.crt", __FILE__),
:verify_peer => nil
}
end
initialize_without_SSL(host, port)
# #ssl initialized after calling the original initialize of TcpServer
#ssl = true if Rails.env.development?
end
alias_method :initialize_without_SSL, :initialize
alias_method :initialize, :initialize_with_SSL
end
end
end
alias_method :initialize_without_SSL, :initialize
alias_method :initialize, :initialize_with_SSL
end
In the above code snippett, #ssl is set to true after calling the original initialize call of Thin::Backend::TcpServer. I had to do this since the TcpServer invokes its parent's initialize (Thin::Backend:Base) that sets the #ssl to nil
#Base initialize method. Thin gem version 1.5.0
def initialize
#connections = []
#timeout = Server::DEFAULT_TIMEOUT
#persistent_connection_count = 0
#maximum_connections = Server::DEFAULT_MAXIMUM_CONNECTIONS
#maximum_persistent_connections = Server::DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS
#no_epoll = false
#ssl = nil
#threaded = nil
end
As noted in nathan's code block, the whole solution appears to be a hack around. In my opinion, I am fine with the snippet considering the code is done within the context of env.development and most importantly it allows debugging with ssl enabled.
Related
I am using a CMS called Radiant (version 0.9.1), Rails 2.3.18 and Ruby 1.8.7. I have to make the routes in this gem use the 'https'. I need to do it in such a way that I won't edit the gem source files itself, but rather override the gem's routes in the extension. How do I do this?
The configuration of the server really depends on what your server stack looks like
To configure your rails application to use SSL you need to force ssl
In your config/environments/production.rb:
config.force_ssl = true
To test ssl locally I would suggest trying thin as a webserver (also put config.force_ssl in development.rb to test this )
Add:
gem 'thin'
To your gemfile and start a thin ssl server:
$ thin start --ssl -p 3000
EDIT Rails 2 :
For Rails 2 this should work:
lib/force_ssl.rb
class ForceSSL
def initialize(app)
#app = app
end
def call(env)
if env['HTTPS'] == 'on' || env['HTTP_X_FORWARDED_PROTO'] == 'https'
#app.call(env)
else
req = Rack::Request.new(env)
[301, { "Location" => req.url.gsub(/^http:/, "https:") }, []]
end
end
end
config/production.rb
config.middleware.use "ForceSSL"
config/application.rb
require File.expand_path('../../lib/force_ssl.rb', __FILE__)
source: Force SSL using ssl_requirement in Rails 2 app
I am trying to start Faye when starting my rails server. I have a faye.ru file in my app root that looks like:
require 'faye'
faye_server = Faye::RackAdapter.new(:mount => '/queue-listener', :timeout => 45)
run faye_server
And whenever I start my rails server, Faye / thin tries to open on the same port as my rails server. I can add something like:
Thread.new do
system("rackup faye.ru -s thin -E production")
end
into an initializer (found this on SO), but then thin starts on both the rails app port and then the default (9292) port. I think it fails to start on the rails port though. I am just confused about how to start up the thin / faye server on a separate port than the rails server. Any ideas?
You can do the following in development. In production I suggesting implementing it as a standalone server w/monitoring:
if Rails.env.development?
require 'eventmachine'
require 'rack'
require 'thin'
require 'faye'
Faye.logger = Logger.new(Rails.root.join('log/faye.log'))
Faye::WebSocket.load_adapter('thin')
thread = Thread.new do
EM.run {
thin = Rack::Handler.get('thin')
app = Faye::RackAdapter.new(mount: '/faye', timeout: 10)
thin.run(app, :Port => 8000) do |server|
## Set SSL if needed:
# server.ssl_options = {
# :private_key_file => 'path/to/ssl.key',
# :cert_chain_file => 'path/to/ssl.crt'
# }
# server.ssl = true
end
}
end
at_exit { thread.exit }
end
I have been running a rails 2.3 app with a rackup config.ru file to load some grape API middleware.
I recently have a need to run a resque server.
My config.ru is set up like this.
require File.dirname(__FILE__) + '/config/environment'
my_app = Rack::Builder.new do
use Rails::Rack::LogTailer #optional
use Rails::Rack::Static # optional
run ActionController::Dispatcher.new
end
Resque::Server.class_eval do
use Rack::Auth::Basic do |user, password|
begin
if user == "admin" and password == "bandana"
true
else
false
end
end
end
end
run Rack::URLMap.new([
"/" => my_app,
"/resque" => Resque::Server.new
])
run Rack::Cascade.new([
GrapeAPI_entry_1,
GrapeAPI_entry_2,
my_app
])
This doesn't give me the desired effect and I don't know why.
I actually found the answer. It turned out that redis was not running, and yes, you can use cascade with map
My final config.ru looks like this.
re File.dirname(__FILE__) + '/config/environment'
require 'resque/server'
my_app = Rack::Builder.new do
use Rails::Rack::LogTailer #optional
use Rails::Rack::Static # optional
run ActionController::Dispatcher.new
end
Resque::Server.class_eval do
use Rack::Auth::Basic do |user, password|
begin
if user == "admin" and password == "bandana"
true
else
false
end
end
end
end
app = Rack::Builder.new {
use Rails::Rack::Static
map "/resque" do
run Resque::Server
end
map "/" do
run my_app
end
}.to_app
run Rack::Cascade.new([
Grape_API_1,
Grape_API_2,
my_app
])
I recently added similar access to resque on one of my rails servers. It works great -- here is how I did it:
# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
require 'resque/server'
run Rack::URLMap.new \
"/" => MyApp::Application,
"/resque" => Resque::Server.new
My app is based on rails 3.2, however. I'm not sure what the difference is in the rack version you're running.
Are you requiring the resque server code?
On my development machine, I use port 10524. So I start my server this way :
rails s -p 10524
Is there a way to change the default port to 10524 so I wouldn't have to append the port each time I start the server?
First - do not edit anything in your gem path! It will influence all projects, and you will have a lot problems later...
In your project edit script/rails this way:
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
APP_PATH = File.expand_path('../../config/application', __FILE__)
require File.expand_path('../../config/boot', __FILE__)
# THIS IS NEW:
require "rails/commands/server"
module Rails
class Server
def default_options
super.merge({
:Port => 10524,
:environment => (ENV['RAILS_ENV'] || "development").dup,
:daemonize => false,
:debugger => false,
:pid => File.expand_path("tmp/pids/server.pid"),
:config => File.expand_path("config.ru")
})
end
end
end
# END OF CHANGE
require 'rails/commands'
The principle is simple - you are monkey-patching the server runner - so it will influence just one project.
UPDATE: Yes, I know that the there is simpler solution with bash script containing:
#!/bin/bash
rails server -p 10524
but this solution has a serious drawback - it is boring as hell.
I like to append the following to config/boot.rb:
require 'rails/commands/server'
module Rails
class Server
alias :default_options_alias :default_options
def default_options
default_options_alias.merge!(:Port => 3333)
end
end
end
One more idea for you. Create a rake task that calls rails server with the -p.
task "start" => :environment do
system 'rails server -p 3001'
end
then call rake start instead of rails server
Combining two previous answers, for Rails 4.0.4 (and up, presumably), this suffices at the end of config/boot.rb:
require 'rails/commands/server'
module Rails
class Server
def default_options
super.merge({Port: 10524})
end
end
end
We're using Puma as a web server, and dotenv to set environment variables in development. This means I can set an environment variable for PORT, and reference it in the Puma config.
# .env
PORT=10524
# config/puma.rb
port ENV['PORT']
However, you'll have to start your app with foreman start instead of rails s, otherwise the puma config doesn't get read properly.
I like this approach because the configuration works the same way in development and production, you just change the value of the port if necessary.
Inspired by Radek and Spencer...
On Rails 4(.0.2 - Ruby 2.1.0 ), I was able to append this to config/boot.rb:
# config/boot.rb
# ...existing code
require 'rails/commands/server'
module Rails
# Override default development
# Server port
class Server
def default_options
super.merge(Port: 3100)
end
end
end
All other configuration in default_options are still set, and command-line switches still override defaults.
Solution for Rails 2.3 - script/server:
#!/usr/bin/env ruby
require 'rack/handler'
module Rack::Handler
class << WEBrick
alias_method :old_run, :run
end
class WEBrick
def self.run(app, options={})
options[:Port] = 3010 if options[:Port] == 3000
old_run(app, options)
end
end
end
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/server'
If you're using puma (I'm using this on Rails 6+):
To change default port for all environments:
The "{3000}" part sets the default port if undefined in ENV.
~/config/puma.rb
change:
port ENV.fetch('PORT') { 3000 }
for:
port ENV.fetch('PORT') { 10524 }
To define it depending on the environment, using Figaro gem for credentials/environment variable:
~/application.yml
local_db_username: your_user_name
local_db_password: your_password
PORT: 10524
You can adapt this to you own environment variable manager.
You could install $ gem install foreman, and use foreman to start your server as defined in your Procfile like:
web: bundle exec rails -p 10524
You can check foreman gem docs here: https://github.com/ddollar/foreman for more info
The benefit of this approach is not only can you set/change the port in the config easily and that it doesn't require much code to be added but also you can add different steps in the Procfile that foreman will run for you so you don't have to go though them each time you want to start you application something like:
bundle: bundle install
web: bundle exec rails -p 10524
...
...
Cheers
For ruby > 3 and For rails > 7
in file app/config/puma.rb, update the port number.
port ENV.fetch("PORT") { 3200 }
I need to build a ruby daemon that will use the freeswitcher eventmachine library for freeswitch.
Since few days I as looking the web for the best solution to build a ruby daemon that will integrate my rails environment, specailly my active record models. I've take a look to the excellent Ryan Bates screencast (episodes 129 custom daemon) but I'm not sure that is still an actual solution.
How do I do that in a good way?
I build daemons for my rails environments all the time. The daemons gem really takes all the work out of it. Here's a little template extracted from my latest rails app (script/yourdaemon), as an example. I use the eventmachine gem, but the idea is the same:
#!/usr/bin/env ruby
require 'rubygems'
require 'daemons'
class YourDaemon
def initialize
end
def dostuff
logger.info "About to do stuff..."
EventMachine::run {
# Your code here
}
end
def logger
##logger ||= ActiveSupport::BufferedLogger.new("#{RAILS_ROOT}/log/your_daemon.log")
end
end
dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
daemon_options = {
:multiple => false,
:dir_mode => :normal,
:dir => File.join(dir, 'tmp', 'pids'),
:backtrace => true
}
Daemons.run_proc('your_daemon', daemon_options) do
if ARGV.include?('--')
ARGV.slice! 0..ARGV.index('--')
else
ARGV.clear
end
Dir.chdir dir
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
YourDaemon.new.dostuff
end
This gives you all the usual script/yourdaemon [run|start|stop|restart], and you can pass arguments into the daemon after a "--". In production you'll want to use god or monit to make sure the daemon gets restarted if it dies. Have fun!