Custom Server

Framework Next.js 13 Custom Server

Run Next.js with Koa.js

Install Koa packages

yarn add koa
yarn add koa-bodyparser
yarn add koa-logger
yarn add @koa/router
yarn add dotenv

Create server.js file

// server.js
// Environment
require('dotenv').config();
const server_port = parseInt(process.env.APP_PORT, 10) || 5566;
const server_hostname = process.env.APP_HOST || 'localhost';
const server_secret_key = process.env.APP_SECRET || 'koa-secret-key';
const nextjs_is_dev_environment = process.env.APP_ENV !== 'production';

// Koa
const Koa = require('koa');
const KoaBodyParser = require('koa-bodyparser');
const KoaLogger = require('koa-logger');
const KoaRouter = require('@koa/router');
const KoaRouterApp = new KoaRouter();

// Next.js
const NextJS = require('next');
// Next.js Server
const NextJSApp = NextJS({ 
  dev: nextjs_is_dev_environment, 
  hostname: server_hostname, 
  port: server_port 
});


NextJSApp.prepare().then(() => {
  // Koa Server
  const KoaServer = new Koa();
  KoaServer.keys = [server_secret_key];

  // Koa Logger
  KoaServer.use(KoaLogger());

  // Koa Parse body
  KoaServer.use(KoaBodyParser());
  
  // Set Response Status
  KoaServer.use(async (context, next) => {
    context.res.statusCode = 200;
    await next();
  });
  
  // Set Router
  KoaServer.use((() => {
    return KoaRouterApp
      .all('(.*)', async (context) => {
        const NextJSRequestHandler = NextJSApp.getRequestHandler();
        await NextJSRequestHandler(context.req, context.res);
        context.respond = false;
      })
      .routes()
  })());

  // Listen Request
  KoaServer.listen(server_port, () => {
    console.log(`> Ready on http://${server_hostname}:${server_port}`);
  });
});

Update packages.json scripts

{
  "scripts": {
    "dev": "node server.js",
    "build": "yarn run lint && next build",
    "start": "APP_ENV=production node server.js",
  }
}

Run Next.js with koa.js

yarn dev
yarn build
yarn start

Run Https on the Next.js with Koa.js

Generate SSL Key

docker run -v $PWD:/work -it nginx openssl \
    req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 \
    -keyout /work/nginx.privateKey.key \
    -out /work/nginx.certificate.crt

Read SSL Key

// server.js
// Https Server
const Https = require('https');
const FileSystem = require('fs');

const HttpsOptions = {
  key: FileSystem.readFileSync('./nginx.privateKey.key'),
  cert: FileSystem.readFileSync('./nginx.certificate.crt')
};

Listen https request

NextJSApp.prepare().then(() => {
  // Listen Https Request
  const HttpsServer = Https.createServer(HttpsOptions, KoaServer.callback());
  HttpsServer.listen(server_port + 1, () => {
    console.log(`> Ready on https://${server_hostname}:${server_port}`);
  });
});

Listen http & https request at the same time

NextJSApp.prepare().then(() => {
  // Listen Http Request
  KoaServer.listen(server_http_port, () => {
    console.log(`> Ready on http://${server_hostname}:${server_port}`);
  });

  // Listen Https Request
  const HttpsServer = Https.createServer(HttpsOptions, KoaServer.callback());
  HttpsServer.listen(server_https_port, () => {
    console.log(`> Ready on https://${server_hostname}:${server_port}`);
  });
});

The full version of the server.js file for Https Server

// server.js
// Environment
require('dotenv').config();
const server_http_port = parseInt(process.env.APP_HTTP_PORT, 10) || 80;
const server_https_port = parseInt(process.env.APP_HTTPS_PORT, 10) || 443;
const server_hostname = process.env.APP_HOST || 'localhost';
const server_secret_key = process.env.APP_SECRET || 'koa-secret-key';
const nextjs_is_dev_environment = process.env.APP_ENV !== 'production';

// Https Server
const Https = require('https');
const FileSystem = require('fs');

const HttpsOptions = {
  key: FileSystem.readFileSync('./nginx.privateKey.key'),
  cert: FileSystem.readFileSync('./nginx.certificate.crt')
};

// Koa
const Koa = require('koa');
const KoaBodyParser = require('koa-bodyparser');
const KoaLogger = require('koa-logger');
const KoaRouter = require('@koa/router');
const KoaRouterApp = new KoaRouter();

// Next.js
const NextJS = require('next');
// Next.js Server
const NextJSApp = NextJS({ 
  dev: nextjs_is_dev_environment, 
  hostname: server_hostname, 
  port: server_port 
});


NextJSApp.prepare().then(() => {
  // Koa Server
  const KoaServer = new Koa();
  KoaServer.keys = [server_secret_key];

  // Koa Logger
  KoaServer.use(KoaLogger());

  // Koa Parse body
  KoaServer.use(KoaBodyParser());
  
  // Set Response Status
  KoaServer.use(async (context, next) => {
    context.res.statusCode = 200;
    await next();
  });
  
  // Set Router
  KoaServer.use((() => {
    return KoaRouterApp
      .all('(.*)', async (context) => {
        const NextJSRequestHandler = NextJSApp.getRequestHandler();
        await NextJSRequestHandler(context.req, context.res);
        context.respond = false;
      })
      .routes()
  })());

  // Listen Http Request
  KoaServer.listen(server_http_port, () => {
    console.log(`> Ready on http://${server_hostname}:${server_port}`);
  });

  // Listen Https Request
  const HttpsServer = Https.createServer(HttpsOptions, KoaServer.callback());
  HttpsServer.listen(server_https_port, () => {
    console.log(`> Ready on https://${server_hostname}:${server_port}`);
  });
});

Reference