# A First Look at Fly

> Fly is a platform for fullstack applications and databases build with Dockerfiles or Buildpacks that need to run globally

- **Collection:** Blog post
- **Published:** 2021-08-04
- **Author:** Anthony Campolo
- **Canonical URL:** https://ajcwebdev.com/first-look-fly/
- **Markdown URL:** https://ajcwebdev.com/first-look-fly/index.md
- **JSON URL:** https://ajcwebdev.com/first-look-fly/index.json

---

> ___All of this project's code can be found in the [First Look monorepo](https://github.com/ajcwebdev/a-first-look/tree/main/deployment/docker-fly/) on my GitHub.___

## Introduction

[Fly](https://fly.io/) is a platform for fullstack applications and databases that need to run globally. Fly executes your code close to users and scales compute in cities where your app is busiest. You can run arbitrary Docker containers and host popular databases like Postgres.

## Fly Setup

### Install flyctl

You can download the CLI on [Mac, Linux, or Windows](https://fly.io/docs/flyctl/install/).

```bash wrap=false
brew install superfly/tap/flyctl
```

### Create Fly Account

If you are a new user you can create an account with `flyctl auth signup`.

```bash wrap=false
flyctl auth signup
```

After your browser opens you can either:

* Sign-up with your name, email and password.
* Sign-up with GitHub and check your email for link to set a password for verification.

You will also be prompted for credit card payment information, required for charges outside the free plan on Fly. See [Pricing](https://fly.io/docs/about/pricing/) for more details.

### Login to Fly Account

If you already have an account you can login with `flyctl auth login`.

```bash wrap=false
flyctl auth login
```

After your browser opens, sign in with your username and password. If you signed up with GitHub, use the Sign-in with GitHub button to sign in.

## Create Project

```bash wrap=false
mkdir ajcwebdev-fly
cd ajcwebdev-fly
npm init -y
npm i express --save
echo > index.js
echo > Dockerfile
echo > .dockerignore
echo 'node_modules\n.DS_Store' > .gitignore
```

### Create Server

```javascript
// index.js

const express = require("express")
const app = express()

const port = process.env.PORT || 3000

app.get("/",
  (req, res) => {
    greeting = "<h1>ajcwebdev-fly</h1>"
    res.send(greeting)
  }
)

app.listen(port,
  () => console.log(`Hello from port ${port}!`)
)
```

### Run Server

```bash wrap=false
node index.js
```

```
Hello from port 3000!
```

![01 - hello-world-localhost-3000](https://ajc.pics/2021/08/04/01-hello-world-localhost-3000.webp)

### Create Dockerfile

Add the following code to `Dockerfile` in the root directory of your project.

```docker wrap=false
FROM node:14-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm i
COPY . ./
EXPOSE 8080
CMD [ "node", "index.js" ]
```

Add the following code to `.dockerignore` in the same directory as your `Dockerfile`.

```
node_modules
Dockerfile
.dockerignore
.git
.gitignore
npm-debug.log
```

## Launch Application on Fly

Run `flyctl launch` in the directory with your source code to configure your app for deployment. This will create and configure a fly app by inspecting your source code and prompting you to deploy.

```bash wrap=false
flyctl launch --name ajcwebdev-fly
```

```
Creating app in /Users/ajcwebdev/ajcwebdev-fly
Scanning source code
Detected Dockerfile app
Automatically selected personal organization: Anthony Campolo
Created app ajcwebdev-fly in organization personal
Wrote config file fly.toml
Your app is ready. Deploy with `flyctl deploy`
? Would you like to deploy now? No
```

This creates a `fly.toml` file.

```toml
app = "ajcwebdev-fly"

kill_signal = "SIGINT"
kill_timeout = 5

[env]

[experimental]
  allowed_public_ports = []
  auto_rollback = true

[[services]]
  http_checks = []
  internal_port = 8080
  protocol = "tcp"
  script_checks = []

[services.concurrency]
  hard_limit = 25
  soft_limit = 20
  type = "connections"

[[services.ports]]
  handlers = ["http"]
  port = 80

[[services.ports]]
  handlers = ["tls", "http"]
  port = 443

[[services.tcp_checks]]
  grace_period = "1s"
  interval = "15s"
  restart_limit = 6
  timeout = "2s"
```

Add the following `PORT` number under `env`.

```toml
[env]
  PORT = 8080
```

### Deploy Application

```bash wrap=false
flyctl deploy
```

### Show Current Application Status

Status includes application details, tasks, most recent deployment details and in which regions it is currently allocated.

```bash wrap=false
flyctl status
```

```
App
  Name     = ajcwebdev-fly       
  Owner    = personal                    
  Version  = 0                           
  Status   = running                     
  Hostname = ajcwebdev-fly.fly.dev  

Deployment Status
  ID          = d94d886a-f338-28cf-4078-1ed838eea224         
  Version     = v0                                           
  Status      = successful                                   
  Description = Deployment completed successfully            
  Instances   = 1 desired, 1 placed, 1 healthy, 0 unhealthy  

Instances
ID       VERSION REGION DESIRED STATUS  HEALTH CHECKS      RESTARTS CREATED 
40591407 0       sjc    run     running 1 total, 1 passing 0        37s ago
```

Open your browser to current deployed application with `flyctl open`.

```bash wrap=false
flyctl open
```

```
Opening http://ajcwebdev-fly.fly.dev/
```

Visit your link (`ajcwebdev-fly.fly.dev` in my case) to see the site.

![02 - ajcwebdev-fly-dev](https://ajc.pics/2021/08/04/02-ajcwebdev-fly-dev.webp)

## Discover Related Content

- [A First Look at Docker](https://ajcwebdev.com/first-look-docker/)
- [Deploy a GraphQL Server with Docker and Fly](https://ajcwebdev.com/deploy-gql-docker-container-with-fly/)
- [A First Look at AWS Fargate](https://ajcwebdev.com/first-look-aws-fargate/)
- [Deploying Railway Applications with StepZen](https://ajcwebdev.com/videos/greg-schier-deploying-railway-applications/) (Video)
- [Fly with Rugwiro Valentin](https://ajcwebdev.com/podcasts/fly-rugwiro-valentin/) (Podcast)
