https://springboot.cloud/21 에서는 컴파일을 통해서 Apache HTTP 웹서버를 설치하는 방법을 알아보았다.
이전 게시물에서 OpenSSL 을 빌드할 때 아래와 같이 빌드했었다.
./config --prefix=/tmp/apache-install/openssl-for-httpd -fPIC shared
make
make install
맨 뒤에 -fPIC shared 옵션이 붙은 것을 볼 수 있다.
-fPIC 옵션은 OpenSSL이 위치독립코드(position independent code)로 동작하도록 빌드한다는 것이고 shared 옵션은 OpenSSL이 shared object에 의존성을 가지도록 빌드한다는 것이다. PIC에 대해서는 https://ko.wikipedia.org/wiki/%EC%9C%84%EC%B9%98_%EB%8F%85%EB%A6%BD_%EC%BD%94%EB%93%9C 를 참조하자.
리눅스는 동적 라이브러리 의존성을 검사하기 위한 ldd 라는 명령어가 있다. -fPIC 옵션만 준 경우와 -fPIC shared 옵션을 준 경우의 openssl 바이너리에 대해서 동적 라이브러리 의존성을 검사해보자
1. -fPIC 옵션만 준 경우
[root@localhost bin]# ldd openssl
linux-vdso.so.1 => (0x00007ffffa3c4000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007faca651b000)
libc.so.6 => /lib64/libc.so.6 (0x00007faca6187000)
/lib64/ld-linux-x86-64.so.2 (0x00007faca6724000)
2. -fPIC shared 옵션을 준 경우
[root@localhost bin]# ldd openssl
linux-vdso.so.1 => (0x00007fff0d7ff000)
libssl.so.1.0.0 => /tmp/apache-install/openssl-for-httpd/lib/libssl.so.1.0.0 (0x00007f6c2f7cb000)
libcrypto.so.1.0.0 => /tmp/apache-install/openssl-for-httpd/lib/libcrypto.so.1.0.0 (0x00007f6c2f390000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f6c2f188000)
libc.so.6 => /lib64/libc.so.6 (0x00007f6c2edf4000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6c2fa3c000)
libssl.so.1.0.0과 libcrypto.so.1.0.0 에 대한 의존성이 다른 것을 알 수 있다.
-fPIC shared의 옵션으로 빌드한 OpenSSL 을 가지고 Apache HTTP 웹서버를 빌드하는 경우 일반적으로는 정상 동작한다. 그런데 한가지 고려할 사항이 있는데 TLS/SSL 활성화를 위해 mod_ssl.so 를 LoadModule 에서 활성화시켰을 경우 apachectl 혹은 httpd 실행시
Cannot load modules/mod_ssl.so into server: libssl.so.1.0.0: cannot open shared object file: No such file or directory 라는 오류 메시지가 나오면서 실행이 실패하는 경우가 있다. mod_ssl.so 가 OpenSSL의 shared object에 의존성을 가지도록 빌드되었는데 해당 .so 파일을 찾지 못해서 생기는 문제이다.
modules 디렉토리에 있는 .so 파일들의 의존성에 어떤 문제가 있는지 한 번 알아보자.
# modules 디렉토리에서 .so 파일들의 의존성을 ldd로 검사
for file in *.so; do echo "$file"; ldd "$file" | grep "not"; done
# not found 라는 문자열이 포함된 .so 파일을 표시
mod_ssl.so
libssl.so.1.0.0 => not found
libcrypto.so.1.0.0 => not found
다른 파일들은 전부 문제가 없는데 mod_ssl.so 는 참조하는 .so 중 libssl.so 와 libcrypto.so 를 찾을 수 없다는 에러가 나온다.
mod_ssl.so 가 참조하고 있는 .so 의존성 전체를 알아보자.
[root@localhost modules]# ldd mod_ssl.so
linux-vdso.so.1 => (0x00007ffe21bca000)
libssl.so.1.0.0 => not found
libcrypto.so.1.0.0 => not found
librt.so.1 => /lib64/librt.so.1 (0x00007f6ddffe4000)
libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f6ddfdad000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f6ddfb8f000)
libc.so.6 => /lib64/libc.so.6 (0x00007f6ddf7fb000)
/lib64/ld-linux-x86-64.so.2 (0x00007f6de042d000)
libfreebl3.so => /lib64/libfreebl3.so (0x00007f6ddf5f8000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f6ddf3f3000)
리눅스는 /lib64 디렉토리나 /usr/lib64 에 위치한 .so 는 기본적으로 찾도록 되어 있다. 그런데 libssl.so 와 libcrypto.so 는 해당 경로에 없기 때문에 에러가 나는 것. OpenSSL 은 알아서 잘 찾더만 이 놈은 왜 못 찾는 것일까... RPATH를 지정하면 이것도 해결할 수 있다고는 하는데, 몇 번 끄적끄적 해 봤는데 그걸 아파치 빌드시에 알아먹게 하는 법은 아직 성공하지 못 하였다... 하면 그 때 또 써보든가 해야지...
어쨌든 못 찾는 녀석들은 어디에 있냐면 위의 -fPIC shared 옵션을 주고 빌드한 OpenSSL 이 참조하는 그 경로에 있다. 조금 전에 빌드했던 OpenSSL 의 디렉토리로 가서 lib 디렉토리를 보자.
[root@localhost lib]# pwd
/tmp/apache-install/openssl-for-httpd/lib
[root@localhost lib]# ls -al
total 8112
drwxr-xr-x. 4 root root 4096 Apr 25 19:13 .
drwxr-xr-x. 6 root root 4096 Apr 25 19:13 ..
drwxr-xr-x. 2 root root 4096 Apr 25 19:13 engines
-rw-r--r--. 1 root root 4400038 Apr 25 19:13 libcrypto.a
lrwxrwxrwx. 1 root root 18 Apr 25 19:13 libcrypto.so -> libcrypto.so.1.0.0
-r-xr-xr-x. 1 root root 2601246 Apr 25 19:13 libcrypto.so.1.0.0
-rw-r--r--. 1 root root 765080 Apr 25 19:13 libssl.a
lrwxrwxrwx. 1 root root 15 Apr 25 19:13 libssl.so -> libssl.so.1.0.0
-r-xr-xr-x. 1 root root 512696 Apr 25 19:13 libssl.so.1.0.0
drwxr-xr-x. 2 root root 4096 Apr 25 19:13 pkgconfig
설치한 OpenSSL 의 lib 폴더에 들어가보면 없다고 하는 그 .so 파일들이 있는 걸 발견할 수 있다. 이걸 /lib64 혹은 /usr/lib64 에 옮겨 넣어도 되고, 리눅스에는 동적 라이브러리의 경로를 지정해주는 사용자 변수인 LD_LIBRARY_PATH라는 환경 변수가 있는데, 여기에 저 경로를 넣어주어도 된다.
[root@localhost modules]# export LD_LIBRARY_PATH=/tmp/apache-install/openssl-for-httpd/lib
[root@localhost modules]# ldd mod_ssl.so
linux-vdso.so.1 => (0x00007fffa43f3000)
libssl.so.1.0.0 => /tmp/apache-install/openssl-for-httpd/lib/libssl.so.1.0.0 (0x00007fbbac019000)
libcrypto.so.1.0.0 => /tmp/apache-install/openssl-for-httpd/lib/libcrypto.so.1.0.0 (0x00007fbbabbde000)
librt.so.1 => /lib64/librt.so.1 (0x00007fbbab9d2000)
libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007fbbab79b000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fbbab57d000)
libc.so.6 => /lib64/libc.so.6 (0x00007fbbab1e9000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fbbaafe5000)
/lib64/ld-linux-x86-64.so.2 (0x00007fbbac4c5000)
libfreebl3.so => /lib64/libfreebl3.so (0x00007fbbaade1000)
LD_LIBRARY_PATH 를 설정 해 준 후에 ldd를 해 보았더니 이제는 not found가 아니라 잘 찾는다. 이러고 나서 Apache를 실행시키면 잘 된다. 물론 export 명령어로 설정하면 해당 터미널 세션에서만 유효하기 때문에 해당 변수를 ~/.bashrc 나 ~/.bash_profile 에 추가해주거나 service 등록시에는 Environment 등록이 필요할 것이다.
그럼 -fPIC 만 주고 빌드한 아파치는 어떨까?
./config --prefix=/tmp/apache-install/openssl-for-httpd -fPIC
make
make install
#설치 후 아파치 모듈 디렉토리로 이동
[root@localhost modules]# ldd mod_ssl.so
linux-vdso.so.1 => (0x00007ffefe5fc000)
librt.so.1 => /lib64/librt.so.1 (0x00007fca7153f000)
libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007fca71308000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fca710ea000)
libc.so.6 => /lib64/libc.so.6 (0x00007fca70d56000)
/lib64/ld-linux-x86-64.so.2 (0x00007fca71bd6000)
libfreebl3.so => /lib64/libfreebl3.so (0x00007fca70b53000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fca7094e000)
애초에 -fPIC 옵션만 주고 빌드한 경우에는 libssl.so.1.0.0이나 libcrypt.so.1.0.0 에 대한 의존성이 없다. 그러므로 -fPIC 옵션만 주고 빌드한 경우에는 제목과 같은 에러가 발생하지 않는다
만약 -fPIC 옵션도 주지 않고 빌드한 OpenSSL을 이용하여 아파치를 빌드할 경우에는 libssl.a: could not read symbols: Bad value 라는 에러를 발생시킨다. 아마도 아파치가 빌드할 때 OpenSSL 의 정적 라이브러리가 위치독립코드가 아니면 제대로 읽어 들일 수 없는 것 같다.
요약하자면
Cannot load modules/mod_ssl.so into server: libssl.so.1.0.0: cannot open shared object file 에러가 나는 경우는?
- OpenSSL 빌드시 -fPIC shared 옵션을 주고 빌드해서 Apache에서 mod_ssl.so 사용시 의존성을 못 찾는 것이다.
이에 대한 해결책은?
1. 의존성을 못 찾는 .so 파일을 찾아 /lib64 혹은 /usr/lib64로 넣어주거나
2. LD_LIBRARY_PATH 환경변수로 해당 .so 가 있는 경로를 지정해주거나
3. mod_ssl.so 가 해당 .so 에 대해 의존성을 가지지 않도록 OpenSSL을 shared 옵션은 때고 -fPIC 옵션만 붙여서 빌드를 해 주거나
만약 -fPIC 옵션도 안 붙이고 빌드한 OpenSSL로 아파치를 빌드한다면?
- 위치독립코드(PIC)가 아닌 OpenSSL은 아파치가 빌드할 때 참조하면 libssl.a: could not read symbols: Bad value 라는 에러가 난다.
라는 점이다. 그럼 안녕... 다음엔 뭐 올리지..?
'dev > Cloud & Infra' 카테고리의 다른 글
High Availability 를 위한 VRRP와 keepalived (2) - keepalived (1) | 2019.05.02 |
---|---|
High Availability 를 위한 VRRP와 keepalived (1) - VRRP (0) | 2019.04.30 |
Apache httpd 를 컴파일로 설치하기 (0) | 2019.04.09 |
ElasticSearch Heap 사이즈 설정 (0) | 2019.02.03 |
systemd 서비스 unit파일 작성에서 했던 실수 (3) | 2019.02.02 |