2025년 3월 15일 토요일

Python 으로 작성한 리버스 프록시 코드 (Flask 사용 내부 테스트용)

파이썬으로 작성한 리버스프록시 코드. 안드로이드 앱이 외부 접속을 할 때 https 가 아니면 안되는 경우가 있어서 제작함.


from flask import Flask, request, Response
import requests
import logging
from logging.handlers import RotatingFileHandler

app = Flask(__name__)
# netsh advfirewall firewall add rule name="Allow [EXTERNAL_PORT]" dir=in action=allow protocol=TCP localport=[EXTERNAL_PORT]
# 포워딩할 대상 URL (내부 HTTP 서버)
INTERNAL_PORT = 54321  # 내부 서버 포트 (예시)
TARGET = f"http://127.0.0.1:{INTERNAL_PORT}"

# 로그 파일 설정: server.log 파일에 최대 10,000바이트까지 저장하며, 1개의 백업 파일 생성
handler = RotatingFileHandler('server.log', maxBytes=10000, backupCount=1, encoding='utf-8')
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
handler.setFormatter(formatter)
app.logger.addHandler(handler)
app.logger.setLevel(logging.INFO)

# 모든 경로와 HTTP 메서드를 처리하도록 라우팅
@app.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'])
@app.route('/', methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'])
def proxy(path):
    target_url = f"{TARGET}/{path}"
    app.logger.info(f"Request: {request.method} {request.url} -> Forwarding to: {target_url}")
    
    headers = {key: value for key, value in request.headers if key.lower() != 'host'}
    
    # 대상 서버에 요청 전송
    resp = requests.request(
        method=request.method,
        url=target_url,
        headers=headers,
        params=request.args,
        data=request.get_data(),
        cookies=request.cookies,
        allow_redirects=False
    )
    
    app.logger.info(f"Response: Status code {resp.status_code} from {target_url}")
    
    # 대상 서버의 응답을 그대로 클라이언트에 전달
    response = Response(resp.content, resp.status_code)
    for key, value in resp.headers.items():
        response.headers[key] = value
    return response

if __name__ == '__main__':
    # Let's Encrypt 인증서 사용 (인증서 파일 경로는 마스킹 처리됨)
    ssl_context = ("[인증서 경로]/fullchain.pem", "[인증서 경로]/privkey.pem")
    EXTERNAL_PORT = 12345  # 외부에 노출될 포트 (예시)
    app.logger.info(f"Starting HTTPS reverse proxy server on port {EXTERNAL_PORT} with Let's Encrypt certificate")
    app.run(host='0.0.0.0', port=EXTERNAL_PORT, ssl_context=ssl_context)


댓글 없음:

댓글 쓰기