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.
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 forexample.com
/etc/ssl/example.com.key
- the private key forexample.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.
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
:
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/
.
Let's have a breakdown of this file:
- In the first
server
block, we redirect all non-existent subdomains to our blog -wirekat.com
. - 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 appropriateserver_name
here. - 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 andserver_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! 😊