Apache: mod_proxy, mod_proxy_html 사용하기 edit

mod_proxy모듈로 내부 백엔드 서버에 Apache를 통해 접속할 수 있고 mod_proxy_html모듈로 그 서버의 내부 소스들(HTML, Javascript, etc)에서 링크된 상대/절대 경로들을 원하는 경로로 바꿀 수 있다.

데비안 Stable 패키지를 설치하거나 소스에서 빌드하여 바로 설치하거나 빌드된 바이너리를 패키징하여 설치할 수 있다.

Download & Build from source for Apache2 using apxs2

$ apt-get install apx2 libxml2-dev

mod_xml2enc

mod_xml2enc모듈은 지원하지 않는 인코딩들을 지원하게 해준다.

$ ./apxs -c -I/usr/include/libxml2 /usr/local/src/mod_xml2enc/mod_xml2enc.c

mod_proxy_html

$ ./apxs -c -I/usr/include/libxml2 -I/usr/local/src/mod_xml2enc /usr/local/src/mod_proxy_html/mod_proxy_html.c

Debian Packaging

각 디렉토리에 .libs라는 디렉토리가 생성되었을 것이다. 필요한것은 .so파일이다.

  1. libapache2-mod-proxy-html_3.1.2_i386디렉토리를 만들고 하위에 DEBIAN디렉토리를 생성한다.
  2. 생성한 DEBIAN디렉토리 안에 control파일을 만든다. 이 파일은 데비안 공식 패키지에서 추출하여 수정해도 된다.

    control:

    Package: libapache2-mod-proxy-html
    Source: mod-proxy-html
    Version: 3.1.2
    Architecture: i386
    Maintainer: me <me@localhost>
    Depends: libc6 (>= 2.7-1), apache2, apache2.2-common, libxml2 (>> 2.5.10)
    Section: web
    Priority: optional
    Description: Apache2 filter module for HTML links rewriting
     mod_proxy_html is an output filter to rewrite HTML links in a proxy
     situation, to ensure that links work for users outside the proxy. It
     serves the same purpose as Apache's ProxyPassReverse directive does for
     HTTP headers, and is an essential component of a reverse proxy.
    
  3. libapache2-mod-proxy-html_3.1.2_i386/usr/lib/apache2/modules/디렉토리들을 생성한다음 컴파일된 mod_proxy_html.so파일을 넣는다.
  4. libapache2-mod-proxy-html_3.1.2_i386/etc/apache2/mods-available/디렉토리들을 생성한다음 생성된 proxy_html.conf파일을 넣어주고 proxy_html.load파일을 만든다.

    proxy_html.load:

    LoadFile /usr/lib/libxml2.so.2
    LoadModule proxy_html_module /usr/lib/apache2/modules/mod_proxy_html.so
    
  5. 상위 디렉토리(../libapache2-mod-proxy-html_3.1.2_i386)에서 패키징한다.
    $ dpkg-deb --build libapache2-mod-proxy-html_3.1.2_i386
  6. 패키징한 libapache2-mod-proxy-html_3.1.2_i386.deb파일을 설치한다.
  7. $ sudo dpkg -i libapache2-mod-proxy-html_3.1.2_i386.deb
  8. mod_xml2enc모듈도 위와같이 패키징하면 된다.

Configuration

모듈 설치 이후 /etc/apache2/mods-enabled/../mods-availalbe/하위에 필요한 모듈과 설정파일들을 심볼링 링크한다.

/etc/apache2/mods-enabled$ sudo ln -s ../mods-available/proxy.load
/etc/apache2/mods-enabled$ sudo ln -s ../mods-available/proxy.conf
/etc/apache2/mods-enabled$ sudo ln -s ../mods-available/proxy_http.load
/etc/apache2/mods-enabled$ sudo ln -s ../mods-available/proxy_html.load
/etc/apache2/mods-enabled$ sudo ln -s ../mods-available/proxy_html.conf
/etc/apache2/mods-enabled$ sudo ln -s ../mods-available/xml2enc.load

데비안 Stable 패키지를 설치하였다면 xml2enc는 현재 squeeze배포판에서 지원하지 않는다.

  • 3.1 이전 버전의 mod_proxy_html에는 SetOutputFilter proxy-html를 사용하며 3.1 버전부터 ProxyHTMLEnable On를 사용한다.
  • 프락시 설정시 끝에 붙는 '/'(슬래시)에 주의.
  • mod_proxy_html모듈은 페이지를 필터링할때 모두 UTF-8로 변경하여 필터링하고 출력 인코딩의 기본값도 UTF-8이며 이것을 변경하려면 ProxyHTMLCharsetOut옵션을 사용해야 하지만 이 옵션을 사용하면 UTF-8 출력을 설정된 인코딩으로 다시 인코딩하기 때문에 오버헤드가 발생한다.
  • ProxyRequests옵션은 포워드 프록시를 켜는 옵션이며 이 옵션을 인증과정없이 켠다면 자신의 서버가 공개프락시가 되는셈이다.
  • RequestHeader unset Accept-Encoding옵션으로 압축되지 않은 응답을 백엔드 서버로부터 전송받아야 mod_proxy_html모듈이 필터링을 할 수 있다.
  • 백엔드 서버의 프로토콜이 HTTPS라면 SSLProxyEngine On옵션을 설정해야 한다.
  • mod_headers 모듈을 추가한다음 RequestHeader옵션으로 Authorization헤더를 추가함으로써 내부 백엔드 서버에 자동으로 로그인 할 수 있다. 혹은 백엔드 서버의 인증 아이디와 비밀번호가 웹서버와 같아도 헤더가 포워딩되서 자동으로 인증된다.
    • RequestHeader set Authorization "Basic BASE64(ID:PASSWORD)"
  • 설정에 대한 더 자세한 사항은 아파치 사이트모듈 사이트를 참고.

ZNC

ProxyRequests off
<Proxy *>
    Order Allow,Deny
    Allow from all
</Proxy>

Redirect /znc https://server.domain/znc/
ProxyPass /znc/ http://localhost:port/
ProxyHTMLURLMap http://localhost:port/ /znc/
<Location /znc>
    ProxyPassReverse /
    SetOutputFilter proxy-html
    ProxyHTMLURLMap / /znc/
    RequestHeader unset Accept-Encoding
    RequestHeader set Authorization "Basic BASE64(ID:PASSWORD)"
</Location>

최신버전의 mod_proxy_html과 mod_xml2enc모듈을 사용하였더니 인코딩이 부분적으로 깨져서 데비안 squeeze의 기본 패키지로 다운그레이드 하였다.

ZNC는 HTTPSock.cpp의 다음과 같은 소스에 의해 Authorization 헤더가 요청으로 들어온다면, 자동으로 아이디와 비밀번호를 BASE64로부터 산출하여 로그인한다. 이로인해 프록시를 설정한 루트도메인에서 다른 아이디와 비밀번호를 설정하였다면 ZNC Webadmin 페이지 접속시 다른 아이디와 비밀번호로 인해 Login Invalid라는 오류메시지가 출력된다.

HTTPSock.cpp:

} else if (sName.Equals("Authorization:")) {
    CString sUnhashed;
    sLine.Token(2).Base64Decode(sUnhashed);
    m_sUser = sUnhashed.Token(0, false, ":");
    m_sPass = sUnhashed.Token(1, true, ":");
    m_bLoggedIn = OnLogin(m_sUser, m_sPass);

Transmission

ProxyRequests off
<Proxy *>
    Order Allow,Deny
    Allow from all
</Proxy>

Redirect /transmission https://server.domain/transmission/web/
ProxyPass /transmission/ http://localhost:port/transmission/
<Location /transmission>
    ProxyPassReverse /
    RequestHeader set Authorization "Basic BASE64(ID:PASSWORD)"
</Location>

IPTIME 공유기

IPTIME 공유기 웹어드민 페이지를 프록시로 아파치를 통해 HTTPS로 접속하여 사용하려고 하였으나, mod_proxy_html사용시 한글 인코딩이 모두 깨지고 페이지가 자바스크립트로 매우 복잡하게 되어있어서 이를 위한 도메인을 따로 독립적으로 사용하여 mod_proxy_html의 필터링 없이 mod_proxy만 사용하여 도메인의 루트경로에서 사용하였다.

인코딩이 깨지는 원인이 공유기 웹어드민 페이지가 응답을 chunked로 주어서 여기에 버그가 있기때문인줄 알았으나 설치된 Apache 데비안 패키지의 버전과 소스를 보니 이미 해당 버그가 패치된 Apache를 사용하고 있었다.(http://grokbase.com/t/apache/dev/074bj0x0kr/mod-proxy-buffering-small-chunks)

특히 mod_proxy_html모듈이 공유기 웹어드민 최상위 경로 접속시 자동으로 /login/login.cgi로 리다이렉션 하는데 이는 HTML의 META태그에 의한것이며 이를 필터링하는데 실패하였다.

독립된 도메인을 사용하면서 크로스 도메인으로 본래의 도메인과 인증없이 연동하여 사용하려고 HTTP Digest Authentication 인증 메쏘드를 사용해 보았지만 대부분의 거의 모든 브라우저가 이를 지원하지 않는다.

Most browsers do not respect the Digest "domain" directive and will not resend credentials for other URIs. As far as I know, Opera is the only browser that honors it. For Opera, the server(s) must respond with the same "realm" string for each URI in the domain list. In other words, if domain="/test /example", the server needs to send "Test Realm - example.com" in the WWW-Authenticate header for both of those URIs. I assume Opera does this because it stores H(A1) instead of the actual password for security. Read into RFC2617 for more on this. Here's my cross-browser solution to this problem: http://travisce.com/arest/

HTTP Digest Authentication 인증 메쏘드에 대한 설정법은 따로 포스팅 한다.

References

0 comments:

Post a Comment

Newer -> <- Older