Can Next.js be integrated with Docker and Nginx for a seamless development environment?

I have a nextjs project that I want to run using Docker and nginx. The setup requires nginx to connect to nextjs behind the scenes, with only nginx being able to communicate with nextjs (users must talk to nginx to access nextjs).

Given the typical nextjs project structure and the contents of the provided dockerfile below, is there a way to utilize nginx in Docker with nextjs?

I am aware that Docker-compose can be used but I prefer keeping it within one docker image as I intend to deploy this image to Heroku web hosting.

NOTE: This setup involves Server Side Rendering.

dockerfile:

# Base on official Node.js Alpine image
FROM node:latest as builder

# Set working directory
WORKDIR /usr/app

# install node-prune (https://github.com/tj/node-prune)
RUN curl -sfL https://install.goreleaser.com/github.com/tj/node-prune.sh | bash -s -- -b /usr/local/bin

# Copy package.json and package-lock.json before other files
# Utilize Docker cache to save re-installing dependencies if unchanged
COPY package.json ./
COPY yarn.lock ./

# Install dependencies
RUN yarn install --frozen-lockfile

# Copy all files
COPY ./ ./

# Build app
RUN yarn build

# remove development dependencies
RUN yarn install --production

# run node prune. Reduce node_modules size
RUN /usr/local/bin/node-prune

####################################################### 

FROM node:alpine

WORKDIR /usr/app

# COPY package.json next.config.js .env* ./
# COPY --from=builder /usr/app/public ./public
COPY --from=builder /usr/app/.next ./.next
COPY --from=builder /usr/app/node_modules ./node_modules

EXPOSE 3000

CMD ["node_modules/.bin/next", "start"]

Dockerfile inspired by https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile.multistage

Edit: nginx default.conf

upstream nextjs_upstream {
  server nextjs:3000;

  # We could add additional servers here for load-balancing
}

server {
  listen 80 default_server;

  server_name _;

  server_tokens off;

  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection 'upgrade';
  proxy_set_header Host $host;
  proxy_cache_bypass $http_upgrade;

  location / {
    proxy_pass http://nextjs_upstream;
  }
}

Answer №1

To successfully combine Nginx and NextJS in a single Docker container without relying on Docker-Compose, the solution lies in utilizing Supervisord.

Supervisor operates as a client/server system that grants users control over multiple processes within UNIX-like operating systems.

The challenge did not stem from nginx configuration or the dockerfile itself. Rather, it pertained to running both nginx and nextjs simultaneously upon starting the container. As the approach of running both directly seemed elusive, the integration of supervisord emerged as the required tool.

The following prerequisites are essential for this setup to function properly:

Dockerfile

# Utilizing the official Node.js Alpine image as base
FROM node:latest as builder

# Defining working directory
WORKDIR /usr/app

# Initial copies of package.json and package-lock.json before other files
# Harnessing Docker cache to prevent re-installing dependencies if they remain unchanged
COPY package.json ./
COPY yarn.lock ./

# Dependency installation
RUN yarn install --frozen-lockfile

# Copying all files
COPY ./ ./

# Building the application
RUN yarn build

# Removing development dependencies
RUN yarn install --production

####################################################### 

FROM nginx:alpine

WORKDIR /usr/app

RUN apk add nodejs-current npm supervisor
RUN mkdir mkdir -p /var/log/supervisor && mkdir -p /etc/supervisor/conf.d

# Clearing any existing configuration files
RUN rm /etc/nginx/conf.d/*

# Copying nginx configuration files
# *.conf files within conf.d/ directory get included in main configuration
COPY ./.nginx/default.conf /etc/nginx/conf.d/

# COPY package.json next.config.js .env* ./
# COPY --from=builder /usr/app/public ./public
COPY --from=builder /usr/app/.next ./.next
COPY --from=builder /usr/app/node_modules ./node_modules

# Supervisor's basic configuration
ADD supervisor.conf /etc/supervisor.conf

# Replacing $PORT in nginx configuration (provided by executor) and initiating supervisord (to run nextjs and nginx)
CMD sed -i -e 's/$PORT/'""$PORT""'/g' /etc/nginx/conf.d/default.conf && \
  supervisord -c /etc/supervisor.conf

supervisor.conf

[supervisord]
nodaemon=true

[program:nextjs]
directory=/usr/app
command=node_modules/.bin/next start
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
autorestart=true

[program:nginx]
command=nginx -g 'daemon off;'
killasgroup=true
stopasgroup=true
redirect_stderr=true
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
autorestart=true

nginx config (default.conf)

upstream nextjs_upstream {
  server localhost:3000;

  # Additional servers can be added here for load-balancing
}

server {
  listen $PORT default_server;

  server_name _;

  server_tokens off;

  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection 'upgrade';
  proxy_set_header Host $host;
  proxy_cache_bypass $http_upgrade;

  location / {
    proxy_pass http://nextjs_upstream;
  }
}

NOTE: employing nginx as a reverse proxy. NextJS will operate on port 3000. Direct access won't be possible for the user, requiring passage through nginx instead.


Constructing the docker image:

docker build -t nextjs-img -f ./dockerfile .

Launching the docker container:

docker run --rm -e 'PORT=80' -p 8080:80 -d --name nextjs-img nextjs-img:latest

Navigate to localhost:8080

Answer №2

One way to set up Nginx and your NextJS app in Docker containers is by utilizing docker-compose. Establish a bridge network between the two containers for seamless communication.

In your nginx configuration file:

server {
    listen       80;
    listen       443 ssl;

    server_name localhost [dns].com;

    ssl_certificate certs/cert.pem;
    ssl_certificate_key certs/cert.key;

    location / {
        proxy_pass http://nextApplication; // refer to your docker-compose file
        proxy_http_version 1.1;
        proxy_read_timeout      90;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host [dns].com;
        proxy_cache_bypass $http_upgrade;
    }
}

Instead of using the upstream script, opt for placing the load balancer on top of Nginx (handled at the cloud provider level).

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can I configure my Next.js middleware to function in both localhost and on Vercel deployments?

Currently, I am delving into the realm of Next.js and have just created a basic middleware.ts: export { default } from 'next-auth/middleware'; export const config = { matcher: ['/items', '/dashboard'] }; While everything work ...

NextJS is not displaying data fetched from getStaticProps on the page, although it is present in the props

I'm facing an issue with NextJS when trying to display text fetched from my API call. Essentially, I send an external HTTP request to retrieve some sample data. The data is returned as props for the component using the getStaticProps method. Within my ...

Can you explain the distinct variations between these two approaches for obtaining API data?

When working with third-party APIs in NextJS 14, I encountered two different methods to query the API that resulted in slightly different outcomes. Method 1: Located within the /api folder as a route handler: export async function GET() { const res = aw ...

The following error has been caught: node::loader::ImportModuleDynamically

While using the t3 stack, I encountered an error when trying to start the server with Next.js. The error message is as follows: node[20481]: ../src/module_wrap.cc:599:MaybeLocal<v8::Promise> node::loader::ImportModuleDynamically(Local<v8::Context& ...

NextJs does not have Bootstrap loaded

I am currently working on a NextJs application where I have integrated bootstrap. Package.json: "dependencies": { "@zeit/next-css": "^1.0.1", "@zeit/next-sass": "^1.0.1", "autoprefixer&q ...

The NextJS application is experiencing issues with appending the API call correctly

Folder structure -Pages --Support ---StaffTable.js await axios.post('api/updateStaffDetails', { data: dataToSubmit }); Encountering an issue: Previously, I added a '/' in front of the API call to resolve it, but this time it's not ...

Terraform creates an ECS Fargate task that fails the health check

Setting up an ECS cluster and Load Balancer using Terraform, I encountered an issue where my Fargate-deployed hello-world node app failed to pass the initial health-check and kept restarting. Despite ensuring that my Dockerfile, Load Balancer, and Task Def ...

Ways to incorporate suspense with NextJS 14 - how can I do it?

I am looking to add a suspense effect to the initial loading of my page while the assets are being fetched. These assets include images on the home screen or as children of the RootLayout component. How can I implement an initial Loading state for these ...

Could it be a path problem if you're directed to the incorrect slug without any errors popping up?

I have two slugs. I'm encountering an issue where I am trying to access the second slug [product] but instead, it keeps redirecting me to the first one [slug]. The slugs are stored in separate folders and there aren't any error messages being dis ...

Why does the incorrect element get updated specifically when files are being uploaded?

I have created a component called CreatePost, which is responsible for creating or editing posts. However, I encountered an issue where if I render this component twice and upload a file from the second instance, it also reflects in the first one. This has ...

Encountering Vue CLI issues during deployment of Vue application using Docker

I've been working on a VUE app locally and now I'm attempting to deploy it to a remote server for testing. My development machine is running Arch with Docker 20.10.17 The VUE app uses the following Dev.Dockerfile for building: FROM node:lts-alp ...

Encountering an error while trying to run a Next.js application on Linux Mint

View the error screenshot After creating a new Next.js app with npx create-next-app, I ran npm run dev and encountered the following error message ...

Next.js encounters an issue: "The text content does not align with the server-rendered HTML"

I just set up a new Next.js project and added a very basic component: const IdPanel = () => { const [id] = useState(`${Math.random()}`); return ( <div> <h1 id={id} className={id}> {id} </h1> </div> ...

The React hook is activated each time a key is pressed, but it should ideally only be triggered when there is

I have created a hook for my Formik form that should be called whenever a specific field's Selection option is chosen. However, I am facing an issue where the hook is being triggered on every key press in every form field. I am not sure what mistake ...

In nextjs, the page scroll feature stops functioning properly following a redirection

Currently, I am running on version 13.5.4 of Next.js In a server-side component, I am using the nextjs redirect function to navigate to another page. However, after the redirection, I noticed that the next page is missing the scroll bar and seems to be st ...

An unexpected error occurred while setting up Stripe payments in Next.js, resulting in an AxiosError message: "Request failed with status code 500."

checkout.js page contains all the necessary code, but I'm encountering an axios error and unsure of what is missing. import React from 'react'; import Head from "next/head"; import Header from "../components/Header&quo ...

Forgetting Passwords: utilizing Next.js with Strapi for password recovery

My current challenge involves sending a reset password email to the user's provided email in the forgot password form. However, when I attempt to do so, I encounter an "Internal Server Error" message... Below is the function that triggers upon submit ...

Is there a way for me to retrieve a variable from outside a function?

I'm trying to access a variable outside of the function in Next.js. I want to retrieve the 'name' from the data object after making an API call. let getDetail = async () => { let body = { code: '12', provider: & ...

What causes my CSS styles to vanish upon refreshing the page in Next.js?

After setting up a CSS folder within my app directory and importing the files into components for use, I noticed that the styles are applied initially. However, upon refreshing the page, they all disappear. I attempted to resolve this issue by going back ...

Oh no! A critical mistake has occurred: Mark-compact operations are not working efficiently near the heap limit, leading to a failed allocation due to the

My project is not particularly complex, I only just started it. However, when I run the command npm run dev, node js consumes more than 4GB of memory and eventually crashes with a fatal error: --- Last few GCs --- [16804:0000018EB02350F0] 128835 ms: Mar ...