Nginx#

Nginx is a versatile tool that can be utilized as a web server, reverse proxy, load balancer, and much more. This page provides an overview of the fundamentals of working with Nginx.

Sources:

For examples, we will run nginx in a docker container - the following cell runs nginx in a docker container.

docker run -itd --name experiment_nginx --rm -p 80:80 nginx
0f36c0c1aa1fa9936f5b0bd323c4a53a99e1f6254f5e4779af68a80e38f0e624

Now we can check if nginx is up by requesting it’s main page.

cat << EOF | displayHTML
<iframe 
    srcdoc='$(curl -s localhost:80)' 
    width='100%' 
    height='600px' 
    style='border:none;'
>
</iframe>
EOF

Note don’t forget to stop container after all.

docker stop experiment_nginx
experiment_nginx

Configuration#

Nginx is mainly controlled by its configuration files, so it’s important to understand where they are. They are usually located in the /etc/nginx/ folder. Find out more in specific page.


The following cell shows the contents of the /etc/nginx command.

docker exec experiment_nginx ls -l /etc/nginx/
total 32
drwxr-xr-x 1 root root 4096 Sep  4 08:52 conf.d
-rw-r--r-- 1 root root 1007 May 28 13:22 fastcgi_params
-rw-r--r-- 1 root root 5349 May 28 13:22 mime.types
lrwxrwxrwx 1 root root   22 May 29 16:45 modules -> /usr/lib/nginx/modules
-rw-r--r-- 1 root root  648 May 29 16:45 nginx.conf
-rw-r--r-- 1 root root  636 May 28 13:22 scgi_params
-rw-r--r-- 1 root root  664 May 28 13:22 uwsgi_params

The most important file here is nginx.conf - it’s the central nginx configuration file. It’s printed in the next cell:

docker exec experiment_nginx cat /etc/nginx/nginx.conf
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/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;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

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

Changing this file will change the behavior of nginx. So in the next cell we do that. With nginx -s reload we reload nginx - this will apply the changes to nginx. The following cell defines the most minimal configuration I’ve found so far - just returning 200 “hello” from the server.

docker exec -i experiment_nginx sh -c 'cat >  /etc/nginx/nginx.conf' <<EOF
events {}
http {server{return 200 "hello";}}
EOF
docker exec -i experiment_nginx nginx -s reload
2024/12/04 16:13:55 [notice] 311#311: signal process started

Here is showen how default behaviour of the nginx changed.

curl localhost:80
hello

We just got message specified in the nginx.conf.

Variables#

Nginx uses variables, which are denoted by the $ symbol before the variable name. There is a set of predefined variables in Nginx that you can use. Find out more in the specific page.


The following cell shows how you can display the value of an arbitrary Nginx variable; in this case, it is $localtime.

Note: The backward slash (\) is used here to escape the $ symbol from bash, which also uses $ to identify variables.

docker exec -i experiment_nginx sh -c 'cat >  /etc/nginx/nginx.conf' <<EOF
events {}

http {
    server {
        listen 80;
        return 200 \$time_local;
    }
}

EOF

docker exec experiment_nginx nginx -s reload
2024/09/04 09:21:38 [notice] 381#381: signal process started

Let’s request gotten endpoint.

curl http://localhost:80
04/Sep/2024:09:28:54 +0000

We get something that looks like a datetime.

Location#

The location directive allows setting configurations based on the request URI. Check corresponding section on the official site.


In the following example, nginx config defines two locations: /pattern and /pattern/ URIs. By looking at the output, you can see exactly which location was triggered. They’re almost the same, but you’ll see that they match the different cases.

docker exec -i experiment_nginx sh -c 'cat >  /etc/nginx/nginx.conf' <<EOF
events {}
http {
    server {
        listen 80;
        
        location /pattern {
            return 200 "location 1 - I use /pattern";
        }

        location /pattern/ {
            return 200 "location 2 - I use /pattern/";
        }
    }
}
EOF

docker exec -it experiment_nginx nginx -s reload
2024/12/04 16:05:03 [notice] 106#106: signal process started

Now we can request different URIs from nginx and see what exactly has been triggered.

The following example shows what happens when you access /pattern (no / at the end of the command).

curl -L http://localhost:80/pattern
location 1 - I use /pattern

The next cell shows what happens when you access /pattern/wow (we use an additional path segment).

curl -L http://localhost:80/pattern/wow
location 2 - I use /pattern/

Server#

With the server directive, you can create so-called “virtual servers” under which you can place locations with the same configuration.

There is a strong relationship to the server_name directive that allows nginx to understand which request should be handled by which virtual server.

Find out more in:


The following cell shows the basic usage - there are two servers. It’s possible to tell which server handled the request Server header of the http response. You can specify which one you want to work with by specifying the Host header in the request.

docker exec -i experiment_nginx sh -c 'cat >  /etc/nginx/nginx.conf' <<EOF
events {}
http {
    server {
        server_name serv1;
        location /loc1 {return 200 "Hello1";}
        location /loc2 {return 200 "Hello2";}
        add_header Server One;
    }

    server {
        server_name serv2;
        location /loc1 {return 200 "Hello1";}
        location /loc2 {return 200 "Hello2";}
        add_header Server Two;
    }
}
EOF
docker exec experiment_nginx nginx -s reload
2024/12/26 10:14:25 [notice] 110#110: signal process started

The following cell shows requests with an unspecified Host header - by default it will go to the server higher in the config.

curl -I localhost/loc1
curl -I localhost/loc2
HTTP/1.1 200 OK
Server: nginx/1.27.3
Date: Thu, 26 Dec 2024 10:14:29 GMT
Content-Type: text/plain
Content-Length: 6
Connection: keep-alive
Server: One

HTTP/1.1 200 OK
Server: nginx/1.27.3
Date: Thu, 26 Dec 2024 10:14:29 GMT
Content-Type: text/plain
Content-Length: 6
Connection: keep-alive
Server: One

As a result, there is a One value under the Server key of the responses.

The same experiment but with Host: serv2 which is corresponds to the value server_name serv2.

curl -I localhost/loc1 -H "Host: serv2"
curl -I localhost/loc2 -H "Host: serv2"
HTTP/1.1 200 OK
Server: nginx/1.27.3
Date: Thu, 26 Dec 2024 11:30:26 GMT
Content-Type: text/plain
Content-Length: 6
Connection: keep-alive
Server: Two

HTTP/1.1 200 OK
Server: nginx/1.27.3
Date: Thu, 26 Dec 2024 11:30:26 GMT
Content-Type: text/plain
Content-Length: 6
Connection: keep-alive
Server: Two

As a result, the headers are the same as specified as the second virtual server.

Reverse proxy#

Another way to use nginx is as a reverse proxy, so you can redirect requests. You can define it with the proxy_pass directive in the server context.

Findout more in specific page.


The following config file makes requests to nginx to redirect to google.com.

docker exec -i experiment_nginx sh -c 'cat >  /etc/nginx/nginx.conf' <<EOF
events {}

http {
    server {
        listen 80;
        location / {proxy_pass "https://google.com/";}
    }
}
EOF

docker exec experiment_nginx nginx -s reload
2024/09/04 08:55:31 [notice] 146#146: signal process started

Now, when we access localhost:80, we get a message that we’ve been redirected.

curl -s localhost:80 | displayHTML
301 Moved

301 Moved

The document has moved here.

By adding the -L option to the curl command, we can follow redirects, allowing us to retrieve Google’s main page.

curl -sL localhost:80 | displayHTML
Google



 

Пашыраны пошук

Даступная мова: русский

© 2024

Logs#

Logging in Nginx is very useful for troubleshooting. There are two main log files in Nginx:

  • /var/log/nginx/access.log: Logs all incoming requests and their details.

  • /var/log/nginx/error.log: Logs cases that lead to errors.

Find out more about logging setup in nginx:


For reasons that are still unclear, we need to reorder the log files in order to be able to read them. So in the following cell we do this for our container.

docker exec -i experiment_nginx bash << EOF

rm /var/log/nginx/access.log /var/log/nginx/error.log
touch /var/log/nginx/access.log /var/log/nginx/error.log
nginx -s reload
EOF

And here is a request to nginx to print the contents of access.log.

curl localhost:80 &> /dev/null
docker exec experiment_nginx cat /var/log/nginx/access.log
172.17.0.1 - - [22/Jul/2024:07:54:09 +0000] "GET / HTTP/1.1" 301 220 "-" "curl/7.81.0"

Connections management#

This section cosiders capabilities of the nginx to manage connections. Check the specific page for this topic.

Build nginx#

To enable some features of the nginx you’ll need to build nginx from sources. For example, to include module for example ngx_http_stub_status_module you need to build nginx with special parameter --with-http_stub_status_module only after that operation you can use features of the included module.

Check corresponding section of the nginx installation page.


The following cell represents dockerfile that can be used for building image of the custom nginx.

cat nginx_files/build_nginx_docker
FROM debian:bookworm-slim

RUN apt update && \
    apt install --no-install-recommends --no-install-suggests -y \
        gnupg1 \
        ca-certificates \
        curl \
        devscripts \
        equivs \
        git \
        libxml2-utils \
        lsb-release \
        xsltproc \
        libpcre3 \
        libpcre3-dev \
        zlib1g \
        zlib1g-dev

ARG NGINX_VERSION="1.27.3"
ARG CONFIG_ARGUMENTS="--conf-path=/etc/nginx/nginx.conf --with-http_stub_status_module"

RUN curl -f -L -O http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \
    tar -zxvf nginx-${NGINX_VERSION}.tar.gz && \
    cd nginx-${NGINX_VERSION} && \
    ./configure ${CONFIG_ARGUMENTS} && \
    make && make install
    
ENV PATH=$PATH:/usr/local/nginx/sbin

CMD ["nginx", "-g", "daemon off;"]

There is such crucial features:

  • Installing packages that are required for building nginx: apt update ... && apt install ....

  • Downloading nginx compiling and instiling it:

    curl -f -L -O http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \
    tar -zxvf nginx-${NGINX_VERSION}.tar.gz && \
    cd nginx-${NGINX_VERSION} && \
    ./configure --conf-path=/etc/nginx/nginx.conf && \
    make && make install
    
    • The ./configure command is particularly important as it allows you to specify additional arguments that affect the behavior of the resulting build. You can check the list of parameters and their meanings on the corresponding page. For convenience, in a Dockerfile, there is a special argument CONFIG_ARGUMENTS where you can specify the set of arguments you want to use to build Nginx.

  • Add the path of the installation to the PATH environment variable - so you can access nginx just by using the nginx command.

In some specific sections of this description, a custom_nginx image can be used, which can be created with the following code:

docker build -f nginx_files/build_nginx_docker -t custom_nginx . &> /dev/null

With the nginx -V command, you can print the Nginx version, compiler version, and configure parameters. Use this to verify if you are indeed working with a custom Nginx build.

docker run -it --rm --name experiment_nginx custom_nginx nginx -V
nginx version: nginx/1.27.3
built by gcc 12.2.0 (Debian 12.2.0-14) 
configure arguments: --conf-path=/etc/nginx/nginx.conf --with-http_stub_status_module