NextJS + Ingress subpath prefixing

Prefixing your NextJS app through Ingress

What do we want to achieve?

By default, NextJS doesn't support serving an application with it's assets from a custom app prefix (in both dev and prod), for example:

https://www.myapp.com/    <-- SomeOtherApp
https://www.myapp.com/portal <--- My NextJS app
https://www.myapp.com/static/portal <--- My NextJS static (cached by CDN)

NextJS configuration

To be able to do this we need to add a custom server.(js|ts), use the setAssetPrefix and pass handling the assets into the NextJS request handler.

const assetPrefix = '/static/portal';

const app = next({ dev: process.env.NODE_ENV !== 'production' });
const handle = app.getRequestHandler();

// Handle the asset and rewrite the pathname
const handleAppAssets = (assetRegexp, handle) => (req, res) => {
  const parsedUrl = parse(req.url, true);
  const pathname = parsedUrl.pathname as string;
  const assetMatch = assetRegexp.exec(pathname);
  const [, asset] = assetMatch;
  req.url = format({
    ...parsedUrl,
    pathname: asset,
  });

  return handle(req, res);
};

app.prepare().then(() => {
  // Set the asset prefix
  app.setAssetPrefix(assetPrefix);

  const server = express();

  // Handle the app assets and route them
  server.get(
    `${assetPrefix}/*`,
    handleAppAssets(new RegExp(`^${assetPrefix}(/.*$)`), handle),
  );

  server.all('*', (req, res) => handle(req, res));
  server.listen(3000, error => {
    if (error) throw error;
    console.log('Server started.');
  });
});

Ingress configuration

By default, ingress will rewrite+proxy to our pod(s), but it'll keep the subpath. By using the rewrite-target annotation, it'll rewrite to the root of our container.

metadata:
  name: frontend-portal
  labels:
    owner: myorg
  annotations:
    # Route all traffic to pod, but don't keep subpath (!)
    nginx.ingress.kubernetes.io/rewrite-target: /

spec:
  rules:
    - host: {{ .Values.clusterDomain }}
      http:
        paths:
            - path: /portal(/.*|$)
              backend:
                serviceName: frontend-portal
                servicePort: 80
            - path: /static/portal(/.*|$)
              backend:
                serviceName: frontend-portal
                servicePort: 80

Result

Now your NextJS app will live in the subpath, with it's assets served separately, and your dev and production environment will be in sync.


You'll only receive email when they publish something new.

More from Geeklab.io
All posts