Installing and Configuring nginx on Ubuntu 22.04
Overview
On Ubuntu 22.04, it is desirable to install the latest nginx directly from the nginx repository, rather than from the main Ubuntu repository. This gives access to better modules, more current nginx, etc.
Installation
Adding the Repository
First, we need to add the nginx repository:
curl -s https://nginx.org/keys/nginx_signing.key | sudo apt-key add -
sudo sh -c 'echo "deb http://nginx.org/packages/ubuntu/ jammy nginx" >> /etc/apt/sources.list.d/nginx_(nginx.org).list'
sudo apt update
sudo apt install nginx libnginx-mod-http-geoipThis will install nginx and the mod-http-geoip module.
Disabling geoip2 nginx Module
Next, we will disable the newer geoip2 nginx module:
cd /etc/nginx/modules-enabled
sudo rm 50-mod-http-geoip2.confConfigure geoip Tables
We will need to create the landing location for the geoip databases:
sudo mkdir /usr/share/geoip
touch geoip_update.shNext, we will add this script to the geoip_update.sh file:
#!/bin/bash
### Sample download script for https://mailfud.org/geoip-legacy/
### - Adjust DBDIR and FILES below
### - Adjust XTABLES and XT_GEOIP_BUILD if needed
### - Copy script to /etc/cron.weekly or similar for your OS,
### note that /etc/cron.* filename MUST NOT HAVE .sh extension,
### rename to /etc/cron.weekly/geoip_update
### Contact: admin@mailfud.org
# Database directory
DBDIR=/usr/share/geoip
# Files to download (.dat.gz suffix not required)
FILES="GeoIP GeoIPCity"
#FILES="GeoIP GeoIPv6 GeoIPCity GeoIPCityv6 GeoIPASNum GeoIPASNumv6 GeoIPOrg GeoIPISP"
# If http proxy needed
#https_proxy="http://foo.bar:3128"
# Uncomment XTABLES to enable iptables xt_geoip updating
# Must contain filename for legacy IPv4/IPv6 CSV file (GeoIP-legacy.csv)
#
# xtables-addons needs to be installed
# (apt-get linux-headers-generic xtables-addons-dkms)
# More info: https://inai.de/projects/xtables-addons/
#
#XTABLES="GeoIP-legacy.csv"
# Standard distribution location for xtables script, change if using custom
#XT_GEOIP_BUILD=/usr/lib/xtables-addons/xt_geoip_build
### v0.24
### - add support for Ubuntu 22.04 /usr/libexec/xtables-addons/xt_geoip_build
### v0.23
### - fix xtables 3.8+, requires dbip-country-lite.csv
### v0.22
### - fix xtables stuff
### v0.21
### - added GeoIPCityv6, GeoIPASNumv6, fix https_proxy export
# DB directory
test -w $DBDIR && cd $DBDIR 2>/dev/null || { echo "Invalid directory: $DBDIR"; exit 1; }
# Sleep 0-600 sec if started from cron
if [ ! -t 0 ]; then sleep $((RANDOM/54)); fi
if [ "$XTABLES" != "" ]; then
FILES="$FILES $XTABLES"
fi
export https_proxy
for f in $FILES; do
# Make sure .gz is stripped
f=${f%*.gz}
# Make sure .dat exists
if [[ ! "$f" =~ \.csv ]]; then f=${f%*.dat}.dat; fi
# .gz files are kept on disk to compare timestamps (-N)
wget -nv -N -T 30 --max-redirect 0 https://mailfud.org/geoip-legacy/$f.gz
RET=$?
if [ $RET -ne 0 ]; then
echo "wget $f.gz failed: $RET" >&2
continue
fi
# Unpack and replace files atomically
if gzip -dc $f.gz >$f.tmp; then
if ! diff $f $f.tmp >/dev/null 2>&1; then
if [ "$f" = "$XTABLES" ]; then XUPD=1; fi
echo "updating $f"
chmod 644 $f.tmp
/bin/mv -f $f.tmp $f
else
echo "$f is up to date"
fi
else
echo "gunzip $f failed" >&2
rm -f $f.gz
fi
rm -f $f.tmp
done
if [ "$XTABLES" != "" ]; then
if [ -z "$XT_GEOIP_BUILD" ]; then
if [ -f /usr/lib/xtables-addons/xt_geoip_build ]; then
XT_GEOIP_BUILD=/usr/lib/xtables-addons/xt_geoip_build
else
XT_GEOIP_BUILD=/usr/libexec/xtables-addons/xt_geoip_build
fi
fi
if [ ! -f "$XT_GEOIP_BUILD" ]; then
echo "xt_geoip_build not found, xtables-addons-common package not installed?" >&2
exit 0
fi
if [ ! -f "GeoIP-legacy.csv" ]; then
echo "GeoIP-legacy.csv not found, cannot update xt_geoip" >&2
exit 0
fi
if [ ! -z "$XUPD" -o "$(find /usr/share/xt_geoip -name 'US.*' -mtime -14 2>/dev/null)" = "" ]; then
mkdir -m 755 /usr/share/xt_geoip 2>/dev/null
# Convert to dbip-country-lite format if needed (xtables-addons 3.8+)
if grep dbip-country-lite $XT_GEOIP_BUILD >/dev/null; then
cat $DBDIR/GeoIP-legacy.csv | tr -d '"' | cut -d, -f1,2,5 >$DBDIR/dbip-country-lite.csv.tmp &&
/bin/mv -f $DBDIR/dbip-country-lite.csv.tmp $DBDIR/dbip-country-lite.csv
XCMD="perl $XT_GEOIP_BUILD -D /usr/share/xt_geoip -S $DBDIR"
else
XCMD="perl $XT_GEOIP_BUILD -D /usr/share/xt_geoip $DBDIR/GeoIP-legacy.csv"
fi
RET=$($XCMD 2>/dev/null | tail -1)
if [[ "$RET" =~ (Zimbabwe|ZW) ]]; then
echo "xt_geoip updated"
else
echo "something went wrong with xt_geoip update" >&2
echo "do you have perl module Text::CSV_XS / libtext-csv-xs-perl installed?" >&2
echo "try running command manually:" >&2
echo "$XCMD" >&2
fi
else
echo "xt_geoip is up to date"
fi
fiWe can then execute this script to get the latest databases:
chmod +x geoip_update.sh
sudo ./geoip_update.shIt is a good idea to put this script in a cron and let it run once a week to stay up to date. Otherwise, log in and run it manually periodically.
Configuring nginx.conf File
Now, we need to add the following block to the nginx.conf module. It is best to comment out the existing access and error log file lines, and place this block directly below it:
# New json 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)
'"remote_addr": "$remote_addr", ' # client IP
'"remote_user": "$remote_user", ' # client HTTP username
'"remote_port": "$remote_port", ' # client port
'"time_local": "$time_local", '
'"time_iso8601": "$time_iso8601", ' # local time in the ISO 8601 standard format
'"request": "$request", ' # full path no arguments if the request
'"request_uri": "$request_uri", ' # full path and arguments if the request
'"args": "$args", ' # args
'"status": "$status", ' # response status code
'"body_bytes_sent": "$body_bytes_sent", ' # the number of body bytes exclude headers sent to a client
'"bytes_sent": "$bytes_sent", ' # the number of bytes sent to a client
'"http_referer": "$http_referer", ' # HTTP referer
'"http_user_agent": "$http_user_agent", ' # user agent
'"http_x_forwarded_for": "$http_x_forwarded_for", ' # http_x_forwarded_for
'"http_host": "$http_host", ' # the request Host: header
'"server_name": "$server_name", ' # the name of the vhost serving the request
'"request_time": "$request_time", ' # request processing time in seconds with msec resolution
'"upstream": "$upstream_addr", ' # upstream backend server for proxied requests
'"upstream_connect_time": "$upstream_connect_time", ' # upstream handshake time incl. TLS
'"upstream_header_time": "$upstream_header_time", ' # time spent receiving upstream headers
'"upstream_response_time": "$upstream_response_time", ' # time spend receiving upstream body
'"upstream_response_length": "$upstream_response_length", ' # upstream response length
'"upstream_cache_status": "$upstream_cache_status", ' # cache HIT/MISS where applicable
'"ssl_protocol": "$ssl_protocol", ' # TLS protocol
'"ssl_cipher": "$ssl_cipher", ' # TLS cipher
'"scheme": "$scheme", ' # http or https
'"request_method": "$request_method", ' # request method
'"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", '
'"http_cf_ray": "$http_cf_ray",'
'"geoip_city_lat": "$geoip_latitude",'
'"geoip_city_lon": "$geoip_longitude",'
'"geoip_city": "$geoip_city",'
'"geoip_region_code": "$geoip_region",'
'"geoip_country_code": "$geoip_country_code"'
'}';
access_log /var/log/nginx/access.log json_analytics;
error_log /var/log/nginx/error.log;
geoip_country /usr/share/geoip/GeoIP.dat;
geoip_city /usr/share/geoip/GeoIPCity.dat;Now, we can test the configuration and make sure it comes back as valid. If so, enable and restart the service:
nginx -t
sudo systemctl enable nginx
sudo systemctl restart nginx