Building a basic HTTP server with plain old Ruby & Rack
Occasionally, I find myself in need for a basic HTTP server that will render some static content (HTML, CSS, images,..), no complex installation, only build and launch. As I am a huge Ruby fan, I was wondering how can I achieve this in the simplest way possible with plain Ruby.
What we will build
A basic HTTP server, serving a static HTML file. The Install process should be as small as possible, and launching the server should be fast and with a single command.
What we need
- Ruby 2.6
Enter rack
According to the rack
documentation:
Rack provides a minimal, modular, and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call.
Rack is used by most of the Ruby web servers you can find (puma, Sinatra, Webrick,..), it has an excellent support, a lot of plugins, and is very modular. Think of it has a framework to build Web servers on top of it.
In the next section, we will use Webrick to build the server, I chose this because it is built-in Ruby, the performances are OK, and it doesn’t need a lot of configuration.
Create the project
We will need to first create a home for our project, that will contain our application logic, I called it static-rb
, you can call it whatever you want.
Inside that project, to create our Ruby server, we will need to create three files:
- A
Gemfile
(contains the dependencies we will need). - A
config.ru
file (the web server logic). - An
index.html
file inside apublic/
folder.
Create those three files with you favorite tool (explorer, VS Code, vim, terminal, …), the folder tree should look like this:
static-rb/
|
config.ru
|
Gemfile
public/
|
index.html
The Gemfile
As the goal is to have a small footprint, we will keep the dependencies short with only one of them, you guessed it, rack
!
# frozen_string_literal: true
source 'https://rubygems.org'
ruby '2.6.6'
# Rack provides a minimal, modular and adaptable interface for developing web applications in Ruby
gem 'rack', '~> 2.2', '>= 2.2.3'
As I said before, no need to install Webrick as it comes built-in with Ruby.
Next, let’s install that dependency using bundler
(the Ruby package manager).
bundle install
The config.ru
This file will hold all the logic behind our web server, and it will fit in ≤ 40 lines of code.
We need the server to listen on a specific port, and respond with our HTML file when we will request the document root /
.
To achieve this, we will have to use the rack
Builder method:
# frozen_string_literal: true
require 'webrick'
# Listen on '/' and display the index.html
app = Rack::Builder.new do
map '/' do
use Rack::Static, urls: ['/'], root: 'public', index: 'index.html'
run lambda { |_env|
[
200,
{
'Content-Type': 'text/html',
'Cache-Control': 'no-cache'
},
File.open('public/index.html', File::RDONLY)
]
}
end
end
It does not grow more complex than this. It is almost finished, we need to plug it to Webrick and roll with it.
# frozen_string_literal: true
require 'webrick'
# Listen on '/' and display the index.html
app = Rack::Builder.new do
map '/' do
use Rack::Static, urls: ['/'], root: 'public', index: 'index.html'
run lambda { |_env|
[
200,
{
'Content-Type': 'text/html',
'Cache-Control': 'no-cache'
},
File.open('public/index.html', File::RDONLY)
]
}
end
end
# Options, like port, logs, SSL config, etc..
webrick_options = {
Port: 3000,
Logger: WEBrick::Log.new($stdout, WEBrick::Log::DEBUG),
DocumentRoot: './'
}
# Launch Webrick server
Rack::Handler::WEBrick.run app, webrick_options
# Shutdown the server with CTRL + C
Signal.trap 'INT' do
Rack::Handler::WEBrick.shutdown
end
We are now ready to use our web server. What’s really cool is that rack
comes up with a useful command line tool that use our config and launch the server with a single command:
rackup # OR bundle exec rackup
Type this in your terminal, and you should see that the server is ready and listening on the port 3000.
[2020-10-08 12:23:30] INFO WEBrick 1.4.2
[2020-10-08 12:23:30] INFO ruby 2.6.6 (2020-03-31) [x86_64-linux]
[2020-10-08 12:23:30] DEBUG WEBrick::HTTPServlet::FileHandler is mounted on /.
[2020-10-08 12:23:30] DEBUG Rack::Handler::WEBrick is mounted on /.
[2020-10-08 12:23:30] INFO WEBrick::HTTPServer#start: pid=182768 port=3000
Open your web browser of choice and enter the URL localhost:3000.
Yeah 🔥 !!!
Wrapping up
We learned to create a small footprint web server, that can host static files, like a documentation, and that you can launch with the help of two small commands: bundle install && rackup
.
Can it be more simple?
Probably yes, but I think it’s simple enough.
Can I use this to host my next big ass web project ?
I would advise you not to 😉.
Can I have SSL support?
Definitely yes, you can see one example on the repository jveillet/static-rb.
Is this useful?
I don’t know, you decide 🙂.
Resources
- rack: A modular Ruby web server interface.
- webrick: HTTP server toolkit.
- jveillet/static-rb: A very stripped-down HTTP server built with Ruby and Rack.