Deploy Next.js websites with Docker
Description
I have found what I believe to be a good solution for deploying websites via Docker on a server, for example.
This approach uses a Dockerfile that provides a base Node image for all services requiring Node.
Website-specific Dockerfiles are built on top of this base, avoiding repeated downloads of the Node image for each website.
TL;DR
When your deploying more than one website on a server, you create a base dockerfile and a dockerfile for each website.
The website dockerfiles inherit from the base dockerfile.
The shared base dockerfile
FROM node:22-bullseye
# Create consistent user/group for all websites
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
To build this container, run:
docker build -f Dockerfile.website-base -t website-base .
You only need to build and not run this container, it’s only used as a base for the website-specific dockerfiles.
More details on how to run this container can be found in the Dockerfile Overview.
The website-specific dockerfile
You can copy this template into the root directory of your website or every website you want to deploy.
The only thing you need to change is the Dockerfile.your-website-name
to match your website name.
# Your website-base image you created earlier
FROM website-base AS base
# Install dependencies only when needed
FROM base AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
# Build the application
RUN npm run build
# Production image
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
# Copy production dependencies from deps stage
COPY --from=deps /app/node_modules ./node_modules
# Copy the public folder
COPY --from=builder /app/public ./public
# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next
# Copy the build output
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]
Deploying your website
Now to build your dockerfile for your specific website, copy and adjust this command:
Don’t forget to change website-name
to match your website name.
docker build -f Dockerfile.website-name -t website-name .
Finally run your container and bring your website to life:
docker run -d --restart=always --name website-name -p 3000:3000 website-name
Include .env
variables
If you need to inject environment variables into your website, add the --env-file
flag to your docker run command
docker run --env-file <your-env-filename> -d --restart=always --name website-name -p 3000:3000 website-name
Keep in mind that if you want to deploy multiple websites on the same server, you need to change the port mapping for each website.
For example, the second website could use -p 3001:3000
Conclusion
When firewall rules are set up correctly, you should be able to access your website via http://your-server-ip:3000
This approach allows you to deploy multiple Next.js websites on a single server efficiently,
leveraging a shared base image to minimize redundancy and optimize resource usage.