Guide to using the NGINX web server and reverse proxy

Guide to using the NGINX web server and reverse proxy

Nginx is a popular web server and reverse proxy that can handle high-performance and high-concurrency web applications. In this tutorial blog post, I will show you how to install and configure nginx on Ubuntu and RHEL-derivatives, how to use different conventions for managing nginx configuration files, and how to use nginx as a reverse proxy for multiple domains and subdomains.

Installing nginx

To install nginx on Ubuntu, you can use the following commands:

sudo apt update
sudo apt install nginx

To install nginx on RHEL-derivatives, such as CentOS or Fedora, you can use the following commands:

sudo dnf update
sudo dnf install nginx

After installing nginx, you can start, stop, restart, or reload the nginx service using the following commands:

sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
sudo systemctl reload nginx

You can also check the status of the nginx service using the following command:

sudo systemctl status nginx

Configuring nginx

Nginx uses configuration files to define how it handles different web requests. The main configuration file is located at /etc/nginx/nginx.conf, which includes other configuration files from different directories.

nginx.conf has many configurations. If you ever want to setup a service and pass it through Nginx, it's likely you'll have to tune some parameters later, depending on the application.

For example, if you get an error upon a file upload, it's probably because the upload file size is too restricted by Nginx.

client_max_body_size 100M; - this way it's now set to 100 megabytes. It can also be set in the server block instead, to limit per service.

There are two common conventions for managing nginx configuration files: the sites-available and sites-enabled directories, and the conf.d directory.

The sites-available and sites-enabled directories

The sites-available and sites-enabled directories are used to store and activate configuration files for different virtual hosts. A virtual host is a way of hosting multiple domains or subdomains on a single web server. The sites-available directory contains all the available configuration files for different virtual hosts, while the sites-enabled directory contains only the symbolic links to the configuration files that are actually enabled.

To create a new virtual host, you need to create a new configuration file in the sites-available directory, and then create a symbolic link to it in the sites-enabled directory. For example, if you want to create a virtual host for the domain example.com, you can use the following commands:

sudo nano /etc/nginx/sites-available/example.com

This will open a text editor where you can write the configuration for the virtual host. A basic configuration file for a virtual host looks something like this:

server {
    listen 80;
    server_name example.com;
    root /var/www/example.com;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

This configuration tells nginx to listen on port 80, use example.com as the server name, use /var/www/example.com as the document root, use index.html as the default index file, and return a 404 error if the requested file or directory is not found.

After saving and closing the file, you need to create a symbolic link to it in the sites-enabled directory using the following command:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

This will activate the virtual host for example.com. To disable the virtual host, you can simply remove the symbolic link from the sites-enabled directory using the following command:

sudo rm /etc/nginx/sites-enabled/example.com

The conf.d directory

The conf.d directory is another way of managing configuration files for different virtual hosts. Unlike the sites-available and sites-enabled directories, the conf.d directory does not use symbolic links, but rather includes all the configuration files that end with .conf in the main configuration file. To create a new virtual host, you just need to create a new configuration file with the .conf extension in the conf.d directory. For example, if you want to create a virtual host for the domain example.com, you can use the following command:

sudo nano /etc/nginx/conf.d/example.com.conf

This will open a text editor where you can write the configuration for the virtual host. The configuration file is the same as the one used in the sites-available directory, except that you do not need to specify the listen directive, as it is already included in the main configuration file. A basic configuration file for a virtual host in the conf.d directory looks something like this:

server {
    server_name example.com;
    root /var/www/example.com;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

After saving and closing the file, the virtual host for example.com is automatically enabled. To disable the virtual host, you can simply rename or remove the configuration file from the conf.d directory.

Using nginx as a web server

To use nginx as a basic web server and host some static web content on your domain, you need to create a new configuration file in the sites-available directory, and then create a symbolic link to it in the sites-enabled directory. For example, if you want to host some static web content on the domain example.com, you can use the following commands:

sudo nano /etc/nginx/sites-available/example.com

This will open a text editor where you can write the configuration for the virtual host. A basic configuration file for a virtual host looks something like this:

server {
    listen 80;
    server_name example.com;
    root /home/ubuntu/web;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

This configuration tells nginx to listen on port 80, use example.com as the server name, use /home/ubuntu/web as the document root, use index.html as the default index file, and return a 404 error if the requested file or directory is not found.

Here's a sample index.html file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Example.com</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: lightblue;
        }

        h1 {
            text-align: center;
            color: white;
        }

        p {
            text-align: justify;
            margin: 20px;
        }

        a {
            color: white;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <h1>Welcome to Example.com</h1>
    <p>This is a sample html file that is served by nginx as a basic web server. It contains some static web content, such as HTML, CSS, and JavaScript. You can access this file by typing example.com in your web browser.</p>
    <p>This file is located in the document root of the virtual host for example.com, which is <code>/home/ubuntu/web</code>. The configuration file for the virtual host is located in the <code>sites-available</code> directory, and is activated by a symbolic link in the sites-enabled directory.</p>
    <script>
        console.log("Hello, world!");
    </script>
</body>
</html>

After saving and closing the file, you need to create a symbolic link to it in the sites-enabled directory using the following command:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

This will activate the virtual host for example.com. To disable the virtual host, you can simply remove the symbolic link from the sites-enabled directory using the following command:

sudo rm /etc/nginx/sites-enabled/example.com

Testing nginx commands

Before applying any changes to the nginx configuration files, it is always a good idea to test them for syntax errors and validity. You can use the following command to test the nginx configuration:

sudo nginx -t

This command will check the configuration files and report any errors or warnings. If the configuration is valid, it will print something like this:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If the configuration is invalid, it will print something like this:

nginx: [emerg] unknown directive "server_nam" in /etc/nginx/sites-available/example.com:2
nginx: configuration file /etc/nginx/nginx.conf test failed

In this case, you need to fix the error and test again until the configuration is valid.

After testing the configuration, you can reload the nginx service to apply the changes without interrupting the existing connections. You can use the following command to reload the nginx service:

sudo systemctl reload nginx

Using nginx as a reverse proxy

A reverse proxy is a web server that acts as an intermediary between the client and the backend server. It can perform various functions, such as load balancing, caching, compression, encryption, authentication, and more. Nginx can be used as a reverse proxy for different web applications, such as Node.js, Python, Ruby, PHP, etc.

It allows you to have many subdomains, such as blog.example.com or configure it so your separate app (a Ghost blog for example) is always at example.com/blog

To use nginx as a reverse proxy, you need to modify the configuration file for the virtual host that you want to proxy. For example, if you have a web application running on port 3000 on the same server as nginx, and you want to proxy it to the domain example.com, you can use the following configuration:

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

This configuration tells nginx to pass all the requests for example.com to the web application running on port 3000, and to set some headers to preserve the original host, IP, and protocol of the client.

You can also use nginx as a reverse proxy for multiple domains and subdomains, by creating different configuration files for each virtual host. For example, if you have another web application running on port 4000 on the same server as nginx, and you want to proxy it to the subdomain cloud.example.com, you can use the following configuration:

server {
    listen 80;
    server_name cloud.example.com;

    location / {
        proxy_pass http://localhost:4000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

This configuration tells nginx to pass all the requests for cloud.example.com to the web application running on port 4000, and to set some headers to preserve the original host, IP, and protocol of the client.

If you want to redirect all the invalid subdomains to the root host, you can use a default server block that catches all the requests that do not match any of the defined server names. For example, you can use the following configuration:

server {
    listen 80 default_server;
    server_name _;
    return 301 http://example.com$request_uri;
}

This configuration tells nginx to redirect all the requests that do not match any of the defined server names to example.com, preserving the original request URI.

Hosting two services in one domain/subdomain

You can also host completely seperate web apps or services under a different directory, such as /api, while your main front end lives in /.

Here's how you'd to this:

server {
    listen 80;
    server_name cloud.example.com;

    location / {
        proxy_pass http://localhost:4000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /api {
        proxy_pass http://localhost:4444;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Using nginx as a reverse proxy with SSL certificates

SSL certificates are digital certificates that verify the identity and encryption of a web server and a web client. They are essential for securing the communication between the web server and the web client, especially when using a reverse proxy. Nginx can be used as a reverse proxy with SSL certificates for different web applications, such as Node.js, Python, Ruby, PHP, etc.

To use nginx as a reverse proxy with SSL certificates, you need to have the following:

  • A server certificate issued by a Certificate Authority (CA) for your domain
  • A private key that matches the server certificate

You can obtain these files from your CA or generate them yourself using tools like OpenSSL. For this guide, we will assume that you have the following files:

  • /etc/ssl/example.com.crt - the server certificate for example.com
  • /etc/ssl/example.com.key - the private key for example.com

For subdomains, a wildcard certificate is needed (that allows any *.example.com, including the root domain)

Many guides use Let's Encrypt for it and it's awesome! However, I've found that if you already use Cloudflare (such as for a domain), they already provide a free SSL wildcard certificate that you can place in your server. You just have to create it for your domain and place it in your server. Other domain registrars may also provide you with one.

To use nginx as a reverse proxy with SSL certificates, you need to modify the configuration file for the virtual host that you want to proxy. For example, if you have a web application running on port 3000 on the same server as nginx, and you want to proxy it to the domain example.com, you can use the following configuration:

server {
    listen 443 ssl;
    server_name example.com;

    # Specify the SSL certificate, key, and chain files
    ssl_certificate /etc/ssl/example.com.crt;
    ssl_certificate_key /etc/ssl/example.com.key;
    ssl_trusted_certificate /etc/ssl/example.com.chain;

    # Redirect all HTTP requests to HTTPS
    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    }

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

This configuration tells nginx to listen on port 443 with SSL enabled, use example.com as the server name, use /var/www/example.com as the document root, use index.html as the default index file, and use the specified SSL certificate, key, and chain files. It also tells nginx to redirect all HTTP requests to HTTPS, and to pass all the requests for example.com to the web application running on port 3000, and to set some headers to preserve the original host, IP, protocol, and scheme of the client.

You can also use nginx as a reverse proxy with SSL certificates for multiple domains and subdomains, by creating different configuration files for each virtual host. For example, if you have another web application running on port 4000 on the same server as nginx, and you want to proxy it to the subdomain cloud.example.com, you can use the following configuration:

server {
    listen 443 ssl;
    server_name cloud.example.com;

    # Specify the SSL certificate, key, and chain files
    ssl_certificate /etc/ssl/example.com.wildcard.crt;
    ssl_certificate_key /etc/ssl/example.com.wildcard.key;
    ssl_trusted_certificate /etc/ssl/example.com.wildcard.chain;

    # Redirect all HTTP requests to HTTPS
    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    }

    location / {
        proxy_pass http://localhost:4000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

This configuration tells nginx to listen on port 443 with SSL enabled, use cloud.example.com as the server name, use /var/www/cloud.example.com as the document root, use index.html as the default index file, and use the specified SSL certificate, key, and chain files. It also tells nginx to redirect all HTTP requests to HTTPS, and to pass all the requests for cloud.example.com to the web application running on port 4000, and to set some headers to preserve the original host, IP, protocol, and scheme of the client.

Wrapping it all up

With our personal example

To wrap things up, we'll show the configuration that we use today in Wirekat.

Here at Wirekat we currently use wirekat.com for out Ghost CRM blog and a.wirekat.com for Plausible Analytics.

Why I chose Ghost as my blogging platform
If you’re reading this, you may be thinking of creating your very own blog. Well... I, too have done the very same thing. And I put quite a bit of effort into this before finally deciding on Ghost. Let me explain. I’m a software developer. I like to host things
Plausible Analytics vs Cloudflare Web Analytics - Which is better?
Web analytics is the process of measuring and analyzing the behavior of visitors on a website. It can help website owners and marketers understand how their site is performing, what their audience is interested in, and how they can improve their user experience and conversions. There’s a lot of such

Redirecting all non-https to https

We want to use HTTPS by default and redirect all HTTP traffic to their secure HTTPS counterparts. We have placed this rule at the bottom of /etc/nginx/nginx.conf:

        server {
                listen 80 default_server;
                server_name _;
                return 301 https://$host$request_uri;
        }

        include /etc/nginx/conf.d/*.com;

nginx.conf - All of our separate domain configurations will be stored in /etc/nginx/conf.d/, as shown in the last line

We also use a single configuration file for each domain. It totally depends on your experience - But for such a small site, for me personally it's easier to manage and have related things neatly in one place is better than multiple files per service without also having to manage symbolic links.

Wirekat.com reverse proxy setup

For wirekat.com and all subdomains (existing and future), we have a wirekat.com file in /etc/nginx/conf.d/.

server {
  listen 443;
  ssl_certificate /etc/ssl/wirekat.com.crt;
  ssl_certificate_key /etc/ssl/wirekat.com.key;

  server_name *.wirekat.com;
  return 301 https://wirekat.com$request_uri;
}

server {
        listen 443 ssl;
        ssl_certificate /etc/ssl/wirekat.com.crt;
        ssl_certificate_key /etc/ssl/wirekat.com.key;

        server_name wirekat.com www.wirekat.com;

        location / {
                proxy_pass http://localhost:2368;
                proxy_set_header Host $host;
                proxy_set_header X-Real-Ip $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_redirect off;
       }
}

server {
        listen 443 ssl;
        ssl_certificate /etc/ssl/wirekat.com.crt;
        ssl_certificate_key /etc/ssl/wirekat.com.key;

        server_name a.wirekat.com www.a.wirekat.com;

        location / {
                proxy_pass http://localhost:8000;
                proxy_set_header Host $host;
                proxy_set_header X-Real-Ip $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_redirect off;
       }
}

wirekat.com nginx file at /etc/nginx/conf.d/wirekat.com

Let's have a breakdown of this file:

  1. In the first server block, we redirect all non-existent subdomains to our blog -wirekat.com.
  2. In the second server block, we only listen to HTTPS requests and we pass the request to our Ghost CRM port (that lives locally on port 2368). We also use the appropriate server_name here.
  3. In the third server block, where we pass our Plausible Analytics service, we do the same as in the second block, but change the destination port and server_name.

That's it!

Conclusion

In this blog post, I have shown you how to install and configure nginx on Ubuntu and RHEL-derivatives, how to use different conventions for managing nginx configuration files, and how to use nginx as a reverse proxy for multiple domains and subdomains.

We also shared our little setup used here at Wirekat. I hope you have found this guide useful and informative. If you have any questions or feedback, please feel free to leave a comment below. Thank you for reading! 😊