# \[Tutorial\] How to use subdomains in Express.js with vhost

**URL:** <https://forum.codeselfstudy.com/t/tutorial-how-to-use-subdomains-in-express-js-with-vhost/2290>\
**Category:** Tutorials\
**Tags:** javascript\
**Created:** [May 5, 2020, 6:24am UTC](https://forum.codeselfstudy.com/t/tutorial-how-to-use-subdomains-in-express-js-with-vhost/2290 "2020-05-05T06:24:49Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Josh](https://forum.codeselfstudy.com/user_avatar/forum.codeselfstudy.com/josh/32/4_2.png) [@Josh](https://forum.codeselfstudy.com/u/Josh)\
**Post date:** [May 5, 2020, 6:24am UTC](https://forum.codeselfstudy.com/t/tutorial-how-to-use-subdomains-in-express-js-with-vhost/2290/1 "2020-05-05T06:24:49Z")

</div>

This quick tutorial shows how to use subdomains with Express.js. If you don’t know Express.js yet, check out some of the previous tutorials, like the [introduction to Node.js/Express servers tutorial](https://forum.codeselfstudy.com/t/tutorial-an-introduction-to-node-js-servers-and-express-js/2211).

## Create a simple Express.js app

Create a new project folder and create two files: `package.json` and `app.js`.

The `package.json` file should look something like this:

```json
{
    "name": "@j127/express_subdomains",
    "version": "0.1.0",
    "description": "A simple example of using subdomains with Express.js",
    "scripts": {
        "start": "npx nodemon app.js",
        "format": "prettier \"**/*.{js,css,html,json,ts}\" --write"
    },
    "author": "your name",
    "license": "BSD-3-Clause"
}

```

The `app.js` file should look like this to start:

```javascript
const express = require("express");

const app = express();

app.get("/", (req, res) => {
    res.send("hello world");
});

const PORT = 3000;
app.listen(PORT, () => console.log(`server is running at 127.0.0.1:${PORT}`));

```

## Install the dependencies

This will install the dependencies and save them:

```plaintext
$ npm install --save express vhost
$ npm install --save-dev nodemon prettier

```

## Formatting your code

For this tutorial, I’ve added `prettier` as a dependency to help people automatically keep their code neat. Put a file named `.prettierrc` in your project with these contents:

```json
{
    "endOfLine": "lf",
    "semi": true,
    "singleQuote": false,
    "tabWidth": 4,
    "trailingComma": "es5"
}

```

Also create a file named `.prettierignore` with these contents:

```json
node_modules/
.git/

```

From this point on, you’ll be able to type one command to format all the code perfectly:

```plaintext
$ npm run format

```

Those files are in all of my sample repos, so if you’re wondering what they do, that’s basically it, except that my editor [formats the code automatically](https://prettier.io/docs/en/editors.html). 🙂

## Edit your hosts file

Next step: to view your server with temporary host names, you’ll need to set up your hosts file so that you can access your local server by some custom domain name.

I’m using Linux, and my hosts file is located at `/etc/hosts`. If you’re using Mac or Windows, find your hosts file with [these instructions](https://www.howtogeek.com/howto/27350/beginner-geek-how-to-edit-your-hosts-file/).

You’ll probably need to use `sudo` to edit the `/etc/hosts` file. You can type something like this to edit it on Linux:

```plaintext
$ sudo nano /etc/hosts

```

Add lines for your local (made-up) domain name and subdomains that point to your local machine (`127.0.0.1`) like this:

```auto
127.0.0.1	mysite.local
127.0.0.1	cats.mysite.local
127.0.0.1	dogs.mysite.local

```

If your server is running on port 3000, then you will be able to visit any of these to view your local development site:

- `mysite.local:3000`
- `cats.mysite.local:3000`
- `dogs.mysite.local:3000`

The names above are arbitrary — you can use whatever names you want in development.

## Check that it’s working

The app should now run if you start it like this:

```plaintext
$ npm start

```

Visit these URLs to check, and the content should be the same for all of them:

- `localhost:3000`
- `mysite.local:3000`
- `cats.mysite.local:3000`
- `dogs.mysite.local:3000`

## Add subdomain routing

Here’s the `app.js` file with working subdomains. It isn’t in the final form yet, but I kept it as simple as possible (in one file) for a first look. Read the comments and code to see what it does.

```javascript
// Import the two dependencies
const express = require("express");
const vhost = require("vhost");

// Create an app for the top-level domain
const app = express();

// Create an app for each subdomain. You can call these whatever you want.
const cats = express();
const dogs = express();

// Set the domain based on whether it's in production or not. If the
// syntax doesn't look familiar, look up "ternary operator javascript"
// in a search engine or leave a comment below.
const domain =
    process.NODE_ENV === "production" ? "example.com" : "mysite.local";

// Mount the extra apps on their subdomains.
app.use(vhost(`cats.${domain}`, cats));
app.use(vhost(`dogs.${domain}`, dogs));

// The routers will be moved to their own files in another step.

// a router for the root domain
app.get("/", (req, res) => {
    res.send(`hello world`);
});

// a router for the cats subdomain
cats.get("/", (req, res) => {
    res.send("here is the cats subdomain");
});

// a router for the dogs subdomain
dogs.get("/", (req, res) => {
    res.send("here is the dogs subdomain");
});

// start the server
const PORT = 3000;
app.listen(PORT, () => console.log(`server is running at 127.0.0.1:${PORT}`));

```

Check the URLs to see the changes:

- `mysite.local:3000`
- `cats.mysite.local:3000`
- `dogs.mysite.local:3000`

## Larger Example

I wrote a quick, larger example and put it on Github. I wrote this tutorial and all the code in two hours, so it’s rough and there are better ways to do some of the things, but it at least shows how to begin splitting things up into their own files. Leave a comment below, or make a pull request if you have suggestions (as long as they don’t make the example too complex).

> **[GitHub - j127/express\_subdomains](https://github.com/j127/express_subdomains)**
>
> Contribute to j127/express\_subdomains development by creating an account on GitHub.

I recommend reading the files in this order:

1. `package.json` – it lists dependencies
2. `app.js` – it sets everything up
3. the files in `routes` – these link the routes to controller functions
4. the files in `controllers` – these contain the functions that generate the pages and send responses
5. the files in `views` – these are the template files that get rendered by the controller functions

## Other Resources

This video shows similar functionality coded from scratch. It’s in Portuguese, but the code is readable.

[![](https://forum.codeselfstudy.com/uploads/default/original/2X/6/6cf56462927e31498b77c36ff5d13698742d557c.jpeg "Vhost com NodeJS e Express") ](https://www.youtube.com/watch?v=GV3hWa5VIQg)

---

<div class="post-metadata">

**Author:** ![PaulH](https://forum.codeselfstudy.com/letter_avatar_proxy/v4/letter/p/e495f1/32.png) [@PaulH](https://forum.codeselfstudy.com/u/PaulH)\
**Post date:** [May 5, 2020, 6:27am UTC](https://forum.codeselfstudy.com/t/tutorial-how-to-use-subdomains-in-express-js-with-vhost/2290/2 "2020-05-05T06:27:23Z")

</div>

Awesome, thanks! I will try this tomorrow, winding down for today. 🙂

---

<div class="post-metadata">

**Author:** ![PaulH](https://forum.codeselfstudy.com/letter_avatar_proxy/v4/letter/p/e495f1/32.png) [@PaulH](https://forum.codeselfstudy.com/u/PaulH)\
**Post date:** [May 20, 2020, 6:38am UTC](https://forum.codeselfstudy.com/t/tutorial-how-to-use-subdomains-in-express-js-with-vhost/2290/3 "2020-05-20T06:38:26Z")

</div>

OK, thanks again for the tutorial! I am just now setting this up.

I managed to get myfooddata.local working, but I can’t get the subdomain tools.myfooddata.local working. Here is what I have so far:

```auto
const express = require("express"); // import express
const vhost = require("vhost"); //For subdomain
const hbs = require('hbs'); //For handlebars partials (like php includes)
const initHandlebars = require("./handlebars"); //Handlebars helper functions

//For nodemon
////--watch contollers/* -e js

require("dotenv").config(); //My SQL configuration
const mysql = require("mysql"); //Adding in MySQL
const db = require("./models/database"); //Points to SQL connections

// create an Express application
const app = express();
const tools = express(); //for subdomain

const domain =
    process.NODE_ENV === "production" ? "myfooddat.com" : "myfooddata.local";

    
app.use(vhost(`tools.${domain}`, tools));

//Point to view directory and declare use of handlebars
const path = require("path");
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "hbs");
app.use(express.static(path.join(__dirname, "public")));
initHandlebars();

//app.set('env development');

// This imports the routers = defines where the files are for routing
const indexRouter = require("./routes/index");
const toolsRouter = require("./routes/tools");
const apiRouter = require("./routes/api");

//ROUTING
// Each router gets mounted here
app.use("/", indexRouter);
app.use("/tools", toolsRouter);
app.use("/api", apiRouter);

```

I think it must be something with the router file.  
Which looks like this:

```auto
const express = require("express");
const ctrl = require("../controllers/toolsController");

const router = express.Router();

/* This runs the code stored in `controllers/pageController.js`
The point of this is so you can call different templates depending on the "Get Request"
or page request*/
//router.get("/", ctrl.homepage);
router.get("/nutrition-facts.php", ctrl.nutritionFacts);
router.get("/recipe-nutrition-calculator.php", ctrl.nutritionCalculator);
router.get("/nutrition-comparison.php", ctrl.nutritionComparison);
router.get("/protein-calculator.php", ctrl.proteinCalculator);

module.exports = router;

```

Calling it a day on my end, so no rush, or we can discuss this at the meetup tomorrow too. Thanks Josh! 🙂

---

<div class="post-metadata">

**Author:** ![Josh](https://forum.codeselfstudy.com/user_avatar/forum.codeselfstudy.com/josh/32/4_2.png) [@Josh](https://forum.codeselfstudy.com/u/Josh)\
**Post date:** [May 20, 2020, 8:07am UTC](https://forum.codeselfstudy.com/t/tutorial-how-to-use-subdomains-in-express-js-with-vhost/2290/4 "2020-05-20T08:07:51Z")

</div>

Did you add it to your `/etc/hosts` file? If not I could show you how to do that tomorrow.

> [@PaulH](#):
>
> `"myfooddat.com"`

It looks like a letter is missing there.

---

<div class="post-metadata">

**Author:** ![PaulH](https://forum.codeselfstudy.com/letter_avatar_proxy/v4/letter/p/e495f1/32.png) [@PaulH](https://forum.codeselfstudy.com/u/PaulH)\
**Post date:** [May 20, 2020, 4:24pm UTC](https://forum.codeselfstudy.com/t/tutorial-how-to-use-subdomains-in-express-js-with-vhost/2290/5 "2020-05-20T16:24:18Z")

</div>

Hmm, yes, the subdomain is in the `etc/hosts` file. I can get it hvosts to work for `http://myfooddata.local/` but not for the subdomain. I think it is probably something in the routing. I spent about 45 minutes on it and can’t get it so I will wait for the call.

Here is a resource I found that I was trying to implement:  
[http://expressjs.com/en/resources/middleware/vhost.html](http://expressjs.com/en/resources/middleware/vhost.html)

---

<div class="post-metadata">

**Author:** ![PaulH](https://forum.codeselfstudy.com/letter_avatar_proxy/v4/letter/p/e495f1/32.png) [@PaulH](https://forum.codeselfstudy.com/u/PaulH)\
**Post date:** [August 16, 2020, 3:15am UTC](https://forum.codeselfstudy.com/t/tutorial-how-to-use-subdomains-in-express-js-with-vhost/2290/6 "2020-08-16T03:15:18Z")

</div>

I am having this issue where the subdomain index page loads the main site index page.

Going to try follow the Portuguese tutorial and report back.

---

<div class="post-metadata">

**Author:** ![PaulH](https://forum.codeselfstudy.com/letter_avatar_proxy/v4/letter/p/e495f1/32.png) [@PaulH](https://forum.codeselfstudy.com/u/PaulH)\
**Post date:** [August 16, 2020, 11:01pm UTC](https://forum.codeselfstudy.com/t/tutorial-how-to-use-subdomains-in-express-js-with-vhost/2290/7 "2020-08-16T23:01:48Z")

</div>

So I want to add to this guide about launching these subdomains on a server that uses Nginx.

If you do, it is helpful to have the subdomain listening on another port.

So in the example above you would have

```auto
// start the server
const PORT = 3000;
app.listen(PORT, () => console.log(`server is running at 127.0.0.1:${PORT}`));

const dogPORT = 3001;
app.listen(dogPORT, () => console.log(`server is running at 127.0.0.1:${dogPORT}`));

const catPORT = 3002;
app.listen(catPORT, () => console.log(`server is running at 127.0.0.1:${catPORT}`));

```

Then in your Nginx server config you can add code for the new apps like so:

```auto
            location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    location /dog {
        proxy_pass http://localhost:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
    location /cat {
        proxy_pass http://localhost:3002;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

```

You will also need to make a new nginx available sites file for `cats.mydomain.com` and `dogs.mydomain.com` and have it listen to the requisite port.

Similar to this example:

```auto
        root /var/www/cats.mydomain.com/html;
        index index.html index.htm index.php index.nginx-debian.html;

        server_name cats.mydomain.com;

        location / {
        proxy_pass http://localhost:3002;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;

}

```

At this point, your subdomain should load appropriately. Just be aware than any relative links such as “./linkto/images” will probably not work in the subdomain as the main domain!
