Jared McFarland

The musings of a 20-something engineer

Serving a Static Website With Heroku

I recently wanted to setup a very simple static HTML site for a friend’s school project. I didn’t want to go through the hassle of setting up hosting, I just wanted to put it somewhere.

In the past I’ve used Heroku for this, but I’d never setup a static site there.

This is how I did it.

Stasis

I used stasis to generate the content. It’s an extremely awesome static site generator using Ruby and all sorts of templating engines. I opted for HAML and SASS.

My file structure looked something like this:

root/
 |
  - config.ru
  - Procfile
  - Gemfile
  - controller.rb
  - index.html.haml
  - layout.html.haml
  - sub_dir/
  - stylesheets/
    |
     - style.css.sass
  - images/

I’ll talk about the config.ru and Procfile later. You can checkout stasis if you want to learn more about it’s structure.

My Gemfile contained the gems necessary for development and deployment, and it looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
source :rubygems

gem "haml"
gem "sass"
gem "unicorn"

gem "rack-contrib"

group :development do
  gem "heroku"
  gem "foreman"
end

Rack

The config.ru is to tell Heroku to use Rack to serve the website. It looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
use Rack::Static,  :urls => ["/stylesheets", "/images"], :root => "public"
run Rack::Directory.new("public")

run lambda { |env|
  [
    200,
    {
      'Content-Type'  => 'text/html',
      'Cache-Control' => 'public, max-age=86400'
    },
    File.open('public/index.html', File::RDONLY)
  ]
}

The Rack::Static line tells it to serve the contents of the directories “public/stylesheets” and “public/images” as static content.

The Rack::Directory.new(“public”) line tells Rack to look for requests matching the contents of the “public” directory and serve the corresponding files.

The last block, the lambda { |env| block, tells Rack to default to rendering the file found at “public/index.html”. This makes “/” work.

Foreman

Heroku uses Foreman. It uses a Procfile in the current working directory to tell it what processes to start and monitor.

My Procfile looks like this:

1
web: bundle exec unicorn -p $PORT

Heroku

Now to tie it all together. You’ll need to create a new app on Heroku like so:

1
heroku apps:create --stack cedar [NAME OF YOUR APP]

Then simply

1
git push heroku master

and you should be working!

Comments