728x90

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가 변한 걸 본적은 없지만

728x90

'' 카테고리의 다른 글

FastAPI: 빠르고 효율적인 웹 프레임워크  (0) 2024.11.10
Flask를 활용한 REST API 개발: 입문 가이드  (0) 2024.11.09
HTTP: Content-Type  (0) 2023.05.05