Fly.io deployment help

Hey there,

Has anyone managed to successfully deploy a RedwoodJS app onto Fly.io? I’m not having much luck using the default settings provided when running flyctl launch. When I deploy the app is not accessible so the container restarts over and over:

[error] failed to connect to machine: gave up after 15 attempts (in 9.272853195s)

[error] instance refused connection. is your app listening on 0.0.0.0:8910? make sure it is not only listening on 127.0.0.1 (hint: look at your startup logs, servers often print the address they are listening on)

Full details are at RedwoodJS deployment is not working - #5 by rubys - Build debugging - Fly.io

Any help is appreciated.

Cheers,
Oliver

Hi @oreid,
I replied to you in your thread on fly.io, let me know if the info helps solve your issue!

I’ll be adding some context to the open issue here #9789 so you can track the progress of the issue as well.

Hope this helps!

1 Like

@oreid – Let us know if you’re able to get everything up and running… We deployed the Conference Badge app via Fly.io. It’s open source, if you want to take a look at any of our settings (like our fly.toml or Dockerfile)

Thanks @tbay06 and @ahaywood. As mentioned in my thread on Fly the issue here has been identified and a work around is available: RedwoodJS deployment is not working - #5 by rubys - Build debugging - Fly.io

I also see that fix(fastify): Prevent duplicate `@fastify/url-data` registration by Josh-Walker-GM · Pull Request #9794 · redwoodjs/redwood · GitHub has been merged and is just awaiting release which will hopefully fix the default generated start script on the fly side.

I am also struggling getting deployed to Fly.IO trying to find a platform to start trying the SSR Streaming and serverful deployments.

I tried from a new create-redwood-app but could not figure out the build errors I was getting so I actually just forked the badge app. I stripped it back down to a basic app just trying to have supabase auth with some of the auth pages working with this repo:

The deploy is a little wonky because I have to make sure it does not overwrite the dockerfile as it’ll try to force it on NODE_VERSION 16.13 as well as remove all the other setup.

It “deploys” but it doesn’t actually have anything showing:
https://flyioishard-young-thunder-8164.fly.dev

FYI, I just successfully deployed a fresh Redwood app (V 8.1.1) on Fly.io. I had a little (actually maybe a lot) of help from Cursor. Here are my Cliff notes…

I followed the instructions at Run a RedwoodJS App · Fly Docs. They are sparse: create a new Redwood app, install the Fly command line tool, and run fly launch. The launch command creates the .fly folder contents and a Dockerfile. The .fly/shart.sh and Dockerfile files needed some adjustments.

I ran fly deploy then fly logs. The first few times I had errors, which I copied and pasted into the Cursor chat window. And, after some iteration, I got it working. The notable fine-tuning included…

Update the Node.js version in the Dockerfile to:
ARG BASE_IMAGE=node:20-alpine

Update the Yarn version in the Dockerfile. I added the following line:
RUN corepack enable && corepack prepare yarn@4.4.0 --activate

Update the Redwood start command in .fly/start.sh. I set it to:
yarn rw serve --web-port ${PORT} --web-host 0.0.0.0 --api-port 8911 --api-host 0.0.0.0

And finally, I did a happy dance when it worked. :man_dancing:

Here is my entire .fly/start.sh file:

#!/bin/sh

set -ex

if [ -n $MIGRATE_ON_BOOT ]; then
  $(dirname $0)/migrate.sh
fi

yarn rw serve --web-port ${PORT} --web-host 0.0.0.0 --api-port 8911 --api-host 0.0.0.0

Here is my entire Dockerfile:

ARG BASE_IMAGE=node:20-alpine
FROM ${BASE_IMAGE} as base

RUN mkdir /app
WORKDIR /app

# Enable Corepack and install the correct Yarn version
RUN corepack enable && corepack prepare yarn@4.4.0 --activate

# Required for building the api and web distributions
ENV NODE_ENV development

FROM base as dependencies

COPY .yarn .yarn
COPY .yarnrc.yml .yarnrc.yml
COPY package.json package.json
COPY web/package.json web/package.json
COPY api/package.json api/package.json
COPY yarn.lock yarn.lock

# Use the correct Yarn version to install dependencies
RUN --mount=type=cache,target=/root/.yarn/berry/cache \
    --mount=type=cache,target=/root/.cache yarn install --immutable

COPY redwood.toml .
COPY graphql.config.js .

FROM dependencies as web_build

COPY web web
RUN yarn rw build web

FROM dependencies as api_build

COPY api api
RUN yarn rw build api

FROM dependencies

ENV NODE_ENV production

COPY --from=web_build /app/web/dist /app/web/dist
COPY --from=api_build /app/api /app/api
COPY --from=api_build /app/node_modules/.prisma /app/node_modules/.prisma

COPY .fly .fly

ENTRYPOINT ["sh"]
CMD [".fly/start.sh"]
2 Likes

I get this warning and nothing renders when I deploy your suggestions.

WARNING The app is not listening on the expected address and will not be reachable by fly-proxy.
You can fix this by configuring your app to listen on the following addresses:
  - 0.0.0.0:8910
Found these processes inside the machine with open listening sockets:
  PROCESS        | ADDRESSES                             
-----------------*---------------------------------------
  /.fly/hallpass | [fdaa:5:60a9:a7b:325:e55b:e928:2]:22  

I do have this line correctly setup… not sure what’s going on.

yarn rw serve --web-port ${PORT} --web-host 0.0.0.0 --api-port 8911 --api-host 0.0.0.0

In my case, if ever someone is looking for a solution at 2025, here’s my setup:

.fly/migrate.sh

#!/bin/bash

set -ex

npx prisma migrate deploy --schema /home/node/app/api/db/schema.prisma

.fly/release.sh

#!/bin/bash

set -ex

if [ ! -n $MIGRATE_ON_BOOT ]; then
  $(dirname $0)/migrate.sh
fi

.fly/start.sh

#!/bin/bash

set -ex

if [ -n $MIGRATE_ON_BOOT ]; then
  $(dirname $0)/migrate.sh
fi

yarn rw serve --web-port ${PORT} --web-host 0.0.0.0 --api-port 8911 --api-host 0.0.0.0

.github/workflows/fly-deploy.sh

# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/

name: Fly Deploy
on:
  push:
    branches:
      - main
jobs:
  deploy:
    name: Deploy app
    runs-on: ubuntu-latest
    concurrency: deploy-group    # optional: ensure only one action runs at a time
    steps:
      - uses: actions/checkout@v4
      - uses: superfly/flyctl-actions/setup-flyctl@master
      - name: Deploy to Fly.io
        run: flyctl deploy --remote-only --config fly.toml
        env:
          FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
          NODE_ENV: production

Dockerfile

# base
# ----
  FROM node:20-bookworm-slim as base

  # RUN corepack enable

  # We tried to make the Dockerfile as lean as possible. In some cases, that means we excluded a dependency your project needs.
  # By far the most common is Python. If you're running into build errors because `python3` isn't available,
  # uncomment the line below here and in other stages as necessary:
  RUN apt-get update && apt-get install -y \
      openssl \
      # python3 make gcc \
      && rm -rf /var/lib/apt/lists/*

  USER node
  WORKDIR /home/node/app

  COPY --chown=node:node .yarnrc.yml .
  COPY --chown=node:node package.json .
  COPY --chown=node:node api/package.json api/
  COPY --chown=node:node web/package.json web/
  COPY --chown=node:node yarn.lock .
  COPY --chown=node:node .yarn/releases/*.cjs .yarn/releases/

  # RUN mkdir -p /home/node/.yarn/berry/index
  # RUN mkdir -p /home/node/.cache

  # RUN --mount=type=cache,target=/home/node/.yarn/berry/cache,uid=1000 \
  #     --mount=type=cache,target=/home/node/.cache,uid=1000 \
  #     CI=1 yarn install

  RUN yarn install

  COPY --chown=node:node redwood.toml .
  COPY --chown=node:node graphql.config.js .
  COPY --chown=node:node .env.defaults .env.defaults

  # api build
  # ---------
  FROM base as api_build

  # If your api side build relies on build-time environment variables,
  # specify them here as ARGs. (But don't put secrets in your Dockerfile!)
  #
  # ARG MY_BUILD_TIME_ENV_VAR

  COPY --chown=node:node api api
  RUN yarn rw build api

  # web prerender build
  # -------------------
  FROM api_build as web_build_with_prerender

  ARG NODE_ENV
  ENV NODE_ENV=$NODE_ENV
  ARG RUNTIME_ENV
  ENV RUNTIME_ENV=$RUNTIME_ENV

  ARG WEB_API_URL
  ENV WEB_API_URL=$WEB_API_URL

  ARG WEB_BUNDLER
  ENV WEB_BUNDLER=$WEB_BUNDLER

  COPY --chown=node:node web web
  RUN yarn rw build web

  # web build
  # ---------
  FROM base as web_build

  ARG NODE_ENV
  ENV NODE_ENV=$NODE_ENV
  ARG RUNTIME_ENV
  ENV RUNTIME_ENV=$RUNTIME_ENV

  ARG WEB_API_URL
  ENV WEB_API_URL=$WEB_API_URL

  ARG WEB_BUNDLER
  ENV WEB_BUNDLER=$WEB_BUNDLER

  COPY --chown=node:node web web
  RUN yarn rw build web --no-prerender

  # api serve
  # ---------
  FROM node:20-bookworm-slim as api_serve

  # RUN corepack enable

  RUN apt-get update && apt-get install -y \
      openssl \
      # python3 make gcc \
      && rm -rf /var/lib/apt/lists/*

  USER node
  WORKDIR /home/node/app

  COPY --chown=node:node .yarnrc.yml .
  COPY --chown=node:node package.json .
  COPY --chown=node:node api/package.json api/
  COPY --chown=node:node yarn.lock .
  COPY --chown=node:node .yarn/releases/*.cjs .yarn/releases/

  # RUN mkdir -p /home/node/.yarn/berry/index
  # RUN mkdir -p /home/node/.cache

  # RUN --mount=type=cache,target=/home/node/.yarn/berry/cache,uid=1000 \
  #     --mount=type=cache,target=/home/node/.cache,uid=1000 \
  #     CI=1 yarn workspaces focus api --production

  RUN yarn workspaces focus api --production

  COPY --chown=node:node redwood.toml .
  COPY --chown=node:node graphql.config.js .
  COPY --chown=node:node .env.defaults .env.defaults

  COPY --chown=node:node --from=api_build /home/node/app/api/dist /home/node/app/api/dist
  COPY --chown=node:node --from=api_build /home/node/app/api/db /home/node/app/api/db
  COPY --chown=node:node --from=api_build /home/node/app/node_modules/.prisma /home/node/app/node_modules/.prisma

  ENV NODE_ENV=production

  # default api serve command
  # ---------
  # If you are using a custom server file, you must use the following
  # command to launch your server instead of the default api-server below.
  # This is important if you intend to configure GraphQL to use Realtime.
  #
  # CMD [ "./api/dist/server.js" ]

  CMD [ "node_modules/.bin/rw-server", "api" ]

  # web serve
  # ---------
  FROM node:20-bookworm-slim as web_serve

  # RUN corepack enable

  USER node
  WORKDIR /home/node/app

  COPY --chown=node:node .yarnrc.yml .
  COPY --chown=node:node package.json .
  COPY --chown=node:node web/package.json web/
  COPY --chown=node:node yarn.lock .
  COPY --chown=node:node .yarn/releases/*.cjs .yarn/releases/

  # RUN mkdir -p /home/node/.yarn/berry/index
  # RUN mkdir -p /home/node/.cache

  # RUN --mount=type=cache,target=/home/node/.yarn/berry/cache,uid=1000 \
  #     --mount=type=cache,target=/home/node/.cache,uid=1000 \
  #     CI=1 yarn workspaces focus web --production

  RUN yarn workspaces focus web --production

  COPY --chown=node:node redwood.toml .
  COPY --chown=node:node graphql.config.js .
  COPY --chown=node:node .env.defaults .env.defaults

  COPY --chown=node:node --from=web_build /home/node/app/web/dist /home/node/app/web/dist

  ENV NODE_ENV=production \
      API_PROXY_TARGET=http://api:8911

  # We use the shell form here for variable expansion.
  CMD "node_modules/.bin/rw-web-server" "--api-proxy-target" "$API_PROXY_TARGET"

  # console
  # -------
  FROM base as console

  # To add more packages:
  #
  # ```
  # USER root
  #
  # RUN apt-get update && apt-get install -y \
  #     curl
  #
  # USER node
  # ```

  COPY --chown=node:node api api
  COPY --chown=node:node web web
  COPY --chown=node:node scripts scripts

  COPY .fly .fly
  COPY --chmod=755 .fly/migrate.sh .fly/migrate.sh

  RUN yarn rw build

  ENTRYPOINT ["sh"]
  CMD [".fly/start.sh"]

fly.toml

# fly.toml app configuration file generated for redwoodjs-app on 2025-05-31T01:09:22+08:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#

app = 'redwoodjs-app'
primary_region = 'sin'

[build]

[deploy]
  release_command = '.fly/release.sh'

[env]
  PORT = '8910'
  REDWOOD_DISABLE_TELEMETRY = '1'

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

[[vm]]
  memory = '1gb'
  cpu_kind = 'shared'
  cpus = 1