Learn how to serve directories from the NextJS app router to subdomains, even for local development!

Encountering challenges in seamlessly serving app router directories from dedicated subdomains in Next.js? This article will guide you through a robust solution to this problem. Let's dive into the intricacies of subdomain routing and how to implement it effectively.

App Structure Overview

Consider the following directory structure for your Next.js app:

.
└── app/
    β”œβ”€β”€ blog/
    β”‚   β”œβ”€β”€ page.tsx
    β”œβ”€β”€ home/
    β”‚   β”œβ”€β”€ page.tsx
    └── admin/
    β”‚   β”œβ”€β”€ page.tsx
    └── layout.tsx

Now, the goal is to serve the following paths on dedicated subdomains:

  • /blog on blog.code-specialist.local
  • /home on code-specialist.local
  • /admin on admin.code-specialist.local

Roadblocks in Existing Solutions

Despite multiple methods described in the Next.js documentation, issues, and discussions, finding a solution without limitations can be challenging. This article aims to provide a clear and effective approach to overcome these hurdles.

Hosts file

To ensure seamless local development, add the following entries to your /etc/hosts file:

127.0.0.1 admin.code-specialist.local
127.0.0.1 code-specialist.local
127.0.0.1 blog.code-specialist.com

For Windows users, locate the file at %windir%\system32\drivers\etc.

NGINX Configuration

The key to successful subdomain routing lies in the NGINX configuration. Below is an exemplary configuration for routing the blog subdomain:

server {
listen 80;
listen [::]:80;
keepalive_timeout 60;
server_name blog.code-specialist.local;
# Exclude resource requests from being rewritten
location ~* \.(js|css|svg|jpg|jpeg|png|gif|ico|json|woff|woff2|ttf|eot)$ {
proxy_pass http://host.docker.internal:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Exclude requests to /_next from being rewritten
location ^~ /_next {
proxy_pass http://host.docker.internal:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location / {
proxy_pass http://host.docker.internal:3000/blog;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Named location for non-root paths
location ~ ^/(?<path>.+)$ {
proxy_pass http://host.docker.internal:3000/blog/$path;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

Note the crucial lines at 7, 26, and 35 that facilitate the routing. Similar configurations can be applied for the other subdomains. Make sure that rewrites are disabled for both _next resources and media assets.

You can find a comprehensive example of this configuration in action at https://github.com/code-specialist/nextjs-nginx-app-router-subdomains.