이번에는 쇼핑몰 전반 콘텐츠를 압축해 속도를 높여주는 압축 프로그램도 보다 보안이 뛰어난 프로그램인 브로틀리 압축((Brotli Compression)을 Nginx에서 쉽게 이용하는 방법에 대해서 살펴 봅니다.

보안과 속도를 위해 브로틀리 압축((Brotli Compression)을 Nginx에서 쉽게 이용하는 방법

쇼핑몰 구축기를 연재하는 이유

최근 지인이 워드프레스를 이용해 쇼핑몰 구축을 시도하면서 배웠던 배웠던 다양한 경험들을 해당 쇼핑몰 블로그에 연재해 왔는데요.

쇼핑몰이 상품만 파는 것이 아니라 쇼핑몰을 방문하는 고객들에게 열가지 유용한 정보를 제공하는 블로그의 효용성이 높다는 점을 십분 활용하고, 처음 시작하는 쇼핑몰의 신뢰성을 주기 위해 비록 삽질이지만 삽질기를 낱낱히 공개하기로 했다고 하네요.

그 쇼핑몰의 주소는  https://puripia.com로 아직도 공사중이기는 합니다.) 

쇼핑몰 구축 시 도와주었던 인연으로 그 쇼핑몰을 알리고 쇼핑몰 구축 경험담을 보다 널리 알리기 위해서 여기 happist.com에도 같이  공유합니다. 조금 사심이 있기는 합니다.

보안과 속도를 위해 브로틀리 압축((Brotli Compression)을 Nginx에서 쉽게 이용하는 방법

여기에서는 보안과 속도 측면에서 좋은 평가를 받고 있는 브로틀리 압축((Brotli Compression)을 Nginx에서 쉽게 이용하는 방법에 대해서 알아 봅니다.

보안과 속도는 상당히 양립하기 어려운 문제죠. 보안을 강화하면서도 속도를 높인다는 것은 쉽지않은 문제이기 때문이죠.

그렇지만 주제가 속도를 빠르게 해주는 솔류션의 문제라면 다르겠죠. 속도를 높여주는 솔류션이 보안과 연계되어 보안을 높이는 요인이 있다면 금상첨화겠죠.

오늘 이야기하려는 브로틀리 압축((Brotli Compression)이 그러한 한 예가 되지않을까 싶습니다.

1. 가장 널리 사용되는 gzip

그동안 서버에서 제반 포맷들을 압축해주는 솔류션으로 gzip이 널리 사용되었습니다.

이 gzip은 대부분의 웹서버가 기본으로 제공하는 기능으로 별다른 조치없이도 적용 옵션만 제대로 명기해 주는 것으로 작동했습니다.

그만큼 안정적이고 적용하기도 어렵지 않았다는 반증이기도 합니다.

그러나 이 gzip은 보안 측면에서는 완벽하지않다는 평가를 받고 있으며, 가능하면 브로틀리 압축((Brotli Compression)으로 대체하라는 주문이 있기도 합니다.

이전에 소개한 “SSL 보안 등급 A+에 도전하는 Let’s Encrypt 인증서 세팅 방법”에서도 잠깐 언급되었던 내용이기도 합니다.

2. 2016년부터 확산되기 시작한 브로틀리 압축((Brotli Compression)

그러는 가운데 구글은 브로틀리 압축((Brotli Compression) 기술을 오픈 소스로 공개했습니다.

그리고 가장 많은 점유율을 가진 크롬이 2016년 5월 27일부터 브로틀리 압축((Brotli Compression)을 지원하기 시작하면서 본격적으로 확산되기 시작했습니다.

지금은 화이어폭스, 마이크로소프트 Edge, 사파리 등 대부분의 주요 브라우져가 이를 지원하고 있습니다. 우리나라에서 아직도 많이 사용하는 IE는 아직 지원하지 않고 있네요.

3. Gzip vs 브로틀리 압축((Brotli Compression)

당연하게도 기존에 널리 사용되었던 gzip과 브로틀리 압축((Brotli Compression) 간의 비교가 관심이 많을 것으로 보입니다.

안전성 여부를 떠나서 압춧 성능과 관련해 비교해 놓은 자료들이 많은데요.

“Text Compression in R: brotli, gzip, xz and bz2 “ 라는 글에서 gzip과 brotli 등 여러 압축 기술들을 평가해 놓은 글을 참조해 봤습니다.

이에 따르면 압축율은 브로틀리 압축((Brotli Compression)이 가장 뛰어납니다.

그러나 압축 속도는 gzip이 브로틀리 압축((Brotli Compression) 보다도 훨씬 뛰어납니다.

여기에서 테스트한 결과를 토대로 정적인 파일(static contents)에는 브로틀리 압축((Brotli Compression)이 뛰어나지만 동적 콘텐츠( on-the-fly)나 스트리밍 데이타에는 적합하지 않다는 평가를 내리고 있습니다.

3. Nginx에서 브로틀리 압축((Brotli Compression) 적용 어려움

종종 언급하지만 nginx는 상당히 장점이 많은 웹서버이지만 때로는 불리한 점도 있습니다.

예를 들어 브로틀리 압축((Brotli Compression)과 같이 새로운 기술의 경우 nginx용으로 개발되어 자동으로 적용되지 않고 별도로 ngix에 맞추어 컴파일을 해줘야 합니다.

이는 nginx 버젼이 바뀌면 이에 맞추어 다시 컴파일해서 세팅해야 한다는 것을 의미합니다. 관리하기 쉽지가 않다는 것이죠.

아래와 같은 글에서 버젼이 바뀌어도 브로틀리 압축((Brotli Compression)을 계속 적용할 수 있다고 하지만 이는 잘 작동하지 않습니다.

아래 글에서 소개하는 방법도 nginx 버젼이 높아지면 별도로 컴파일하는 절차를 다시 진행해야 합니다.

[사이트 속도 개선] 브로틀리 압축(Brotli Compression)으로 속도를 개선해 보기

4. 명령어 하나로 브로틀리 압축((Brotli Compression) 적용하고 데이트하기

그냥 nginx가 업데이트되면 자동으로 브로틀리 압축((Brotli Compression)도 업데이트되면 가장 좋겠지만 이게 가능하지 않으므로 차선으로 쉬운 방법을 찾아 보았습니다.

안벽하지는 않지만 아주 쉽게 자동화할 수 있는 방법이 인터넷에 소개되어 있습니다. 아래 링크를 참조..

Compile Nginx from Source with Brotli Support

여기서 소개하고 있는 brotli.sh 파일을 서버 root에 설치하고 bash 명령어로 실행 시키면 됩니다.

4.1. brotli.sh 만들기

아래처럼 nano와 같은 편집기 명령어를 이용해 brotli.sh 파일을 만듭니다.

nano brotli.sh

이 파일에는 아래 내용을 추가합니다.

#!/usr/bin/env bash

# version 1.2

# use it while developing / testing.
# you may use it in production as well.
# set -o errexit -o pipefail -o noclobber -o nounset
# set -x

# compile Nginx from the official repo with brotli compression

[ ! -d ${HOME}/log ] && mkdir ${HOME}/log

G_DIR="$(pwd)"

# logging everything
log_file=${HOME}/log/brotli.log
exec > >(tee -a ${log_file} )
exec 2> >(tee -a ${log_file} >&2)

# Defining return code check function
check_result() {
    if [ $1 -ne 0 ]; then
        echo "Error: $2"
        exit $1
    fi
}

export DEBIAN_FRONTEND=noninteractive

printf '%-72s' "Updating apt repos..."
sudo apt-get -qq update
echo done.

printf '%-72s' "Installing pre-requisites..."
sudo apt-get -qq install dpkg-dev build-essential zlib1g-dev libpcre3 libpcre3-dev unzip
echo done.

codename=$(lsb_release -c -s)

# function to add the official Nginx.org repo
nginx_repo_add() {
    distro=$(gawk -F= '/^ID=/{print $2}' /etc/os-release)
    if [ "$codename" == "juno" ] ; then
        codename=bionic
    fi

    if [ "$distro" == "elementary" ] ; then
        distro=ubuntu
    fi

    if [ "$distro" == "linuxmint" ] ; then
        distro=ubuntu
    fi

    [ -f nginx_signing.key ] && rm nginx_signing.key
    curl -LSsO http://nginx.org/keys/nginx_signing.key
    check_result $? 'Nginx key could not be downloaded!'
    sudo apt-key add nginx_signing.key &> /dev/null
    check_result $? 'Nginx key could not be added!'
    rm nginx_signing.key

    # for updated info, please see https://nginx.org/en/linux_packages.html#stable
    nginx_branch= # leave this empty to install stable version
    # or nginx_branch="mainline"

    if [ "$nginx_branch" == 'mainline' ]; then
        nginx_src_url="https://nginx.org/packages/mainline/${distro}/"
    else
        nginx_src_url="https://nginx.org/packages/${distro}/"
    fi

    [ -f /etc/apt/sources.list.d/nginx.list ] && sudo rm /etc/apt/sources.list.d/nginx.list
    echo "deb ${nginx_src_url} ${codename} nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
    echo "deb-src ${nginx_src_url} ${codename} nginx" | sudo tee -a /etc/apt/sources.list.d/nginx.list

    # finally update the local apt cache
    sudo apt-get update -qq
    check_result $? 'Something went wrong while updating apt repos.'
}

case "$codename" in
    "stretch")
        nginx_repo_add
        ;;
    "xenial")
        nginx_repo_add
        ;;
    "bionic")
        nginx_repo_add
        ;;
    "juno")
        codename=bionic
        nginx_repo_add
        ;;
     "tara")
        codename=bionic
        nginx_repo_add
        ;;
    *)
        echo "Distro: $codename"
        echo 'Warning: Could not figure out the distribution codename. Continuing to install Nginx from the OS.'
        ;;
esac

sudo install -o ${UID} -g $(id -gn $USER) -d /usr/local/src/${USER}
cd /usr/local/src/${USER}
apt-get source nginx
sudo apt-get build-dep nginx -y

git clone --recursive https://github.com/eustas/ngx_brotli
sudo ln -s /usr/local/src/${USER}/ngx_brotli /usr/local/src/ngx_brotli
sudo chown ${USER}:$USER:$(id -gn $USER) /usr/local/src/ngx_brotli
cd /usr/local/src/${USER}/nginx-*/

# modify the existing config
sed -i -e '/\.\/configure/ s:$: --add-module=/usr/local/src/ngx_brotli:' debian/rules

# if gcc 8 is installed add patch to nginx 
if [ "$(gcc -dumpversion)" == "8" ]; then
    mkdir -p debian/patches
    cp ${G_DIR}/gcc-8_fix.diff debian/patches/gcc-8_fix
    echo "gcc-8_fix" > debian/patches/series
fi

# build the updated pacakge
dpkg-buildpackage -b

# optional
# install the updated package in the current server
cd /usr/local/src/${USER}

# take a backup
[ ! -d ~/backups/ ] && mkdir ~/backups
cp nginx*.deb ~/backups/nginx-$(date +%F)/

# sudo apt-mark unhold nginx
sudo dpkg -i nginx_*.deb

# print info about remove all the sources and apt sources file
cd ~/

printf "
# To clean up after install You can run
 rm -rf /usr/local/src/$(echo ${USER})/nginx*
 rm -rf /usr/local/src/$(echo ${USER})/ngx_brotli
 sudo rm /etc/apt/sources.list.d/nginx.list
 sudo apt-get -qq update
"
# hold the package nginx from updating accidentally in the future by someone else!
sudo apt-mark hold nginx

# stop the previously running instance, if any
sudo nginx -t && sudo systemctl stop nginx

# start the new Nginx instance
sudo nginx -t && sudo systemctl start nginx

이렇게 만들어진 brotli.sh의 파일 권한을 변경합니다.

chmod +x brotli.sh

이 파일을 아래와 같이 bash 명령을 사용해 실행합니다.

bash britli.sh

그러면 설치 전과정을 알아서 진행합니다. nginx 버젼을 파악해서 말이죠.

nginx 버젼이 변경될때마다 위에서 소개한 bash brotli.sh 명령으로 자동으로 새로 업데이트된 ngix에 맞추어 브로틀리 압축((Brotli Compression)을 적용할 수 있습니다.

LEAVE A REPLY

Please enter your comment!
Please enter your name here