[Python] wsgi를 이용해서 apache에 웹 서버를 구축하는 방법


Development note/Python  2020. 2. 21. 09:00

안녕하세요. 명월입니다.


이 글은 Python의 wsgi를 이용해서 apache에 웹 서버를 구축하는 방법에 대한 글입니다.


wsgi란 파이썬에서는 웹 서버가 필요없이 http.server나 bottle 모듈, Flask 모듈을 사용하면 웹 서버를 구축할 수 있습니다.

그러나 bottle 모듈이나 Flask 모듈은 아무래도 컴파일된 web server도 아니고 웹 서버만을 위한 모듈이 아니기 때문에 성능이나 보안에 취약할 수가 있습니다.


그래서 apache 웹 서버라는 강력한 웹 서버에 게이트웨이 인터페이스(Web Server Gateway Interface)를 만들어 python을 웹 서버에서 동작할 수 있게끔 만드는 모듈입니다.

예전에 제가 CGI를 통해서 apache에 python을 기동한 적이 있습니다.

링크 - [Python] Apache cgi에서 python을 사용하는 방법

위 방법은 간단한 python 모듈을 사용하거나 값이 필요할 때 사용하기는 좋습니다. (별도의 모듈 설치가 필요없이 Python을 사용할 수 있기 때문에)

그러나 사양이 조금 복잡하거나 단일 페이지의 결과가 아닌 페이지 별로 분산된 처리를 해야한다면 wsgi를 사용하는 것이 좋습니다.


wsgi를 사용하기 위해서는 bottle이나 Flask 라는 Python 웹 모듈을 이용해야 합니다.

이전에 저는 bottle 웹 모듈에 대해 설명한 적이 있습니다. 참고해 주세요.

링크 - [Python] 웹 서버를 구축하는 방법(bottle 모듈)


그럼 먼저 wsgi를 사용하기 위해서는 wsgi 모듈을 설치해야 합니다.

pip install mod_wsgi

저는 설치하는 중간에 에러가 났습니다. 내용은 apache 서버 경로가 설정되어 있지 않다는 군요.

set MOD_WSGI_APACHE_ROOTDIR=D:\apache

아파치 경로를 설정하고 다시 설치합니다.

저는 설치 중에 또 에러가 발생했습니다. vc14++ build tool이 없다고 없다는 에러입니다. Visual studio가 설치되어 있는데도 build tool이 없다네요...

Visual studio가 설치되어 있지 않는 분은 아래의 링크에서 community 버젼을 다운로드 받습니다.

link - https://visualstudio.microsoft.com/ko/downloads/

저는 이미 설치되어 있기 때문에 install를 실행하겠습니다

다시 설치를 시도합니다.

설치가 완료되었습니다.(그래도 안되시는 분은 아래의 링크에서 build tool를 설치하면 됩니다.)

link - https://www.microsoft.com/ko-KR/download/confirmation.aspx?id=48159


이제 mod_wsgi-express를 사용할 수 있는데 그 명령어로 conf 설정 정보를 얻습니다.

mod_wsgi-express module-config

이 세 줄을 그대로 apache의 httpd.conf파일에 설정합니다.

설정되었으면 host 설정을 합니다.

...
<VirtualHost *:80>
  ServerName localhost
  WSGIScriptAlias / D:/Python/blog/app.wsgi
  <Directory D:/Python/blog/>
    Require all granted
  </Directory>
</VirtualHost>
..

저는 예전에 bottle파이릉ㄹ Python/blog의 경로에서 작업했습니다.

그리고 그 경로에 app.wsgi 파일을 생성합니다.

# 웹 document root 설정
import os;
import sys;
# 웹 모듈
import bottle;
os.chdir(os.path.dirname(__file__));

# module path 입력
sys.path.insert(0, "D:/Python/blog")
# 예전에 bottle 모듈로 작성한 python 파일 import
import main;
# 서버 기동
application = bottle.default_app();

그리고 예전에 작성한 python 파일의 가장 하단의 run를 주석 처리합니다.

# ajax의 응답으로 json처리를 하기 위해 json 모듈을 사용
import json;
# bottle 모듈
from bottle import route, run, error, static_file, template, request, response, view;
 
# favicon.ico가 아래의 index함수로 들어가는 것을 막기 위해.
# re:로 설정하면 정규식으로 검색할 수 있다. 해당 조건이 참이면 send_inmage의 함수를 호출한다.
@route('/<filename:re:.*.ico>')
def send_image(filename):
  # 파일에서 읽어와서 응답한다.
  return static_file(filename, root='d:\\python\\blog', mimetype='image/ico')

# route는 브라우저의 요청에 응답하는 데코레이터
# 「/」에서 「/test」를 사용하면 name은 test로 설정
@route('/', method='GET')
@route('/<name>', method='GET')
# view는 같은 디렉토리 상의 index.tpl 파일을 읽어온다.
@view('index')
# 「/」로 오면 name값을 'Guest'로 설정한다.
def index(name='Guest'):
  # Query string의 값은 request.query로 받을 수 있다. setClear의 값이 1이면 쿠키를 삭제한다.
  if request.query.setClear == '1':
    name = 'Guest';
    # 쿠키 Name값을 삭제한다. expires를 0으로 설정.
    response.set_cookie("Name", '', expires=0);
  else:
    # 값이 Guest가 아니면 쿠키에 Name을 설정한다.
    if name != 'Guest':
      # 쿠키를 set_cookie로도 설정이 가능하지만 header를 설정하는 방법에 대한 예제이다.
      response.set_header('Set-Cookie', f'Name={name}');
      # 기존의 header값에서 추가할 때 사용한다.
      #response.add_header('Set-Cookie', f'next={name}');
    # name값이 Guest일 경우,
    if name == 'Guest':
      # 쿠키로부터 Name을 받아와서 설정한다.
      buf = request.get_cookie("Name");
      # 쿠키값이 설정되어 있으면
      if buf is not None:
        # name을 바꾼다.
        name = buf;
  # 값을 딕셔너리 값으로 넘긴다.
  return dict(name=name);

@route('/ajax', method='POST')
def ajax():
  # request.forms은 폼 데이터 이다. ajax로 넘어온 param의 값을 받아서 json으로 만든다.
  str = json.dumps({'param':request.forms.get('param')});
  # string 타입을 리턴한다.
  return str;
# js폴더안의 자바스크립트 파일을 보낸다.
@route('/js/<filename:path>')
def download(filename):
  # javascript 파일을 보낸다.
  return static_file(filename, root="d:\\python\\blog", download=False);

# 위의 모든 조건에 맞지 않고 404가 에러가 발생하면 호출된다.  
@error(404)
def error404(error):
  # 에러가 발생하면 표시하는 메시지
  return 'Nothing here, sorry';
 
# 위 route 설정이 완료되면 실제 서버를 기동한다. (apache에서 기동하기 때문에 필요없다. 주석처리합니다.)
# run(host='localhost', port=80, debug=True);
<html>
  <head><title>python bottle test</title></head>
  <body>
    <!-- download함수가 호출된다.-->
    <script src="/js/jquery-3.4.1.min.js"></script>
    <!-- python 소스에서 받아온 값이다. -->
    Name : {{name}}
    <br />
    <textarea></textarea>
    <script>
        // ajax 함수가 호출된다.
        $(function(){
            var ajax = $.ajax({
                type: "POST",
                url: "/ajax",
                dataType: 'json',
                data: {'param':'hello world'}
            });
            ajax.done(function(data){
                $("textarea").html(data.param);
            });
        });
    </script>
  </body>
</html>

이제 아파치를 기동하곘습니다.


브라우저에 localhost로 접속하니 제대로 나옵니다.

그리고 name에 nowonbun을 입력하겠습니다.

Name도 제대로 변경이 되는 군요. 예전에 bottle 모듈에서 사용하는 것처럼 사용이 됩니다.

bottle 모듈이 apache에서 온전히 사용 가능하네요.


개인적인 생각으로 python으로 웹 서버 개발을 할일은 없다고 생각됩니다.

python의 성능이 떨어져서 web 스크립트로 적합하지 않다라는 건 아닙니다. 오히려 개인적으로 잘 사용하면 ruby나 PHP보다 더 나을 수도 있습니다. python이 모듈이나 라이브러리 면에서도 압도적으로 많으니 활용만 잘하면 좋은 제품이 나올 수도 있겠네요.

문제는 python으로 웹 서버를 개발하는 건 아직 보편적이지 않고, 그 뜻은 Python으로 웹 개발하는 커뮤니티가 크지 않을 것이라고 생각합니다.(개인적인 생각입니다.)

그럼 문제가 발생했을 때, 해결 방법을 찾기가 힘들기 때문에, 굳이 Web API 언어가 많은 시점에 어렵게 갈 일은 없겠네요.


그러면 전혀 사용할 일이 없을 것인가 했을 때, Python은 그래프 데이터를 만들고 통계 데이터를 만들때 꽤 유용한 모듈이 많습니다. 물론 apache에 직접 붙히지 않고 서버 내에서 python의 결과 값을 받고 처리해도 됩니다.

그래서 필요에 따라... 쓰일 일이 있을 것입니다.


링크 - https://bottlepy.org/docs/dev/deployment.html

링크 - https://cmry.github.io/notes/bottle


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.


여기까지 Python의 wsgi를 이용해서 apache에 웹 서버를 구축하는 방법에 대한 글이었습니다.