Skip to content

Host Your Personal Projects on a Single VPS

9 min read

Is Heroku becoming too expensive? Are you looking for a cheaper alternative to host your personal projects?

What if you could save money and learn valuable skills in the process? Skills that will make you stand out in the job market among your peers.

Perhaps you've asked yourself:

How do I deploy my backend on the same site as the frontend so the API calls go through api.mydomain.com?

In this article, you'll discover three different methods of project organisation — by domain, subdomain or subdirectory. You'll see how they work behind the scenes and learn how to host multiple projects on a single server.

Why host your personal projects on a VPS?

When you use a Platform-as-a-Service (PaaS) like Heroku, AWS Elastic Beanstalk or Google App Engine, you're paying for each application which quickly gets expensive. Alternatively, static site hosting like Netlify and Vercel can't host databases and a serverless backend is limited in what it can do.

In many cases, having your own VPS is the cheapest way to host your portfolio website along with your personal projects. Using a VPS is a great way to learn how to secure a server, get more familiar with the command line and practice deploying applications. It's also tremendously fun to have your own server in the cloud to play with.

The downside of a VPS is that you are in charge of deployments and making sure your application stays alive. If you just want to quickly ship and have more time to focus on a product that generates revenue, managing a server may not be the best choice.

However, personal projects are not businesses. They're meant to showcase your skills and value to a potential employer or client. Additionally, some familiarity with Linux and deployments are valuable skills in the job market. In which case, a VPS is an excellent choice.

Where can you get a VPS

The provider landscape is split into two groups — the corporate giants and the smaller businesses. In the giant's category, there is AWS EC2 (Amazon), Google Compute Engine (Google) and Azure VM (Microsoft). On the other end, there is Digital Ocean, Linode, Vultr and a long tail of smaller providers.

Main differences between the two provider groups are the number of cloud services they offer and the user-friendliness of their products. While the smaller businesses offer fewer services, they make up for it in user-friendly UI and clear documentation.

If you're already familiar with any of the above-mentioned providers, go with that. Otherwise, I suggest choosing one of the smaller providers so you don't waste time navigating the cumbersome UI of bigger co's. The smaller providers are pretty much on par when it comes to price, support and quality so it doesn't matter which one you choose. If you're in decision paralysis, go with Digital Ocean 😉.

Organising your personal projects

There are three ways you can organise your projects — by domain, subdomain or subdirectory. Given three applications, the resulting URLs would look as follows:

  • Domain - recipeapp.com, weatherapp.com, ecommerceapp.com
  • Subdomain - recipeapp.yourdomain.com, weatherapp.yourdomain.com, ecommerceapp.yourdomain.com
  • Subdirectory - yourdomain.com/recipeapp, yourdomain.com/weatherapp, yourdomain.com/ecommerceapp

Organising by domain involves buying separate domains for all of your applications. For most developers, that's too much hassle to go through for their personal projects. However, if you have already done some volunteer or client work, you probably went this route as it has a more professional look and it doesn't interfere with your personal domain. You can still host applications on different domains on a single VPS. You just have to make sure their DNS records point to the same IP address.

Subdomains are a great choice since you only need to buy one parent domain. But you still have to add a DNS record and configure SSL for each project, unless you use wildcard records.

Organising by subdirectory allows you to quickly add new projects since you don't need any DNS changes. The downside of this approach is you have to change all the links and routes in your application to work with the subdirectory (e.g.: /weatherapp) instead of the root path (/). This can be tricky to get right. It's also a bit more effort to extract one application out to a different server if you wish to do so in the future.

The three methods are not mutually exclusive. You can mix them together on a single VPS. In a later section, I'm going to show you how to configure for each method.

Serving multiple applications from a single server

First, if you're organising your projects by domain or subdomain, you need to make sure they all point to the same IP address. You can configure this in the dashboard of your DNS provider. The process is different for each provider, but you're looking to set a type A record with the domain/subdomain as the name, and the IP address of your server as the content. You can find the IP address of your server in the dashboard of your VPS provider.

If I would have a personal project named weatherapp on a separate subdomain, my DNS records would look like this:

maximorlov.com.             299  IN  A  104.27.181.7
weatherapp.maximorlov.com.  299  IN  A  104.27.181.7

To serve multiple applications from a single server you will need to use a reverse proxy. That's because only one application is allowed to listen on the same port at one time. When someone types a URL in the browser, the request goes to the default internet port — port 80 for HTTP or port 443 for HTTPS. It's possible to send a request from the browser to a different port if you specify it in the URL, for example, yourdomain.com:3000, but that's awkward for your visitors.

A reverse proxy takes all incoming requests on the default internet ports and routes them to the respective application. Nginx is the most popular reverse proxy in the Node.js community. You can also use a different reverse proxy, like Apache, if that's what you're familiar with.

Configuring Nginx for static file hosting and reverse proxying

I'm going to jump straight to configuring Nginx and show you some basic configurations so you get an idea of how a reverse proxy works. To get started with Nginx, I recommend this detailed installation tutorial written by the folks at Digital Ocean.

As long as there are enough resources available (CPU, RAM etc.), you can host as many applications as you want on a single VPS. Let's say we have three personal projects:

  • A recipe application that's just a frontend without a backend
  • A weather application with a frontend and a backend that does some API requests to a 3rd party, but no database
  • An e-commerce website with a frontend, a backend and a database

As far as Nginx is concerned, it doesn't care whether the application has a database or not. I'm using these examples to show you the flexibility a VPS gives you to host whatever you want. I'll explain how to deploy each application in future articles, as that is very specific to the stack you're using.

We'll assume the Node.js servers for the weather and e-commerce apps have been started properly and listen on ports 3000 and 3001, respectively. The recipe app will be served by Nginx directly since it doesn't have a backend. Nginx can do that since it in itself, is a server.

Domain-based configuration

For domain-based organisation, we define a virtual server for each application. When a request comes in, Nginx goes through each server block from top to bottom and compares the request Host header with the server_name value. Upon a match, that request is handled by the respective server block. Have a look at the configuration file below:

# Basic Nginx configuration routing traffic based on organising by domain
events {}

http {
    # Configuration block for recipeapp.com
  server {
    listen 80; # HTTP
    server_name recipeapp.com;

    # Build directory of a frontend-only application
    root /home/node/recipeapp;
  }

  # Configuration block for weatherapp.com
  server {
    listen 80; # HTTP
    server_name weatherapp.com;

    # Route all requests to port 3000 on localhost
    location / {
      proxy_pass http://localhost:3000;
    }
  }

  # Configuration block for ecommerceapp.com
  server {
    listen 80; # HTTP
    server_name ecommerceapp.com;

    # Route all requests to port 3001 on localhost
    location / {
      proxy_pass http://localhost:3001;
    }
  }
}

proxy_pass is where the actual reverse proxying is happening — Nginx hands off the request to the Node.js servers.

You'll notice recipe app doesn't have a reverse proxy configuration because that application doesn't have a backend Node.js server. Instead, Nginx will serve its files from the root location matching the URL. As an example – given a request to recipeapp.com/images/pie.png, Nginx will look for a file at the following location: /home/node/recipeapp/images/pie.png.

Subdomain-based configuration

The configuration for organising projects by subdomain is very similar. The only difference is the server_name values have changed to their respective subdomains:

# Basic Nginx configuration routing traffic based on organising by subdomain
events {}

http {
  # Configuration block for recipeapp.yourdomain.com
  server {
    listen 80; # HTTP
    server_name recipeapp.yourdomain.com;

    # Build directory of a frontend-only application
    root /home/node/recipeapp;
  }

  # Configuration block for weatherapp.yourdomain.com
  server {
    listen 80; # HTTP
    server_name weatherapp.yourdomain.com;

    # Route all requests to port 3000 on localhost
    location / {
      proxy_pass http://localhost:3000;
    }
  }

  # Configuration block for ecommerceapp.yourdomain.com
  server {
    listen 80; # HTTP
    server_name ecommerceapp.yourdomain.com;

    # Route all requests to port 3001 on localhost
    location / {
      proxy_pass http://localhost:3001;
    }
  }
}

Subdirectory-based configuration

Configuring Nginx for projects on different subdirectories is a little bit different. Instead of multiple server blocks, we have multiple location blocks. Nginx decides how to process a given request by looking for a location block that matches the URL path.

# Basic Nginx configuration routing traffic based on organising by subdirectory
events {}

http {
  server {
    listen 80; # HTTP
    server_name yourdomain.com;

    # Configuration block for yourdomain.com/recipeapp
    location /recipeapp {
      # Build directory of a frontend-only application minus the path
      root /home/node;

      # Serve files root + path location, otherwise look for an index.html file in the folder before responding with a 404 status code
      try_files $uri $uri/index.html =404;
    }

    # Configuration block for yourdomain.com/weatherapp
    location /weatherapp {
      # Route all requests to port 3000 on localhost
      proxy_pass http://localhost:3000;
    }

    # Configuration block for yourdomain.com/ecommerceapp
    location /ecommerceapp {
      # Route all requests to port 3001 on localhost
      proxy_pass http://localhost:3001;
    }
  }
}

Because Nginx adds the URL path to the root when looking for a file's location, we've changed the root value from /home/node/recipeapp to /home/node.

The try_files $uri $uri/index.html =404 directive instructs Nginx to look for files that match the URL path or an index.html file before responding with a 404 status code. This way users won't have to type yourdomain.com/recipeapp/index.html but yourdomain.com/recipeapp will work as well.

When you organise projects by subdirectory, don't forget to change the links in your application. If you previously had a link pointing to yourdomain.com/amsterdam in your weather app, it now has to be yourdomain.com/weatherapp/amsterdam. This includes static assets such as images, JavaScript and CSS files.

These basic examples give you an idea of how to host several projects on a single VPS. In production, you often want to include additional configuration for caching, security and SSL so your applications work over HTTPS.

In summary

A VPS is an excellent choice to host your portfolio website along with your personal projects. It's often cheaper than the alternatives and a great way to learn more about Linux and the command line.

You can organise your projects by domain, subdomain or subdirectory and we've seen how to configure Nginx for each method.

Now it's your turn! Go out and apply what you've just learned to your portfolio website.

Write clean code. Stay ahead of the curve.

Every other Tuesday, I share tips on how to build robust Node.js applications. Join a community of 1,526 developers committed to advancing their careers and gain the knowledge & skills you need to succeed.

No spam! 🙅🏻‍♀️ Unsubscribe at any time.

You might also like

Set up Automated Deployments From Github With Webhook

Set up Heroku-like auto-deployments on your server. Redeploy every time you push to your Github repository.
Read article

4 Essential Steps to Securing a VPS

How do you protect your data and keep the bad guys out? Secure your server with these 4 simple steps.
Read article

How Do You Start a Node.js Server in Production?

Confidently start a Node.js app that's always available to serve incoming requests, just like you programmed it.
Read article