Deploy SSR + RSC to Fly.io

I had posted in here a couple months back, but wanted to circle around as that repo was just SSR:

I know the ticketing badge site used SSR and RSC, but I am having some trouble going between the files Fly generates automatically when you run:

fly launch

vs. the new Docker docs:
Redwood Docker Docs

vs. the ticketing badge app repo:
Redwood Conf Ticketing Badge App

I have my test repo here:

I can get it to “deploy” but it just has a 404 error for anything happening and doesn’t actually return content and eventually shuts the machine down after 10 restart attempts.

I am pretty sure it is more my lack of experience with Fly and Docker than anything else, but I am wondering if there is something I need to do to fly.toml, Dockerfile, or the fly migrate.sh, start.sh and release.sh to get this live!

I have the fly.toml here just trying to use sqllite to get this live:

app = 'may-rsc-app'
primary_region = 'lax'

[build]
  build-target = "api_fe_serve"

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

[env]
  DATABASE_URL = 'file://data/sqlite.db'
  MIGRATE_ON_BOOT = 'true'
  PORT = '8910'
  REDWOOD_DISABLE_TELEMETRY = '1'

[[mounts]]
  source = 'data'
  destination = '/data'

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

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

the Dockerfile here I am definitely not too sure on:

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

RUN mkdir /app
WORKDIR /app

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

RUN corepack enable
RUN corepack prepare yarn@4.1.1 --activate

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

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 .


# api build
# ------------------------------------------------
FROM dependencies as api_build

COPY api api
RUN yarn rw build api

# web build
# ------------------------------------------------
FROM dependencies as web_build

COPY web web
RUN yarn rw build web


# DB and data migrations
# ------------------------------------------------
# ideal place for `prisma migrate` and `@redwood/data-migrate`


# serve api and fe
# ------------------------------------------------
    FROM node:20-bookworm-slim as api_fe_serve




    WORKDIR /home/node/app

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

    RUN yarn plugin import workspace-tools
    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 web --production

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

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

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

    ENV NODE_ENV=production
    ENV PRISMA_HIDE_UPDATE_MESSAGE=true
    ENV RWJS_EXP_SSR_GRAPHQL_ENDPOINT=http://127.0.0.1:8910/.redwood/functions/graphql

    COPY .fly .fly

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

Some notes of things I had to edit to get the app to this stage where it is deploying but deploying wrongly:

In the start.sh in the .fly I had to change port to webPort thanks to Jace on this once:

set -ex

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

npx rw-server --webPort ${PORT} $@

in my redwood.toml I had to add a host to make sure host set correctly:


[web]
  title = "Redwood App"
  host = '0.0.0.0'
  port = 8910
  apiUrl = "/.redwood/functions" # You can customize graphql and dbauth urls individually too: see https://redwoodjs.com/docs/app-configuration-redwood-toml#api-paths
  includeEnvironmentVariables = [
    # Add any ENV vars that should be available to the web side to this array
    # See https://redwoodjs.com/docs/environment-variables#web
  ]
[api]
  port = 8911
  host = '0.0.0.0'
[browser]
  open = true
[notifications]
  versionUpdates = ["latest"]

[experimental.streamingSsr]
  enabled = true

[experimental.rsc]
  enabled = true

It gave me some error on the FatalErrorPage because it was called DevFatalErrorPage. I had to change it to:

const FatalErrorPage =
  DevFatalErrorPage ||
  (() => (
    <main>
       ...
   </main>

in App.tsx it also was being weird with only building if I used dot notation vs. naming the folder directly:

THIS WORKED~~~~~~
import FatalErrorPage from './pages/FatalErrorPage'
import Routes from './Routes'

THIS GAVE ERRORS~~~~
import FatalErrorPage from 'src/pages/FatalErrorPage'
import Routes from 'src/Routes'

So now I am getting logs on Fly.io that look like it is deploying, but I do not see html coming back just 404 errors:

2024-06-06T05:36:20.015 app[machine] lax [info] 2024/06/06 05:36:20 INFO SSH listening listen_address=[fdaa:5:80e4:a7b:bf88:8fe6:4c17:2]:22 dns_server=[fdaa::3]:53
2024-06-06T05:36:20.020 app[machine] lax [info] + '[' -n true ]
2024-06-06T05:36:20.020 app[machine] lax [info] + dirname .fly/start.sh
2024-06-06T05:36:20.021 app[machine] lax [info] + .fly/migrate.sh
2024-06-06T05:36:20.022 app[machine] lax [info] + npx rw-server --webPort 8910
2024-06-06T05:36:20.029 runner[machine] lax [info] Machine started in 512ms
2024-06-06T05:36:20.031 proxy[machine] lax [info] machine started in 519.994195ms
2024-06-06T05:36:21.699 app[machine] lax [info] Starting API and Web Servers...
2024-06-06T05:36:21.753 app[machine] lax [info] {"level":30,"time":1717652181752,"pid":340,"hostname":"4d89645c6eed08","msg":"Web server listening at http://0.0.0.0:8910"}
2024-06-06T05:36:21.761 app[machine] lax [info] Importing Server Functions...
2024-06-06T05:36:22.412 proxy[machine] lax [info] machine became reachable in 2.380962287s
2024-06-06T05:36:22.577 app[machine] lax [info] /graphql 816 ms
2024-06-06T05:36:22.577 app[machine] lax [info] ...Done importing in 817 ms
2024-06-06T05:36:22.578 app[machine] lax [info] {"level":30,"time":1717652182578,"pid":340,"hostname":"4d89645c6eed08","msg":"API server listening at http://0.0.0.0:8911"}
2024-06-06T05:36:22.579 app[machine] lax [info] Took 880 ms
2024-06-06T05:36:22.579 app[machine] lax [info] Web server listening at http://0.0.0.0:8910
2024-06-06T05:36:22.579 app[machine] lax [info] API server listening at http://0.0.0.0:8911/
2024-06-06T05:36:22.579 app[machine] lax [info] GraphQL endpoint at http://0.0.0.0:8911/graphql
2024-06-06T05:36:22.583 app[machine] lax [info] {"level":30,"time":1717652182583,"pid":340,"hostname":"4d89645c6eed08","reqId":"req-1","req":{"method":"GET","url":"/","hostname":"may-rsc-app.fly.dev","remoteAddress":"xxx","remotePort":35274},"msg":"incoming request"}
2024-06-06T05:36:22.593 app[machine] lax [info] {"level":40,"time":1717652182591,"pid":340,"hostname":"4d89645c6eed08","reqId":"req-1","msg":"Trying to send a NotFound error inside a 404 handler. Sending basic 404 response."}
2024-06-06T05:36:22.595 app[machine] lax [info] {"level":30,"time":1717652182593,"pid":340,"hostname":"4d89645c6eed08","reqId":"req-1","res":{"statusCode":404},"responseTime":10.150360000000092,"msg":"request completed"}

I feeeeeeeeel like this is mostly me not being used to Docker and that I need to do a build step before serving with RSC + SSR and I do not think that is happening correctly or else I should at least get html back over the wire.
If you have any suggestions give me a holler. Otherwise I think I am deep diving Docker this weekend haha.

1 Like

Hey @QuinnsCode :wave:

I recently published our bighorn website on fly and it wasn’t a nice JustWorks experience like you highlight.

One thing I did have to do was switch from:

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

to:

COPY --from=web_build /home/node/app/web /home/node/app/web

The full branch for that is GitHub - redwoodjs/bighorn-website at fly where you can see the Dockerfile and fly setup if you want to.

If you could try that change and see if it helps. I’ll try to work through your files here and see if I can spot anything else too.

1 Like

Alright just so I remember and if others follow I do find myself needing to call fly deploy using my file path or else it won’t take changes as well as --no-cache

fly deploy -c /Users/path/to/project's/fly/toml/fly.toml --no-cache

Should it also avoid /dist for api?

COPY --chown=node:node --from=api_build /home/node/app/api/dist /home/node/app/api/dist
to:
COPY --chown=node:node --from=api_build /home/node/app/api /home/node/app/api

I then seem to hit problems with it finding rw-serve-fe and rw-server:

Tried advice from here:
https://community.fly.io/t/redwoodjs-deployment-is-not-working/17429/10

changed slightly to build web and build specifying ports as well in the .fly/start.sh:

node ./node_modules/.bin/rw-serve-fe --port 8910 &
node ./node_modules/.bin/redwood serve api --port 8910
to:
node ./node_modules/.bin/redwood serve api --port 8910 &
node ./node_modules/.bin/redwood serve web --port 8910

It seems to then hit errors where i may also be looking for the files in /dist. These are where it error in fly logs:

2024-06-09T00:47:35.918 app[xx] lax [info] requireStack: [ '/home/node/app/node_modules/@redwoodjs/web/dist/bins/redwood.js' ]

2024-06-09T00:47:35.918 app[xx] lax [info] }

2024-06-09T00:47:35.922 app[xx] lax [info] node:internal/modules/cjs/loader:1148

2024-06-09T00:47:35.922 app[xx] lax [info] throw err;

2024-06-09T00:47:35.922 app[xx] lax [info] ^

2024-06-09T00:47:35.922 app[xx] lax [info] Error: Cannot find module '@redwoodjs/cli/package.json'

2024-06-09T00:47:35.922 app[xx] lax [info] Require stack:

2024-06-09T00:47:35.922 app[xx] lax [info] - /home/node/app/node_modules/@redwoodjs/web/dist/bins/redwood.js

2024-06-09T00:47:35.922 app[xx] lax [info] at Module._resolveFilename (node:internal/modules/cjs/loader:1145:15)

2024-06-09T00:47:35.922 app[xx] lax [info] at Function.resolve (node:internal/modules/helpers:190:19)

2024-06-09T00:47:35.922 app[xx] lax [info] at Object.<anonymous> (/home/node/app/node_modules/@redwoodjs/web/dist/bins/redwood.js:5:59)

2024-06-09T00:47:35.922 app[xx] lax [info] at Module._compile (node:internal/modules/cjs/loader:1358:14)

2024-06-09T00:47:35.922 app[xx] lax [info] at Module._extensions..js (node:internal/modules/cjs/loader:1416:10)

2024-06-09T00:47:35.922 app[xx] lax [info] at Module.load (node:internal/modules/cjs/loader:1208:32)

2024-06-09T00:47:35.922 app[xx] lax [info] at Module._load (node:internal/modules/cjs/loader:1024:12)

2024-06-09T00:47:35.922 app[xx] lax [info] at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:174:12)

2024-06-09T00:47:35.922 app[xx] lax [info] at node:internal/main/run_main_module:28:49 {

2024-06-09T00:47:35.922 app[xx] lax [info] code: 'MODULE_NOT_FOUND',

2024-06-09T00:47:35.922 app[xx] lax [info] requireStack: [ '/home/node/app/node_modules/@redwoodjs/web/dist/bins/redwood.js' ]

2024-06-09T00:47:35.922 app[xx] lax [info] }

2024-06-09T00:47:35.922 app[xx] lax [info] Node.js v20.14.0

2024-06-09T00:47:35.924 app[xx] lax [info] Node.js v20.14.0

2024-06-09T00:47:36.682 app[xx] lax [info] INFO Main child exited normally with code: 1