IT/Linux/Kubernetes

What is HTTP/2(h2)? & CentOS6 HTTP/2

안녕하세요. ManVSCloud 김수현입니다.

오늘은 CentOS 6에서 HTTP/2를 적용해보려 합니다.
CentOS 6은 2020년 11월 30일 이미 지원이 중단된 OS지만 아직 쓰고 계시는 사용자들이 많아 CentOS 6부터 적용 방법을 작성하기로 했습니다.


WHAT IS HTTP/2(H2)?

현재 HTTP/3 까지 출시되었으나 아직까지 많은 유저들은 1999년에 출시된 HTTP1.1을 가장 많이 사용하고 있습니다.
최근들어 HTTP/2를 적용하는 분들이 늘어나고 있어 HTTP/2에 대해 소개를 해드리고자 합니다.

우선 HTTP/2는 HTTP/1.1을 대체하는 것이 아닌 확장한 것인데 HTTP 메소드, 상태 코드, URI, 헤더 필드를 사용하여 동일하게 유지되고 있습니다.

HTTP/1.1로 시작하여 클라이언트가 HTTP/2를 지원하면 연결이 업그레이드 되는 방식입니다.

https://blog.knoldus.com/still-not-switch-to-http-2/

HTTP1.1은 연결 시 하나의 요청과 응답만 처리하기에 동시 데이터 전송이나 여러개의 리소스를 처리하는데에 속도와 성능이 떨어집니다.(전체 용량에 도달하기 전 여러 번의 소규모 전송으로 인한 지연 발생) 또한 서버와 클라이언트 간에 추가 요청이나 메타데이터 교환으로 반복적인 헤더와 쿠키 전송으로 응답 속도가 느려지는 현상이 나타납니다.

HTTP/2를 사용하게되면 이러한 문제를 해결할 수 있습니다. 클라이언트가 단일 TCP 연결을 통해 다수의 모든 요청을 동시에 보낼 수 있게 됩니다.
다만 무조건적으로 HTTP/2가 좋은 것만은 아니기에 내가 운영하는 서비스가 HTTP/2를 사용하기에 적합한지 판단이 필요합니다.

HTTP/2를 사용하게될 경우 단일 연결을 사용하여 동시 요청을 보내게 됩니다. 이는 예측할 수 없는 스파이크가 발생할 수 있는 원인이 될 수 있습니다. 게다가 HTTP/2 Server Push 기법을 이용하여 클라이언트가 요청하기 전에 서버가 클라이언트로 리소스를 보낼 수 있습니다. 이는 리소스를 선점적으로 로드하는데 도움이 되지만 이 또한 재방문자가 캐시된 파일 복사본이 있을 수 있으며 이 경우 서버에서 리소스를 푸시하지 않도록 Push Cache를 인식하도록 해주어야 합니다.(Cache-Control max-age 등 헤더 적용)

HTTP/2 사용은 응답 시간이 중요하지 않은 애플리케이션, 제한된 IoT 장치나 안정적인 연결이 필요한 곳 그리고 WebSockets, Server-Sent Events (SSE), Pub/Sub 메시징과 같이 적절한 기술이 사용되는 경우 등이 적합하다고 볼 수 있겠습니다.

HTTP/2를 적용하기 위해서는 조건이 있습니다.
만약 Apache를 사용할 것이라면 Apache 2.4.17버전 이상이 이어야하며 openssl 버전도 1.0.2 이상이 되어야합니다. PHP의 경우 libcurl 사용 즉, cURL을 이용하여 HTTP/2 POST를 요청하기 위해서는cURL 7.43 이상, PHP 버전도 5.5.24 이상의 환경이 필요합니다.

오늘은 간단하게 CentOS6에서 Apache로 http2 사용하기를 준비했습니다.


Using HTTP/2 on CentOS 6

mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo_org
vi /etc/yum.repos.d/CentOS-Base.repo

우선 CentOS6은 지원 중단으로 Base repo를 아래와 같이 변경해주었습니다.

# CentOS-Base.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client.  You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
# If the mirrorlist= does not work for you, as a fall back you can try the 
# remarked out baseurl= line instead.
#
#

[base]
name=CentOS-$releasever - Base
release=$releasever&arch=$basearch&repo=os&infra=$infra
baseurl=https://vault.centos.org/6.10/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

#released updates 
[updates]
name=CentOS-$releasever - Updates
release=$releasever&arch=$basearch&repo=updates&infra=$infra
baseurl=https://vault.centos.org/6.10/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
release=$releasever&arch=$basearch&repo=extras&infra=$infra
baseurl=https://vault.centos.org/6.10/extras/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
release=$releasever&arch=$basearch&repo=centosplus&infra=$infra
baseurl=https://vault.centos.org/6.10/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

#contrib - packages by Centos Users
[contrib]
name=CentOS-$releasever - Contrib
release=$releasever&arch=$basearch&repo=contrib&infra=$infra
baseurl=https://vault.centos.org/6.10/contrib/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

만약 위와 같이 Base repo를 변경했는데도 정상적으로 yum 설치가 되지 않는다면
지원이 중단된 다른 repo가 있는지 확인해보신 후 중단된 repo를 제거 및 yum clean all 후 재진행 해보시기 바라며 그 후에도 되지않는다면 /etc/resolv.conf 에 nameserver가 정상적으로 등록되어 있는지 확인해보시기 바랍니다.

[root@manvscloud ~]# yum update -y
[root@manvscloud ~]# yum install wget perl gcc zlib-devel epel-release -y

위는 필수 설치 패키지 입니다.

기존에 운영하고 계시던 서비스가 존재한다면 yum update 전에 update 시 예외처리가 필요한 패키지들을 반드시 exclude해주시기 바랍니다.

yum update –exclude= 방식으로 exclude할 수 있으며 /etc/yum.conf에 exclude 설정을 해줄 수도 있습니다.


Install openssl and upgrade version

<OpenSSL Site>

openssl부터 설치해보도록 합시다.
CentOS 6은 기본적으로 1.0.1버전의 openssl이 설치되는데 1.0.2를 설치해주기 위해 컴파일 작업을 진행할 것입니다.

// 컴파일 설치 진행
[root@manvscloud ~]# cd /usr/local/src
[root@manvscloud src]# wget https://www.openssl.org/source/old/1.0.2/openssl-1.0.2u.tar.gz
[root@manvscloud src]# tar zxvf openssl-1.0.2u.tar.gz
[root@manvscloud src]# cd openssl-1.0.2u
[root@manvscloud openssl-1.0.2u]# ./config --prefix=/usr/local/openssl shared zlib
[root@manvscloud openssl-1.0.2u]# make
[root@manvscloud openssl-1.0.2u]# make install

// ldconfig 및 버전 확인
[root@manvscloud openssl-1.0.2u]# echo "/usr/local/openssl/lib" >  /etc/ld.so.conf.d/openssl.conf
[root@manvscloud openssl-1.0.2u]# cat /etc/ld.so.conf.d/openssl.conf 
/usr/local/openssl/lib
[root@manvscloud openssl-1.0.2u]# ldconfig
[root@manvscloud openssl-1.0.2u]# mv /usr/bin/openssl /usr/bin/openssl-1.0.1
[root@manvscloud openssl-1.0.2u]# ln -s /usr/local/openssl/bin/openssl /usr/bin/openssl
[root@manvscloud openssl-1.0.2u]# openssl version
OpenSSL 1.0.2u  20 Dec 2019

// 기존 certs 복사 
[root@manvscloud certs]# cp -avp /etc/pki/tls/certs /usr/local/openssl/ssl/
`/etc/pki/tls/certs/ca-bundle.crt' -> `/usr/local/openssl/ssl/certs/ca-bundle.crt'
`/etc/pki/tls/certs/Makefile' -> `/usr/local/openssl/ssl/certs/Makefile'
`/etc/pki/tls/certs/renew-dummy-cert' -> `/usr/local/openssl/ssl/certs/renew-dummy-cert'
`/etc/pki/tls/certs/ca-bundle.trust.crt' -> `/usr/local/openssl/ssl/certs/ca-bundle.trust.crt'
`/etc/pki/tls/certs/make-dummy-cert' -> `/usr/local/openssl/ssl/certs/make-dummy-cert'

위와 같이 진행해준다면 openssl 버전이 1.0.2로 설치가 된 것입니다!


Apache + apr, apr-util, pcre

yum install -y nghttp2 libnghttp2 libnghttp2-devel gcc-c++ libstdc++-devel expat-devel pcre-devel

이제 HTTP/2 적용을 위한 Apache를 설치해봅시다.

apache 2.4 버전부터는 apr과 apr-util도 설치해주어야하는데 우선 apr 설치 과정입니다.

[root@manvscloud ~]# cd /usr/local/src
[root@manvscloud src]# wget http://mirror.apache-kr.org/apache/apr/apr-1.6.5.tar.gz
[root@manvscloud src]# tar zxvf apr-1.6.5.tar.gz 
[root@manvscloud src]# cd apr-1.6.5
[root@manvscloud apr-1.6.5]# ./configure --prefix=/usr/local/apr
[root@manvscloud apr-1.6.5]# cp -arp libtool libtoolT
[root@manvscloud apr-1.6.5]# make
[root@manvscloud apr-1.6.5]# make install

아래는 apr-util 과정입니다.

[root@manvscloud ~]# cd /usr/local/src
[root@manvscloud src]# wget http://mirror.apache-kr.org/apache/apr/apr-util-1.6.1.tar.gz
[root@manvscloud src]# tar zxvf apr-util-1.6.1.tar.gz 
[root@manvscloud src]# cd apr-util-1.6.1
[root@manvscloud apr-util-1.6.1]# ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr
[root@manvscloud apr-util-1.6.1]# make
[root@manvscloud apr-util-1.6.1]# make install

pcre도 설치해줄 건데 이후 modsecurity를 사용하기 위해서도 pcre가 필요합니다.

[root@manvscloud ~]# cd /usr/local/src
[root@manvscloud src]# wget https://ftp.pcre.org/pub/pcre/pcre-8.43.tar.gz
[root@manvscloud src]# tar zxvf pcre-8.43.tar.gz 
[root@manvscloud src]# cd pcre-8.43
[root@manvscloud pcre-8.43]# ./configure --prefix=/usr/local/pcre
[root@manvscloud pcre-8.43]# make
[root@manvscloud pcre-8.43]# make install

Apache 2.4버전을 컴파일할 모든 준비가 되었습니다.
우선 아래 옵션을 보시면 event방식으로 설치했습니다.

[root@manvscloud ~]# cd /usr/local/src
[root@manvscloud src]# wget http://archive.apache.org/dist/httpd/httpd-2.4.48.tar.gz
[root@manvscloud src]# tar zxvf httpd-2.4.48.tar.gz 
[root@manvscloud src]# cd httpd-2.4.48
[root@manvscloud httpd-2.4.48]# ./configure --prefix=/usr/local/apache \
--enable-mods-shared=all --enable-http2 \
--enable-ext-filter --enable-ssl --with-ssl=/usr/local/openssl \
--enable-so --enable-cache --enable-proxy \
--enable-deflate --enable-suexec --enable-file-cache \
--with-mpm=event --with-apr=/usr/local/apr \
--with-apr-util=/usr/local/apr-util \
--with-pcre=/usr/local/pcre/bin/pcre-config \
--enable-modules=all --enable-module=shared
[root@manvscloud httpd-2.4.48]# make
[root@manvscloud httpd-2.4.48]# make install

(event 방식으로 설치 시 event + fcgi proxy + php-fpm 구조가 일반적입니다.)
왜 event 방식으로 설치했느냐?

prefork 방식은 http/2를 지원하지 않습니다.
prefork 방식이 지원되지 않는 이유는 무엇인가?에대한 질문에 대답은 간단합니다.
HTTP/2는 클라이언트가 단일 TCP 연결을 통해 서버에서는 다수의 모든 요청 즉, 동시 요청을 보내야합니다.

prefork의 단일 스레드 요구 사항을 HTTP/2에 매핑하는 것이 불가능한 것입니다.
처리 모델의 충돌이라고 볼 수있죠. (worker와 event는 다중 스레드 지원)

[root@manvscloud ~]# echo "PATH=$PATH:$HOME/bin:/usr/local/apache/bin" >> /etc/profile
[root@manvscloud ~]# echo "export PATH"  >> /etc/profile
[root@manvscloud ~]# tail -n 2 /etc/profile
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin:/usr/local/apache/bin
export PATH
[root@manvscloud ~]# source /etc/profile

/usr/local/apache/bin 아래 명령어들을 편하게 사용할 수 있게 위와 같이 등록해주었습니다.
이제 apache에서 모듈을 추가해줍시다.

// 모듈 확인
[root@manvscloud ~]# apachectl -M | grep http2

//http2 모듈 확인
[root@manvscloud ~]# cat -n /usr/local/apache/conf/httpd.conf | grep http2
   144	#LoadModule http2_module modules/mod_http2.so

//주석 제거
[root@manvscloud ~]# sed -i '144s/#LoadModule/LoadModule/g' /usr/local/apache/conf/httpd.conf

//모듈 적용 확인
[root@manvscloud ~]# apachectl -M | grep http2
 http2_module (shared)

// Protocols 추가
[root@manvscloud ~]# cat << EOF >> /usr/local/apache/conf/httpd.conf 
> <IfModule http2_module>
>         ProtocolsHonorOrder On
>         Protocols h2 h2c http/1.1
> </IfModule>
> EOF

위 작업 후 apachectl start를 하여 apache를 실행해주고 웹사이트가 정상적으로 잘 출력되는지 확인해보시기 바랍니다. Apache가 정상적으로 실행됐는데 페이지 출력이 안되면 iptables가 실행되어있지 않은지? 상단 방화벽 등 어딘가에 막히는 것이 없는지 확인해보시고 그래도 출력이 안되신다면 /usr/local/apache/logs 아래 생성된 로그를 참고하여 해결이 필요합니다.

HTTP2.Pro에서 HTTP/2가 잘 적용되었는지 확인해보니 잘 적용되었다고 나오는군요.
해당 사이트는 아래 링크를 통해 바로 접속이 가능합니다.


Nginx

[root@manvscloud ~]# yum list nginx
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * epel: d2lzkl7pfhq30w.cloudfront.net
Available Packages
nginx.x86_64                                                                                                                         1.10.3-1.el6                                                                                                                         epel

[root@manvscloud ~]# nginx -V
nginx version: nginx/1.10.3
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-23) (GCC) 
built with OpenSSL 1.0.1e-fips 11 Feb 2013
TLS SNI support enabled
configure arguments: --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/var/run/nginx.pid --lock-path=/var/lock/subsys/nginx --user=nginx --group=nginx --with-file-aio --with-ipv6 --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --with-http_perl_module=dynamic --with-mail=dynamic --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream=dynamic --with-stream_ssl_module --with-debug --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic' --with-ld-opt=' -Wl,-E'

CentOS 6에서 Nginx는 epel에서 1.10.3으로 주네요.
openssl 버전만 맞춰준 뒤에 yum 설치만 해도 됩니다. nginx -V 옵션으로 보면 –with-http_v2_module 옵션이 보이시나요?

단 Nginx에서 http2 적용 테스트 시 주의할 점이 있다면 아래와 같이 HTTPS(443) SSL 설정을 해줍시다.
listen 80 http2 default_server; 으로 설정할 경우 사이트 접속이 안되고 다운로드가 됩니다.🤣

server {
    listen       443 ssl http2 default_server;
    listen       [::]:443 ssl http2 default_server;
.
. 생략
.
}

CentOS 6에서 Nginx는 크게 어려움이 없을 것으로 보입니다.


Et cetera

나머지는 도움될만한 내용만한 자료만 첨부해두도록 하겠습니다.

cURL은 위 링크를 참고하면 HTTP/2 적용을 위해 cURL을 설치하는 과정이 나와있습니다.
물론 무작정 영상 그대로 따라하기보다 영상에서 주는 옵션을 보며 해당 옵션과 경로가 나의 환경에 맞는지 검토하는 것은 필수입니다.

마지막으로 Tomcat은 className을 org.apache.coyote.http2.Http2Protocol로 설정해주어야합니다.

<Connector port="8080" protocol="HTTP/1.1">
.
. //생략
.
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
.
. //생략
.
</Connector>

Tomcat 역시 버전만 맞춰주면 크게 어려울 것 없어보입니다. 😎


Personal Comments

지금까지 CentOS 6에 HTTP/2를 적용에 대해 알아보았습니다.
앞으로 CentOS 7, Rocky 8, Naver Cloud Platform Load Balancer, AWS ELB 등에서 HTTP/2를 적용하는 방법에 대해서도 추가적으로 포스팅 될 예정입니다.

긴 글 읽어주셔서 감사합니다.

Previous Post Next Post

You Might Also Like

No Comments

Leave a Reply