description: "My mandatory settings for Nginx as a web server, reverse proxy; including VTS module, analysis, and logging."
# linkTitle:
date: 2024-04-25T00:00:09+07:00
lastmod:
draft: false
noindex: false
# comments: false
nav_weight: 1000
# nav_icon:
# vendor: bootstrap
# name: toggles
# color: '#e24d0e'
series:
# - Tutorial
categories:
- SysAdmin
- Snippets
tags:
- Nginx
# -
images:
# menu:
# main:
# weight: 100
# params:
# icon:
# vendor: bs
# name: book
# color: '#e24d0e'
authors:
- ditatompel
---
Since the first time I used [**Nginx**](https://nginx.org/) in mid-2011, Nginx immediately became my favorite web server. I am slowly starting to leave [Apache](https://httpd.apache.org/) behind, which was previously the _"standard" web server_ on the Linux operating system.
As time went by, several new _web servers_ began to appear, such as [Caddy](https://caddyserver.com/) and [Traefik](https://traefik.io/traefik/). As a _system administrator_, of course I have tried to use it, although only to the extent of using personal projects.
However, my heart always seems to return to Nginx. Applications, services, or **anything that I can expose via Nginx, I will expose that using Nginx**. Maybe because I'm become too comfortable with the configuration and pleasant experience with Nginx. XD
## My use case
Because I have very **limited IPv4**, I mostly use Nginx as a **reverse proxy** for services that don't have a public IP (VMs with local / internal networks). This really helps save public IP allocation. Using Nginx as reverse proxy, I played a lot with `proxy_cache` and `http upstream` to implement _load balancing_ or _failover_.
Back then, when I created programs using **PHP**, I used Nginx and PHP-FPM without Apache (`.htaccess`) behind it. So I play a lot with Nginx `rewrite` and `fastcgi_cache`. When I started making applications using **Rust** and **Go**, Nginx always act as _reverse proxy_ while also performing _SSL termination_.
Besides HTTP _reverse proxy_, I sometimes use the Nginx `stream`_module_ for TCP, UDP, and _Unix socket_ data streams.
Regarding traffic monitoring, I always use [**Nginx VTS module**](https://github.com/vozlt/nginx-module-vts). There are [nginx-vts-exporter](https://github.com/sysulq/nginx-vts-exporter) for [Prometheus](https://prometheus .io/) which is very easy to operate to process data from Nginx VTS module. Meanwhile, for _logging_, some logs for _virtual hosts_ that I consider crucial are sent in _real-time_ to the **remote syslog server**.
It's perfect, all the features I need are met by Nginx. And it's time for me to start documenting the installation and configuration process.
I have an open-source project called {{<bs/alert-link"nginx-kickstart""https://github.com/ditatompel/nginx-kickstart">}} (boilerplate) to make it easier to install Nginx from the official repository and compile the Nginx VTS module on a FRESH Debian 12 or Ubuntu 22.04 server.
This documentation was created for **Debian 12** and **Ubuntu 22.04**, and I used the official repository from Nginx, not the distribution-provided package.
First and foremost, always make sure the system is _up-to-date_ by running `sudo aptget update && sudo apt-get dist-upgrade`. Then install required packages.
Load the following `http_geoip_module` and `stream_geoip_module`. Put the `load_module`**above**`event{}`_block_ and `geoip_country` inside `http{}` block:
If there is a virtual host behind a Cloudflare reverse proxy, it is highly recommended to add the Cloudflare IP addreses to the _trusted proxy_ in the Nginx configuration.
Create the following _executable shell script_`/etc/nginx/cloudflare-ips.sh`:
# if your vhost is behind CloudFlare proxy and you want your site only
# accessible from Cloudflare proxy, add this in your server{} block:
# if (\$cloudflare_ip != 1) {
# return 403;
# }" >> $CF_WHITELIST_PATH
nginx -t && systemctl reload nginx
# vim: set ts=4 sw=4 et:
```
The shell script above will fetch Cloudflare's IP list to be processed and stored in `/etc/nginx/snippets/cloudflare_*.conf`. Please create a `cronjob` to run the script periodically (per week / per month).
For the Nginx configuration, add the following configuration to the `http{}` block in `/etc/nginx/nginx.conf`:
```nginx
http {
# ...
# Cloudflare IPs
################
include /etc/nginx/snippets/cloudflare_real_ips.conf;
real_ip_header X-Forwarded-For; # atau CF-Connecting-IP jika menggunakan Cloudflare
# cloudflare map
include /etc/nginx/snippets/cloudflare_whitelist.conf;
# ...
```
## Logging
The _logging_ feature may slowing down server performance (mainly due to high **DISK I/O**) on high traffic sites. However, logging is also very important for monitoring and analyzing server activity.
### Log format
There are several log formats that are commonly used and can be integrated with _3rd-party_ applications, for example the `(V)COMMON` or `(V)COMBINED` format.
#### VCOMBINED format
Add the following configuration to the `http{}` block:
```nginx
http {
# ...
# VCOMBINED log format style
log_format vcombined '$host:$server_port '
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
# ...
```
> I usually use `VCOMBINED` format logs which I then integrate with [GoAccess](https://goaccess.ditatompel.com/).
#### Custom JSON log format
For some cases, I use **Nginx integration** in **Grafana Cloud** which uses _custom access log format_ (JSON):
```nginx
http {
# ...
# JSON style log format
log_format json_analytics escape=json '{'
'"msec": "$msec", ' # request unixtime in seconds with a milliseconds resolution
'"connection": "$connection", ' # connection serial number
'"connection_requests": "$connection_requests", ' # number of requests made in connection
'"pid": "$pid", ' # process pid
'"request_id": "$request_id", ' # the unique request id
'"request_length": "$request_length", ' # request length (including headers and body)
'"server_protocol": "$server_protocol", ' # request protocol, like HTTP/1.1 or HTTP/2.0
'"pipe": "$pipe", ' # "p" if request was pipelined, "." otherwise
'"gzip_ratio": "$gzip_ratio", '
'"geoip_country_code": "$geoip_country_code"'
'}';
# ...
}
```
### Conditional (dynamic) logging
With `map`, and `if`_keyword_, we can determine what to log and what not to log. For example, I don't do _logging_ if the URI contains the word _"local"_ or _User Agent_ contains the word _"Uptime-Kuma"_:
For me, log centralization really makes my job easier in carrying out server analysis and troubleshooting.
In Nginx, we can easily send logs to _remote servers_ in _real-time_. For example, we can send logs to a remote `rsyslog` server** (UDP) with the following example configuration:
**Nginx VTS module** is not available in the Official Nginx repository, so we cannot install it using `apt`. To compile the VTS module requires `C`_compiler_, `git`, `libpcre`, `libssl`, and `zlib`. Install the required packages by running this command:
This is a very important part, if you want to use a *dynamically linked module*, the compile module option must be the same as the Nginx _binary file_ that will be used, as well as the version of Nginx used. To find out the information we need, run `nginx -V` command. Example output:
```plain
nginx version: nginx/1.26.0
built by gcc 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)
Extract the Nginx _source code_ archive, then go to it's directory:
```shell
tar -xvzf nginx-1.26.0.tar.gz
cd nginx-1.26.0
```
Clone the `vozlt/nginx-module-vts` repository and use the [latest release tag](https://github.com/vozlt/nginx-module-vts/tags). When this article was written, the last tag release was `v0.2.2`, so:
To display the **VTS traffic status** page, add the following example configuration to the `server{}` block (for example in `/etc/nginx/conf.d/default.conf`):
As a final configuration reference, please look at [https://github.com/ditatompel/nginx-kickstart/tree/main/etc/nginx](https://github.com/ditatompel/nginx-kickstart/tree/main/etc/nginx).