Post

ngrok 사용법 (Colab에서 로컬서버 공개하기)

ngrok 사용법 (Colab에서 로컬서버 공개하기)

🗂️ 목차

  1. intro
  2. ngrok란?
  3. Colab 환경
  4. Flask + ngrok 실습
  5. pydantic 활용하기
  6. fastAPI 활용하기
  7. request 활용하기(보너스)
  8. 주의사항

1. intro

데이터 분석이나 간단한 API 테스트를 위해 Colab에서 Flask 서버를 실행할 수 있다.
하지만 Colab은 클라우드 환경이기 때문에 외부에서 접근이 불가능한데, 이때 ngrok이라는 툴을 사용하면 로컬에서 실행 중인 서버를 외부에서 접근 가능한 URL로 노출시킬 수 있다.


2. ngrok란?

ngrok은 로컬에서 실행 중인 웹 애플리케이션을 공용 인터넷 주소(https://xxxx.ngrok.io 등)로 노출시켜주는 도구.

🔍 주요 기능

  • 로컬 개발 서버를 외부에서 접근 가능하게 함
  • 웹훅 테스트, 서버 연동 등에 유용
  • 무료로도 사용 가능 (유료 시 고정 도메인 가능)

3. Colab 환경

Colab은 Google의 클라우드 기반 파이썬 실행 환경으로,

  • 외부에서 접근할 수 있는 고정 IP/포트가 없음
  • Flask 등의 웹 서버를 띄우더라도 외부에서 접근 불가

➡️ 이를 해결하기 위해 flask-ngrok 패키지를 사용


4. Flask + ngrok 실습

Colab에서 다음과 같이 설치하고 실행할 수 있습니다. 👍

1. ngrok 가입
ngrok 공식 사이트

  • 무료 회원가입 후 -> 토큰 확인
    ngrok 토큰 확인

2. 패키지 import

  • flask pyngrok import 및 토큰 연동
1
2
3
4
5
!pip install flask pyngrok ## flask 설치

!ngrok config add-authtoken <your_token> ## ngrok 인증 설정

!pip install fastapi uvicorn nest-asyncio ## 웹 서버 구동을 위한 라이브러리
  • fastapi : REST API 서버 개발, 머신러닝 모델 서빙 API, 실시간 데이터 처리 API
  • uvicorn : FastAPI를 실행시키는 ASGI 서버의 비동기 버전으로 Python 웹 서버와 웹 프레임워크 사이의 표준 인터페이스
  • nest-asyncio : Jupyter/Colab 같은 이미 asyncio(비동기 I/O 작업을 처리하기 위한 기반 프레임워크)

3. 기본 설정 연결 확인

FastAPI 인스턴스를 생성한 뒤 해당 경로에서 JSON 응답이 잘 나오는지 확인해보자~

먼저 필요한 라이브러리를 import 한 뒤

1
2
3
4
5
6
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from pyngrok import ngrok
import nest_asyncio
import uvicorn
import threading

아래 코드를 실행 한 후

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# FastAPI 앱 정의
app = FastAPI()

@app.get("/")
def read_root():
  return {"message": "🚀 Hello from Colab + ngrok!"}
  
@app.get("/hello")
def say_hello(name: str = "world"):
    return {"greeting": f"Hello, {name}!"}

# asyncio 루프 재설정
nest_asyncio.apply()

# FastAPI 서버 실행 함수
def run():
    uvicorn.run(app, host="0.0.0.0", port=8000)

# 서버를 백그라운드에서 실행
threading.Thread(target=run).start()

# ngrok으로 8000 포트 열기
public_url = ngrok.connect(8000)
print("Public URL:", public_url)

나오는 ngrok 경로로 들어가보자 아래 사진과 같이 서버 연결이 잘 되었음을 확인할 수 있다.

1
Public URL: NgrokTunnel: "https://b022a8b4da23.ngrok-free.app" -> "http://localhost:8000"

서버 연결

5. pydantic 활용하기

Python에서 데이터 유효성 검사와 직렬화를 쉽게 해주는 라이브러리
주로 FastAPI에서 요청(Request) 데이터를 검증하고 모델링할 때 필수로 사용한다고 함.

👉 딕셔너리 같은 데이터 → 타입 검사 + 자동 변환 + 모델 객체로 바꿔주는 도구

!! 런타임 재시작 !!
🚫 참고로, Colab은 터미널처럼 프로세스를 명확히 관리하기 어려워서 런타임 재시작한 후에 다음 단계 진행해야 함!!
pip install한 것들을 한번 더 실행하는 것 잊지 말기!

1
2
3
4
5
6
7
8
9
from pydantic import BaseModel

class User(BaseModel): ## BaseModel extend
  name : str
  age : int

data = {"name" : "Alice", "age" : "25"}
user = User(**data) #User(name='Alice', age='25')와 같은 효과. data 딕셔너리의 키-값 쌍을 User 클래스의 생성자에 키워드 인수(keyword arguments) 로 전달
print(user)

형태 확인

1
2
user.model_dump() #user.dict()
user.model_dump_json() # json 형태

/user 경로에서 확인해보기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from fastapi import FastAPI
from pydantic import BaseModel
from pyngrok import ngrok
import uvicorn
import nest_asyncio
import threading

# FastAPI 앱 선언
app = FastAPI()

# Pydantic 모델 정의
class User(BaseModel):
    name: str
    age: int

# ✅ 1번: POST 방식 (Pydantic 모델로 body 받기)
@app.post("/user")
def create_user(user: User):
    return {
        "message": f"Hello {user.name}, you're {user.age} years old! (POST)",
        "as_dict": user.model_dump(),
        "as_json": user.model_dump_json()
    }

# ✅ 2번: GET 방식 (쿼리 파라미터로 name, age 받기)
@app.get("/user")
def get_user(name: str, age: int):
    return {
        "message": f"Hello {name}, you're {age} years old! (GET)",
        "as_dict": {"name": name, "age": age}
    }

# ngrok 연결
public_url = ngrok.connect(8000)
print(f"🌐 ngrok URL: {public_url}")

# Colab 이벤트 루프 허용
nest_asyncio.apply()

# Uvicorn 서버 실행 (스레드로 백그라운드에서 실행)
def run():
    uvicorn.run(app, host="0.0.0.0", port=8000)

threading.Thread(target=run).start()

위에서 실행한 결과를 Chorme의 확장 프로그램인 Talend API Tester를 이용해 확인해보자.

✅ 1번: POST 방식 (Pydantic 모델로 body 받기)

서버 연결 서버 연결

✅ 2번: GET 방식 (쿼리 파라미터로 name, age 받기)
GET 방식을 사용하기 위해 url에 파라미터 전달 /user?name=Alice&age=25
⚠️ 만약 서버 연결이 원할히 되지 않는다면, 런타임 재시작!

서버 연결 서버 연결

연결이 잘 되고 있음을 확인 할 수 있다.


6. fastAPI 활용하기

fast API?
빠르고, 간단하고, 자동 문서화까지 되는 Python 비동기 웹 프레임워크
/docs 를 이용해서 Swagger에 자동 문서화!

-> 아래와 같은 단계로 진행 모델 학습 -> FastAPI 서버 연결 -> ngrok 연결

1. 모델 학습: load_iris() 데이터를 이용해 DecisionTreeClassifier 학습

  • 가장 쉽게 접할 수 있는 iris 데이터를 활용한다.
  • DecisionTreeClassifier 를 이용해 모델 학습한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from fastapi import FastAPI
from pydantic import BaseModel
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from pyngrok import ngrok
from typing import List
import uvicorn
import nest_asyncio
import threading

# -------------------
# 1. 모델 학습
# -------------------
iris = load_iris()
X, y = iris.data, iris.target

model = DecisionTreeClassifier()
model.fit(X, y)

2. FastAPI 서버: /predict, /predict2 두 가지 방식으로 예측 API 제공

  • 같은 모델을 사용하지만 JSON에 보내는 방식이 다름
  • /predict : IrisInput (명시적 key-value)
  • /predict2 : ListInput (리스트 하나만)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# -------------------
# 2. FastAPI 정의
# -------------------
app = FastAPI()

class ListInput(BaseModel):
    values: List[float]

class IrisInput(BaseModel):
    sepal_length: float
    sepal_width: float
    petal_length: float
    petal_width: float

@app.post("/predict")
def predict(data: IrisInput):
    input_data = [[
        data.sepal_length,
        data.sepal_width,
        data.petal_length,
        data.petal_width
    ]]
    prediction = model.predict(input_data)[0]
    label = iris.target_names[prediction]
    return {"prediction": int(prediction), "label": label}

@app.post("/predict2")
def predict(data: ListInput):
    prediction = model.predict([data.values])[0]
    label = iris.target_names[prediction]
    return {"prediction": int(prediction), "label": label}

3. ngrok 연결: 외부에서 API 호출 가능하도록 URL 생성 (ngrok.connect)

1
2
3
4
5
6
7
8
9
# -------------------
# 3. 서버 실행 및 ngrok 연결
# -------------------
nest_asyncio.apply()
def run():
    uvicorn.run(app, host="0.0.0.0", port=8000)
threading.Thread(target=run).start()
public_url = ngrok.connect(8000)
print(f"Public FastAPI URL: {public_url}")

4. docs 연결: FastAPI 대화형 문서 (/docs)를 통해 swagger에서 확인

  • 1,2,3 번 실행 후 나오는 ngrok경로 확인
  • public_url.public_url : ngrok 경로
1
public_url.public_url+"/docs"  #swagger ui

위의 docs 경로로 이동하면 아래와 같이 swagger ui와 함께 api test를 할 수 있는 환경이 나온다.
swagger

✔️ /predict 경로에서 JSON 형태로 body를 전송 -> setosa라고 예측!

✔️ /predict2 경로에서 값을 바꿔 리스트 형태로 body를 전송 -> versicolor로 예측!

빠르고 간단하게 colab에서 fast API연동을 통해 Swagger 까지 사용해봤다.

7. request 활용하기 (보너스)

코랩 환경 내에서 외부 API를 사용하기 전에 연동이 잘 되는지 확인하고 싶다면…

1
2
3
4
5
6
7
8
!pip install requests
import requests

url = "https://ngrok_address/predict"
data = {"sepal_length": 5.1, "sepal_width": 3.5, "petal_length": 1.4, "petal_width": 0.2}
response = requests.post(url, json=data)

print(response.json())

위의 코드를 참고해 ngrok 주소를 넣고, 실행하면 아래와 같이 잘 작동하는 것을 확인할 수 있다.

request

=>setosa로 예측함!!

8. 주의사항

  • 무료 플랜이다보니 서버를 3개까지밖에 열수 없다! -> 런타임 재시작
  • 현재 활성화된 ngrok 터널 목록 확인하면서 작업하자!
1
2
3
4
5
6
7
8
9
from pyngrok import ngrok

tunnels = ngrok.get_tunnels()
if tunnels:
    print("현재 활성화된 ngrok 터널 목록:")
    for tunnel in tunnels:
        print(f"- {tunnel.public_url} -> {tunnel.data['config']['addr']}")
else:
    print("현재 활성화된 ngrok 터널이 없습니다.")
  • 만약 서버를 종료해야 한다면
    1
    2
    3
    
    print("모든 ngrok 터널 종료 중...")
    ngrok.kill()
    print("모든 ngrok 터널이 종료되었습니다.")
    

ngrok 사용방법을 바탕으로 서버 배포 전 빠르게 프로토타입 API를 구축할 수 있고,
데모 테스트나 프론트엔드 연동까지 유연하게 진행할 수 있어 실험과 협업에 매우 유용하다!

데이터 분석 하면서 발표할때 한번씩 써봤으면 좋았겠다 하는 약간의 후회가…

(본 글에서 사용된 코드는 신한 금융 SW 풀스택 개발자 양성 과정 중 금융공학 수업 중 사용된 코드를 기반으로 작성되었다. 😉)

This post is licensed under CC BY 4.0 by the author.