Run a Go App

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

In this guide we’ll learn how to deploy a Go application on Fly.io.

The Example Application


You can get the code for the example from the GitHub repository. Just git clone https://github.com/fly-apps/go-example to get a local copy.

The go-example application is, as you’d expect for an example, small. It’s a Go application that uses the http server and templates from the standard library. Here’s all the code from main.go:

package main

import (
    "embed"
    "html/template"
    "log"
    "net/http"
    "os"
)

//go:embed templates/*
var resources embed.FS

var t = template.Must(template.ParseFS(resources, "templates/*"))

func main() {
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        data := map[string]string{
            "Region": os.Getenv("FLY_REGION"),
        }

        t.ExecuteTemplate(w, "index.html.tmpl", data)
    })

    log.Println("listening on", port)
    log.Fatal(http.ListenAndServe(":"+port, nil))
}

The main function starts a server that responds with a html page showing the fly region that served the request. The template lives in ./templates/ and is embedded into the binary using the embed package in go 1.16+.

The template itself, index.html.tmpl, is very simple too:

<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<h1>Hello from Fly</h1>
{{ if .Region }}
<h2>I'm running in the {{.Region}} region</h2>
{{end}}
</body>
</html>

Building the Application


As with most Go applications, a simple go build will create a hellofly binary which we can run. It’ll default to using port 8080 and you can view it on localhost:8080 with your browser. So, the raw application works. Now to package it up for Fly.

Install Flyctl and Login


We are ready to start working with Fly and that means we need flyctl, our CLI app for managing apps on Fly. If you’ve already installed it, carry on. If not, hop over to our installation guide. Once that’s installed you’ll want to log in to Fly.

Launch the app on Fly


To launch an app on fly, run flyctl launch in the directory with your source code. This will create and configure a fly app for you by inspecting your source code, then prompt you to deploy.

flyctl launch
Scanning source code
WARN no go.sum file found, please adjust your Dockerfile to remove references to go.sum
Detected a Go app
Creating app in /path/to/your/app
We're about to launch your Go app on Fly.io. Here's what you're getting:

Organization: Your                   (fly launch defaults to the personal org)
Name:         hellofly               (derived from your directory name)
Region:       Ashburn, Virginia (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? n
...
Your app is ready! Deploy with `flyctl deploy`

First, this command scans your source code to determine how to build a deployment image as well as identify any other configuration your app needs, such as secrets and exposed ports.

After your source code is scanned and the results are printed, you’ll be prompted to ask if you want to change any of the defaults flyctl has set.

Choosing yes will bring you to a page in your browser where you can change any configuration, such as the region to deploy into or the size of the VM created.

Once that is complete, flyctl will create a fly.toml file containing the configuration selected. It might then begin a deployment, or let you know you should start a deployment yourself via flyctl deploy.

Inside fly.toml


The fly.toml file now contains a default configuration for deploying your app. In the process of creating that file, flyctl has also created a Fly-side application slot of the same name, “hellofly”. If we look at the fly.toml file we can see the name in there:

app = 'hellofly'
primary_region = 'iad'

[build]
  [build.args]
    GO_VERSION = '1.21.5'

[env]
  PORT = '8080'

[http_service]
  internal_port = 8080
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 0
  processes = ['app']

[[vm]]
  cpu_kind = 'shared'
  cpus = 1
  memory_mb = 1024

The flyctl command will always refer to this file in the current directory if it exists, specifically for the app name value at the start. That name will be used to identify the application to the Fly service. The rest of the file contains settings to be applied to the application when it deploys.

You can see in the [build] section the builder image and the version of Go that was detected in your go.mod file. You can change or add build arguments to configure the build process using the [build.args] section.

Inside Dockerfile


To keep Docker images small, we use an Alpine base image. However, if you need CGO you may want to instead use Debian base images:

# ...

- FROM golang:${GO_VERSION}-alpine as builder
+ FROM golang:${GO_VERSION}-bookworm as builder

# ...

- FROM alpine:latest
+ FROM debian:bookworm

If you want to use Alpine with CGO enabled, read here.

Deploying to Fly


To deploy your app, just run:

flyctl deploy

This will lookup our fly.toml file, and get the app name hellofly from there. Then flyctl will start the process of deploying our application to the Fly platform. Flyctl will return you to the command line when it’s done.

Viewing the Deployed App


Now the application has been deployed, let’s find out more about its deployment. The command flyctl status will give you all the essential details.

flyctl status
App
  Name     = hellofly
  Owner    = demo
  Hostname = hellofly.fly.dev
  Image    = hellofly:deployment-abcdefghxyz

Machines
PROCESS  ID         VERSION  REGION  STATE      ROLE  CHECKS    LAST UPDATED
app      0ac9ed79   1        iad     running                2024-02-13T12:52:38Z
app      1bd10fe8   1        iad     stopped                2024-02-13T12:52:38Z
$

As you can see, the application has been deployed with a DNS hostname of hellofly.fly.dev, and an instance is running in Virginia. Your deployment’s name will, of course, be different.

Connecting to the App


The quickest way to browse your newly deployed application is with the flyctl apps open command.

flyctl apps open
opening https://golang-example.fly.dev ...

Your browser will be sent to the displayed URL.

Bonus Points


If you want to know what IP addresses the app is using, try flyctl ips list:

flyctl ips list
TYPE ADDRESS                              CREATED AT
v4   50.31.246.73                         23m42s ago
v6   2a09:8280:1:3949:7ac8:fe55:d8ad:6b6f 23m42s ago

Arrived at Destination


You have successfully built, deployed, and connected to your first Go application on Fly.