How to rewrite subdomain to subpath without using a reverse proxy?

Table of contents

Hey friends 👋,
Overview
I was re-coding a website service for nfthost.app and I wanted users to have their websites linked to a subdomain of my application.
My project is using Next.js and it was deployed with Vercel.
This blog will show you step by step how I managed to rewrite a dynamic subdomain to a dynamic subpath.
Setting Up Vercel
Navigate to Vercel’s Dashboard and choose the project that you are working on. Go to Settings → Domains and add a wildcard subdomain by adding .example.com
.
Setting Up Next.js
Now that we finished setting up Vercel, you can now setup your next.js project. Add a middleware.js
file at the root of your project.
Enter the following code:
import { NextResponse } from 'next/server'
export const config = {
matcher: ['/', '/_sites/:path'],
}
export default async function middleware(req) {
const url = req.nextUrl;
const hostname = req.headers.get('host');
const subpath = process.env.NODE_ENV === 'production' ? hostname.slice(0, hostname.indexOf('.')) : 'www';
if (subpath !== 'www') {
url.pathname = `/_sites/${subpath}${url.pathname}`;
}
return NextResponse.rewrite(url);
}
(Relative source code: https://github.com/stephenasuncionDEV/nfthost/blob/main/middleware.js)
The code above sees if one of the matcher elements matches with the URL entered. It gets the subdomain from the host of the request and rewrites the page to https://nfthost.app/_sites/<subdomain>
.
Now that you’ve setup your middleware, go to your dynamic page and add the following code:
export const getStaticPaths = async () => {
const mappedSubdomains = await axios.get(`${config.serverUrl}/api/website/getMappedSubdomains`, {
headers: {
Authorization: `bearer ${process.env.CREATE_WEBSITE_TOKEN}`
}
});
// mapped subdomains returns an array of the possible subdomains
// so you would need to find all the website data that has the route key (in my case)
// and create an array of { params: { siteRoute: websiteData.route } }
//
// example:
// exports.getMappedSubdomains = async (req, res, next) => {
// try {
// ...
// const websites = await Website.find({ route: {
// $exists: true,
// $ne: ''
// } });
// const mappedSubdomains = websites.map((websiteData) => {
// return { params: { siteRoute: websiteData.route } }
// })
// res.status(200).json(mappedSubdomains);
// } catch (err) {
// next(err);
// }
// }
return {
paths: mappedSubdomains.data,
fallback: true,
}
}
export const getStaticProps = async ({ params: { siteRoute } }) => {
// Gets the route from https://nfthost.app/_sites/<siteRoute>
// and pass it to the component's props
const site = await axios.get(`${config.serverUrl}/api/website/getWebsiteByRoute`, {
params: {
route: siteRoute
},
headers: {
Authorization: `bearer ${process.env.CREATE_WEBSITE_TOKEN}`
}
});
// site will return the website data
return {
props: site.data,
revalidate: 3600
}
}
(Relative source code: https://github.com/stephenasuncionDEV/nfthost/blob/main/pages/_sites/[siteRoute]/index.js)
Demo
Here is my website: https://test.nfthost.app/ which rewrites to https://www.nfthost.app/_sites/test
Reference
https://vercel.com/blog/wildcard-domains
https://github.com/vercel/examples/tree/main/edge-functions/hostname-rewrites
Subscribe to my newsletter
Read articles from Stephen Asuncion directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Stephen Asuncion
Stephen Asuncion
20 years old