How to deploy your Jekyll site on Scalingo
Jekyll is a static site generator based on Ruby. Scalingo is a hosting provider (similar to Heroku, Platform-as-a-Service). One of the great things about Scalingo is that they are an European company with a data center in France.
At Ravioli, we’re moving all our apps to EU-based hosting providers to ensure the privacy of customers. This is necessary because the USA has very lax privacy laws, and it’s easy for the US government to access customer data that is residing on data centers owned or operated by US legal entities. So, even if you host your app on AWS’s Frankfurt server, you compromise your users' privacy.
If you’re still reading this after my privacy detour, thanks! Let’s get to the juicy part.
Scalingo doesn’t offer a native way to serve static applications such as Jekyll or Hugo. Rather, they recommend that you run an Express server that serves the static assets.
Sounds easy enough. Why do we need a wordy blog post for this?
Because there are two gotchas which make deploying your Jekyll site not that straight-forward. The good news is that I have the solution right here for you.
Like Heroku, Scalingo works with buildpacks. Buildpacks tell Scalingo which environment to install before deploying and running your app. We are basically running an Express app that just serves the static files generated by Jekyll. Therefore, we need to choose the nodejs
buildpack.
When you do that, you’ll quickly realize that your build fails. The reason is simple: The nodejs
build pack doesn’t include Ruby, but before deploying we need Ruby to generate the static files for our website. The Jekyll command for that is bundle exec jekyll build
.
Of course, we could run the command before and check in the static build output (usually the _site
folder) to our version control. But this would be a major pain in the ass.
We need a buildpack that somehow contains Node and Ruby. It’s our lucky day! Scalingo offers Multi Buildpacks. To combine multiple build packs, add a file called .buildpacks
to your root with this content:
https://github.com/Scalingo/ruby-buildpack
https://github.com/Scalingo/nodejs-buildpack.git
The order is important. The nodejs
buildpack needs to come last, because we’re deploying a Node application.
Our package.json
should look like this:
{
"scripts": {
"start": "node server.js",
"build": "bundle exec jekyll build"
},
"dependencies": {
"express": "^4.18.2"
}
}
The nodejs
buildpack runs the build
task before deploying. That’s where we build our Jekyll static files. And then it uses the start
task to run the Express server.
Speaking of Express, our second gotcha comes to mind. In their documentation, Scalingo suggests this setup for server.js
:
var express = require('express');
var app = express();
var directory = '/' + (process.env.STATIC_DIR || 'dist')
app.use(express.static(__dirname + directory));
var port = process.env.PORT || 3000;
app.listen(port, function () {
console.log('Listening on', port);
});
With Jekyll, this works ok for the index page, but not for any other page. That’s because it expects the .html
extension. So, /about
won’t work, but /about.html
will. But that’s a bit too 1995 for me. Fortunately, a simple modification to server.js
fixes this problem:
app.use(express.static(__dirname + directory), { extensions:['html'] });
That’s it. Using an Express server and leveraging Scalingo’s Multi Buildpacks, you should be able to deploy any static website on Scalingo.
This static website that you’re reading is generated with Hugo and ironically still runs on Netlify. I’ll make sure to migrate it over to Scalingo one of these days.