Deploy Node.js and connect MySQL by fly.io

When Heroku canceled its free policy last November, developers are looking for other small free deployment platforms to deploy their side projects. Currently, Vercel, Render, and fly.io are used to do this. The reason for choosing fly.io this time is that I had read and attempted to deploy on it before, but failed. Now I have time to study the method of deployment in this platform.

Step for deploying the application (app)

  • Install CLI

Open your terminal and run the code below to install flyctl.

Homebrew:

$ brew install flyctl

Script:

$ curl -L https://fly.io/install.sh | sh

Notice: The executed command fly xxxx can be written in flyctl xxxx

  • Sign up and Sign in

Sign up for the account and need to add the credit card number cause this platform will not allow you to pass the authentication when you deploy. After creating the account, run the code line below in your terminal.

$ fly auth login

and it will open the browser to log in to your account. After login successfully, it will show the figure below.

image

Open the path of your app in the terminal and run the code as follows:

$ fly launch

and it shows some messages that you need to decide:

- Choose an app name (leave blank to generate one)

- Choose a region for deployment

- Would you like to set up a Postgresql database now?

- Would you like to set up an Upstash Redis database now?

-  Would you like to deploy now?

The app name only accepts lowercase letters, dashes, and numbers or you can leave it blank and it will generate itself. In the last message, I suggest that you don't need to deploy your app immediately because your project folder also creates a new file (fly.toml) at the same time. The deployment configuration is in the toml file. You can read the official document to know what each parameter does in this file (app configuration in toml). Here is an example toml file:

# fly.toml app configuration file generated for app_name on 2023-05-08T12:10:20+08:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#

app = "your_app_name"

kill_signal = "SIGINT"
kill_timeout = 5
# Deploy region
primary_region = "sin"
processes = []

[env]
  PORT = "8080"
  NODE_ENV = "production"

[deploy]
  release_command = "npx sequelize db:migrate"

[experimental]
  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]]
    force_https = true
    handlers = ["http"]
    port = 80

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

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

There is one thing you need to notice the connected PORT. The default value is 8080 and if you don’t change this, you have to set the same port value in your app.js.

  • Set the sensitive environmental variable

In toml file, it has a risk of security to write the secrete in [env]. You can run the code below in the terminal to set the secrets and fry.io encrypt these data.

# Set the secret
flyctl secrets set FACEBOOK_SECRET=xxxxxxx

# Remove the secret
flyctl secrets unset FACEBOOK_SECRET=xxxxxxx

# show the list of secrets
flyctl secrets list

After checking the configuration, you can start to deploy by running the code:

$ fly deploy

You will see the figure if it deployed successfully.

image

You can go to the website fly.io to check the dashboard

image

or run the code to check it in terminal. It showed the example below.

# Choose one to run in terminal
fly status 
fly status -a app_name
# The result in terminal
App
  Name     = xxxxx                                        
  Owner    = personal                                              
  Hostname = xxxx.fly.dev                                
  Image    = xxxx:deployment-xxxxx
  Platform = machines                                              

Machines
ID                PROCESS    VERSION    REGION    STATE      HEALTH CHECKS    LAST UPDATED         
xxxxxxxxxxxxxx    app        2          nrt       started                     2023-05-08T02:46:04Z

After deploying, you can run the code fly open to check the website of app.

Connect the database to your app (MySQL)

From the description of the document, the step to deploy the database as an app on fly.io. Some settings are a little different. Here are the steps:

  1. Create an independent folder and launch it.

The folder you can place it anywhere and run the code below:

# You can name the folder by yourself
mkdir flyio-mysql
cd flyio-mysql

Then you have to run fly launch to launch the database to create the fly.toml. Of cause, you have to set the location of database.

  1. Set some parameters and secrets

(a) Set the volume of database:

Run the code to set the volume of your database and the unit is GB. You can set only 1 GB is your database is just for side projects.

# Create a volume named "mysqldata" within our app "wen-mysql"
fly volumes create mysqldata --size 1 # gb

image

There is one thing you have to notice that this database can be shared by many apps. If you want to expense scale, you have to change the setting by following the document.

(b) Set the secrets:

Run the code as follows to set password of database

# Set secrets:
# MYSQL_PASSWORD      - password set for user $MYSQL_USER
# MYSQL_ROOT_PASSWORD - password set for user "root"
fly secrets set MYSQL_PASSWORD=xxxxx MYSQL_ROOT_PASSWORD=xxxxx

(c) Set the fly.toml file in database app

Open your fry.toml and notice that your app is on V2 of fly platform. Here is the setting on V2 in official document. (It is a different setting if your app is on V1, please watch the official document.)

# fly.toml app configuration file generated for wen-mysql on 2023-05-08T22:00:35+08:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#

app = "your_app_name"
kill_signal = "SIGINT"
kill_timeout = 5

# If copy/paste'ing, adjust this
# to the region you're deploying to
primary_region = "sin"

[processes]
app = "--datadir /data/mysql --default-authentication-plugin mysql_native_password --performance-schema=OFF --innodb-buffer-pool-size 64M"

[mounts]
  source="mysqldata"
  destination="/data"

# MYSQL_DATABASE can name your database and will created aftering deploy
[env]
  MYSQL_DATABASE = "some_db" 
  MYSQL_USER = "non_root_user"

# As of 04/25/2023:
# MySQL 8.0.33 has a bug in it
# so avoid that specific version
[build]
  image = "mysql:8.0.31"

In the parameter of [env], you can write the name of database and it will be created at the same time when the app is deployed. If you want to create the other database, you have to connect this app from outside to use the command in terminal or GUI tool.

  1. Deploy the database and connect it by app

Run the code fly deploy to deploy the database app and it shows the figure when deploying successfully.

image

Then, open your app to which you want to connect to the database app and change the settings inside config.js and fly.toml.

At the section of production in config.js file, you need to adjust the name of database and host. The host is your name of database app with “.internal” appended. Here is an example of setting.

{
    "development": {
        ...
    },
    "test": {
        ...
    },
    "production": {
        "username": "root",
        "password": "xxxx",
        "database": "your_database_name",
        "host": "database_app_name.internal",
        "dialect": "mysql"
    }
}

In a MySQL database, you need to run migration or set a seeder in your app. Go to the fly.toml file in your app and check if it has a [deploy] section. Then, add the release_command and input the command that you want to run, such as npx sequelize db:migrate or nps sequelize db:seed. Finally, deploy the app. This command will be executed during deployment.

# fly.toml app configuration file generated for todo-sequelize on 2023-05-08T12:10:20+08:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#

app = "todo-sequelize"

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

[env]
  PORT = "8080"
  NODE_ENV = "production"

# only build one command when deploying
# need to redeploying if you want to build the other command
[deploy]
  release_command = "npx sequelize db:migrate"

[experimental]
  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]]
    force_https = true
    handlers = ["http"]
    port = 80

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

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

If you run the command successfully during deploying, it will show the image below.

However, there is only one command can be declared. If you want to run another command, you have to re-write the release_command and deploy it again.

image

Connect the database app from outside(MySQL GUI)

In fly app platform, it is different from Heroku to connect database of MySQL. It sets the proxy as localhost to activate the database without URL. The default value of proxy is 3306 and you can run the code as follows:

# Default port is 3306 and you can run this code if it is not used
fly proxy 3306 -a wen-mysql

# if port 3306 is used you can use this code to change the default port.
fly proxy 13306:3306 -a wen-mysql

Most people set proxy 3306 to their MySQL. You can run the second code to do the same thing. and it will show the success as the following image.

image

Don’t turn off it and open your GUI tool to set the configuration as follows:

image

Now you can operate the database in GUI.

There is one thing you need to notice: the hostname is provided on the fly.io dashboard. However, if you want to operate the remote database on your computer, you must execute fly commands through the CLI and activate your local IP address, 127.0.0.1. Therefore, the hostname should be set to your local IP, not a URL.

Reference

https://uu9924079.medium.com/fly-io-%E4%BD%BF%E7%94%A8%E5%BF%83%E5%BE%97-%E5%BE%9E%E8%A8%BB%E5%86%8A-%E4%BD%88%E7%BD%B2-nodejs-%E5%B0%88%E6%A1%88%E5%88%B0%E7%B6%B2%E5%9F%9F%E8%A8%AD%E5%AE%9A-2fee3b64fbe6

https://medium.com/@teppei.252033/%E7%94%A8-fly-io-%E9%83%A8%E7%BD%B2%E9%A4%90%E5%BB%B3%E8%AB%96%E5%A3%87-33c6562d6e09