Next.js Discord

Discord Forum

Dockerizing Django + Next.js application

Unanswered
Siberian posted this in #help-forum
Open in Discord
SiberianOP
I'm using Docker to containerize three services: Nginx, Django and Next.js. Next.js is acting mainly as a headless frontend and Django is a RESTful API where Next will fetch data from. Nginx is serving everything and handling routes to backend or frontend from the client.

The Docker build process works when using "root" as the container user. I'm able to run docker compose up and will get a running Nginx server--- Next.js on the frontend, fetching data from Django. The problem I'm facing is this... When I introduce container users, Next needs to build the application in the container (npm run build) to setup the .next folder and subfolders, as well as all the permissions for the files in there. However, I'm unable to run npm run build because my fetch commands will fail! The backend (dockerized Django REST API) doesn't exist yet!

Is the only way to handle this situation to make the API available externally (i.e., fetch('https://otherserver.com/endpoint')? For local development, I'd like to still use npm run dev with a mounted volume from the host. However, I'm getting the error Error: EACCES: permission denied, unlink '/app/frontend/.next/server/app-paths-manifest.json'. I believe this is because I'm neglecting the npm run build step in my Dockerfile and instead use npm run dev in my up Docker compose command.

Is there a way to generate .next build files/permissions w/o actually doing the build?

Code screenshots attached

13 Replies

@Siberian I'm using Docker to containerize three services: Nginx, Django and Next.js. Next.js is acting mainly as a headless frontend and Django is a RESTful API where Next will fetch data from. Nginx is serving everything and handling routes to backend or frontend from the client. The Docker build process works when using "root" as the container user. I'm able to run `docker compose up` and will get a running Nginx server--- Next.js on the frontend, fetching data from Django. The problem I'm facing is this... When I introduce container users, Next needs to build the application in the container (`npm run build`) to setup the `.next` folder and subfolders, as well as all the permissions for the files in there. However, I'm unable to run `npm run build` because my `fetch` commands will fail! The backend (dockerized Django REST API) doesn't exist yet! Is the only way to handle this situation to make the API available externally (i.e., `fetch('https://otherserver.com/endpoint')`? For local development, I'd like to still use `npm run dev` with a mounted volume from the host. However, I'm getting the error `Error: EACCES: permission denied, unlink '/app/frontend/.next/server/app-paths-manifest.json'`. I believe this is because I'm neglecting the `npm run build` step in my Dockerfile and instead use `npm run dev` in my `up` Docker compose command. **Is there a way to generate `.next` build files/permissions w/o actually doing the build?** Code screenshots attached
give permission of current dir to that user with chown
SiberianOP
I think my Docker container command (npm run dev) is somehow creating the folders as container's "root" user? If you don't mind checking out the screenshots of the code, you can see I'm doing:
COPY --from=builder --chown=1001:1001 /app/frontend/.next ./.next
on line 56 of my frontend.Dockerfile

I think because the "chown" is happening before the npm run dev, the Node script might be running as root or creating those files as root?
The file in question .../.next/server/app-paths-manifest.json exists on the host (outside the container) before build. So it should be copied over as 1001:1001 too...?
SiberianOP
Does the npm run build step that Next.js shows in their example repo setup those permissions at that point? But I can't build without my local API up...
The root folder is settings nextjs:nodejs correctly, but my .next/ folder is root:root :/
(screenshots from inside Docker container)
I don't think I know docker enough to help you
@Siberian Repo's public rn too: https://github.com/l00sed/django-nextjs
European sprat
Where's the Dockerfile?
SiberianOP
I scrotted and attached earlier, it's actually not updated in the repo. Screenshot is most recent
SiberianOP
FROM node:20.4-bookworm-slim AS deps

WORKDIR /home/node

COPY app/frontend/package.json ./
COPY app/frontend/package-lock.json ./

# Update NPM to latest version
RUN npm i -g npm@latest
# Install application node modules
RUN npm i

FROM node:20.4-bookworm-slim AS builder

WORKDIR /home/node
COPY --from=deps /home/node/node_modules ./node_modules
COPY app/frontend .

FROM node:20.4-bookworm-slim AS runner

WORKDIR /home/node

# ENVIRONMENT VARIABLES ===========================
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8

ENV NODE_ENV development
# Disable NEXT.js telemetry 😡
ENV NEXT_TELEMETRY_DISABLED 1

# Ensure headless Debian (for apt installation)
ENV DEBIAN_FRONTEND noninteractive

# UPDATES =========================================
# Update debian packages
RUN apt-get update -y
# Install Neovim for file editing and alias vim -> nvim
RUN apt-get install -y neovim
RUN alias vim=nvim
# Use vi-mode for shell navigation
RUN set -o vi

# Re-create frontend "node" user with host's UID/GID
RUN userdel -f node || echo 'User "node" does not exist.'
RUN if getent group node;then groupdel node;fi
RUN groupadd -g 1001 node || echo 'Group "node" already exists.'
RUN useradd -l -u 1001 -g node node || echo 'User "node" already exists.'
RUN install -d -m 0755 -o node -g node /home/node || echo 'User directory already exists for "node".'

# Copy application code to container
COPY --from=builder --chown=1001:1001 /home/node .
#COPY --from=builder --chown=1001:1001 /home/node/.next ./.next
COPY --from=builder /home/node/node_modules ./node_modules
COPY --from=builder /home/node/package.json ./package.json

RUN chown --changes --silent --no-dereference --recursive 1001:1001 /home/node
RUN mkdir -p /home/node/.npm
RUN chown --changes --silent --no-dereference --recursive 1001:1001 /home/node/.npm

# Switch to the "node" user
USER node
CMD ["npm", "run", "dev"]
SiberianOP
This Dockerfile ended up working out for me. Using a non-root user is kind of a nightmare with any service, but this was especially painful. I think using node as user is important, according to some stuff I've read online. I needed to also chown some very specific files and folders. Will see where I can improve... I'm not sure whether or not the --no-dereference and --changes flags are actually doing anything.
Thanks for suggestions