Getting Started

Getting an application running on Fly.io is essentially working out how to package it as a deployable image and attach it to a database. Once packaged it can be deployed to the Fly.io global application platform.

In this guide we’ll learn how to deploy an Elixir Phoenix application on Fly.io and connect it to a PostgreSQL database.

NOTE: This guide is for apps generated on Phoenix 1.6.3 or later, where deployment is streamlined significantly. If you’re on an earlier version and can’t upgrade, check out our legacy deployment guide.

We’ll be using the standard web application generated by the Elixir Phoenix Framework.

Preparation


If you don’t already have Elixir and Phoenix installed, get them set up before starting this guide. When you install Elixir, the Mix build tool ships with it.

You can install the Phoenix project generator phx.new from a Hex package as follows:

mix archive.install hex phx_new

Generate the app and deploy with Postgres


If you just want to see how Fly.io deployment works, this is the section to focus on. Here we’ll bootstrap the app and deploy it with a Postgres database.

First, install flyctl, your Fly app command center, and sign up to Fly if you haven’t already.

Now let’s generate a shiny, new Phoenix app:

mix phx.new hello_elixir

The output ends with instructions for configuring the database and starting the app manually. The Fly.io launcher is going to take care of this, so we can ignore them.

When you run fly launch from the newly-created project directory, the launcher provides some defaults for your new app, and gives you the option to tweak the settings.

Run:

cd hello_elixir
fly launch

You’ll get a summary of the defaults chosen for your app:

Organization: MyOrgName              (fly launch defaults to the personal org)
Name:         hello_elixir            (derived from your directory name)
Region:       Secaucus, NJ (US)      (this is the fastest region for you)
App Machines: shared-cpu-1x, 1GB RAM (most apps need about 1GB of RAM)
Postgres:     <none>                 (not requested)
Redis:        <none>                 (not requested)

? Do you want to tweak these settings before proceeding? Yes
Opening https://fly.io/cli/launch/bea626e2d179a083a3ba622a367e24ec ...

Type y at the prompt to open the Fly Launch page, and make the following changes to your app config:

  • Change the default app name and region, if needed.
  • For Databases, select Fly Postgres, give the Postgres database app a name (for example, your app name with -db appended) and choose a configuration.

Once you confirm your settings, you can return to the terminal, where the launcher will:

  • Run the Phoenix deployment setup task
  • Build the image
  • Set secrets required by Phoenix (SECRET_KEY_BASE, for example)
  • Deploy the application in your selected region
Waiting for launch data... Done
Created app 'hello_elixir' in organization 'personal'
Admin URL: https://fly.io/apps/hello_elixir
Hostname: hello_elixir.fly.dev
Set secrets on hello_elixir: SECRET_KEY_BASE
Creating postgres cluster in organization personal
Creating app...
Setting secrets on app hello_elixir-db...
Provisioning 1 of 1 machines with image flyio/postgres-flex:15.3@sha256:44b698752cf113110f2fa72443d7fe452b48228aafbb0d93045ef1e3282360a6
Waiting for machine to start...
Machine 2865550c7e96d8 is created
==> Monitoring health checks
  Waiting for 2865550c7e96d8 to become healthy (started, 3/3)

Postgres cluster hello_elixir-db created
  Username:    postgres
  Password:    EChe3BrhCjsPQEI
  Hostname:    hello_elixir-db.internal
  Flycast:     fdaa:2:45b:0:1::1d
  Proxy port:  5432
  Postgres port:  5433
  Connection string: postgres://postgres:EChe3BrhCjsPQEI@hello_elixir-db.flycast:5432

Save your credentials in a secure place -- you won't be able to see them again!

Connect to postgres
Any app within the MyOrgName organization can connect to this Postgres using the above connection string

Now that you've set up Postgres, here's what you need to understand: https://fly.io/docs/postgres/getting-started/what-you-should-know/
Checking for existing attachments
Registering attachment
Creating database
Creating user

Postgres cluster hello_elixir-db is now attached to hello_elixir
The following secret was added to hello_elixir:
  DATABASE_URL=postgres://aa_hello_elixir2:Er6pLzUBuhKcbBl@hello_elixir-db.flycast:5432/aa_hello_elixir2?sslmode=disable
Postgres cluster hello_elixir-db is now attached to hello_elixir
Generating rel/env.sh.eex for distributed Elixir support
Preparing system for Elixir builds
Installing application dependencies
Running Docker release generator
Wrote config file fly.toml
Validating /Users/anderson/test-elixir-gs/hello_elixir2/fly.toml
✓ Configuration is valid
==> Building image
Remote builder fly-builder-black-pine-7645 ready
Remote builder fly-builder-black-pine-7645 ready
==> Building image with Docker
--> docker host: 20.10.12 linux x86_64

...

--> Pushing image done
image: registry.fly.io/hello_elixir:deployment-01HPMGHTG8XSYH3ZCV82SF5CEZ
image size: 126 MB

Watch your deployment at https://fly.io/apps/hello_elixir/monitoring

Provisioning ips for hello_elixir
  Dedicated ipv6: 2a09:8280:1::2a:bc0b:0
  Shared ipv4: 66.241.124.79
  Add a dedicated ipv4 with: fly ips allocate-v4

Running hello_elixir release_command: /app/bin/migrate

-------
 ✔ release_command 784eee4c294298 completed successfully
-------
This deployment will:
 * create 2 "app" machines

No machines in group app, launching a new machine
Creating a second machine to increase service availability
Finished launching new machines
-------
NOTE: The machines for [app] have services with 'auto_stop_machines = true' that will be stopped when idling

-------
Checking DNS configuration for hello_elixir.fly.dev

Visit your newly deployed app at https://hello_elixir.fly.dev/

Make sure to note your Postgres credentials from the output.

That’s it! Run fly apps open to see your deployed app in action.

Try a few other commands:

  • fly logs - Tail your application logs
  • fly status - App deployment details
  • fly status -a postgres-database-app-name - Database deployment details
  • fly deploy - Deploy the application after making changes

To recap, the fly launch command detected that we are using Phoenix, set up a Fly app, created a Fly Postgres app and configured it for us, updated our Dockerfile, and created special modules and scripts to run ecto migrations for us!

Storing secrets on Fly.io

You may also have some secrets you’d like set on your app.

Use fly secrets to configure those.

fly secrets set MY_SECRET_KEY=my_secret_value

Deploying again

When you want to deploy changes to your application, use fly deploy.

fly deploy

The fly deploy command uses a Fly.io remote builder app to build the image.

You can always check on the status of a deploy:

fly status

Check your app logs:

fly logs

If everything looks good, open your app on Fly.io!

fly apps open

Important IPv6 settings

The flyctl command attempts to modify your project’s Dockerfile and append the following lines:

# Appended by flyctl
ENV ECTO_IPV6 true
ENV ERL_AFLAGS "-proto_dist inet6_tcp"

If you customized your Dockerfile or launched without the Dockerfile, this setting may not have been set for you. These values are important and enable your Elixir app to work smoothly in Fly’s private IPv6 network.

Check for this if you encounter network-related errors like the following:

Could not contact remote node my-app@fdaa:0:31d4:a5b:9d36:7c1e:f284:2, reason: :nodedown. Aborting...

What’s Next?

Next up, IEx into Your Running App!

Additional resources