Microsoft MVP성태의 닷넷 이야기
글쓴 사람
홈페이지
첨부 파일
 

아파치 서버 2.4를 위한 mod_aspdotnet 마이그레이션

지난 글에서 소개한,

아파치 서버에서 ASP.NET을 실행하는 mod_aspdotnet 모듈
; https://www.sysnet.pe.kr/2/0/11290

mod_aspdotnet 모듈이 현재 개발자의 사정인지 2009년 이래로 더 이상 업데이트가 안되고 있습니다. 그래서, 별로 기능 업데이트를 할 수는 없지만 Apache 2.4에서도 돌아갈 수 있게끔 변경한 버전을 다음의 github에 배포했습니다.

stjeong/mod_aspdotnet
; https://github.com/stjeong/mod_aspdotnet

개인적으로도 사실 시간이 많지 않아 별로 기능 업데이트를 할 생각은 없지만 그래도 누군가 contributor로 참여해 기능을 추가할 수 있는 여지는 남기는 것이 좋을 것 같아 repo를 열었습니다. (관심있으신 분은 참여를! ^^)




우선, 소스코드는 다음의 마지막 snapshot을 이용했습니다.

mod-aspdotnet-code-222.zip
; https://sourceforge.net/p/mod-aspdotnet/code/HEAD/tarball

Apache 2.4 지원을 위해 xampp를 이용해 설치한 아파치 서버의 include, lib 폴더를 사용했습니다.

나머지 작업은 이제 Apache 2.4로 소스코드를 마이그레이션하는 건데요. 다음의 문서에 따라 은근히 변한 것이 있습니다.

API Changes in Apache HTTP Server 2.4 since 2.2
; https://httpd.apache.org/docs/2.4/developer/new_api_2_4.html

우선, remote_ip와 remote_addr 필드가 변경되었습니다.

conn_rec->remote_ip and conn_rec->remote_addr
  ==> conn_rec->client_ip and conn_rec->client_addr

또한, ap_log_... 관련 함수에 3번째 인자로 module_index가 추가되었습니다.

#ifdef DOXYGEN
AP_DECLARE(void) ap_log_rerror(const char *file, int line, int module_index,
                               int level, apr_status_t status,
                               const request_rec *r, const char *fmt, ...);
#else
#ifdef AP_HAVE_C99
/* need additional step to expand APLOG_MARK first */
#define ap_log_rerror(...) ap_log_rerror__(__VA_ARGS__)
#define ap_log_rerror__(file, line, mi, level, status, r, ...)              \
    do { if (APLOG_R_MODULE_IS_LEVEL(r, mi, level))                         \
             ap_log_rerror_(file, line, mi, level, status, r, __VA_ARGS__); \
    } while(0)
#else
#define ap_log_rerror ap_log_rerror_
#endif
AP_DECLARE(void) ap_log_rerror_(const char *file, int line, int module_index,
                                int level, apr_status_t status,
                                const request_rec *r, const char *fmt, ...)
                                __attribute__((format(printf,7,8)));
#endif

아파치 모듈 인덱스는 소스 코드에 AP_DECLARE_MODULE를 해주면 된다고 해서 포함시켰습니다.

#ifdef AP_DECLARE_MODULE
AP_DECLARE_MODULE(mod_aspdotnet);
#endif

그 외에 다음과 같은 컴파일 오류가 발생했는데요.

Error C2079 'apr_sockaddr_t::sin6' uses undefined struct 'sockaddr_in6' mod_aspdotnet   e:\git_clone\mod_aspdotnet\trunk\apache2_4_include\apr_network_io.h 269 

mod_aspdotnet.cpp 파일에 ws2tcpip 헤더 파일을 추가하는 것으로 해결했습니다.

#include <ws2tcpip.h>

위의 작업까지만 해주면 일단 Apache 2.4 지원을 위한 마이그레이션은 대충 완료됩니다.




문제는, Visual Studio 2017에서 빌드하는 경우 C++/CLI 프로젝트의 어셈블리가 .NET 4.0에 의존성을 갖는다는 점입니다. 이 때문에 Apache.Web.dll이 .NET 2.0 GAC가 아니라 .NET 4.0 GAC에 등록됩니다.

따라서, Apache 2.4에서 .NET 2.0~3.5용의 ASP.NET을 구동하는 경우 crash가 발생하는데 디버깅을 해 보니 다음의 라인에서 발생합니다.

static apr_status_t asp_net_stop(void *dummy)
{
    global_conf->pHostFactory->Destroy(); // pHostFactory == nullptr

    if (global_conf->pHostFactory) {

        global_conf->pHostFactory->Release();
    }
    if (global_conf->pCorRuntime) {
        global_conf->pCorRuntime->Stop();
        global_conf->pCorRuntime->Release();
    }

    // ...[생략]...
}

이 상태에서 아파치 에러 로그(\xampp\apache\logs)는 다음과 같이 보여줍니다.

[Wed Aug 30 17:14:16.117970 2017] [core:notice] [pid 16020:tid 544] mod_aspdotnet: CorBindToRuntimeEx has loaded version v2.0.50727 of the .NET CLR engine.
ed Aug 30 17:16:00.679504 2017] [core:error] [pid 1764:tid 584] (-2146304894)Unknown error: mod_aspdotnet: Could not create the .NET interface for the Apache.Web.HostFactory.
[Wed Aug 30 17:16:00.679504 2017] [core:crit] [pid 1764:tid 584] (-2146304894)Unknown error: mod_aspdotnet: Failed to start Asp.Net Apache.Web host factory
AH00016: Configuration Failed

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Apache.Web, Version=2.4.0.2199, Culture=neutral, PublicKeyToken=9b9b842f49b86351' or one of its dependencies. The system cannot find the file specified.
File name: 'Apache.Web, Version=2.4.0.2199, Culture=neutral, PublicKeyToken=9b9b842f49b86351'
   at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
   at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
   at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Activator.CreateInstance(String assemblyName, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, Evidence securityInfo, StackCrawlMark& stackMark)
   at System.Activator.CreateInstance(String assemblyName, String typeName)
   at System.AppDomain.CreateInstance(String assemblyName, String typeName)

위의 오류를 해결하기 위해 CLR 4를 로드하도록 변경했고 하위 호환성으로 .NET 2.0~3.5용의 ASP.NET이 동작하게 되어 있습니다.

단지, 현재 .NET 2.0~3.5만 설치된 환경에서 ASP.NET을 Apache 2.4에서 구동하는 방법은 없습니다. 만약 원한다면 Visual Studio 2008 설치 후 소스코드를 빌드하시면 됩니다.




위의 작업을 모두 마치고 나면 바이너리에 대한 마이그레이션은 전부 끝나지만 아쉽게도 httpd.conf에 대한 변경 사항이 Apache 2.4에서 달라진 것이 있어 기존의 mod_aspdotnet 사용 방법의 문서대로 하면 다음과 같은 오류가 발생합니다.

[Thu Aug 31 11:22:44.772053 2017] [authz_core:error] [pid 22704:tid 2724] [client ::1:63160] AH01630: client denied by server configuration: C:/temp/xampp/aspdocs/test.aspx

웹 브라우저 화면에는 이런 메시지가 뜹니다.

접근이 거부됨!

요청한 객체에 접근할 수 있는 권한이 없습니다. 읽기 보호가 되어 있거나 웹서버가 읽을 수 없도록 되어 있습니다. 

만약 이것이 서버 오류라고 생각되면, 웹 관리자에게 연락하시기 바랍니다. 

Error 403

localhost
Apache/2.4.27 (Win32) OpenSSL/1.0.2l PHP/7.1.8 mod_aspdotnet/2.4 

문제는 다음의 설정이었는데,

    <Directory "c:/temp/xampp/aspdocs">
    Options FollowSymlinks ExecCGI
    Order allow,deny
    Allow from all
    DirectoryIndex index.htm index.aspx index.asp
    </Directory>

아래의 문서에 보면 2.4에서 바뀌었다고 합니다.

Client denied by server configuration
; https://wiki.apache.org/httpd/ClientDeniedByServerConfiguration

따라서, mod_aspdotnet for Apache 2.4의 경우 다음과 같은 식으로 .conf 파일을 변경해야 합니다.

LoadModule aspdotnet_module modules/mod_aspdotnet.so
AddHandler asp.net asax ascx ashx asmx aspx axd config cs csproj licx rem resources resx soap vb vbproj vsdisco webinfo

<IfModule mod_aspdotnet.cpp>
    AspNetMount /aspdocs "c:/temp/xampp/aspdocs"
    Alias /aspdocs "c:/temp/xampp/aspdocs"

    <Directory "c:/temp/xampp/aspdocs">
Require all granted
    </Directory>

    AliasMatch /aspnet_client/system_web/(\d+)_(\d+)_(\d+)_(\d+)/(.*) "C:/Windows/Microsoft.NET/Framework/v$1.$2.$3/ASP.NETClientFiles/$4"

    <Directory "C:/Windows/Microsoft.NET/Framework/v*/ASP.NETClientFiles">
    Options FollowSymlinks
    Order allow,deny
    Allow from all
    </Directory>

</IfModule>




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]





[최초 등록일: ]
[최종 수정일: 9/4/2017 ]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer@outlook.com

비밀번호

댓글 쓴 사람
 




... 31  32  33  34  35  36  37  38  39  40  41  [42]  43  44  45  ...
NoWriterDateCnt.TitleFile(s)
11230정성태6/28/20174074제니퍼 .NET: 26. 제니퍼 닷넷 적용 사례 (6) - 잦은 Recycle 문제
11229정성태6/27/20174137오류 유형: 402. Windows Server Backup 관리 콘솔이 없어진 경우
11228정성태6/26/20174345개발 환경 구성: 320. Visual Basic .NET 프로젝트에서 내장 Manifest 자원을 EXE 파일로부터 제거하는 방법파일 다운로드1
11227정성태6/19/20178664개발 환경 구성: 319. windbg에서 python 스크립트 실행하는 방법 - pykd [5]
11226정성태6/19/20174659오류 유형: 401. Microsoft Edge를 실행했는데 입력 반응이 없는 경우
11225정성태6/19/20174506오류 유형: 400. Outlook - The required file ExSec32.dll cannot be found in your path. Install Microsoft Outlook again.
11224정성태6/13/20174424.NET Framework: 661. Json.NET의 DeserializeObject 수행 시 속성 이름을 동적으로 바꾸는 방법파일 다운로드1
11223정성태8/2/20174008개발 환경 구성: 318. WCF Service Application과 WCFTestClient.exe
11222정성태6/10/20175462오류 유형: 399. WCF - A property with the name 'UriTemplateMatchResults' already exists.파일 다운로드1
11221정성태6/10/20174277오류 유형: 398. Fakes - Assembly 'Jennifer5.Fakes' with identity '[...].Fakes, [...]' uses '[...]' which has a higher version than referenced assembly '[...]' with identity '[...]'
11220정성태6/10/20175779.NET Framework: 660. Shallow Copy와 Deep Copy파일 다운로드2
11219정성태6/7/20174844.NET Framework: 659. 닷넷 - TypeForwardedFrom / TypeForwardedTo 특성의 사용법
11218정성태6/1/20176298개발 환경 구성: 317. Hyper-V 내의 VM에서 다시 Hyper-V를 설치: Nested Virtualization
11217정성태6/1/20174347오류 유형: 397. initerrlog: Could not open error log file 'C:\...\MSSQL12.MSSQLSERVER\MSSQL\Log\ERRORLOG'
11216정성태6/1/20174999오류 유형: 396. Activation context generation failed
11215정성태6/1/20175303오류 유형: 395. 관리 콘솔을 실행하면 "This app has been blocked for your protection" 오류 발생 [1]
11214정성태6/1/20174680오류 유형: 394. MSDTC 서비스 시작 시 -1073737712(0xC0001010) 오류와 함께 종료되는 문제 [1]
11213정성태5/26/20175829오류 유형: 393. TFS - The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
11212정성태5/26/20176941오류 유형: 392. Windows Server 2016에 KB4019472 업데이트가 실패하는 경우
11211정성태5/26/20174657오류 유형: 391. BeginInvoke에 전달한 람다 함수에 CS1660 에러가 발생하는 경우
11210정성태5/25/20174677기타: 65. ActiveX 없는 전자 메일에 사용된 "개인정보 보호를 위해 암호화된 보안메일"의 암호화 방법
11209정성태5/25/201716171Windows: 143. Windows 10의 Recovery 파티션을 삭제 및 새로 생성하는 방법 [6]
11208정성태5/25/20177326오류 유형: 390. diskpart의 set id 명령어에서 "The specified type is not in the correct format." 오류 발생
11207정성태5/24/20177986Windows: 142. Windows 10의 복구 콘솔로 부팅하는 방법
11206정성태5/24/20175712오류 유형: 389. DISM.exe - The specified image in the specified wim is already mounted for read/write access.
11205정성태5/24/20174667.NET Framework: 658. C#의 tail call 구현은?
... 31  32  33  34  35  36  37  38  39  40  41  [42]  43  44  45  ...