Build secret in Dockerfile not found

Hi, I’ve included the following code in my dockerfile to set the the DATABASE_URL env variable in a NextJS project, I am using the echo command to log the DATABASE_URL_SECRET variable first to check that it has been correctly added:

# Set DATABASE_URL_SECRET
RUN --mount=type=secret,id=DATABASE_URL_SECRET \
    DATABASE_URL_SECRET="$(cat /run/secrets/DATABASE_URL_SECRET)" \ && echo "DATABASE_URL_SECRET: $DATABASE_URL_SECRET"

# Set DATABASE_URL from DATABASE_URL_SECRET
ENV DATABASE_URL=$DATABASE_URL_SECRET

However when I run

fly deploy \
    --build-secret DATABASE_URL_SECRET=TEST_VAL

I get the error

 > [base 3/3] RUN --mount=type=secret,id=DATABASE_URL_SECRET     DATABASE_URL_SECRET="$(cat /run/secrets/DATABASE_URL_SECRET)"  && echo "DATABASE_URL_SECRET: $DATABASE_URL_SECRET":
#0 0.251 /bin/sh: 1:  : not found

You will need to pass the secret on the deploy step, but that can be automated. For more information, see: Build Secrets · Fly Docs

Disregard my previous comment. There is a syntax error in the above. At a minimum, remove the &&. Either remove the \ or have it be the last character on the line.

1 Like

Got it, would you recommend the secrets approach over something like this?

# Define a build argument for DATABASE_URL with a default value
ARG DATABASE_URL=""

# Set the DATABASE_URL environment variable using the build argument
ENV DATABASE_URL=${DATABASE_URL}

then in the command line call
fly deploy --build-arg DATABASE_URL=DB_URL

If you take care to put that in a throw-away build stage that would be fine, I would just make sure that the secret isn’t captured in the image itself which would increase the change of it leaking.

I’m still getting ERR_INVALID_URL with this command, does it still contain a syntax error with the && and \ removed before the echo part?

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

Try:

# Set DATABASE_URL_SECRET
RUN --mount=type=secret,id=DATABASE_URL_SECRET \
    DATABASE_URL_SECRET="$(cat /run/secrets/DATABASE_URL_SECRET)" \ 
    echo "DATABASE_URL_SECRET: $DATABASE_URL_SECRET"

I’m calling

# Set DATABASE_URL_SECRET
RUN --mount=type=secret,id=DATABASE_URL_SECRET \
    DATABASE_URL_SECRET="$(cat /run/secrets/DATABASE_URL_SECRET)" \ 
    echo "DATABASE_URL_SECRET: $DATABASE_URL_SECRET"

# Set DATABASE_URL from DATABASE_URL_SECRET
ENV DATABASE_URL=$DATABASE_URL_SECRET

Then in the command line running

fly deploy \
    --build-secret DATABASE_URL_SECRET=DB_URL

But NextJS is returning the error

#0 1.141 - info Linting and checking validity of types...
#0 11.20 - info Creating an optimized production build...
#0 24.35 - info Compiled successfully
#0 24.35 - info Collecting page data...
#0 24.95 TypeError [ERR_INVALID_URL]: Invalid URL
#0 24.95     at new NodeError (node:internal/errors:400:5)
#0 24.95     at URL.onParseError (node:internal/url:565:9)
#0 24.95     at new URL (node:internal/url:645:5)
#0 24.95     at parseUrl (file:///app/node_modules/postgres/src/index.js:491:18)
#0 24.95     at parseOptions (file:///app/node_modules/postgres/src/index.js:389:30)
#0 24.95     at Postgres (file:///app/node_modules/postgres/src/index.js:50:19)
#0 24.95     at /app/.next/server/pages/db.js:2050:68 {
#0 24.95   input: '',
#0 24.95   code: 'ERR_INVALID_URL'
#0 24.95 }
#0 24.96 
#0 24.96 > Build error occurred
#0 24.96 Error: Failed to collect page data for /db
#0 24.96     at /app/node_modules/next/dist/build/utils.js:1158:15 {
#0 24.96   type: 'Error'
#0 24.96 }
------
Error: failed to fetch an image or build from source: error building: failed to solve: executor failed running [/bin/sh -c npm run build]: exit code: 1

This error doesn’t occur when I use --build-arg.

--mount=type=secret will only set the secret for that one RUN statement. Find the place in your Dockerfile where you need access to this secret, and replace the word RUN with the first two lines of the above.

Thanks. I passed the secret as DATABASE_URL in front of the npm run build line and now the deploy works.

# Set DATABASE_URL
RUN --mount=type=secret,id=DATABASE_URL \
    DATABASE_URL="$(cat /run/secrets/DATABASE_URL)" \ 
    npm run build

Do I need to add the secret in the command line call every time I deploy to fly:

fly deploy \
    --build-secret DATABASE_URL=DB_URL

Or is there a way to automatically do this whenever a deploy is triggered? I have the DB_URL in a .env file but was getting errors when I tried reading the value in a package.json script I define like npm run deploy.

Ah! Now finally the post I said to disregard applies:

You should be able to write a script that reads the .env file; or you can have npm run deploy use fly console with the Dockerfile that you see on the above page.

Thank you. Here is what ended up working for me:

  1. Create fly-deploy.sh file in root directory with the following contents:
#!/bin/bash

# Load environment variables from the .env.local file
source .env.local

# Run the fly deploy command with the loaded environment variable
fly deploy --build-secret DATABASE_URL="$DATABASE_URL"
  1. In command line run
    chmod +x fly-deploy.sh
    so that .sh file has execute permissions

  2. Add "deploy": "./fly-deploy.sh", to package.json "scripts"
    so that calling npm run deploy deploys to fly.

Hope this helps anyone facing a similar issue!

1 Like