Web server with nginx

Published on 24.2.2025

Edited on 2.5.2025

Content

What is it about

This page is a manual to make your own web server to host your website. We won't dive too deep into networking, but it will give necessary information to understand the further material.

The article is suited more for those, who want to deploy their web resource in the Internet and not to learn systematically how networks, web servers and sites, etc. work. It's a practical guide.

We will start by configuring your internet connection. Further, we'll try to get a domain name of your website with an example of a russian registrar - REG.RU. After that, we'll set up our web server with nginx. We'll end by configuring of the HTTPS server to meet modern web standards.

To make your website, which is available from the Internet, you need a programme which is called a web server and an access to the Internet. Before the web server setup, let's configure your internet connection.

Setup of internet connection

Perhaps, you have a home area network (a.k.a a home LAN), which is served by your (Wi-Fi) router and your PC is connected to it. Depending on its settings, your connetction through this network may not be suitable to host the website. The common problem is a dynamic internet (IP) address and a (CG)NAT.

A dynamic internet address changes every time when your router connects to the Internet. While you have a dynamic IP address your position in the Internet will vary, so users will lose your website. Therefore, you need a static IP address. You can get it at your ISP (Internet Service Provider) for an additional fee, usually, about one dollar per mounth.

The second issue is a (CG)NAT. Just image you have the home LAN and the home devices: phones, cameras, tablets, computers, your fridge, room lights, etc. are connected to it. Every device must have its IP address, but if we look at the structure of an internet address we will figure out that it consists of four numbers, e.g. 200.23.102.4, where every number can take a value from 255 to 0. Consequently, we have 256 by 256 by 256 and by 256 = 2564 = 4 294 967 296 valid addresses. And what would you think, right - we have already exceeded this limit. That problem is called the IPv4 address exhaustion.

There is an alternative so-called the IPv6 protocol family which gives more valid addresses, but people don't hurry to move to them. And to avoid these limitations the NAT mechanism was invented. The NAT (Network Address Translation) maps addresses from ones into others. You could notify that your PC (or another device) is connetcted to the home network has one IP address if look it in the network settings app or the web interface of your router (DHCP list or something like active connections), but has another one if look it in a website, e.g., https://www.whatismyip.com/. It is the NAT in action. For instance, an internet address of a host that serves this resource is 95.139.93.56, but the server is within a LAN and has a local IP address which is 192.168.2.120.

It is literarly a mathching table like the following.

Source address Destination address
145.3.23.0 78.0.42.124
195.213.232.3 80.60.26.124
185.33.113.34 37.0.0.15

The NAT mechanism has its kind - the CGNAT (Carrier-Grade NAT). While the usual NAT can map addresses into other ones, some ISPs want to map local IP addresses into one external (public) IP one to serve customers more easily. The such approach is called the CGNAT.

If you have a such network configuration you will need to set up an internet address (IP) forwarding. You need to make it in the web interface of the router. Find an IP forwarding (or something like it) menu and create a new forwarding rule. You will need to set up the external port (service port), it is a port of your router which will recieve data from the Internet, the next is the internal port, it's a port which will be listened by your server.

Get domain name

Usually, those actions are sufficient and the connection preparing is almost done. But if you want your own domain, you need to register (rent) it. You need to choose a domain name registrar. There are a lot of domain name registrars, the most popular are GoDaddy, Hostinger, Namecheap, IONOS, etc. But we will register on REG.RU, because a domain name of this website is registered on it. Nevertheless, the process of registration isn't much different from-to a site.

So, let's:

  1. Go to the site of REG.RU. This site is in Russian
  2. Make your account
  3. Choose a domain name at https://www.reg.ru/buy/domains/ (something like MyWebsiteDomainName.com)
  4. Buy it (only choose the domain name registration service: you don't need the website hosting, services of security, etc. - only pay for the name)
  5. Go to your domain names section
  6. Click on your domain entry
  7. There is the DNS record section (Resource records) and you don't have anyone, let's create one by clicking on "to add a record"
  8. Choose the "A" record from the list
  9. Put @ character into the Subdomain field and your public internet address into the IP Address field
  10. Click done

That's all. Now, you need to wait from a few minutes to several hours for your DNS record to appear in DNS servers. After that, you can get an access to your website by the domain name.

You can pass the following text.

You may have a question: What does domain name rent mean? Well, when you buy your domain name in fact you entrust the registrar to service the name, i.e. add the domain name record into their authoritative nameservers, local DNS resolvers, and TLD Nameservers. You just get opportunity to reserve "your" domain names for a limited amount of time. Learn more.

Nginx

Now, we are ready to make our web sever with nginx.

The first, we need to download it. If you use Windows, nginx is in the beta-like status, but as it says on its website:

At this time, it provides almost the same functionality as a UNIX version of nginx except for XSLT filter, image filter, GeoIP module, and embedded Perl language.

nginx for Windows

So, you can download the mainline version of nginx from https://nginx.org/en/download.html. After, go through the steps which are there to install nginx properly.

If you have GNU/Linux distro, it is the same: go through the steps which are https://nginx.org/en/linux_packages.html.

When you installed nginx, you need to find the configuration file. If you on Windows, then go to the unpacked directory; if you on GNU/Linux - go to, usually, the /etc/nginx, or /usr/local/nginx/conf, or /usr/local/etc/nginx folder.

There will be your main web server file is nginx.conf. Open it by a text editor. You will see the initial setup. Now, delete everything there and put the following:


user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {    
    worker_connections  100;
}

http {
    server_tokens off;
    include /etc/nginx/mime.types;
    server {
        listen 80;
        listen [::]:80;
	server_name MyWebsiteDomainName.com;
        location  / {
            root /home/user/website;
            index ./main.html;
        }
    }
}

Save the file. What did we put. The first line is user nginx; and keeps the name of nginx process. You can see at the task manager or system monitor. Tne next is worker_processes auto;. It says how much worker processes will be created by the main process. You have to know nginx has two kinds of process: the main one and worker ones. The main one reads and evaluates configuration and maintains worker processes. The worker ones do actual processing of requests. If you have GNU/Linux you will have the following files: error_log /var/log/nginx/error.log notice; and pid /var/run/nginx.pid;. The first one keeps errors of nginx and the second keeps the process id. The next is the events block which defines a connection processing.

Now, we need to understand how the nginx configuration works. nginx consists of modules which are controlled by directives are put into the configuration, e.g. worker_processes, events, server, server_name, etc. Directives can be two kinds which are block directives and single-line directives. The last consist of a directive name and arguments, a line ends with ;. The block ones are the same only have no arguments, but have directives are put into {}. Every block directive forms its so-called context. Directives wich aren't placed in any block one have the main context. Each directive only can be placed in its specified context, e.g. the events and http directives reside in the main context, server in http, and location in server.

The work_connections directive determines how much connections our server can process.

The http context keeps our servers which can listen to input connections on different ports.

The serve_token enables or disables a emitting nginx version in error messages and in the "Server" response header field.

The include directive includes other configuration files. By it, you can separate your server configuration.

The server directive defines request processing, domain names, listening ports, etc.

The listen directive sets the address and port for an IP on which the server will accept requests. The internet address can be a domain name. If we just left the port, then the server will listen to requests only from it, but if the no addresses, then it will listen to any port. This listen is defined for IPv4, the next listen is for IPv6 and any address.

The server_name defines what domain names which are in the request accept to process.

The location defines a server configuration depending on a prefix string and a request URI. If you set up the / prefix, then a MyWebsiteDomainName.com/ URI will match that. If you send a MyWebsiteDomainName.com/images it will also match the /, but and a /images prefix. nginx will choose the longest one.

Further, if you define the root directive, then after the matching the URI to the prefix string it will append to the path which is put after the root directive to send the file to the client. E.g., your root is /website/content, the request is /main.html, and the location is /. Then, after the request, /main.html will append to the /website/content, i.e. /website/content/main.html. If this path is valid and nginx have a permission to read it, nginx will send this file to the client. The root can only contain a directory.

And the last setting, the index directive sets up a forwarding from the request (like MyWebsiteDomainName.com/) to the file (/main.html). It is useful if you want to send the index file of your website to the domain name request, i.e. http://mywebsitedomainname.com/.

After the above, you will need to adjust these settings to your needs.

The setting up ended. Now, you can restart nginx by the nginx -s reload, because it usually starts on its own. Try get a main page of your website.

HTTPS server

Well, we have the working web server. If we want to make this to be secure, we must set up the HTTPS support. That support means our website will use the HTTPS protocol to transmit data between a client web browser and our web server securely. The HTTPS protocol is based on, you've probably already heard it, SSL/TLS: SSL is Secure Sockets Layer, TLS is Transport Layer Security. They are the same, just designate different versions of "one protocol". As said one of protocol authors Tim Dierks that renaming from "SSL" to "TLS" were a face-saving gesture to Microsoft (Transport Layer Security @ Wikipedia):

...we had to make some changes to SSL 3.0 (so it wouldn't look the IETF was just rubberstamping Netscape's protocol), and we had to rename the protocol (for the same reason). And thus was born TLS 1.0 (which was really SSL 3.1). And of course, now, in retrospect, the whole thing looks silly.

Tim Dierks. Security Standards and Name Changes in the Browser Wars

These protocols use encryption to encrypt web communications and, consequently, protect them by so-called an asymmetric public key infrastructure. HTTPS connection (transmission) is established by the TLS (SSL) handshake which consists of:

  1. data encryption
  2. authentication: ensures that the parties exchanging information are who they claim to be
  3. integrity: verifies that the data has not been forged or tampered with

For our website can use TLS (HTTPS), we must install a TLS certificate which contains important information about who owns the domain and the server's public key. It is important for validating our web server's identity. These certificates must be issued by a certificate authority, e.g. Let's Encrypt, DigiCert, GlobalSign, Sectigo, Cloudflare.

Usually, to get such certificates we must pay, but there is free issued certificates. We will use Let's Encrypt's certificates. As said at their web site:

Let’s Encrypt issues certificates through an automated API based on the ACME protocol.

In order to interact with the Let’s Encrypt API and get a certificate, a piece of software called an “ACME client” is required.

Getting Started @ Let's Encrypt

The most popular ACME client is Certbot. To install Certbot you can consult these interactive instructions. If you use a GNU/Linux distro, Certbot developers recommend to use the Snap version, but the Debian Certbot version installation will be shown here.

Go to a terminal and type:


sudo aptinstall certbot python3-certbot-nginx

The first package is Certbot, the second is a plugin to connect Certbot to our nginx. This bot will make all certificate tasks automatically. So, it's the best solution for us.

Further, run Certbot from the terminal by the following way:


sudo certbot --nginx -d your-domain-1 -d your-domain-2 ...

You add your (sub)domains for which TLS is necessary. But before these settings you should back up the current working nginx configuration.

After, you will be asked to register to get certificate and Certbot will change your nginx configuration.

After the certificate setting up, you can go to nginx.conf and check it. You should see something like that:


server {    
    server_name (your domains);
    
    (settings)
    
    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl default; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/(your domain)/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/(your domain)/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
    (blah-blah-blah)

server {
    if ($host = (one of your domains)) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
    listen 80;
    listen [::]:80;
    server_name (your domains);
    return 404; # managed by Certbot

What did Certbot do. In brief, it added the necessary settings to enable the TLS support in nginx, specified the paths to the certificate, private key, necessary SSL and other settings to authenticate your Certbot for Let's Encrypt servers. Also, it defined the redirections to redirect HTTP requests to HTTPS ones.

Your TLS is done, but it isn't all. We come back to the NAT. You can remember you must set up the forwarding within your router. Now, you need to make it again, but you need to forward input traffic from a 443 port of the router to a 443 port of your PC/web server.

That's done. You have set up TLS within your server.