30분만 투자하면 사용하는 API 문서 검색 엔진, Doxygen 외부 검색 설정하기

🧐 | 2023-06-22

안녕하세요, 넷마블 기술관리실 기술관리팀 이중민입니다.

개발 문서를 효율적으로 작성하려고 고민하다 보면 여러 가지 방법을 떠올리기 마련입니다. 그중 소스 코드 기반으로 문서를 자동 생성하는 종류에는 API 문서가 있습니다. API 문서를 자동 문서화해주는 도구는 JavaDoc, docfx, Sphinx, Doxygen 등 많습니다. 요즘은 프로그래밍 언어별로 지원하는 도구가 하나 이상은 꼭 있다고 말할 정도로 굉장히 다양합니다.

제 경우 실제 개발 문서 관련 업무를 맡다 보면 자주 접하는 프로그래밍 언어로 C++와 C#이 있습니다. 이때 C++의 API 문서 생성은 Doxygen을 사용합니다(참고로 Doxygen은 C++뿐만 아니라 C, Java, Python 등 다양한 언어를 지원합니다). 그런데 별도의 문서 변환 과정없이 Doxygen에서 생성한 API 문서 그대로를 사용하려다 보니 기본으로 제공하는 서버 기반 문서 검색 기능(SERVER_BASED_SEARCH)에 좀 아쉬움이 있었습니다. Doxygen은 단어 단위로 검색을 수행할 때 단어 사이의 공백을 단어 구분자로 처리하기 때문에 검색어에 공백이 포함되었거나 숫자와 공백이 있는 경우 정확한 검색 결과를 얻기 어렵기 때문입니다.

그래서 Doxygen 1.8.3 이후로 외부 검색 기능을 지원하려고 EXTERNAL_SEARCH라는 옵션이 추가되었습니다. 이는 기존 문서에 Xapian이라는 오픈 소스 검색 엔진을 사용할 수 있도록 합니다. 그리고 (아마 하위 호환성을 염두에 두고) CGI 바이너리 파일을 제공합니다.

그런데 정작 Doxygen에서는 External Indexing and Searching이라는 문서를 제공하지만 구체적인 WAS 설정 방법까지는 제공하지 않습니다.

또한 WAS에 따라서는 CGI 바이너리 파일 실행을 지원하는 방법이 다르죠. 이 부분을 깔끔하게 정리하는 자료는 생각보다 찾기 어려웠습니다. 그래서 이번에는 아파치 HTTP 서버와 NGINX를 이용해 Doxygen의 외부 검색 기능을 설정하는 방법 몇 가지를 정리해 보았습니다.

이 문서를 작성했을 때의 기준 환경은 다음과 같습니다.

  • 우분투 리눅스 v22.02.04.2
  • NGINX v1.18.0
  • 아파치 HTTP 서버 v2.4.52

아파치 HTTP 서버에 CGI 설정하기

아파치 HTTP 서버를 사용하는 분이라면 CGI를 사용할 수 있도록 설정합니다. 먼저 CGI 관련 파일을 실행시킬 디렉터리를 하나 정합니다. 필요하면 직접 생성해도 좋습니다. 아파치 HTTP 서버의 기본 웹 경로 위치는 /var/www/html/입니다. 그럼 /var/www/cgi-bin/ 정도로 설정하는 것도 좋습니다. 여기에서는 /var/www/cgi-bin/으로 정했다고 가정하고 진행하겠습니다.

아파치 기본 설정 파일(/etc/nginx/apache2.conf 혹은 [Apache Dir]/conf/httpd.conf)의 맨 아래에 다음과 같은 설정을 입력합니다.

# Adding capaility to run CGI-scripts

# 특정 도메인이나 IP를 설정해야 한다면 localhost 대신 입력하기 바랍니다.
ServerName localhost 

ScriptAlias /cgi-bin/ /var/www/cgi-bin/

Options +ExecCGI
AddHandler cgi-script .cgi

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

ServerName localhost는 서버 이름이 localhost라는 뜻이고 특정 도메인이나 IP를 설정해야 한다면 바꿔주면 됩니다.

ScriptAlias /cgi-bin/ /var/www/cgi-bin/를 이용해 cgi-bin 주소를 /var/www/cgi-bin으로 설정한다는 뜻입니다.

Options +ExecCGI는 CGI 스크립트 파일을 실행하겠다는 것입니다.

AddHandler cgi-script .cgi는 실행할 CGI 스크립트 파일 확장명을 정합니다. 여기에서는 .cgi만 설정했는데 Perl 파일인 .pl이나 파이썬 파일인 .py를 입력해도 됩니다.

다음으로 아파치 설정 파일 중 serve-cgi-bin.conf 파일의 설정 일부를 수정해야 합니다

컴파일 설치라면 httpd.conf에 해당 내용을 그대로 설정합니다.

<IfModule mod_alias.c>
        # 중간 생략
        <IfDefine ENABLE_USR_LIB_CGI_BIN>
                # 기존 설정 주석 처리
                # ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
                # <Directory "/usr/lib/cgi-bin">
                #       AllowOverride None
                #       Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
                #       Require all granted
                #</Directory>

                # 이 부분은 새로 설정
                # cgi-bin config
                ScriptAlias /cgi-bin/ /var/www/cgi-bin/
                <Directory "/var/www/cgi-bin/">
                        AllowOverride None
                        Options +ExecCGI
                </Directory>
        </IfDefine>
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

<Directory "var/www/cgi-bin/">는 /var/www/cgi-bin/ 디렉터리에 CGI 설정을 하겠다는 뜻입니다.

AllowOverride None은 어떻게 접근을 허락할 것인가에 대한 설정입니다. NoneAccessFileName에 지정된 파일을 접근 인증 파일로 인식하지 않습니다. 즉, 새로운 접근 방식을 오버라이드하지 않는다는 뜻입니다.

Options +ExecCGI는 CGI 스크립트 파일을 실행하겠다는 것입니다.

설정 변경이 끝나면 아파치 HTTP 서버를 재시작합니다.

FcgiWrap로 NGINX에서 FastCGI 설정하기

최근 WAS 중 가장 점유율이 높은 NGINX는 전통적인 CGI 대신 FastCGI를 지원합니다. 이때 가장 단순하게 CGI 바이너리 파일을 실행하려면 FcgiWrap이라는 패키지를 이용하는 것이 좋습니다.

다음 명령을 실행해 FcgiWrap 패키지를 설치합니다.

$ sudo apt install fcgiwrap

설치가 완료되었다면 다음 명령을 실행해 해당 서비스가 잘 동작하는지 확인합니다.

$ systemctl status fcgiwrap.service

# 실행 결과의 Active 항목이 active여야 함

$ systemctl status fcgiwrap.socket

# 실행 결과의 Active 항목이 active여야 함

$ systemctl is-enabled fcgiwrap.service 
indirect
$ systemctl is-enabled fcgiwrap.socket 
enable

이제 FcgiWrap 패키지를 설치했을 때 포함된 기본 설정 파일을 /etc/nginx에 복사해야 합니다. 다음 명령을 실행합니다.

$ sudo cp /usr/share/doc/fcgiwrap/examples/nginx.conf /etc/nginx/fcgiwrap.conf

다음으로 fcgiwrap.conf 파일의 설정을 변경해야 합니다. 다음처럼 설정을 변경합니다.

# Include this file on your nginx.conf to support debian cgi-bin scripts using
# fcgiwrap

# ~*.cgi는 웹 서버와 관련된 범위 어디에서든 .cgi 파일을 실행하는 설정
location ~*.cgi$ {
  # Disable gzip (it makes scripts feel slower since they have to complete
  # before getting gzipped)
  gzip off;

  # Set the root to /usr/lib (inside this location this means that we are
  # giving access to the files under /usr/lib/cgi-bin)
  root  /var/www/html

  # Fastcgi socket
  fastcgi_pass  unix:/var/run/fcgiwrap.socket;

  # Fastcgi parameters, include the standard ones
  include /etc/nginx/fastcgi_params;

  # Adjust non standard parameters (SCRIPT_FILENAME)
  # /var/www/html는 nginx 기본 웹 루트 디렉터리 설정임.
  fastcgi_param SCRIPT_FILENAME  /var/www/html$fastcgi_script_name;
}

NGINX location 구문의 ~*는 대소문자를 구분하지 않으면서 정규표현식과 일치하는 모든 문자열을 의미합니다. *.cgi는 .cgi로 끝나는 모든 문자열을 의미합니다. 따라서 location ~*.cgi$는 대소문자를 구분하지 않는 모든 문자열 중 .cgi로 끝나는 문자열을 파일을 지정하는 것입니다.

fastcgi_pass unix:/var/run/fcgiwrap.socket;는 fcgiwrap이 실행되는 소켓 파일을 지정하는 것입니다. fcgiwrap은 기본적으로 /var/run/fcgiwrap.socket 파일을 사용합니다.

fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;는 fcgiwrap이 실행할 CGI 스크립트 파일의 경로를 지정하는 것입니다. $fastcgi_script_name은 NGINX가 요청한 CGI 스크립트 파일의 경로를 의미합니다. 따라서 이 설정은 /var/www/html/ 이후에 있는 스크립트 파일 경로를 지정하는 것입니다.

nginx.conf(혹은 /etc/nginx/sites-available/default)에 방금 수정한 fcgiwrap.conf 파일의 설정을 가져올 수 있도록 해야 합니다. 다음 설정을 참고해 include fcgiwrap.conf;를 적당한 위치에 삽입합니다.

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        # SSL configuration
        # 주석 생략

        root /var/www/html;

        # Add index.php to the list if you are using PHP
        index index.html index.htm index.nginx-debian.html;

        server_name _;

        # fcgiwrap.conf의 설정 추가
        include fcgiwrap.conf;

        # 이후 생략
}

NGINX의 서버 설정에 따라서 서버 운영에 문제가 되지 않는 상황에 CGI가 실행되도록 include fcgiwrap.conf; 설정 위치는 잘 선택해야 합니다.

설정이 완료되었다면 NGINX를 재시작합니다.

아파치 HTTP 서버로 NGINX에 리버스 프록시 설정하기

만약 FcgiWrap을 사용할 수 없다면 아파치 HTTP 서버에서 CGI를 설정한 후 NGINX에 리버스 프록시를 설정해 NGINX 기반의 서버에서 CGI 기능을 사용하도록 설정할 수 있습니다.

먼저 아파치 HTTP 서버에 CGI 설정하기를 참고해 아파치 HTTP 서버에 CGI 설정을 해둡니다. 그리고 NGINX를 설치하기 전 다음 설정 내용을 참고해 /etc/apache2/sites-available/000-default.conf (혹은 httpd.conf)를 열고 아파치 HTTP 서버의 가상 호스트 포트를 변경합니다.

# 변경 전

<VirtualHost *:80>

# 변경 후

<VirtualHost *:8080>

포트 번호는 사용자의 환경에 따라 임의로 변경해도 괜찮습니다.

HTTPS를 사용한다면 /etc/apache2/ports.conf(컴파일 설치라면 httpd.conf)와 의 설정도 변경해줍니다. 다음과 같이 수정하거나 추가해 줍니다.

# 주석 생략

Listen 8080  # 기본 80 이외의 임의의 포트 설정

<IfModule ssl_module>
        Listen 445  # 기본 443 이외의 임의의 포트 설정
</IfModule>

<IfModule mod_gnutls.c>
        Listen 445  # 기본 443 이외의 임의의 포트 설정
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

그리고 NGINX가 정상적으로 동작하는지 확인한 후 /etc/nginx/sites-available/default(컴파일 설치라면 nginx.conf)에 다음 설정을 추가합니다.

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        # 중간 생략

        server_name _;

        # 리버스 프록시를 위한 location 설정
        location /var/www/cgi-bin/ {
                proxy_pass http://localhost:8080/cgi-bin/;
        }

        # 위가 추가 설정 끝

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
        }

        # 이후 주석 생략
}

마지막으로 WAS 각각을 재실행한 후 웹 브라우저에서 http://localhost와 https://localhost/cgi-bin/doxysearch.cgi?test에 접속해봅니다.

localhost에 접속했을 때 nginx 시작 페이지가 등장하고 /cgi-bin/doxysearch.cgi?test에 접속했을 때 Test Successful이라는 메시지가 나오면 리버스 프록시 설정이 된 것입니다.

Doxygen 외부 검색 설정하기

마지막으로 Doxygen의 기본 외부 검색 설정을 살펴봅니다. 이 설정에는 Doxygen 리눅스용 배포 파일 안에 있는 doxysearch.cgi라는 CGI 바이너리 파일이 필요합니다.

다음 명령을 실행해 적당한 디렉터리를 하나 생성하고 Doxygen 리눅스용 배포 파일을 다운로드합니다. 여기에서는 ~/doxygen/이라는 디렉터리를 만들고 다운로드 및 압축을 해제하겠습니다.

$ sudo mkdir doxygen/
$ cd doxygen/
$ wget https://github.com/doxygen/doxygen/releases/download/Release_1_9_7/doxygen-1.9.7.linux.bin.tar.gz
$ tar -xzvf doxygen-1.9.7.linux.bin.tar.gz

우리가 원하는 doxysearch.cgi 파일은 ~/doxygen/doxygen-1.9.7/bin/ 디렉터리에 있습니다. 나중에 여러분이 설정한 cgi-bin 디렉터리에 해당 파일을 복사해야 합니다.

최신 버전 혹은 특정 버전의 바이너리 파일을 다운로드할 때는 https://github.com/doxygen/doxygen/releases/에 접속해 버전을 확인한 후 doxygen-x.x.x.linux.bin.tar.gz 파일을 다운로드하기 바랍니다.

Doxygen에서 외부 검색과 doxysearch.cgi를 사용하려면 다음 사항을 꼭 설정해야 합니다. 첫 번째로 Doxygen GUI([Expert] → [HTML] 설정을 확인합니다)나 Doxyfile 설정에서 다음 항목을 꼭 설정해 API 문서를 생성합니다.

  • SEARCHENGINE = YES
  • SEVER_BASED_SEARCH = YES
  • EXTERNAL_SEARCH = YES
  • SEARCHENGINE_URL = “”
  • SEARCHDATA_FILE = searchdata.xml

두 번째로 searchdata.xml이 생성된 후 다음 명령을 실행해 새로 생성한 API 문서의 root 디렉터리에 doxysearch.db라는 디렉터리를 생성해야 합니다. 이때 WAS로 배포하려는 문서의 root 디렉터리에 doxysearch.cgi와 doxysearch.db라는 디렉터리가 있어야 합니다.

# Windows PowerShell
PS > & 'C:\Program Files\doxygen\bin\doxyindexer.exe' -o <새로 생성한 API 문서의 root 디렉터리> <searchdata.xml가 위치한 디렉터리/searchdata.xml>

# Unix Shell
$ doxyindexer -o <새로 생성한 API 문서의 root 디렉터리> <searchdata.xml가 위치한 디렉터리/searchdata.xml>

searchdata.xml를 생성할 때는 숫자 코드나 특정 키워드를 생성할 때 공백(예: c l a s s, 1 2 3 4 5 6 7 8)을 포함해 생성하는 경우가 있습니다. 정규표현식 등을 이용해 공백을 줄여주어야 합니다.

다음으로 Xapian 검색 엔진이 정상 동작하도록 Xapian 런타임 라이브러리를 포함하는 libxapian30과 Xapian 개발 라이브러리 및 헤더를 포함하는 libxapian-dev 패키지를 설치합니다.

$ sudo add-apt-repository universe
$ sudo apt update
$ sudo apt install --reinstall libxapian30 libxapian-dev

설치가 끝났다면 WAS를 재실행합니다. 그리고 다음 명령을 실행해 다운로드해둔 doxysearch.cgi 파일을 /var/www/cgi-bin/ 디렉터리로 복사합니다.

$ sudo cp ~/doxygen/doxygen-1.9.7/bin/doxysearch.cgi /var/www/html/doxysearch.cgi

복사가 완료되면 웹 브라우저에서 http://localhost/doxysearch.cgi?test를 입력해 Test successful이라는 메시지가 나타난다면 정상적으로 CGI가 동작하는 것입니다.

빠르게 검색 기능을 적용해야 한다면 좋은 선택입니다

Doxygen의 외부 검색 기능은 간단하게 구현할 수 있고, Doxygen의 특성에 맞는 검색 기능을 구현하기에 좋습니다. 빠르게 API 문서를 배포해야 하는 상황에서는 매우 유용합니다. 또한 실제 API 문서를 배포하기 전 필요한 내용이 포함되었는지를 확인하는 등에도 유용하게 사용할 수 있다는 장점도 있습니다. 필요한 분이라면 이 글의 내용을 토대로 외부 검색 기능을 빠르게 적용해 보기 바랍니다.

개인적으로 테크니컬 라이터의 역할이 단순히 좋은 문서를 작성하거나 편집하는 직군에 머물러서는 안 된다는 생각이 있습니다. 개발 문서의 형식을 이해하고 이를 상황에 맞게 변환하거나 개발 문서를 배포하는 다양한 환경에 대한 기술적인 이해는 꼭 필요하다고 생각합니다. 그런 의미에서 Doxygen의 검색 기능 적용 방법을 직접 찾아보고 정리하는 것은 매우 흥미 있었습니다. 앞으로도 이렇게 개발 문서와 관련된 도구나 기능과 관련된 내용이라면 적극 소개할 수 있도록 노력하겠다는 다짐과 함께 글을 마칩니다.