At Watford Consulting we use Krystal for our web hosting.

Like many web hosting providers, Krystal offers their customers a cPanel interface to configure their service. One of the nice benefits for customers is that we can use cPanel to configure serving of web applications written in various languages such as Ruby, Python and Node.js.

Running a Node.js app through cPanel is pretty simple, but running a Next.js app can be a bit more complex due to Next.js applications, by default, attempting to build themselves on the deployment host. Attempts to build a Next.js application will likely fail due to limits of memory and the number of processes you can spawn under your web hosting account.

All is not lost! We can still deploy a Next.js application to a cPanel web host provider as long as we pre-build the application before deployment and use a custom Node.js server to load the Next.js application.

Demonstration

In this article we’ll demonstrate how to build and deploy a very basic Next.js application to a cPanel based web hosting provider.

The demo uses the basic Next.js application that get created by the create-next-app command and the result can be viewed here.

Check available Node.js versions

To avoid problems later, we’ll want to check on the versions of Node.js supported by our web hosting provider and ensure we use the same version in our build.

Sign in to your hosting provider’s website and access cPanel. Open the Setup Node.js App screen.

Setup Node.js App highlighted in cPanel

Click on the Create Application button and note the available versions of Node.js.

Ensure you have a version of node installed on your development host which matches a version available from your web hosting provider. In this case we will use Node.js version 12.

Create and build the Next.js application

Create a working directory in your development environment and execute:

npx create-next-app nextjs-cpanel

This will create a basic Next.js application with a single index page and an example REST api endpoint. The node_modules directory will have already been populated by the above command.

Change into the new application’s directory (cd nextjs-cpanel) and create file next.config.js with the following content:

module.exports = {
    basePath: '/apps/nextjs-cpanel'
}

We set the above basePath to correspond with the Application URL where we will mount the application. In our case the Next.js application will be accessible at https://www.watfordconsulting.com/apps/nextjs-cpanel.

Note that the basePath must be set before the following build steps. If you wish to change the basePath later then you must re-run the build.

At the terminal run the following:

rm -rf .next/
npm run build

The .next/ directory will contain a copy of any built files for the Next.js application, so if it already exists it is recommended that you clean it in case any artifacts were created by the create-next-app process.

npm run build will build the Next.js project and write the results to the .next/ directory.

Next create file server.js with the following content:

const { createServer } = require('http')
const next = require('next')

const isDevMode = process.env.NODE_ENV !== 'production'
const port = process.env.PORT ? process.env.PORT : 3000

const nextjsApp = next({ dev: isDevMode })
const nextjsRequestHandler = nextjsApp.getRequestHandler()

nextjsApp
  .prepare()
  .then(() => {
    createServer((req, res) => {
      // The request url likely will not include a protocol or host, therefore
      // resolve the request url against a dummy base url.
      const url = new URL(req.url, "http://w.w")
      nextjsRequestHandler(req, res, url)
    }).listen(port, (err) => {
      if (err) throw err
    })
  })
  .catch((ex) => {
    console.error(ex.stack)
    process.exit(1)
  })

You should now be able to exercise the Next.js app by running:

NODE_ENV=production node server.js

server.js should start an http server listening on port 3000, and forward any incoming requests to the Next.js application. To see the application in action visit http://localhost:3000/apps/nextjs-cpanel.

Deploying the Next.js application via cPanel

The components needed for the deployment to cPanel are the .next/ directory and files next.config.js, package.json and server.js. Create a suitable directory on your hosting account, e.g. /home/username/apps/nextjs-cpanel, and copy the components there.

In cPanel open the Setup Node.js App screen and click on Create Application.

Make sure you choose an appropriate Node.js version based on the version you used to build the Next.js application.

Set Application mode to Production.

The Application root needs to match the directory where you copied the applications components to, and the Application URL needs to match the baseUrl specified in the next.config.js file.

Finally the Application startup file must be set to the server.js file.

Once you have entered all required information click on the Create button.

Your application will be created and immediately launched by your web hosting provider. However the application will fail to run since we haven’t yet installed our dependencies.

Click on the Stop App button and then click Run NPM Install to download dependencies to the node_modules directory.

Once all dependencies are installed click on Start App to restart your application and then open visit the Application URL in your browser.

Too many redirects

If when visiting your new Next.js web application you see an error page similar to the above it means the browser has been redirected too many times.

If we check the Network tab in the browser’s developer tools (F12) we can see that the browser was redirected back and forth between /apps/nextjs-cpanel and /apps/nextjs-cpanel/. The difference is the trailing slash in the requested path.

In the above case, something in the processing chain – such as the hosting provider’s web-server – is redirecting the browser to an address which includes the trailing slash. Our Next.js application won’t see the request until the browser visits us again with the modified address.

By default Next.js is configured to redirect browsers to addresses with the trailing slash removed. Therefore when Next.js is eventually called to handle the browser request it immediately instructs the browser to redirect to the same address, but without the trailing slash.

The browser simply follows the redirects until the maximum redirect count is reached and then displays an error.

To resolve this issue we must stop one of the parties responsible for redirects from doing so. To stop Next.js from removing trailing slashes modify next.config.js to have the following content:

module.exports = {
    basePath: '/apps/nextjs-cpanel',
    trailingSlash: true
}

Rebuild the application, redeploy to hosting server and restart the Node.js application.

You should now be able to visit the application without hitting the too-many redirects error.