The application works correctly when I run it locally, but if I try to dockerize it, I get a 500 fetch failed
error with no logs. I also tried running the application with node --trace-warnings
but no errors appear. The project is a pnpm
monorepo, and the folder structure is
apps
│
├── backend
│ ├── Dockerfile
│ └── package.json
│
├── frontend
│ ├── Dockerfile
| ├── nuxt.config.ts
│ └── package.json
│
├── docker-compose.yaml
├── package.json
├── pnpm-lock.yaml
└── pnpm-workspace.yaml
Here is the apps/frontend/Dockerfile
###################
# STAGE 1: BUILD
###################
FROM node:20-alpine AS build
# Set working directory inside the image
WORKDIR /app
# Copy application dependency manifests to the container image.
COPY --chown=node:node ./package.json ./pnpm-lock.yaml ./pnpm-workspace.yaml ./
COPY --chown=node:node ./apps/frontend/package.json ./apps/frontend/package.json
# Install pnpm globally
RUN npm install -g pnpm
# Install app dependencies using the `pnpm install --frozen-lockfile`
RUN pnpm install --frozen-lockfile
# Bundle app source
COPY --chown=node:node ./apps/frontend ./apps/frontend/
# Build the Nuxt.js application
RUN pnpm --filter=@myapp/frontend build
# Use the node user from the image (instead of the root user)
USER node
###################
# STAGE 2: PRODUCTION
###################
FROM node:20-alpine AS production
# Set working directory inside the image
WORKDIR /app
# Copy compiled static files from the build stage (Stage 1)
COPY --chown=node:node --from=build /app/apps/frontend/.output/ ./
# Port and host for the nitro
ENV NITRO_HOST=0.0.0.0
ENV NITRO_PORT=3000
# Expose the port the app runs on
EXPOSE 3000
# Use the node user from the image (instead of the root user)
USER node
# Default command to start Nuxt
CMD [ "node", "/app/server/index.mjs" ]
Here is the docker-compose.yaml
version: '3.8'
services:
frontend:
container_name: frontend
build:
context: .
dockerfile: apps/frontend/Dockerfile
ports:
- '3000:3000'
networks:
- mynetwork
depends_on:
- backend
backend:
container_name: backend
build:
context: .
dockerfile: apps/backend/Dockerfile
ports:
- '3001:3001'
depends_on:
- db
networks:
- mynetwork
environment:
- POSTGRES_HOST=postgres
- POSTGRES_PORT=5432
- POSTGRES_USERNAME=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DATABASE=database
- SERVER_ADDRESS=0.0.0.0
- SERVER_PORT=3001
db:
container_name: postgres
image: postgres:13
ports:
- '5432:5432'
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: database
networks:
- mynetwork
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
networks:
mynetwork:
driver: bridge
Here is the nuxt.config.ts
export default defineNuxtConfig({
devtools: { enabled: true },
modules: [
"@nuxtjs/apollo",
"@nuxtjs/tailwindcss",
"@nuxtjs/color-mode",
"@nuxt/icon",
"@element-plus/nuxt",
"@nuxt/image",
],
plugins: [{ src: "~/plugins/vue-toastification.ts", mode: "client" }],
apollo: {
clients: {
default: {
httpEndpoint: `${ process.env.SERVER_URL ?? "http://127.0.0.1:3001/graphql"}`,
inMemoryCacheOptions: {
addTypename: false,
},
defaultOptions: {
watchQuery: {
fetchPolicy: "no-cache",
},
query: {
fetchPolicy: "no-cache",
},
},
},
},
},
css: ["@fontsource-variable/inter/index.css"],
});
I also tried setting the frontend
service environment variable SERVER_URL
with the name of the backend
service container, but I still get the same error.
services:
frontend:
container_name: frontend
build:
context: .
dockerfile: apps/frontend/Dockerfile
ports:
- '3000:3000'
networks:
- mynetwork
depends_on:
- backend
environment:
- SERVER_URL=backend:3001/graphql
backend:
container_name: backend
build:
context: .
dockerfile: apps/backend/Dockerfile
In the end, I found the problem: you need to set two different URLs for GraphQL in nuxt.config.js
, one for the server-side and one for the client-side in Nuxt, so that the server-side URL points to the container while the client-side URL points to the URL exposed by the container.
Here is the updated nuxt.config.js where we have defined httpEndpoint
(for the server-side) and browserHttpEndpoint
(for the client-side):
export default defineNuxtConfig({
...
apollo: {
clients: {
default: {
httpEndpoint: `${ process.env.SERVER_URL ?? "http://127.0.0.1:3001/graphql"}`,
browserHttpEndpoint: "http://127.0.0.1:3001/graphql",
},
},
},
...
});
Here is the updated docker-compose.yaml
where we pass the argument SERVER_URL
used in the build stage of the Nuxt.js project.
services:
frontend:
container_name: frontend
build:
context: .
dockerfile: apps/frontend/Dockerfile
args:
- SERVER_URL=http://backend:3001/graphql
ports:
- '3000:3000'
networks:
- mynetwork
depends_on:
- backend
In the Dockerfile
of the Nuxt.js project, we need to add the environment variable SERVER_URL
in the build stage before running the build command
...
# Custom server URL
ARG SERVER_URL
ENV SERVER_URL=$SERVER_URL
# Build the Nuxt.js application
RUN pnpm --filter=@weroad/frontend build
...