Fly Secrets not populated during build

I am facing one big issue at the moment; with a base NextJS app, I try to connect to MongoDB for static generation but the secrets haven’t been populated into the environment variables during the build process, which means I cannot access the database.

I know this works after the build as I have hard coded temporary credentials and logged them to the console after the build, but they are undefined during the build step.

Is this how most NextJS apps work? We don’t (yet) have a way to do builds with your secrets exposed, or in the same network as your apps. But you can build the image locally and pass credentials to it.

If you have environment variables set, run this:

docker built . -t nextjs-app -e DATABASE_URL

This will pass the current DATABASE_URL environment variable through to Docker. You can also set it in the command: DATABASE_URL=mongodb://myserver/db

Then you can deploy the image tag:

flyctl deploy -i nextjs-app

See if that works for you. It would make sense to do builds with the secrets accessible, or have a pre-deploy step, or similar. We have some changes coming to the remote builder that will make this a little easier.

Sorry, I missed out the details about the remote build using NodeJS builtin.

It is used as part of the incremental static generation. NextJS will use the data at build to create the pages, which can also be configured to regenerate as users request the page. Whilst it may not currently be widely adopted - I definitely think there is a case for secrets to be included in the remote builds.

Build the image locally is a good work around for the secrets though - thank you.

Now using this local build my deployment fails and the logs are showing:
UnhandledIoError(Os { code: 8, kind: Other, message: “Exec format error” })

Any idea what this could be?

Would you mind sharing your docker-entrypoint.sh?

Looks like an error like that can be caused by a missing shebang line at the top of your file (#!/bin/bash for example).

Edit: I think it could also be true if your file is not executable, or if it’s not found. Make sure it’s executable and maybe try an absolute path or prefix with ./? Worth a shot :slight_smile:

Will you share your Dockerfile too? There are some ways of specifying CMD and Entrypoint (and SHELL) that we want to make sure we’re handling well.

@jerome
Thanks for your suggestions. Docker is still relatively new to me so I don’t have a custom entrypoint file - I am just using the node:alpine image and CMD from the dockerfile.

@kurt

FROM node:alpine
RUN mkdir -p /usr/src
WORKDIR /usr/src
COPY . /usr/src
RUN npm install
RUN npm run build
EXPOSE 8080
CMD [“npm”, “start”]

I have tried variations CMD [“npm”, “start”], CMD npm run start, etc.

EDIT: my npm start command is: “next start -H 0.0.0.0 -p 8080” maybe it has something to do with access to the next command?

That could be the problem, if the next binary isn’t in the path it might throw that error.

Do you have Docker installed locally? The simplest thing to do might be to poke around at the Docker image to see where things are. You can try running your app like this:

docker build . -t my-next-app
docker run -ti my-next-app npm start

I did that, and got a similar error, so I launched a shell to poke around:

docker run -ti my-next-app /bin/sh

The next binary is installed at /usr/src/node_modules/.bin/next. The simplest thing to do is to change your CMD to:

CMD ["/usr/src/node_modules/.bin/next", "start", "-H", "0.0.0.0", "-p", "8080"]

You could also try changing the PATH environment variable.

Did that work for you? I tried this but I am still seeing the same issue :frowning:

It did! Can you share your package.json file? If that’s not working it seems like next might not be getting installed in the image.

I just created a default nextjs app and a new fly project to see if it would work for me without any extra dependencies and it didn’t (repo: https://github.com/melloradamj/fly-next-error)

Could it be that its the Apple M1 version of Docker locally?

Oh! Yes it could be. I wonder if it built the image for arm64. Try flyctl deploy --remote-only which will build with our remote builders running on x86_64.

I’ll try and see if I can fix it for local Docker environments on arm64.

I’ve just released flyctl v0.0.171 that will prevent building on non-x86_64 platforms. It will spin up a remote builder when that’s the case.

1 Like

The remote builds work but now I am back to the beginning for not having environment variables during the build step :sweat_smile:

I’m working on adding environment variables to flyctl deploy, but for now you can try something like this:

FROM node:alpine
RUN mkdir -p /usr/src
WORKDIR /usr/src
COPY . /usr/src
ARG DATABASE_URL
ENV DATABASE_URL=${DATABASE_URL}
RUN npm install
RUN npm run build
EXPOSE 8080
CMD [“npm”, “start”]

and run flyctl like:

flyctl deploy --remote-only --build-arg DATABASE_URL=your-database-url
1 Like

I just wanted to say this was the key to an afternoon-long unsticking for getting Font Awesome Pro into my build step, with my setup as…

GitHub repo secrets > GitHub Actions > flyctl-actions > Dockerfile

…and looked like this…

workflow.yml

on:
  workflow_dispatch:
env:
  FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
jobs:
  deploy:
    name: Deploy app
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Deploy to Fly
        uses: superfly/flyctl-actions@1.1
        with:
          args: "deploy --app ${{ secrets.STAGING_APP_NAME }}
          --build-arg FONT_AWESOME_TOKEN=${{ secrets.FA_TOKEN }}"

.npmrc

@fortawesome:registry=https://npm.fontawesome.com/
//npm.fontawesome.com/:_authToken=${FONT_AWESOME_TOKEN}

Dockerfile

FROM hexpm/elixir:1.10.3-erlang-23.2.7-alpine-3.14.0 AS build
ARG FONT_AWESOME_TOKEN
ENV FONT_AWESOME_TOKEN=${FONT_AWESOME_TOKEN}

[... other things...]

RUN npm run --prefix ./assets build

I’m trying to get this to work using the fly.io generated docker file AND the generated fly.toml can you guide me on how to set those up?

Hi!

I think this token would be better used as a secret instead of an env var that lives in the fly.toml file - here’s what I would do (let me know if I’m off-base in what your issue is!).

Some explanation: Secrets set via fly secrets set... are not available at build time, but instead only during run-time of the app (in other words, secrets aren’t set as env vars when running “docker build…”).

To get secrets into the build steps, you can use Docker (BuildKit) secrets.

This means updating your Dockerfile to mount secrets in:

RUN --mount=type=secret,id=font_awesome_token \
    echo "$(cat /run/secrets/font_awesome_token)"

:warning: You won’t want to echo that secret in reality, but I wanted to show you that the secret gets mounted as a file, and you can get the secret value from that file’s contents

Then when deploying the app, you can add the secrets to be mounted:

fly deploy \
    --build-secret font_awesome_token=abcdefghijklmnopqrstuvwxyz
3 Likes

the working topic example where I answered