dev/Cloud & Infra

Apache HTTP 구동시 Cannot load modules/mod_ssl.so into server: libssl.so.1.0.0: cannot open shared object file

lugi 2019. 4. 26. 05:35

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 라는 에러가 난다.

 

라는 점이다. 그럼 안녕... 다음엔 뭐 올리지..?