Flynn is a relatively new and cool open source platform (PaaS) for running applications in production. Flynn started more than 3 years ago with a crowdfunding campaign on Hacker News, and shipped their 1.0 this past July.

If you are not familiar with what a PaaS is, a PaaS is a piece of software that provide a platform for developing, testing, running and managing web applications in production and development environment.

PaaS platforms drastically minimise the time and effort needed to provision, build, and deploy your a web application, PaaS also provide a quick way to provision a database and connect it to your webapp.

There are many successful PaaS platforms running in the wild; some proprietary ones like heroku and many other open sourced one, like dokku, deis.io and others.

In this article, I will explain how to use flynn 1. Flynn gives you many thing out of the box, it helps you build and run the application, it provisions and connect a database, manages scaling, provides good tutorial and documentation on how to deploy to AWS, Azure and your custom servers ... and many other cool stuff.

Let's get this started.

Installing Flynn and flynn local server

In order to install flynn on macos (my current machine) Follow the steps bellow. If any of the steps are not working, or you want to read it from the source, refer to flynn installing instructions.

First start by installing the flynn CLI app:

L=/usr/local/bin/flynn && curl -sSL -A "`uname -sp`" https://dl.flynn.io/cli | zcat >$L && chmod +x $L  

Next, we'll install flynn local server on our machine, this local server can be used as a development or staging environment for when we are developing our app.

Flynn website provide a step-by-step explanation on how to create this local server using virtual box and vagrant.

If the steps worked correctly or you, you should have a vagrant machine provisioned. We can check that you have it by running:

> vagrant global-status

id       name    provider   state   directory  
-------------------------------------------------------
1dedb1e  default virtualbox running /SomePath/flynn/demo  

To check that the machine is currently running (and not suspended or shutdown), we run (replacing 1dedb1e with the actual id of your vagrant machine):

> vagrant status 1dedb1e

Current machine states:  
default                   running (virtualbox)

In addition to creating the vagrant machine, the installation steps should have also pointed your browser to a flynn dashboard. If that didn't happen, we can get the dashboard URL by getting the flynn dashboard application info:

> flynn -a dashboard info

=== dashboard
Web URL:  https://dashboard.demo.localflynn.com  

Pointing your browser to https://dashboard.demo.localflynn.com should launch the flynn dashboard.

Creating the phoenix application

Now that we have a running flynn server, lets proceed at creating the phoenix app that we're going to deploy:

mix phoenix.new --no-ecto hello-flynn  

Flynn depends on git to publish releases to the server, we'll have to init a repo inside this newly created phoenix app:

cd hello-flynn  
git init  

Following, we're going to create the flynn application itself:

flynn create hello-flynn  

This newly created application will have its own git url (for pushing and deploying). To check the info of this flynn application, we run:

> flynn -a hello-flynn info

=== hello-flynn
Git URL:  https://git.demo.localflynn.com/phoenix.git  

The Git URL up there, is how we get to deploy our code. In order to use it, we need to add it as a remote in our git repo. flynn provides a convenience method to do just that:

flynn -a hello-flynn remote add  

Inspecting our git repo remote shows that flynn remote have been added:

> git remote -v

flynn    https://git.demo.localflynn.com/hello-flynn.git (fetch)  
flynn    https://git.demo.localflynn.com/hello-flynn.git (push)  

Environment and buildpacks

Flynn does it best at discovering how to build your webapp, however, phoenix (and elixir) is not yet discoverable at the time of writing.

Luckily, flynn is compatible with heroku buildpacks, which means we can use the same buildpacks we use in heroku when deploying with flynn.

Lets go ahead and specify the elixir buildpacks to build our webapp.

flynn -a hello-flynn env set BUILDPACK_URL=https://github.com/HashNuke/heroku-buildpack-elixir.git  

In order to deploy the app successfully, we also need for the secret key to be set correctly in our phoenix app.

That means we first need to generate it:

> mix phoenix.gen.secret

uXOVw6OAJFs0d5BQjSw2qy06dKV/YQyeV+VMgmUnKKuS5KfjwpXRrZwyPS5hBxmX  

And then we need to set it as an env var in the flynn application (replace the secret with your generated secret):

flynn -a hello-flynn env set SECRET_KEY_BASE=VWDUxgG9gBHpbnav9hMt0u6V1gTvo2TEgjVP6vyACiD2Oer9xApPpbc8a7o2HR7D  

Finally, for this secret ket to work, we need to edit the default phoenix configuration to accept the secret key as a system environment variable (the default is using prod.secret.exs).

To do that, open config/prod.exs and remove last line import_config "prod.secret.exs". And add secret_key_base to the config/prod.exs

config :testing_flynn2, TestingFlynn2.Endpoint,  
  http: [port: {:system, "PORT"}],
  url: [host: "example.com", port: 80],
  cache_static_manifest: "priv/static/manifest.json",
  secret_key_base: System.get_env("SECRET_KEY_BASE")

The last environment variable that we have to set is the desired port, we do that with:

flynn -a hello-flynn  env set PORT=80  

The dashboard for this application should now look like this
Flynn dashboard for our application that shows the environment variables

Procfile

Flynn needs to know what commands to use to launch your phoenix webapp. It uses procfile configuration file to figure out that.

In this example, we want to start our phoenix server on the port specified by the environment.

That is achieved by creating a Procfile with:

web: MIX_ENV=prod PORT=$PORT mix phoenix.server  

The string before the colon defines the name of the job. web is normally used as the default name of the main application to launch in a webapp, we will leave it as that for this demo.

Build a release

In flynn, release are built when we push to its git remote. We do that by adding our changes, committing and pushing to flynn remote.

git add .  
git commit -m "Initial commit"  
git push flynn master  

After pushing to flynn, the build process should commence on the flynn server. The terminal should output something like this:

Counting objects: 16, done.  
Delta compression using up to 4 threads.  
Compressing objects: 100% (16/16), done.  
Writing objects: 100% (16/16), 51.86 KiB | 0 bytes/s, done.  
Total 16 (delta 4), reused 0 (delta 0)  
-----> Building phoenix...
-----> Fetching custom buildpack
-----> Elixir app detected
-----> Checking Erlang and Elixir versions
       WARNING: elixir_buildpack.config wasn't found in the app
       Using default config from Elixir buildpack
       Will use the following versions:
       * Stack cedar-14
       * Erlang 18.3
       * Elixir 1.2.6
       Will export the following config vars:
       * Config vars DATABASE_URL
       * MIX_ENV=prod
-----> Using cached Erlang 18.3
-----> Installing Erlang 18.3

-----> Using cached Elixir v1.2.6
-----> Installing Elixir v1.2.6
-----> Installing Hex
    ....
    More lines here
    ....
-----> Discovering process types
       Procfile declares types -> web
       Default process types for Elixir -> web
-----> Compiled slug size is 67M
-----> Creating release...
=====> Application deployed
To https://git.demo.localflynn.com/phoenix.git  
   e82acb8..0508f75  master -> master

Some of the important bits above:

  • Fetching custom buildpack: flynn is using the buildpack, which describes how to build an elixir app, to build our application
  • * Erlang 18.3 and * Elixir 1.2.6: These versions of Erlang and Elixir were used
  • Procfile declares types -> web: Procfile was read and parsed, a job with name web was found
  • =====> Application deployed: The app was deployed successfully 😽

Note: If you want to customise what version elixir/Erlang to use when building the elixir app, you can create a elixir_buildpack.config file on the root of your repo. This file will be read by the buildpacks and used to customise the build process. Read more about this from github

Visiting the website

If we got the Application deployed message above, it means the website has been deployed.

Let's navigate to it. To get its URL we run:

> flynn -a hello-flynn info

=== hello-flynn
Git URL:  http://json.demo.localflynn.com/json.git  
Web URL:  http://json.demo.localflynn.com  

Visiting http://json.demo.localflynn.com should show you the hello phoenix app welcome page. Woot Woot 🤖

Well, Actually... If you (as it happened with me) got the phoenix welcome screen rendered without css:
Phoenix welcome page without css styles

It means that the static files are not getting generated. Thats can be fixed with a couple (or a dozen) of consequent npm commands. I will leave that for the reader as it's not relevant to flynn (sorry 😿).


Sum up

We saw in this post how (relatively) easy it is to use flynn as a PaaS platform to deploy our phoenix application. We started by installing flynn and ended with deploying a phoenix application on our local flynn server. If you are already familiar with heroku, you can see how flynn maps almost 1:1 with it.

In a follow up article I will explain how to use flynn to deploy your application on an azure instance. Stay tuned 🚀

As always, if you enjoyed it consider following me on twitter @ifnottrue to keep in touch :)


  1. My preferred PaaS currently