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

ZNC: Self-written Query Message Relay, Query Buffering, Webadmin Patch edit

ZNC(IRC Bouncer)는 자기자신이 상대방에게 보낸 쿼리 메시지(ACTION 포함)를 클라이언트(ZNC 서버에 접속된 클라이언트)들에게 릴레이 시키지 않고 수신된 쿼리 메시지를 포함하여 버퍼링하지 않는다.

이 패치는 내가 상대방에게 보낸 쿼리 메시지들을 다른 클라이언트들에 릴레이 시켜주고, 버퍼링시켜준다.

이 패치를 적용한 이후 Angel이 ZNC를 사용하고 있고, Angel과 Wiz가 쿼리로 대화를 한다는 상황을 가정하여 이를 ZNC에 접속된 클라이언트들의 입장에서 본다면,

Client 1(현재 사용중인 클라이언트) Client 2
<Angel> hey Wiz?
<Wiz> hey Angel!
* Angel Waves her hand
<Wiz> <***> <Angel> hey Wiz?
<Wiz> hey Angel!
* Wiz <***> * Angel Waves her hand

위와 같이 내가(Angel) 보낸 메시지들을 상대방의 입장에서 릴레이 시키는 이유는 추측하건데 대부분의 IRC 클라이언트 소프트웨어들이 아래와 같은 구문이 서버측에서 전송되어 온다면(ZNC->Client) 내가 나에게 쿼리메시지를 보낸것으로 해석하기 때문이다.

:Angel!user@mask PRIVMSG Wiz :Message

확인된 클라이언트들 중 위와 같은 구문을 재대로(Angel이 Wiz에게 쿼리메시지를 보낸것으로) 해석하는 클라이언트는 weechat이 있고, 재대로 해석하지 못하는 클라이언트들에는 mIRC, AndChat(android)이 있다. 바운서 서버와 클라이언트끼리의 통신은 일반적이지 않기때문에 대부분의 클라이언트가 지원하지 않을것이다.

Webadmin Patch

Webadmin 패치는 ZNC Webadmin을 Apache웹서버에서 프록시 모듈들(mod_proxy_html 포함)을 이용하여 ProxyPass하여 사용할때 /mods/perform 링크로 이동시 맨끝에 /(슬래시)가 없으면 ZNC 웹서버가 mods/perform/ 으로 리다이렉션 시키는데 이때 맨 처음부분에 슬래시가 없어서 생기는 문제를 해결하였다.

원래 경로가 http://host:port/mods/perform 이지만 ProxyPass를 사용하면서 mod_proxy_html으로 http://host/custom-path/mods/perform/ 으로 경로가 변경되어 생기는 문제인것 같다. 이 패치를 하면 본래의 ZNC 웹서버에서 맨 처음에 슬래시가 두개 붙여질 수도 있다.

Downloads

이 패치를 znc 206버전에 자동으로 적용할 수 있고 다른 버전는 수동으로 적용할 수 있다.

diff: https://gist.github.com/2486642

Debian package: znc_0.206-custom_i386.deb (md5: 844074f55a89987692072ead73953bc5)

참고로 데비안 패키지에는 swig, mod_perl, mod_python 와 같은 스크립트 모듈들이 포함되어 있지 않다.

References

Apache: _default_ VirtualHost overlap on port 443 edit

http://www.twopenguins.it/2011/04/apache-_default_-virtualhost-overlap-on-port-443-the-first-has-precedence/

If you have just added another VirtualHost with SSL and Apache is giving to you this error:

[warn] _default_ VirtualHost overlap on port 443, the first has precedence

Probably you miss a

NameVirtualHost *:443

at the top of your httpd-vhosts.conf file.

Debian

데비안에서는 /etc/apache2/ports.conf 파일안에 <IfModule mod_ssl.c></IfModule>사이에 넣어준다.

Get root permission and save a file inside of vim editor edit

http://stackoverflow.com/questions/1005/getting-root-permissions-on-a-file-inside-of-vi
:w !sudo tee %

Debian .deb package file download and extract or view content edit

Download .deb package file

$ aptitude download package-name

View content

$ ar tv package-name.deb

Extract

$ ar xv package-name.deb

ffmpeg audio encoding edit

$ ffmpeg -i in.mp3 -ab 128k out.mp3

Windows suspend cmd edit

rundll32.exe powrprof.dll,SetSuspendState 0,1,0
Newer -> <- Older