Nginx setup for Next.js subdomain routing
Tags: nextjs, nginx
Published: 2023-08-12 07:01:13

> **Don't do it unless you can 100% control your nginx**

In this article, I will guide you through the process of setting up Nginx(_only_) for subdomain routing to a Next.js router. To illustrate this, I'll use a page router as an example.

Here's a sample page router structure:
```txt
pages/
├──subdomain-1/
│           ├──index.tsx
│           └──blogs/
└──subdomain-2/
            ├──index.tsx
            └──orders/
```
The expect behavior is 
1. subdomain-1.com -> /pages/subdomain-1/index.tsx
2. subdomain-1.com/blogs -> /pages/subdomain-1/blogs/index.tsx
3. subdomain-2.com/orders -> /pages/subdomain-2/orders/index.tsx

## nginx.conf
The idea is simple, use `server_name` to setup 2 virtual hosts and `proxy_pass` proxy to the backend
```
http {
    upstream nextjs {
        http://localhost:3000;
    }
    server {
        listen 80;
        server_name subdomain-1.com;
        
        location / {
            # for i18n
            set $locale_prefix '/subdomain-1';
            set $rest $request_uri;
            if ($request_uri ~ ^/(en|ja|zh-TW)(.*)$) {
                set $locale_prefix '/$1/subdomain-1';
                set $rest $2;
            }
            proxy_pass http://nextjs$locale_prefix$rest;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }

    server {
        listen 80;
        server_name subdomain-2;
        location / {
          set $locale_prefix '/subdomain-2';
          set $rest $request_uri;
          if ($request_uri ~ ^/(en|ja|zh-TW)(.*)$) {
              set $locale_prefix '/$1/subdomain-2';
              set $rest $2;
          }
          proxy_pass http://nextjs$locale_prefix$rest;
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}
```
## next.js
you need to replace your paths in code, use `router.push('/blogs')` instead of `router.push('/domain-2/blogs')` and separate the local and production environment's behavior.
```ts
// @ts-nocheck
export const setPath = (path: string): string => {
  const PATH_PREFIXES = ['/subdomain-1', '/subdomain-2'];
  if (process.env.NODE_ENV !== 'development') {
    for (const prefix of PATH_PREFIXES) {
      if (path.startsWith(prefix)) {
        return path.slice(prefix.length);
      }
    }
  }
  return path;
};

router.push(setPath('/subdomain-1/blogs'));
```

## pros and cons
- pros
  - microservices alignment
  - deployment specific subdomain won't affect your application
  - tls are managed by nginx, you can support different level of subdomain
  - cleaner code structure, each folder points to a subdomain
- cons
  - development and deployment are more complex
  - difficult to maintain, next.js folder will be constrained  by nginx config
  - initial setup is difficult, frontends need to know about nginx config

Typically, in Next.js, you should use **[middleware](https://nextjs.org/docs/pages/building-your-application/routing/middleware)** for subdomain routing.

> **Don't do it unless you can 100% control your nginx**