cloudflare에서 도메인을 구매했다.
cloudflare를 선택한 이유는 가장 기본적인 요금만 받기 때문이였다.
aws를 사용하거나 클라우드 서버를 사용할 수 있으면 좋으련만 수익이 없는 상태에서 과금 서비스를 이용하기는 싫었다.
홈 서버를 구축하기로 했다.
일단 외부에서 도메인으로 접속을 하려면 공인 ip와 도메인을 연결해야 한다.
문제는 공인 ip가 유동 ip라는 것이다.
유동ip일 경우 도메인과 매핑을 해도 ip가 주기적으로 변하기 떄문에 변할 때 마다 수정해줘야 한다.
이를 해결하기 위해 공인 ip를 고정ip로 사용하려면 추가 요금을 월마다 내야한다.
앞서 말했듯이 수익이 생기기 전에 과금 서비스는 최소화하고 싶었다.
ip 변할 때 자동으로 DNS 레코드를 수정하도록 해보자.
DDNS
DDNS(Dynamic Domain Name System)는 IP 주소가 변경될 때 도메인 이름을 자동으로 업데이트하여 항상 최신 IP로 연결되도록 하는 서비스입니다. 주로 가정용 라우터나 서버에서 공인 IP가 자주 바뀌는 환경에서 사용됩니다. 예를 들어, No-IP나 DynDNS 같은 서비스를 통해 설정할 수 있습니다.
공유기에서도 구매한 도메인과 공인ip를 연결하도록 ddns를 설정을 할 수 있지만 우리집 공유기는 안되더라.
하여 python으로 ddns 설정을 하기로 했다.
import os
import time
import requests
from cloudflare import Cloudflare
from dotenv import load_dotenv
load_dotenv()
# 환경 변수 로드
API_TOKEN = os.getenv('CF_API_TOKEN')
ZONE_ID = os.getenv('CF_ZONE_ID')
RECORD_NAMES = os.getenv('RECORD_NAMES', '').split(',')
if not API_TOKEN or not ZONE_ID or not RECORD_NAMES:
print("Error: Missing environment variables (CF_API_TOKEN, CF_ZONE_ID, RECORD_NAMES)")
exit(1)
# Cloudflare 클라이언트 초기화
cf = Cloudflare(api_token=API_TOKEN)
def get_public_ip():
"""공인 IP 확인"""
try:
response = requests.get('https://api.ipify.org')
external_ip = response.text
return external_ip
except requests.RequestException as e:
print(f"외부 IP 주소를 가져오는 중 오류가 발생했습니다: {e}")
return None
def get_dns_record_id_and_ip(record_name):
"""DNS 레코드 ID와 현재 IP 가져오기"""
try:
records = cf.dns.records.list(zone_id=ZONE_ID, type="A", name=record_name)
if records and records.result:
record = records.result[0]
return record.id, record.content
else:
print(f"No record found for {record_name}")
return None, None
except Exception as e:
print(f"Error fetching record for {record_name}: {str(e)}")
return None, None
def update_dns_record(record_id, record_name, new_ip):
"""DNS 레코드 업데이트"""
try:
cf.dns.records.edit(
dns_record_id=record_id,
zone_id=ZONE_ID,
type="A",
name=record_name,
content=new_ip,
ttl=1, # 자동 TTL
proxied=True # Cloudflare 프록시 활성화 (필요 시 False로 변경)
)
print(f"Updated {record_name} to {new_ip}")
except Exception as e:
print(f"Error updating {record_name}: {str(e)}")
def create_dns_record(record_name, new_ip):
"""DNS 레코드 등록"""
try:
cf.dns.records.create(
zone_id=ZONE_ID,
type="A",
name=record_name,
content=new_ip,
ttl=1, # 자동 TTL
proxied=True # Cloudflare 프록시 활성화 (필요 시 False로 변경)
)
print(f"Created {record_name} to {new_ip}")
except Exception as e:
print(f"Error creating {record_name}: {str(e)}")
def main():
while True:
current_ip = get_public_ip()
print(f"Current public IP: {current_ip}")
for record_name in RECORD_NAMES:
if not record_name:
continue
record_name = record_name.strip()
record_id, record_ip = get_dns_record_id_and_ip(record_name)
if record_id:
if record_ip != current_ip:
update_dns_record(record_id, record_name, current_ip)
else:
print(f"No update needed for {record_name}: IP {record_ip} matches current {current_ip}")
else:
create_dns_record(record_name, current_ip)
time.sleep(300) # 5분 대기
if __name__ == '__main__':
main()
API_TOKEN = cloudflare에서 발급한 API 토큰 / dns 수정 권한을 줘야함
ZONE_ID = cloudflare 대시보드 페이지에서 "영역 ID"라고 번역되는 id
RECORD_NAMES = 매핑할 url를 ,(comma)으로 구분
공인 ip를 조회하고
RECORD_NAME를 가져와
dns 레코드에 설정이 없을 경우 create
있는데 공인ip가 다를 경우 update
5분마다 반복하도록 코딩
어쨌든 서비스가 원할하게 돌아가려면 고정ip는 필수 일 듯 하다.
5분마다 실행 되기 때문에 공인ip가 변할 경우 최대 5분 동안 서비스가 중지된다.
또한 dns레코드가 수정 될 경우 반영 될 때까지 시간이 걸리기 때문에 최대 72시간까지 소요될 수도 있다고 한다.
물론 유동ip가 변한 걸 본적은 없지만
'웹' 카테고리의 다른 글
| FastAPI: 빠르고 효율적인 웹 프레임워크 (0) | 2024.11.10 |
|---|---|
| Flask를 활용한 REST API 개발: 입문 가이드 (0) | 2024.11.09 |
| HTTP: Content-Type (0) | 2023.05.05 |