Skip to Content
DockerDeploy Next.js Websites with Docker

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

Dockerfile.website-base
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:

Terminal
docker build -f Dockerfile.website-base -t website-base .
Note

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.

Dockerfile.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:

Note

Don’t forget to change website-name to match your website name.

Terminal
docker build -f Dockerfile.website-name -t website-name .

Finally run your container and bring your website to life:

Terminal
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

Terminal
docker run --env-file <your-env-filename> -d --restart=always --name website-name -p 3000:3000 website-name
Note

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.