I am running a Next.js app on Docker. However, when calling my API I get the following error
TypeError: fetch failed
at node:internal/deps/undici/undici:13178:13
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async m (/app/.next/server/chunks/961.js:3:716)
at async b (/app/.next/server/pages/user/administration.js:51:1030)
at async e3 (/app/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/next/dist/compiled/next-server/pages.runtime.prod.js:31:594)
at async doRender (/app/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/next/dist/server/base-server.js:1425:30)
at async cacheEntry.responseCache.get.routeKind (/app/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/next/dist/server/base-server.js:1599:28)
at async NextNodeServer.renderToResponseWithComponentsImpl (/app/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/next/dist/server/base-server.js:1507:28)
at async NextNodeServer.renderPageComponent (/app/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/next/dist/server/base-server.js:1924:24)
at async NextNodeServer.renderToResponseImpl (/app/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/next/dist/server/base-server.js:1962:32) {
[cause]: AggregateError [ECONNREFUSED]:
at internalConnectMultiple (node:net:1118:18)
at afterConnectMultiple (node:net:1685:7)
at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) {
code: 'ECONNREFUSED',
[errors]: [ [Error], [Error] ]
This only happens when calling the API from getServerSideProps
. Calling it from the client side, everything works as expected, including authenticated and public API calls.
The API is built with .NET Core and running on localhost:5068
(not in Docker). The Next app is running on localhost:3050
from Docker.
Everything works as expected when I run the Next app locally. So I'm assuming I need some configuration somewhere in Next (or .NET API) to make a successful call from getServerSideProps
when Next is running in Docker context.
Dockerfile
FROM node:22.4-alpine AS base
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json pnpm-lock.yaml* ./
RUN corepack enable pnpm && pnpm i --frozen-lockfile
FROM base AS builder
ENV NEXT_PRIVATE_STANDALONE true
ENV NEXT_PUBLIC_BACKEND_ROOT_URI http://localhost:5068
ENV NEXT_PUBLIC_FRONTEND_URI http://localhost:3050
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN corepack enable pnpm && pnpm run build
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
RUN mkdir .next
RUN chown nextjs:nodejs .next
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3050
ENV PORT 3050
CMD HOSTNAME="0.0.0.0" node server.js
Docker Compose
services:
sweetnotes.fe:
image: myimage
container_name: mycontainer
build:
context: .
dockerfile: Dockerfile
ports:
- '3050:3050'
By default, Docker containers run on a Docker virtual network created by Docker to isolate the containers from the host. For network purposes, you can think of each container as a separate machine. And localhost
in a container means the container itself.
To reach the host from a container, you need to add the host to the known hostnames of the container using extra_hosts
in your compose file. It's common to use the name host.docker.internal
as the hostname of the host.
In your case, it'd look like this
services:
sweetnotes.fe:
image: myimage
container_name: mycontainer
build:
context: .
dockerfile: Dockerfile
ports:
- '3050:3050'
extra_hosts:
- 'host.docker.internal:host-gateway'
Then you can change the URL of the backend to
ENV NEXT_PUBLIC_BACKEND_ROOT_URI http://host.docker.internal:5068
in your Dockerfile and it should work after rebuilding the image.