What is rack in ruby? What is puma in ruby? - ruby

According to the definition, the puma is kind of web server and the rack is an interface between web server and application server.
But, lots of videos mention that rack is a interface between web framework and web server. So can I interpret that we use web framework to build our application, so the rack is an interface between web framework and web server?
Another question is that if puma is kind of web server, can I use Apache or Nginx to replace it?

Puma is an application server, more specifically a Rack app server. (There are more than just Puma: Unicorn, Passenger etc. There are also application servers for different interfaces; for example, Tomcat and JBoss are Java application servers.) An application server accepts a HTTP request, parses it into a structure in the application's language, hands it off to the application, and awaits a response object which it then returns to the client.
Nginx/Apache are general purpose web servers. Apache does not know how to serve Rack applications, and Puma doesn't know how to do a bunch of other things Nginx/Apache do (e.g. CGI scripts, URL rewriting, proxies, balancing, blacklisting...)
Rack is a library for Ruby that accepts parsed HTTP requests from an app server, funnels them through a configurable stack of middleware (such as e.g. session handling) passing the request object to a handler, and returning the response object the app server, making web development in Ruby easy. You can execute a Rack app directly (or rather, with a very simple server that is installed with Rack), but it is not recommended outside development, which is where "proper" application servers come in: they know how to keep your app alive, restart it if it dies, guarantee that there is the predetermined number of threads running, things like that.
Thus, typically, you have your Web server accept connections, then using simple reverse proxy pass the appropriate requests to your Rack application, which is executing inside the Rack app server. This gives you the benefits from all the involved pieces.

Related

Enabling HTTPS with Rack, Puma and Sinatra?

I have a Ruby web application built with Sinatra, Rack and Puma. I'm using Sinatra to implement the controllers (MVC pattern), each handling a different route, and each controller class extends Sinatra::Base. I'd like to enable TLS so that all connections to the server are served over HTTPS.
My Rack config.ru looks like:
require 'sinatra'
require 'rack'
# Start my database ...
run Rack::URLMap.new(
'/api/foo' => FooController.new,
'/api/bar' => BarController.new
)
Puma is picked up automatically by Rack.
How do I enable HTTPS? To start, I'm happy to use a self-signed certificate, but how can I configure the server with a valid cert? None of this seems well-documented at all, which I find quite frustrating. Am I overlooking an option I can just set at the top-level in my Rack config file, something like set :ssl => true maybe?
Similar yet fruitless SO posts:
How to make Sinatra work over HTTPS/SSL?
How to enable SSL for a standalone Sinatra app?
Since you mentioned that you use Puma, you can find this in their docs:
Need a bit of security? Use SSL sockets!
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'
In production deployments a dedicated load balancer (e.g. nginx, HAProxy, AWS ELB) is usually responsible for SSL termination, and forwards plain HTTP traffic to application servers over the internal network. These heavy duty web servers are usually much faster, more stable, and better audited.

How to find out the worker/socket number from within app code running in thin web server

I've recently started using a centralized log server (graylog2) and have been happily adding info to be logged.
I'm also running several Ruby web applications (Rails and Sinatra) under the thin web server, each with a number of workers (1-4). The workers listen to UNIX sockets.
I'd like to log which of the thin workers (i.e. worker #1, worker #2) is serving the request. The idea is to check that all workers get roughly the same load from the load balancer.
There seems to be no HTTP header or ENV variable set up for this in thin.
Anyone know if this information can be made available to the web app running inside the worker ?

HTTP upload server in Ruby

I'm thinking to build an HTTP upload server in Ruby for my project. So far, I'm looking at setting up a Rack server to run with "Rainbow!" or a sinatra server with Rack middleware. The server is required to support HTTP uploads with multipart and chunking. Is this a good choice?
I'd love to see some examples how to set up a simple HTTP upload server but I couldn't find anywhere on the 'net.
Since a file upload can take a while, an important point of uploading files in Ruby are blocking processes while a file is uploaded. You might want to look into projects that are based on EventMachine and/or Goliath to achieve non-blocking processing of HTTP requests. Some ideas here:
http://isurfsoftware.com/blog/2011/05/12/2011-experimenting-with-goliath-and-EventMachine/
https://gist.github.com/rweald/969981
http://www.bigfastblog.com/rubys-eventmachine-part-3-thin

Are WebSockets really meant to be handled by Web servers?

The WebSocket standard hasn't been ratified yet, however from the draft it appears that the technology is meant to be implemented in Web servers. pywebsocket implements a WebSocket server which can be dedicated or loaded as Apache plugin.
So what I am am wondering is: what's the ideal use of WebSockets? Does it make any sense to implement a service using as dedicated WebSocket servers or is it better to rethink it to run on top of WebSocket-enabled Web server?
The WebSocket protocol was designed with three models in mind:
A WebSocket server running completely separately from any web server.
A WebSocket server running separately from a web server, but with traffic proxied to the websocket server from the web server (allowing websocket and HTTP traffic to co-exist on the same port)
A WebSocket server running as a plugin in the web server.
The model you pick really depends on the application you are trying to build and some other constraints that may limit your choices.
For example, if your application is going to be served from a single web server and the WebSocket connection will always be back to that same server, then it probably makes sense to just run the WebSocket server as a plugin/module in the web server.
On the other hand if you have a general WebSocket service that is usable from many different web sites (for example, you could have continuous low-latency traffic updates served from a WebSocket server), then you probably want to run the WebSocket server separate from any web server.
Basically, the tighter the integration between your WebSocket service and your web service, the more likely you will want to run them together and on the same port.
There are some constraints that may force one model or another:
If you control the server(s) but not the incoming firewall rules, then you probably have no choice but to run the WebSocket server on the same port(s) as your HTTP/HTTPS server (e.g. 80 and 443). In which case you will have to use a web server plugin or proxy to the real WebSocket server.
On the other hand, if you do not have super-user permission on the server where you are running the WebSocket server, then you will probably not be able to use ports 80 and 443 (below 1024 is generally a privileged port range) and in that case it really doesn't matter whether you run the HTTP/S and WebSocket servers on the same port or not.
If you have cookie based authentication (such as OAuth) in the web server and you would like to re-use this for the WebSocket connections then you will probably want to run them together (special case of tight integration).

Ruby: How to serve static HTML and an EventMachine WebSocket server from the same application?

I'm writing a simple chat application. The only "front-end" required is a single html file, a javascript file, and a few stylesheets. The majority of the application is the server-side EventMachine WebSocket server.
I'm also trying to host this on Heroku.
I currently have a sinatra app that just serves the static files, and a separate app that serves the WebSocket server (on a different port).
Is there a way I can combine these so that I can start up one application which serves/responds to port 80 (for the static files) and another port for the WebSocket server?
It's probably not a good idea to have your WebSocket server run on a different port. WebSockets run on port 80 specifically because that port is not blocked on most networks. If you use a different port, you will find users behind some firewalls unable to use your application.
Running your event server separate from your web server is probably the best way to go.
If you want something a bit more experimental, Goliath has WebSocket support in the master branch and can also serve the needed resources. If you look in the examples directory there is a WebSocket server that also serves it's HTML page.

Resources