Menggunakan Modul Brotli pada NGINX yang telah Terinstal

347

(Buru-buru? Loncat ke langkah pemasangan.)

Gzip adalah salah satu algoritma kompresi data populer yang dirilis pada tahun 1992. Gzip berbasis DEFLATE. Modul gzip adalah salah satu modul terintegrasi pada NGINX, yang digunakan untuk mengecilkan ukuran respon dan file (misalnya resource website seperti CSS, JS, dan lain-lain). Gzip ini punya rasio kompresi dan performa yang lumayan, namun jika ingin menggunakan algoritma yang lebih baik, kita bisa menggunakan algoritma Brotli.

Brotli dirilis pada tahun 2015 oleh engineer Google. Ia merupakan kombinasi dari berbagai algoritma kompresi yang telah ada. Terkait web server, brotli dirancang untuk menggantikan gzip. Hasil kompresi data dengan brotli berukuran 20% - 30% lebih kecil dari gzip. Level kompresinya pun berkisar dari 0 hingga 11 (paling agresif namun paling lambat). Brotli level 11 jauh lebih lambat dibandingkan dengan gzip level 9. By default, NGINX menggunakan Brotli level 6, namun level 4 dan 5 bisa dianggap sweet spot.

Adapun kode sumber Brotli bersifat open source.

Sayangnya, Brotli belum terintegrasi penuh dengan NGINX; kita harus mem-build ulang NGINX dari source lengkap dengan modul Brotli jika ingin menggunakannya. Modul brotli juga merupakan modul dinamis yang hanya dapat digunakan di satu versi NGINX saja.

Bagaimana jika kita ingin menggunakan Brotli pada NGINX yang sudah terpasang sebelumnya pada distro (misalnya via apt)? Tenang, karena seorang developer web bernama Majal telah membuat script untuk memasang Brotli pada NGINX yang telah terpasang sebelumnya.

Langkah Instalasi

Instal beberapa program yang diperlukan jika belum ada:

sudo apt install git libpcre3 libpcre3-dev zlib1g zlib1g-dev openssl libssl-dev

Sebelumnya, cek dan catat versi nginx, misalnya 1.18.0.

sudo nginx -v

Jalankan script di bawah sebagai root atau via sudo. Pastikan script bisa dijalankan dengan menambahkan hak akses +x.

touch mkbrotli
sudo chmod +x mkbrotli

(mkbrotli adalah nama file script yang kita buat dengan perintah touch.)

PERINGATAN: nginx yang dimaksud di artikel ini adalah nginx yang diinstal via repo bawaan OS, misalnya dengan cara sudo apt install nginx. Nginx milik saya minim modifikasi dan script berhasil dijalankan dengan baik.

...dan berikut isi script mkbrotli yang dimaksud, silakan gunakan editor teks favorit masing-masing untuk menyalin dan menulis ke file ini, (misalnya dengan vim/nano):

#!/bin/bash

# https://www.majlovesreg.one/tag/code/
# https://www.majlovesreg.one/adding-brotli-to-a-built-nginx-instance
# https://github.com/majal/maj-server/tree/master/nginx-modules-brotli

# Install needed development packages if not yet installed in the system
# sudo apt -y install git libpcre3 libpcre3-dev zlib1g zlib1g-dev openssl libssl-dev

# For predefined NGINX version, use:
# ngver=1.17.1

# For passing the version via the command line (i.e.: user@server:~$ ./mkbrotli 1.17.1), use:
ngver=$1

# For automated detection of currently installed NGINX version (not to be used for auto-updating, see hooks in post), use:
# ngver=$(nginx -v 2>&1 | grep -o '[0-9\.]*')

[ "${ngver}" ] || { echo "Please supply NGINX version. Exiting..."; exit 7; }

# Get configure parameters of installed NGINX. Not needed if NGINX was configured '--with-compat'.
# Uncomment one of the lines below if the script sucessfully builds modules but NGINX throws a "not binary compatible" error.
# confparams=$(nginx -V 2>&1 | grep -o -- '--prefix='.*)
# confparams=$(nginx -V 2>&1 | grep -o -- '--[^with]'.*)
# confparams=$(nginx -V 2>&1 | grep -- '--' | sed "s/.*' //")
# confparams=$(nginx -V 2>&1 | grep -o -- "--prefix='.*'$")

# To automatically select NGINX modules directory:
[ -d /usr/share/nginx/modules ] && moddir=/usr/share/nginx/modules
[ -d $(nginx -V 2>&1 | grep -o 'prefix=[^ ]*' | sed 's/prefix=//')/modules ] && moddir="$(nginx -V 2>&1 | grep -o 'prefix=[^ ]*' | sed 's/prefix=//')/modules"
[ -d $(nginx -V 2>&1 | grep -o 'modules-path=[^ ]*' | sed 's/modules-path=//') ] && moddir="$(nginx -V 2>&1 | grep -o 'modules-path=[^ ]*' | sed 's/modules-path=//')"

# To manually set NGINX modules directory:
# moddir=/path/to/modules/directory
[ "${moddir}" ] || { echo '!! missing modules directory, exiting...'; exit 1; }

# Set temporary directory and build on it
builddir="$(mktemp -d)"
cd "${builddir}"

echo
echo '################################################################################'
echo
echo "Building Brotli for NGINX ${ngver}"
echo "Temporary build directory: ${builddir}"
echo "Modules directory: ${moddir}"
echo

# Download and unpack NGINX
wget https://nginx.org/download/nginx-${ngver}.tar.gz && { tar zxf nginx-${ngver}.tar.gz && rm nginx-${ngver}.tar.gz; } || { echo '!! download failed, exiting...'; exit 2; }

# Download, initialize, and make Brotli dynamic modules
git clone https://github.com/google/ngx_brotli.git
cd ngx_brotli && git submodule update --init && cd ../nginx-${ngver}
[ "${confparams}" ] && nice -n 19 ionice -c 3 "./configure --add-dynamic-module=../ngx_brotli ${confparams}" || nice -n 19 ionice -c 3 ./configure --with-compat --add-dynamic-module=../ngx_brotli
nice -n 19 ionice -c 3 make modules || { echo '!! configure or make failed, exiting...'; exit 4; }

# Replace Brotli in modules directory
[ -f "${moddir}/ngx_http_brotli_filter_module.so" ] && sudo mv "${moddir}/ngx_http_brotli_filter_module.so" "${moddir}/ngx_http_brotli_filter_module.so.old"
[ -f "${moddir}/ngx_http_brotli_static_module.so" ] && sudo mv "${moddir}/ngx_http_brotli_static_module.so" "${moddir}/ngx_http_brotli_static_module.so.old"
sudo cp objs/*.so "${moddir}/"
sudo chmod 644 "${moddir}/ngx_http_brotli_filter_module.so" || { echo '!! module permissions failed, exiting...'; exit 5; }
sudo chmod 644 "${moddir}/ngx_http_brotli_static_module.so" || { echo '!! module permissions failed, exiting...'; exit 6; }

# Clean up build files
cd "${builddir}/.."
sudo rm -r "${builddir}/ngx_brotli"
rm -r "${builddir}"

echo
echo "Sucessfully built and installed latest Brotli for NGINX ${ngver}"
echo "Modules can be found in ${moddir}"
echo "Next step: Configure dynamic modules and reload/restart NGINX."
echo
echo '################################################################################'
echo

# Start/restart NGINX.
# Not recommended if script is hooked since NGINX is automatically restarted by the package manager (e.g. apt) after an upgrade.
# Restarting NGINX before the upgrade could cause a module version mismatch.
# sudo nginx -t && { systemctl is-active nginx && sudo systemctl restart nginx || sudo systemctl start nginx; } || true
# echo
# systemctl --no-pager status nginx
# echo

Intinya, script di atas mengunduh kode nginx lengkap dengan brotli via wget ke temp dir, lalu memindahkan modul brotli yang dihasilkan ke dir nginx sungguhan di komputer. Simple kan??

Jalankan script:

sudo ./mkbrotli 1.18.0

Mengaktifkan brotli

Buka file config utama nginx (punya saya di /etc/nginx/nginx.conf). Di luar blok, di awal file, tuliskan:

load_module modules/ngx_http_brotli_filter_module.so;
load_module modules/ngx_http_brotli_static_module.so;

dan yang terakhir, yang paling penting, aktifkan brotli. Bisa di blok http, server, atau location.

brotli on;
brotli_comp_level 6;
brotli_min_length 256;
brotli_static on;
brotli_types application/atom+xml application/javascript application/json application/rss+xml
             application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype
             application/x-font-ttf application/x-javascript application/xhtml+xml application/xml
             font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon
             image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml;

Kode di atas adalah config minimal yang optimal. Kalau mau, silakan baca penjelasan di GitHub soal apa maksud var-var di atas.

Cek seluruh config nginx lalu restart nginx:

sudo nginx -t
sudo systemctl restart nginx

Gambar di bawah adalah tangkap layar dari web developer tools di Firefox:

br FF

content-encoding pada header respon menunjukkan br untuk Brotli

Auto-update Modul Dinamis

Jadi,.. jika kita memperbarui nginx setelah memasang brotli, modul brotli itu menjadi invalid. Solusinya, sebelum update nginx, jalankan dulu script di atas setelah mengetahui versi nginx yang akan dipasang. Buatlah file bernama /etc/apt/apt.conf.d/05nginxmodules:

// Hook to build and install dynamic modules before NGINX upgrades
// Script calls individual build scripts and passes back error codes
// Place this file in /etc/apt/apt.conf.d/

DPkg::Pre-Install-Pkgs {"/usr/local/sbin/nginx-mod-preinstall";};

Seperti bisa kalian tebak, buatlah file bernama /usr/local/sbin/nginx-mod-preinstall dengan izin eksekusi (x):

#!/bin/bash
# Call NGINX module build scripts and pass error codes to apt hook

# Get NGINX version to upgrade to
read ngfile < <(grep '/nginx_') || exit 0
ngver=$(echo $ngfile | sed 's/-.*//' | sed 's/.*_//')

# List of build scripts to run:
/usr/local/sbin/mkbrotli $ngver || exit $?
# /usr/local/sbin/mkmodsec $ngver || exit $?
# /usr/local/sbin/mkpagespeed $ngver || exit $?

Sudah? Beluum! Pastikan /usr/local/sbin/mkbrotli benar-benar ada ya... Apa isi file tersebut? Ya script panjang di atas tadi donks. Jangan lupa beri izin eksekusi file (sama seperti sebelumnya) (sudo chmod +x nama_file).

Bagaimana dengan Web Hosting?

Untuk website yang menggunakan shared hosting, pastikan hosting-nya sudah support LiteSpeed Cache. Baca manual di web hosting atau tanya IT Support.

Oiya, blog ini masih menggunakan gzip.

Referensi