Subdomain web server implementation with Express/Node.js

Tan Bui
4 min readFeb 28, 2022

The number of online tools is exploded these days because of the pandemic. Some famous tools such as Slack, Jira, ProductBoard support customized subdomains while others (Figma, Miro, etc) keep the traditional subdirectory approach.

Let’s discuss the pros and cons of those and take a look at how a simple subdomain web server is implemented with Node.js / Express / Typescript.

What

A domain is a name/string that has been registered by DNS Service Provider for an IP address, so that when you enter that name on the browser’s address bar, the computer would know which IP address to send the request from the browser.

The IP address usually belongs to the webserver which serves the website, and the domain is the “web address” or “URL” that usually relates to your business.

For example, “medium.com” is a domain assigned to “162.159.152.4” (this IP address might be different from your region).

A minimal web address — a domain that intends to serve a website— includes protocol, a domain with extension. For example https://medium.com is equal to https://medium.com:443 where ports 443/80 are the default for https/http protocols.

A subdirectory is another level after the domain to classify the resources of the web app, e.g. https://medium.com/@tanbt.

A subdomain is an extension before the main domain name https://tanbt.medium.com/ to separate a sub-business from the main area. In this term, www is also considered a subdomain but it is usually configured (by the hosting provider) to be redirected to the main domain.

Why subdomain

More explanation could be found at https://blog.hubspot.com/marketing/subdomain-vs-subdirectory. Below are my additional opinions.

Pros:

  • Gives a feel of personalization/customization for customers.
  • Provides convenient access to target highly engaged users, such as users in an organization who use the tool every day.

Cons:

  • Implementation / maintaining / deployment complexity but it shouldn’t be a huge problem.

SEO discussion

Google says the site crawls, indexes, and ranks subdomains and subdirectories the same way. But some measurements show that subdirectories are more effective.

I would choose between subdomains or subdirectories based on the business.

  • For public content that I want SEO optimizations, I’ll put them into subdirectories, such as blog , support , Q&A , etc.
  • For private tools/services that target personal/organizational users, I’ll let them be personalized in a subdomain. Note that SEO doesn’t work on the content that requires authentication.

How

The example uses vhost middleware to handle requests based on their domain in an Express.js server. The use cases are:

  • The guest opens the [Home page](http://localhost.local:3000/).
    — The guest can access the Register page.
    — The guest can access the Login page
  • After successfully authenticated, the user is redirected to his company page such as http://my-comp.localhost.local:3000
    — If the user tries to access another company page, he will be redirected to the Login page.
    — If the user goes back to the main Home page (no subdomain), his info is displayed.
    — From the main Home page, the user can log out.
  • The guest can open the [Blog page](http://blog.localhost.local:3000/) which is an isolated app (fixed subdomain).

The demo project includes simple JWT authentication with EJS templates, all in Typescript. So it’d be helpful if you’re looking for examples of those.

[Just wanna see the code? 😄 Full source code here]

Project structure:

The app.ts bootstrap includes the main app which acts like a reverse proxy which analyzes the request URLs to decide which target apps to use:

  • blog.*.* requests are served by blogApp
  • *.* requests are served by a static app on public resource, or by ejsApp

blogApp and ejsApp are internal apps for my company / service / tool / content which are not related to any customers.

  • *.*.* requests are served by companyApp which is the app for authenticated users who belong to an organization.

The internal-apps.ts for handling the blog page and internal pages (login, logout, register) with JWT/cookie authentication. Pay attention to the comments in the code:

  • Cookie scope based RFC 6565 specs:
    — A cookie is set for example.com can only be read by example.com
    .example.com → can be read by example.com and any subdomain, including foo.example.com, baz.bar.foo.example.com, and baz.example.com.
    foo.example.com → can only be read by foo.example.com
    .foo.example.com → can be read by foo.example.com and any subdomain, including baz.bar.foo.example.com, but not example.com or baz.example.com.
  • When cleaning up the cookie, the domain option should be specified.

The company-app.ts is basically an Express app with EJS engine that verifies and reads user data from the cookie.

I would personally avoid using dynamic subdomains in an MVP version as it could slow down the development process with additional complexities:

  • Domain/hosting configuration
  • Load balancing — server forwarding
  • Staging environment
  • Development environment
  • Development process

But it definitely a good consideration to improve user experiences. Also, having static subdomains for separating businesses or technical matters (e.g. api.mysite.com instead of mysite.com/api) could be considered.

Again, Full source code of my demo project.

--

--

Tan Bui

Software Engineer @Smartly.io, phototaker, naturelover.