How to run multiple apps mapped to different domains on a Nginx Server

Learn how to use Nginx to host both backend services and Single Page Applications (SPAs) on a single server. This guide covers the setup of Nginx configuration files, utilizing the sites-available and sites-enabled directories for better organization, and managing server configurations for different domains.

GraphQL has a role beyond API Query Language- being the backbone of application Integration
background Coditation

How to run multiple apps mapped to different domains on a Nginx Server

Who doesn’t love creating webapps, webpages or like to show off their beautiful design? We do!Development is just a part of the process, the step that lets us show-off our app is how we host our app for the audience to see.
A server is a necessary component when we are hosting our app, and if we are hosting a single app in one server, we are already set and we can stop our blog right here! but this is not the case.
In today's web development landscape, it is common practice to host multiple websites or applications on a single server. Nginx, known for its efficiency and versatility, provides a robust solution for this.
Too technical? How about we understand Nginx in a simpler way? Let’s consider an example:
In kindergarten, every child is free to play any games of their choice, and there’s no distinction of their classes or divisions (consider the children here as web apps) and then when the play time is over, the teacher (playing the role of Nginx) directs the children to their respective classes or divisions.
In this guide, we will explore how to configure Nginx to host multiple websites or web services, each mapped to a different domain name, on a single Nginx server.

  • Backend services: These can be any web app, web API, or microservices written in backend technologies/frameworks like Golang, NodeJS, or Python. They will be mapped to a specific domain name (e.g., your_app.api.dev).
  • Single Page Applications (SPA): These can be built using frontend technologies/frameworks like React, Vue, or Flutter-Web. They will be mapped to a completely different domain name (e.g., your_app.com).

All of this can be achieved on a single server instance with Nginx installed!

Nginx Configuration File (nginx.conf):

Nginx relies on its main configuration file, nginx.conf, to manage server-wide settings.
The http block within this file plays a pivotal role in defining the global settings for web server functionality. It enables Layer 7 proxying and serving static files.
Within the http block, you can create multiple server blocks. Each server block can listen on different ports and choose to either:

  • Re-route requests to different proxied servers, acting as a reverse proxy.
  • Serve static files, such as .html/css/js files, acting as a static web server.

# nginx.conf

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    # Server block for Backend
    server {
        listen 80;
        server_name your_app.api.dev;

        location / {
            proxy_pass http://localhost:your_backend_port;
            # Other proxy configurations as needed
        }

        # Add any other configurations specific to your backend here
    }

    # Server block for SPA
    server {
        listen 80;
        server_name your_app.com;

        location / {
            root /path/to/your/spa;
            try_files $uri $uri/ /index.html;
            # Other configurations specific to serving the SPA
        }

        # Add any other configurations specific to your SPA here
    }
}

The same can be achieved by creating two separate config files, for instance, SPA.conf and nginx.config , which we shall be learning about in the next section.

Leveraging the sites-available and sites-enabled folders:

While directly configuring within nginx.conf works, a more organized approach involves using sites-available and sites-enabled directories. Let's explore this method, which offers better organization and manageability.
In Nginx, the sites-available and sites-enabled directories are used to organize and manage server configurations for different websites or web applications.
The sites-available directory contains individual configuration files for each website or application hosted on the server. Each file represents a server block configuration specific to a particular domain or application. For example, you can have separate configuration files for your backend services and your Single Page Application (SPA).
On the other hand, the sites-enabled directory contains symbolic links (or shortcuts) to the configuration files located in sites-available. By creating these symbolic links, you can enable or disable specific server configurations without modifying the original files in sites-available. This allows for easy management of multiple websites or applications hosted on the same Nginx server.
To enable a website or application, you create a symbolic link from the sites-available directory to the sites-enabled directory. Conversely, to disable a website or application, you remove the symbolic link from the sites-enabled directory.
Using the sites-available and sites-enabled directories provides a more organized approach to managing Nginx server configurations. It allows you to easily enable or disable specific websites or applications, making it simpler to manage and maintain your server's configuration files, sometimes root access maybe required to access or edit these files.
In this approach, configurations are segregated into individual files within sites-available directory. For the backend, we create a server block configuration file (backend.conf).


# backend.conf

server {
    listen 80;
    server_name your_app.api.dev;

    location / {
        proxy_pass http://localhost:your_backend_port;
        # Other proxy configurations as needed
    }

    # Add any other configurations specific to your backend here
}

Similarly, for the SPA hosted on a separate domain, we create another server block configuration file (spa.conf) within sites-available.


# spa.conf

# Server block for SPA
server {
    listen 80;
    server_name your_app.com;

    location / {
        root /path/to/your/spa;
        try_files $uri $uri/ /index.html;
        # Other configurations specific to serving the SPA
    }

    # Add any other configurations specific to your SPA here
}

To create corresponding files in the sites-enabled folder from the files we created in the sites-available folder, we can use symbolic links.

1. Navigate to the sites-enabled directory:


$ cd /etc/nginx/sites-enabled

Create a symbolic link for the backend.conf file:


$ ln -s /etc/nginx/sites-available/backend.conf

3. Create a symbolic link for the spa.conf file:


$ ln -s /etc/nginx/sites-available/spa.conf

By creating these symbolic links, we are enabling the server configurations for our backend and SPA in the sites-enabled directory.
Before restarting nginx, we have to include the sites-enabled directory in the main nginx.conf file, which can be done using the include directive in the http block of the nginx.conf file:


# nginx.conf

http {
    ...
    include /etc/nginx/sites-enabled/*;
    ...
}

This line tells Nginx to include all configuration files within the sites-enabled directory when reading the main nginx.conf file. By doing so, we can now manage and organize our server configurations using the separate files in the sites-available and sites-enabled directories.
After adding this line, we can now save the nginx.conf file and restart Nginx for the changes to take effect.
On Ubuntu or Debian, you can restart Nginx using the following command:


$ sudo service nginx restart

Now, Nginx will use the configurations from the sites-enabled directory and your backend and SPA will be properly hosted on your single Nginx server, each mapped to their respective domain names.

Request Flow in the Nginx Setup

When an incoming request is received by the Nginx server, it goes through the setup we have created so far before being served to the appropriate website or application. Here is an overview of the request flow:

  1. The request first reaches the Nginx server and is processed by the http block in the nginx.conf file.
  2. Within the http block, Nginx reads the include directive, which includes the configuration files from the sites-enabled directory.
  3. The server blocks defined in the included configuration files are evaluated sequentially.
  4. For each server block, Nginx checks the listen directive to determine the port on which the server is listening for incoming requests.
  5. When a request matches the server_name specified in a server block, Nginx processes the corresponding location block within that server block.
  6. If the request is for a backend service, Nginx proxies the request to the backend server specified in the proxy_pass directive. This allows for reverse proxying, where Nginx acts as an intermediary between the client and the backend server.
  7. If the request is for a Single Page Application (SPA), Nginx serves the static files specified in the root directive. The try_files directive ensures that if the requested file is not found, Nginx falls back to serving the index.html file, which is typically the entry point of the SPA.
  8. Based on the specific configurations within each server block, Nginx may also apply additional settings such as caching, SSL/TLS encryption, or access control.

By following this request flow, Nginx efficiently routes incoming requests to the appropriate backend service or serves the static files of the Single Page Application, allowing multiple websites or applications to run on a single Nginx server, each mapped to its own domain name.

Want to receive update about our upcoming podcast?

Thanks for joining our newsletter.
Oops! Something went wrong.