레이블이 brotli인 게시물을 표시합니다. 모든 게시물 표시
레이블이 brotli인 게시물을 표시합니다. 모든 게시물 표시

httpd content-encoding 헤더 누락 문제

# nginx proxy -> apache httpd 웹서버 구성에서
# apache httpd 2.4 버전업과 brotli(br) 압축을 적용했다.
# 다음과 같이 nginx 에 br 인코딩 헤더로 요청을 준다.
# 참고로 -I 로 헤더만 보는경우 curl 은 HEAD method 로 요청하기 때문에
# 실제 GET 요청에서 응답받는 헤더를 보려면 GET method 로 지정해야 한다.
curl 'http://ysoftman-nginx/test?param=ysoftman'-H 'accept-encoding:br' -I -X GET

# 다음과 같이 content-encoding: br 응답헤더를 볼 수 있다.
HTTP/2 200
date: Thu, 03 Oct 2019 13:13:34 GMT
content-type: text/html; charset=utf-8
vary: Accept-Encoding
content-encoding: br
server: ysoftman-nginx
cache-control: private, no-cache, max-age=0
expires: -1

# gzip 요청도 테스트 해보면
curl 'http://ysoftman-nginx/test?param=ysoftman'-H 'accept-encoding:gzip' -I -X GET

# 다음과 같이 content-encoding: gzip 응답헤더를 볼 수 있다.
HTTP/2 200
date: Thu, 03 Oct 2019 13:09:34 GMT
content-type: text/html; charset=utf-8
vary: Accept-Encoding
content-encoding: gzip
server: ysoftman-nginx
cache-control: private, no-cache, max-age=0
expires: -1

# 문제
# nginx 에서 packetbeat 을 설치해 httpd 의 응답 헤더를 수집해 elasticsearch(es) 보냈다.
# kibana 로 content-encoding 헤더가 br 또는 gzip 을 카운트 하려는데
# http.response.headers.content-encoding 헤더 자체가 없는 로그가 있다.
# "accept-encoding" 요청이 없으면 plain text 로 헤더가 없는게 맞지만
# "accept-encoding: gzip" 요청은 있어야 한다.
# http.response.headers.content-encoding: br 은 잘 남고 있었다.
# 원인
# curl 이나 실제 브라우저에서 테스트 해보면
# content-encoding: br 또는 gzip 응답이 확인된다.
# 하지만 nginx 가 아닌 httpd 로 요청하면
# gzip 요청에 대해선 content-encoding 응답헤더가 없었다.
curl 'http://ysoftman-httpd/test?param=ysoftman'-H 'accept-encoding:gzip' -I -X GET

# gzip 처리를 nginx 가 해줘 nginx 의 packetbeat 은
# httpd 로 부터의 응답에서 "content-encoding: gzip" 찾을 수 없었던 것이다.
# 찾아보니 httpd.conf 에서 응답 필터 처리시
# 다음과 같이 brotli 만 응답 필터링한게 문제였다.
SetOutputFilter BROTLI_COMPRESS

# 해결
# SetOutputFilter 는 주석처리하고
# 다음과 같이 AddOutputFilterByType 로
# deflate(gizp에서 사용하는 무손실 압축 알고리즘), brotli 둘다 사용할 수 있게 했다.
# 먼저 추가한 필터가 우선순위를 가져 br 먼저 설정해야 한다.
AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/xml text/css text/javascript application/x-javascript application/javascript application/json application/x-font-ttf application/vnd.ms-fontobject image/x-icon

AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/x-javascript application/javascript application/json application/x-font-ttf application/vnd.ms-fontobject image/x-icon

# 그리고 AddOutputFilterByType 사용하려면 filter 모듈을 추가해야 한다.
LoadModule filter_module modules/mod_filter.so

# 이제 httpd 요청시에도 "content-encoding: gzip" 헤더를 받을 수 있고,
# packetbeat 에서도 잘 수집돼 -> es -> kibana 로 content-encoding 값을 구분 할 수 있다.

# 참고
https://httpd.apache.org/docs/current/mod/mod_filter.html#AddOutputFilterByType
https://www.tunetheweb.com/performance/brotli/

nginx http2 brotli 사용하기

nginx 에서 http2 를 적용 후 기존 gzip 을 대체하는 brotli 를 압축을 사용할 수 있다.
우선 nginx 용으로 만들어진 모듈을 다운받는다.

# deps 디렉토리가 brotli (https://github.com/google/brotli) 를 바라보고 있어
# clone 시 --recursive 옵션을 사용하여 brotli 까지 모두 다운 받아야 한다.
git clone --recursive https://github.com/google/ngx_brotli

# nginx 빌드시 brotli 모듈을 추가해 빌드한다.
--add-module=/home/ysoftman/ngx_brotli

# nginx.conf 설정에서 brotli 사용
# MIME 설명
https://developer.mozilla.org/ko/docs/Web/HTTP/Basics_of_HTTP/MIME_types
http {
    brotli on;  # on-the-fly 로 요청마다 brotli 압축
    brotli_static on;  # 미리 압축해논 .br 파일을 사용
    brotli_types *; # on-the-fly 때 압축할 MIME 타입 설정
}

# 크롬 브라우저는 https(http2) 요청시 brotli(br) 이 지원되어 다음과 같이 gzip 과 함께 br 을 명시한다.
accept-encoding:gzip, deflate, br

# nginx 는 https(http2) 의 요청에 대해서 다음과 같이 br 로 인코딩하여 응답한다.
content-encoding:br
content-type:text/html
date:Mon, 26 Jun 2017 06:03:57 GMT
etag:W/"5950a3c7-264"
last-modified:Mon, 26 Jun 2017 06:03:51 GMT
server:nginx
status:200

# 참고
# 이미 브라우저가 해당 리소스(ex. html 파일)를 가지고 있다면 캐쉬되어
# 304(not modified, 서버의 리소스가 클라가 캐시와 비교해 변경된것이 없다.)
# 응답을 주면 다음과 같이  "content-encoding:br" 명시될 필요가 없다.
date:Mon, 26 Jun 2017 06:19:00 GMT
etag:"59506b41-264"
last-modified:Mon, 26 Jun 2017 02:02:41 GMT
server:nginx
status:304

curl 유용한 옵션

# wget
# 예전에는 웹에 올라온 파일을 콘솔환경에서 다운받을때 wget 명령어를 주로 사용했다.
# 다음과 같이 다운받을 대상 url 만 명시하면 파일이 다운로드되는 형식이다.
wget http://ysoftman.com/ysoftman.tar.gz

# ysoftman.out 파일로 내용 저장
wget -O ysoftman.out http://ysoftman.com/ysoftman.html

# -O 뒤 - 주면 stdout 으로 다운받은 내용을 강제 출력한다.
wget -O - http://ysoftman.com/ysoftman.html

# curl
# 언제부터인가 wget 대신 curl 을 많이 사용하게 된다.
# 보통 curl 특정 특정 웹의 html 응답을 파악할때 사용한다.
curl http://www.google.com

# curl 로 파일을 받을때는 -O (대문자 o) 옵션을 주면 된다.
curl -O http://ysoftman.com/ysoftman.tar.gz

# -o 로 파일을 명시할 수 도 있다.
# -o- 로 -를 주면 stdout 으로 다운받은 내용을 강제 출력한다.
curl -o ysoftman.out http://ysoftman.com/ysoftman.tar.gz

# 만약 다운받은 파일이 예상했던 크기보다 작다면 -v 옵션으로 다운로드 과정을 살펴보자.
curl -Ov http://ysoftman.com/ysoftman.tar.gz

# HTTP/1.1 302 (redirect) 로 해당 파일을 redirect 하여 다운로드를 받아야한다면
# -L 옵션으로 redirect 를 따라가서 파일을 다운로드 받을 수 있다.
# 참고로 wget 은 별도의 옵션없이 redirect 처리가 된다.
curl -OLv http://ysoftman.com/ysoftman.tar.gz

# POST 방식으로 data 를 요청할때
# -X POST 방식(-d 가 있으면 생략가능)
# -d 데이터, 파일을 사용할때는 @파일명
# --trace-ascii /dev/stdout 표준 출력을 트레이스하여 데이터 내용을 확인할 수 있다.
curl -v -X POST http://ysoftman.com -d "ysoftman" --trace-ascii /dev/stdout

# 파일 업로드
# -F 멀티파트 폼데이터로 파일 전송
# zzz : form 필드에서 aaa.txt 데이터가 들어갈 위치(키)
# @전송할 파일명,
curl -X POST -F 'zzz=@./aaa.txt' http://ysoftman.com/upload

# -s, --silent 진행상태 에러메시지등 표시하지 않기
curl -s http://www.google.co.kr

# -i --include 헤더와 바디 보기
curl -i http://www.google.co.kr

# -I, --head 헤더만 보기
curl -I http://www.google.co.kr

# -I 는 기본적으로 HEAD 커맨드를 사용한다.
# GET 요청시에서의 헤더만 보기
curl -I -X GET http://www.google.co.kr

# -L 302 redirect 하여 응답헤더 보기
curl -IL http://www.google.com

# -D filename 헤더 덤프해서 보기(- 로 파일명을 안줄 수 있다)
curl -D - http://www.google.co.kr

# -H, --header 요청헤더 설정(헤더는 대소문자 구분하지 않는다.)
curl -I -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36' -H 'Accept-Encoding: br' https://www.google.co.kr

# 응답 데이터 크기만 보기
curl -s http://www.google.co.kr -w '%{size_download}\n' -o /dev/null

# 응답 상태 코드만 보기
curl -s http://www.google.co.kr -w '%{http_code}\n' -o /dev/null

# elapsed(경과시간) 측정
curl http://www.google.co.kr -w "\n\nConnect time: %{time_connect} Time to first byte: %{time_starttransfer} Total time: %{time_total}"

# https + http2 요청
curl -sI http://www.google.co.kr --http2

# https + http1.1 요청
curl -sI http://www.google.co.kr --http1.1

Apache httpd 에서 https http2 brotli 사용하기

# 2019-07-16 최신 버전 기준으로 내용 수정
# HTTP 2 는 기존 HTTP 1.x 의 비효율적인 속도를 개선한 버전으로 Multiplexed Strem, Header Compression 등의 기술이 포함되어 있다.
# 참고
# http://www.bloter.net/archives/210122
# https://icing.github.io/mod_h2/howto.html
# http://httpd.apache.org/docs/trunk/new_features_2_4.html
# http://httpd.apache.org/docs/2.4/programs/configure.html#installationdirectories

# apr 설치
wget http://apache.mirror.cdnetworks.com/apr/apr-1.7.0.tar.gz
tar zxvf apr-1.7.0.tar.gz
cd apr-1.7.0
./configure --prefix=${HOME}/apr
make -j8 && make install

# apr-util 설치
wget http://apache.mirror.cdnetworks.com//apr/apr-util-1.6.1.tar.gz
tar zxvf apr-util-1.6.1.tar.gz
cd apr-util-1.6.1
./configure --prefix=${HOME}/apr-util --with-apr=${HOME}/apr --with-crypto
make -j8 && make install

# openssl 설치
wget https://github.com/openssl/openssl/archive/OpenSSL_1_1_1c.tar.gz
tar zxvf OpenSSL_1_1_1c.tar.gz
cd openssl-OpenSSL_1_1_1c
./config --prefix=${HOME}/openssl -fPIC
make -j8 && make install

# nghttp2 설치
# 아파치 httpd 에서는 mod_http2 모듈을 로딩하여 HTTP 2 처리를 하게 된다.
# 자세한 내용은 https://httpd.apache.org/docs/2.4/mod/mod_http2.html
wget https://github.com/nghttp2/nghttp2/releases/download/v1.39.1/nghttp2-1.39.1.tar.gz
tar zxvf nghttp2-1.39.1.tar.gz
cd nghttp2-1.39.1
./configure --prefix=${HOME}/nghttp2 OPENSSL_CFLAGS="-I${HOME}/openssl/include" OPENSSL_LIBS="-L${HOME}/openssl/lib -lssl -lcrypto"
make -j8 && make install

# brotli 설치
# gzip 보다 향상된 압축방식이다.
# cmake 로 빌드하기 때문에 없으면 설치하자.
sudo yum install cmake
wget https://github.com/google/brotli/archive/v1.0.7.tar.gz
tar zxvf v1.0.7.tar.gz
cd brotli-1.0.7

# 빌드 결과물이 현재 위치에 생성되기 때문에 out 디렉토리를 생성하고 빌드하자.
mkdir -p out
cd out
../configure-cmake --prefix=${HOME}/brotli
make -j8 && make install

# httpd 설치
# 아파치 httpd 2.4.17 (부터 http2 지원) 이후 버전을 설치하자.
wget http://apache.tt.co.kr//httpd/httpd-2.4.39.tar.gz
tar zxvf httpd-2.4.39.tar.gz
cd httpd-2.4.39
./configure \
--prefix=${HOME}/apache-httpd \
--with-apr=${HOME}/apr \
--with-apr-util=${HOME}/apr-util \
--enable-brotli \
--with-brotli=${HOME}/brotli \
--enable-http2 \
--with-nghttp2=${HOME}/nghttp2 \
--enable-ssl \
--with-ssl=${HOME}/openssl \
--with-mpm=prefork \
--enable-mods-shared="unixd authz_core authz_user rewrite authz_host include log_config mime_magic headers unique_id setenvif mime status dir alias"
make -j8 && make install

# 참고
# apr, apr-util 소스를 별도로 빌드하지 않고
# httpd/srclib/apr, httpd/srclib/apr-util 이름으로 압축을 해제하면
# --with-apr --with-apr-util 옵션을 사용하지 않고 httpd 빌드할 수 있다.
# libapreq 설치
wget http://mirror.apache-kr.org//httpd/libapreq/libapreq2-2.13.tar.gz
tar zxvf libapreq2-2.13.tar.gz
cd libapreq2-2.13
./configure --with-apache2-apxs=${HOME}/apache-httpd/bin/apxs

# ${HOME}/apache-httpd/modules/mod_apreq2.so 로 설치된다.
make -j8 && make install

# http2 를 사용할 수 있도록 설정파일에 다음을 추가한다.
sudo vi conf/httpd.config
LoadModule http2_module modules/mod_http2.so
<IfModule http2_module>
LogLevel http2:info
</IfModule>

# h2 -> TLS(SSL) https 로 요청되는 경우
# h2c -> http 로 요청되는 경우
Protocols h2 h2c http/1.1

# 아파치 httpd 시작시 nghttpd 라이브러리를 참조할 수 있도록 환경변수 스크립트 수정
# 기존 경로에 openssl 과 nghttp2 를 추가해 준다.
vi ${HOME}/apache-httpd/bin/envvars
LD_LIBRARY_PATH="${HOME}/apache-httpd/lib:${HOME}/openssl/lib:${HOME}/nghttp2/lib:$LD_LIBRARY_PATH"
export LD_LIBRARY_PATH

# brotli 설정 추가
sudo vi conf/httpd.config
LoadModule brotli_module modules/mod_brotli.so
SetOutputFilter BROTLI_COMPRESS

# 아파치 httpd 시작~
sudo ${HOME}/apache-httpd/bin/apachectl -k start

# gzip brotli 압축 사용시 사이즈 보기
curl -H "Accept-Encoding: gzip" -o out.gz https://ysoftman.com/test
curl -H "Accept-Encoding: br" -o out.br https://ysoftman.com/test

# gzip 압축해제
gzip -d -k out.gz

# brotli 압축해제
# brew install brotli 설치
# https://github.com/google/brotli/blob/master/c/tools/brotli.md