How to write a small ruby web server? - ruby

I have a ruby script that also needs to serve a few static files in a directory (such as an index.html, CSS and JS directories). What is the best way to write a little inline web server to serve these files?
Solution:
require 'webrick'
web_server = WEBrick::HTTPServer.new(:Port => 3000, :DocumentRoot => Dir.pwd + '/web')
trap 'INT' { web_server.shutdown }
web_server.start
Or add this to your .bash_profile for an easy way to serve up the files in any directory:
alias serve="ruby -rwebrick -e\"s = WEBrick::HTTPServer.new(:Port => 3000, :DocumentRoot => Dir.pwd); trap('INT') { s.shutdown }; s.start\""

You can use the simplest ruby HTTP server you can find:
ruby -run -e httpd . -p 5000
It will serve content from the running directory on port 5000.

If you're looking for something pure-Ruby and simple, WEBrick is a good choice. Because it is pure-Ruby, it won't go very fast.
Mongrel is partially implemented in C and Ruby and is better for performance than WEBrick. (The Ruby on Rails development mode will use Mongrel in preference to WEBrick if Mongrel is installed.)
If you'd like your server to scale better than either of WEBrick or Mongrel, then thin is probably the choice -- it glues Mongrel together on top of EventMachine to scale further than the other, simpler, systems can scale.
Nothing will quite replace running a full-blown web server such as nginx, but integrating that into your application is significantly more work for you and your users.

As #sarnold mentioned that thin is a good server, rack will use thin with a very high priority. And bellow is a one line way to go if you have the rack gem installed:
rackup -b "use Rack::Static, :index => 'index.html'; run Rack::File.new('.')"
If there's no 'index.html' in the current directory, the directory contents will be listed.

Have you looked at Sinatra?
It might be what you're looking for.

Related

How do you translate a rackup invocation to a self-contained script?

I'm trying to make a gem out of an app that did:
spawn("rackup", "--port", PORT.to_s, "--server", "thin", "-E", "development", File.expand_path("../server.ru", __FILE__))
If I use this in the gem I get a LoadError for thin (after packaging it and installing it) (thin is in my gemspec but I guess the error has to do with the spawning of the rackup executable, which is not part of the gem's bundle).
Replacing:
run app
with
Rack::Handler::Thin.run app
in the server.ru file will start the server, but I need to set the parameters too.
I tentatively tried:
ENV['RACK_ENV']='development'
Rack::Handler::Thin.run app, host: 'localhost', port: PORT.to_s
to no avail. What is the recipe for translating parameterized rackup invocations to executable *.ru files with explicit handlers?
Rack::Handler::Thin had a valid_options method.
None of those keys worked, nor did various combinations.
The SERVER_PORT and SERVER_HOST env variables didn't work either.
I endend up running the thin executable with the *.ru file as an argument and that did it.
It may well be that the things I've tried would've worked with some handler other than Thin (i.e., thin might be a crappy rack citizen). I don't know or care. Just needed to get this working. I will, of course, appreciate (upvote/accept) answers that shed more light on this

How Can I use nginx X-Accel-Redirect in a ruby cgi script

I'm using nginx to run a ruby script. I've already set up the nginx config correctly as it works with php-fpm
In php I set
header('X-Accel-Redirect, file_path)
Is there an equivalent for it in ruby.
I have tried it with
cgi = CGI.new
cgi.out( "X-Accel-Redirect" => new_file)
But it doesn't seem to work...
Is any any gem that I could include.
I'm new to ruby. any help would be highly appreciated.
Assuming you are using a Rack application (Rails, Sinatra, Padrino etc.) the same way you used your php-fpm apps (i.e. behind Nginx as a reverse proxy), you should be able to do the same thing you did in PHP:
response['X-Accel-Redirect'] = file_path

How to designate a Rack handler

Rackup is successfully running any Rack app via Rack's default handler. e.g.:
class RackApp
def call(environment)
[
'200',
{'Content-Type' => 'text/html'},
["Hello world"]
]
end
end
run RackApp.new
But rackup is giving "NoMethodError at / undefined method `call' for nil:NilClass" when the last line is changed to instead use Rack's built-in CGI handler:
Rack::Handler::CGI.run RackApp.new
The same objection is raised for Rack's other built-in handlers. e.g. Rack::Handler::Thin, Rack::Handler::FastCGI, even Rack::Handler::WEBrick (which is the handler Rack selects above in default mode).
What's the correct syntax here?
The rackup command reads the config file and starts a server. The Rack::Handler::XXX.run methods also start a server, independently of the rackup command (CGI is slightly different as it isn't actually a server as such).
What happens when you change the line
run RackApp.new
to
Rack::Handler::CGI.run RackApp.new
and run rackup is as follows. The server starts and parses the config file. When the Rack::Handler::CGI.run RackApp.new line is reached it is executed as any other Ruby code would be. In the case of the CGI handler this calls the app and writes the output to the standard output as it would if running as a CGI script (have a look at your terminal when you run rackup). Afterwards the 'rackup' server is started as normal, but without an app to run. When you try to access the page you'll get the NoMethodError, since the app is nil.
Using Rack::Handler::Thin is similar, but in this case, as Thin actually is a web server, it is started and will serve RackApp, but listens on Thin's default port of 8080 (not the rack default of 9292). After stopping Thin (e.g. with Ctrl-C) the default rackup server (Mongrel or Webrick) will start listening on port 9292, again with no app specified so you'll get the NoMethodError.
If you run your modified 'config.ru' as a plain Ruby script rather than using rackup you'll see the same behaviour, but without the rackup server being started. (You'll need to require rack first, so use ruby -rrack config.ru). In the CGI case the output of a single call to your app will be printed to the console, in the Thin case Thin will be started serving your app.
In order to specify the server to use with rackup, you can use the -s option, e.g. rackup -s thin will start the app using Thin (this time on the rackup default port of 9292). You can also do rackup -s cgi but this won't really work in any useful way - it just prints out the html of an error page to the console.
CGI
If you're trying to run your app as a CGI there are a couple of options. You need to create a CGI script that calls your app using the CGI handler. This could itself be a ruby script that calls Rack::Handler::CGI.run directly, in fact you could use your modified config.ru directly (you might want to rename it first and add an explicit require 'rack' line).
Alternatively you can use a shell script which then calls rackup config.ru. In this situation rackup detects that it's running as CGI and automatically uses the correct handler
http://guides.rubyonrails.org/rails_on_rack.html (see point 3.5)
also interesting:
http://railscasts.com/episodes/151-rack-middleware
http://railscasts.com/episodes/222-rack-in-rails-3

Running Sinatra on port 80

I installed Sinatra and it works but it uses port 4567 by default. I want it to run on port 80.
In an effort to get it to work on port 80, I tried this:
require 'rubygems'
require 'rack/handler/webrick'
require 'sinatra'
Sinatra::Application.default_options.merge!(
:run => false,
:env => :production,
:port => 80
)
get '/' do
"Hello World"
end
But I get this error:
$ ruby -rubygems index.rb
index.rb:5:in `<main>': undefined method `default_options' for Sinatra::Application:Class (NoMethodError)
Any idea what's going on?
Can't you just use (http://www.sinatrarb.com/configuration.html):
set :port, 80
Note that in order to bind a socket to port 80, you'll need to have superuser privileges.
And, by the way,
Using Sinatra.default_options to set base configuration items is obsolete
From: http://www.sinatrarb.com/one-oh-faq
An alternate way to accepted answer
rvmsudo rackup -p 80
In case one is using RVM to manage Ruby versions, you may not be able to use sudo that easily (or else would need to setup ruby in path).
Any port below 1024 is for privileged processes only. You'd have to run as root to run the sinatra app directly on 80. You could reverse proxy - http://sinatra-book.gittr.com/#deployment.
Yes, running anything other than Apache, Nginx, Varnish or HAProxy or port 80 is in my opiniona dangerous game. Those tools are very good at what they do. A reverse proxy setup is the way to go.

Passing options to rackup via a Sinatra application

I'm new to ruby, learning Sinatra. While creating a Sinatra site by requiring 'sinatra' and setting up the routes directly under is pretty easy and rather well documented, creating an application by requiring 'sinatra/base' and writing a class that inherits from 'Sinatra::Base', while still relatively easy, is very poorly documented (maybe because it's a pretty recent feature of Sinatra).
And that's exactly what I am doing. I am not having too much trouble on the Sinatra part, however I am having a bit of trouble on the rackup/thin/server part. Apparently there are two ways to deploy the application: using Sinatra itself (using the run! method) and using a rackup file (typically config.ru).
Using Sinatra's run! method is extremely intuitive and works like a charm, but apparently it doesn't work if I want to deploy my app on heroku. As a matter of fact, almost all the Sinatra apps that I have encountered on GitHub use a config.ru file.
Using a rackup file might be equally intuitive, but I can't manage to understand how to pass options from the Sinatra app to the server (ir: the port). I tried to merge options to rackup's default options array:
MyApp::App.default_options.merge!(
:run => false,
:env => :production,
:port => 4567
)
run MyApp::App
by adding options directly to the app:
MyApp::App.set :port, 4567
MyApp::App.set :run, false
MyApp::App.set :env, :production
run MyApp::App
by setting options from within the application class:
module MyApp
class App < Sinatra::Base
set :port, 4567
set :run, false
set :env, :production
# ...
# config.ru
require 'app'
run MyApp::App
All the methods above failed, either by showing error messages or by just not taking any of the options into consideration. So is there any way to pass options to rackup/thin/the sever via a Sinatra app when using a rackup file? Or the options in questions should be passed directly to rackup/thin/the sever via command-line options?
As a reference to the problem, here is the little Sinatra application I am building: https://github.com/AzizLight/Wiki/
You're actully going to pass options to thin on the command line directly or via a configuration file. See all options:
$ thin -h
For production, use a configuration file:
$ thin -C thin-production.yml -R config.ru start
Here is an example thin-production.yml file:
---
address: localhost
port: 3020
servers: 4
max_conns: 1024
max_persistent_conns: 512
timeout: 30
environment: production
pid: tmp/pids/thin-production.pid
log: log/thin-production.log
daemonize: true
I know I'm resurrecting an ancient question here, but I came across another useful solution not yet mentioned. As stated in this rack wiki tutorial:
the first line starting with #\ is treated as if it was options, allowing rackup arguments to be specified in the config file.
So if you wanted to set your host to 0.0.0.0 and port to 5656, you would add the following line to the beginning of your config.ru file:
#\ -o 0.0.0.0 -p 5656

Resources