> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fly.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Run a Crystal App

<Warning>
  We haven't yet updated this page for Fly Machines, which are the VMs now at the core of all Fly Apps. You might notice that some features don't work the same way anymore. Visit our <a href="https://community.fly.io/">community forum</a> if you need help with your app.
</Warning>

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 platform.

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

## *Creating a Lucky App*

Our example will be using a basic Lucky app with PostgreSQL. We'll assume you
already have [lucky+crystal installed](https://luckyframework.org/guides/getting-started/installing).

Once lucky is installed, we can create a new project by running the following command:

```bash theme={null}
lucky init
```

This will walk you through project options and create a new project.

```bash theme={null}
✗ lucky init
Welcome to Lucky v0.29.0 🎉

Project name?: hello-lucky

Lucky can generate different types of projects

Full (recommended for most apps)

 ● Great for server rendered HTML or Single Page Applications
 ● Webpack included
 ● Setup to compile CSS and JavaScript
 ● Support for rendering HTML

API

 ● Specialized for use with just APIs
 ● No webpack
 ● No static file serving or public folder
 ● No HTML rendering folders

API only or full support for HTML and Webpack? (api/full): full

Lucky can be generated with email and password authentication

  ● Sign in and sign up
  ● Mixins for requiring sign in
  ● Password reset
  ● Token authentication for API endpoints
  ● Generated files can easily be removed/customized later

Generate authentication? (y/n): y

-----------------------

Done generating your Lucky project

  ▸ cd into hello-lucky
  ▸ check database settings in config/database.cr
  ▸ run script/setup
  ▸ run lucky dev to start the server
```

## *Running The Application*

To run the application, first run `script/setup` to install dependencies and
create the database. Then run `lucky dev` to start the application.

Connect to the address displayed in the console.

This should bring you to the "Hello Lucky" page.

## *Install Flyctl and Login*

It's time to install `flyctl`, the CLI app for managing apps on Fly.io. If you've already installed it, carry on. If not, hop over to [our installation guide](/flyctl/install). Once that's installed you'll want to [log in to Fly.io](/getting-started/sign-up-sign-in).

## *Launch the app on Fly*

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:

```sh theme={null}
cd hello-lucky
fly launch
```

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

```output theme={null}
Organization: MyOrgName              (fly launch defaults to the personal org)
Name:         hello-lucky            (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  deployment setup task
* Build the image
* Set secrets required by  (`SECRET_KEY_BASE`, for example)
* Deploy the application in your selected region

```output theme={null}
Waiting for launch data... Done
Created app 'hello-lucky' in organization 'personal'
Admin URL: https://fly.io/apps/hello-lucky
Hostname: hello-lucky.fly.dev
Set secrets on hello-lucky: SECRET_KEY_BASE
Creating postgres cluster in organization personal
Creating app...
Setting secrets on app hello-lucky-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-lucky-db created
  Username:    postgres
  Password:    EChe3BrhCjsPQEI
  Hostname:    hello-lucky-db.internal
  Flycast:     fdaa:2:45b:0:1::1d
  Proxy port:  5432
  Postgres port:  5433
  Connection string: postgres://postgres:EChe3BrhCjsPQEI@hello-lucky-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-lucky-db is now attached to hello-lucky
The following secret was added to hello-lucky:
  DATABASE_URL=postgres://aa_hello_elixir2:Er6pLzUBuhKcbBl@hello-lucky-db.flycast:5432/aa_hello_elixir2?sslmode=disable
Postgres cluster hello-lucky-db is now attached to hello-lucky
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-lucky:deployment-01HPMGHTG8XSYH3ZCV82SF5CEZ
image size: 126 MB

Watch your deployment at https://fly.io/apps/hello-lucky/monitoring

Provisioning ips for hello-lucky
  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-lucky 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-lucky.fly.dev

Visit your newly deployed app at https://hello-lucky.fly.dev/
```

<Note>
  Make sure to note your Postgres credentials from the output.
</Note>

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

## *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, "hello-lucky". If we look at the `fly.toml` file we can see the name in there:

```toml theme={null}
app = "hello-lucky"

kill_signal = "SIGINT"
kill_timeout = 5
processes = []

[env]

[experimental]
  allowed_public_ports = []
  auto_rollback = true

[[services]]
  http_checks = []
  internal_port = 8080
  processes = ["app"]
  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 = 0
    timeout = "2s"
```

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 platform. The rest of the file contains settings to be applied to the application when it deploys.

We'll have more details about these properties as we progress, but for now, it's enough to say that they mostly configure which ports the application will be visible on.

## *Deploying to Fly*

To deploy changes to your app, just run just run:

```bash theme={null}
flyctl deploy
```

This will lookup our `fly.toml` file, and get the app name `hello-lucky` 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.

Alternatively, you can use [GitHub Actions to deploy your app to Fly](/launch/continuous-deployment-with-github-actions)

## *Viewing the Deployed App*

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

<CodeGroup>
  ```bash cmd theme={null}
  fly status
  ```

  ```output output theme={null}
  App
    Name     = hello-lucky
    Owner    = personal
    Version  = 0
    Status   = running
    Hostname = hello-lucky.fly.dev

  Deployment Status
    ID          = 8d35eade-8c68-499e-e0a9-c6829e3c1c9d
    Version     = v0
    Status      = successful
    Description = Deployment completed successfully
    Instances   = 1 desired, 1 placed, 1 healthy, 0 unhealthy

  Instances
  ID              PROCESS VERSION REGION  DESIRED STATUS  HEALTH CHECKS           RESTARTS        CREATED
  235f9667        app     0       ord     run     running 1 total, 1 passing      0               1m2s ago
  ```
</CodeGroup>

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

<CodeGroup>
  ```bash cmd theme={null}
  flyctl ips list
  ```

  ```out out theme={null}
  TYPE ADDRESS             REGION CREATED AT
  v4   66.51.123.94        global 3m20s ago
  v6   2a09:8280:1::3:23f4 global 3m20s ago
  ```
</CodeGroup>

## *Connecting to the App*

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

<CodeGroup>
  ```bash cmd theme={null}
  flyctl apps open
  ```

  ```output output theme={null}
  Opening https://hello-lucky.fly.dev/
  ```
</CodeGroup>

Your browser will be sent to the displayed URL.

## Multi-Region Deployment with Postgres (Optional)

Fly also supports multi-region deployments.

To deploy to multiple regions, first [Create a PostgreSQL Cluster](/postgres), then follow these steps:

1. Configure your primary region by setting the `PRIMARY_REGION` in your fly.toml.

```toml theme={null}
[env]
PRIMARY_REGION = "ord"
```

1. Add the [superfly/fly.cr shard](https://github.com/superfly/fly.cr) to your project

```yaml theme={null}
dependencies:
fly:
  github: superfly/fly.cr
  version: ~> 0.1
```

1. Require `fly/pg/error_handler` and `fly/avram` *after* `avram`

```crystal theme={null}
# src/shards.cr
# ...
require "avram"
# ...
require "fly/pg/error_handler"
require "fly/avram"
# ...
```

1. Add the `Fly::PG::ErrorHandler` middleware to your list of middlewares, *after* the `Lucky::ErrorHandler`

```crystal theme={null}
# src/app_server.cr
# ...
  def middleware : Array(HTTP::Handler)
    [
      # ...
      Lucky::ErrorHandler.new(action: Errors::Show),
      Raven::Lucky::ErrorHandler.new,
      Fly::PG::ErrorHandler.new,
      # ..,.
    ]of HTTP::Handler
  end
# ...
```

1. Deploy with `fly deploy`

2. You can see replays in the `fly log`

## *Arrived at Destination*

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