웹/배포

[Cloud 12] 내 서비스에 이름 붙이기: Route53 도메인 및 탄력적 IP 연결

jumemory 2025. 9. 5. 18:36

 

[Cloud 12] 내 서비스에 이름 붙이기: Route53 도메인 및 탄력적 IP 연결

서버를 만들고 DB를 연결했지만, 아직 우리 서비스에 접속하려면 13.124.xx.xx 같은 IP 주소를 입력해야 합니다. 사용자가 기억하기 쉽도록 **탄력적 IP(EIP)**로 주소를 고정하고, Route53을 통해 도메인을 연결해 봅시다.


1. 변하지 않는 주소: 탄력적 IP (Elastic IP)

EC2 인스턴스는 기본적으로 중지 후 재시작하면 IP 주소가 변경됩니다. 도메인을 연결하기 전에 반드시 IP를 고정해야 합니다.

⚙️ 설정 방법

  1. AWS 콘솔: EC2 서비스의 [네트워크 및 보안] -> [탄력적 IP]로 이동합니다.
  2. 할당: [탄력적 IP 주소 할당]을 눌러 새로운 공인 IP를 받습니다.
  3. 연결: 할당된 IP를 선택하고 [동작] -> [탄력적 IP 주소 연결]을 클릭하여, 현재 실행 중인 EC2 인스턴스에 연결합니다.

⚠️ 주의사항: 탄력적 IP는 할당받고 나서 실행 중인 인스턴스에 연결하지 않으면 시간당 비용이 발생합니다. 사용하지 않을 때는 반드시 '릴리스(해제)'해야 합니다.


2. 세상에 하나뿐인 이름: Route53과 도메인

AWS의 Route53은 도메인 이름을 IP 주소로 연결해 주는 가용성이 뛰어난 DNS(Domain Name System) 서비스입니다.

① 호스팅 영역 생성

  1. Route53 콘솔에서 [호스팅 영역 생성]을 누릅니다.
  2. 내가 구매한 도메인 이름(예: dev-portfolio.com)을 입력하고 생성합니다.

② 네임서버(NS) 설정

  • 호스팅 영역을 만들면 4개의 네임서버 주소가 생성됩니다.
  • 가비아, 후이즈 등 도메인을 구매한 대행 업체 사이트에 접속하여, 해당 도메인의 네임서버 정보를 AWS가 준 4개의 주소로 교체해야 합니다. (반영까지 최대 24~48시간 소요될 수 있습니다.)

3. 레코드 등록: 도메인과 IP 연결하기

이제 도메인과 우리 서버의 탄력적 IP를 실제로 매핑합니다.

  • A 레코드 생성:
    • 레코드 이름: 비워둠 (루트 도메인 example.com) 또는 www 입력.
    • 레코드 유형: A - IPv4 주소로 트래픽 라우팅.
    • 값: 위에서 설정한 탄력적 IP 주소를 입력합니다.

[Image showing Route53 record creation screen with A record pointing to an Elastic IP address]


4. Django 설정 업데이트 (ALLOWED_HOSTS)

도메인을 연결한 후에는 Django가 이 도메인을 통한 접속을 허용하도록 설정해야 합니다.

settings.py 수정:

Python
 
# .env 파일 등을 활용하는 것이 좋습니다.
ALLOWED_HOSTS = [
    '13.124.xx.xx',           # 탄력적 IP
    'dev-portfolio.com',      # 내 도메인
    'www.dev-portfolio.com',  # www 서브도메인
]

5. [선생님의 심화 보충] HTTPS(SSL) 예고

도메인을 연결하고 나면 브라우저 주소창에 "주의 요함"이라는 문구가 뜰 것입니다. 이는 HTTP 통신을 하고 있기 때문입니다.

  • 보안을 위해 HTTPS 적용이 필수입니다.
  • 다음 단계인 Nginx 설정에서 **Certbot(Let's Encrypt)**을 사용하여 무료로 SSL 인증서를 발급받고 적용하는 과정이 이어집니다. 도메인이 연결되어 있어야만 이 인증서를 발급받을 수 있으므로 지금 단계가 매우 중요합니다.

6. 전체 구조 요약

  1. 사용자가 도메인(example.com) 입력.
  2. Route53이 도메인을 확인하고 탄력적 IP 주소를 응답.
  3. 사용자 브라우저가 탄력적 IP가 할당된 EC2 서버로 접속.
  4. 서버 안의 **Docker(Nginx/Gunicorn)**가 요청을 받아 Django 앱 실행.

✍️ 블로그 작성을 위한 마지막 조언

독자들에게 **"드디어 내 서비스가 고유한 주소를 갖게 되었습니다"**라고 축하해 주세요. 이제는 지인들에게 IP 번호가 아닌 멋진 URL을 공유할 수 있다는 점이 가장 큰 즐거움이죠.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

앞에서 작성한 view.py를 폴더로 분리해서 관리하기

 

__init__.py 파일이란?

  • 파이썬에서 **패키지(package)**를 만들 때 꼭 들어가는 특별한 파일이에요.
  • “이 폴더는 그냥 일반 폴더가 아니라, 파이썬에서 불러올 수 있는 패키지야!” 라고 표시하는 역할을 해요.

즉, __init__.py가 있으면 그 폴더를 모듈처럼 import 해서 쓸 수 있어요.


예시로 이해하기

📂 프로젝트 구조가 이렇게 있다고 해볼게요:

 
my_project/ ├── math_tools/ │ ├── __init__.py │ ├── add.py │ ├── subtract.py └── main.py

1) __init__.py가 없을 때

  • math_tools 폴더는 그냥 일반 폴더일 뿐이에요.
  • import math_tools 같은 코드를 쓰면 에러가 나요.

2) __init__.py가 있을 때

  • 이제 math_tools는 파이썬에서 패키지로 인식돼요.
  • main.py 안에서 이렇게 쓸 수 있어요:
 
import math_tools.add import math_tools.subtract

__init__.py 안에는 뭐가 들어가나?

  1. 비워둬도 돼요
    그냥 폴더가 패키지라는 표시만 해도 충분해요.
  2.  
    # __init__.py (빈 파일)
  3. 초기 설정을 넣을 수도 있어요
    패키지를 불러올 때 자동으로 실행할 코드나, 미리 불러올 모듈을 지정할 수 있어요.그러면 main.py에서이렇게 더 간단히 쓸 수 있어요.
  4.  
    from math_tools import add_numbers
  5.  
    # __init__.py from .add import add_numbers from .subtract import subtract_numbers

정리

  • __init__.py = “이 폴더는 패키지야” 라고 표시하는 파일.
  • 안에 아무것도 없어도 되고, 초기 실행 코드나 모듈 연결 코드도 넣을 수 있음.
  • 덕분에 파이썬에서 import 할 수 있게 됨.

 

 

 

 

한 줄 요약

  • 웹서버: 정적 파일(HTML/CSS/JS/이미지)을 빠르게 내보내고, 동적 요청은 뒤의 앱으로 프록시(중계). (예: Nginx, Apache HTTPD)
  • WAS(애플리케이션 서버): 비즈니스 로직을 실행해 동적 페이지를 만들어 응답. (예: Tomcat, WildFly, Spring Boot(내장 톰캣), Node/Express, Django+Gunicorn/Uvicorn, FastAPI+Uvicorn)

역할 비교 (핵심만)

웹서버

  • 정적 파일 서빙(캐싱·압축·HTTP/2/HTTP/3 최적화)
  • SSL/TLS 종료(HTTPS 처리), 리버스 프록시/로드밸런싱
  • 속도와 동시성에 최적화, 가볍고 빠름
  • 예: Nginx, Apache HTTP Server

WAS

  • 라우팅, 컨트롤러, 서비스, DB 연동, 세션/인증 등 애플리케이션 로직
  • 스레드풀/커넥션풀 관리, 트랜잭션, 미들웨어
  • 언어별 런타임/프레임워크 위에서 동작
  • 예: Tomcat/Jetty/WildFly(WebSphere/WebLogic), Spring Boot(내장 톰캣), Node.js(Express/Nest), Django(FastAPI) + Gunicorn/uWSGI/Uvicorn

요청 흐름(전형적 구조)

 
[클라이언트 브라우저] ↓ HTTPS(443) [웹서버: Nginx/Apache] ← 정적(캐시/압축) ↓ 내부 HTTP/Unix Socket [WAS: 애플 서버] ← 비즈니스 로직/DB 질의 ↓ [DB/Redis 등]
  • 보통 80/443(공인 포트)은 웹서버가 받고,
  • 내부 포트(예: 8000/8080/3000)는 WAS가 듣습니다.
  • 웹서버가 정적은 바로 응답, 동적은 WAS로 프록시 패스.

스택별로 보면

  • Django / FastAPI (Python)
    • 웹서버: Nginx
    • WAS: Gunicorn/uWSGI + Uvicorn(ASGI) 위에 Django/FastAPI 앱
    • 정적 파일은 Nginx가, API/동적은 Uvicorn으로 프록시
  • Java
    • 웹서버: Nginx/Apache
    • WAS: Tomcat/Jetty/WildFly, 또는 Spring Boot(내장 톰캣) 단독 실행
    • 대규모 엔터프라이즈는 WAS 용어가 특히 익숙
  • PHP
    • 웹서버: Nginx/Apache
    • WAS 역할: php-fpm(FastCGI) 프로세스 풀
    • Nginx ↔ php-fpm로 동적 처리
  • Node.js
    • Node 프로세스(Express/Nest)가 사실상 앱 서버(WAS) 역할
    • 보통 Nginx 리버스 프록시 앞단에 둬서 HTTPS/정적/로드밸런싱 담당

왜 굳이 나누나?

  1. 성능: 정적은 웹서버가 초고속 처리, 동적만 WAS에 전달 → 전체 처리량↑
  2. 보안: TLS 종료·WAF·속도 제한·리라이트 규칙을 웹서버에서 통제
  3. 확장성: 웹서버는 가볍게 여러 대로, WAS는 로직 중심으로 스케일 아웃
  4. 운영 편의: 무중단 배포, 헬스체크, 트래픽 분산, Canary 등 운영 패턴에 유리

자주 쓰는 포트 & 프로토콜

  • 웹서버 외부: 80(HTTP), 443(HTTPS)
  • 웹서버 → WAS 내부: 8000/8080/3000 등 HTTP, 또는 Unix Socket
  • DB: 5432(PostgreSQL), 3306(MySQL/MariaDB)
  • 연결 프로토콜: HTTP, FastCGI(PHP), AJP(과거 Tomcat), gRPC(근래 일부)

헷갈리기 쉬운 포인트

  • 요즘은 경계가 흐림:
    • Spring Boot는 WAS(톰캣)를 내장해 단독으로 8080에서 떠요. 하지만 앞단에 Nginx 두면 운영·보안·정적 처리에 더 좋아요.
    • Node/Express도 자체 서버가 있지만, 실서비스에선 Nginx 앞단이 일반적.
  • 개발/테스트에선 WAS만 띄워도 됨(간단) ↔ 운영에선 웹서버+WAS 분리가 표준.

최소 예시 (Django/FastAPI 배치 감 잡기)

1) Uvicorn/Gunicorn으로 앱(WAS) 실행

 
# Django(ASGI) 혹은 FastAPI uvicorn app:app --host 127.0.0.1 --port 8000 # 내부 포트에서 대기 # 또는 gunicorn -k uvicorn.workers.UvicornWorker app:app -b 127.0.0.1:8000

2) Nginx가 앞에서 프록시(웹서버)

 
server { listen 80; server_name example.com; # 정적 파일 location /static/ { alias /var/www/static/; expires 1h; } # 동적(애플리케이션) 요청은 WAS로 전달 location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

최종 정리

  • 웹서버문지기 + 캐시 + 정적 파일 전문가이자 프록시/로드밸런서 역할.
  • WAS로직을 실행해 동적 컨텐츠를 만드는 애플리케이션 엔진.
  • 개발은 단독 WAS로 시작해도 OK, 운영은 웹서버 앞단 + WAS 뒷단이 정석.

 

 

# ✅ Django 운영 서버 준비 (Gunicorn + Nginx)

# 1) Gunicorn 설치 (Python WSGI 서버)
pip install gunicorn
# -> Django/Flask 같은 Python 웹앱을 운영 환경에서 실행할 때 사용

# 2) Nginx 설치 (웹 서버)
sudo dnf install nginx -y
# -> 정적 파일 서빙, 리버스 프록시 역할 (Gunicorn 앞단에서 트래픽 관리)

# 3) Nginx 서비스 상태 확인
sudo systemctl status nginx
# -> 설치 후 Nginx가 실행 중인지, 에러 없는지 확인

# 4) Nginx 실행
sudo systemctl start nginx
# -> 웹 서버 시작 (기본 포트: 80, https는 443)

 

 

settings.py

 

DEBUG = False

STATIC_URL = 'static/'                   # 정적 파일을 요청할 때 사용할 URL prefix
STATICFILES_DIRS = [BASE_DIR / 'static'] # 개발 시 프로젝트 내 static 폴더 지정

 

 
  • 개발 모드에서는 DEBUG = True
    • 에러 화면에서 상세한 디버깅 정보 표시
    • 정적 파일(CSS/JS/이미지)을 Django가 직접 서빙 (편의용)
  • 운영(배포) 모드에서는 DEBUG = False
    • 에러 화면은 사용자 친화적인 500 에러 페이지로 보임
    • Django는 정적 파일을 직접 제공하지 않음 → 대신 Nginx 같은 웹 서버가 정적 파일을 제공해야 함

👉 정리: 운영할 땐 디버깅 끄고 보안·성능에 맞는 구조로 바꿔야 함

 

python manage.py collectstatic

 

  • 프로젝트 안의 여러 앱(app/static/…)과 루트 static/에 흩어진 파일들을
  • 한 곳(STATIC_ROOT)에 모아줌
  •  

 

 

sudo vim /etc/nginx/nginx.conf
user  play;
worker_processes  auto;


error_log  /var/log/nginx/error.log  notice;
pid        /run/nginx.pid;


# 동적 모듈 로드 (필요하면)
include /usr/share/nginx/modules/*.conf;


events {
    worker_connections 1024;
}

http {
    # 기본 MIME, 로그 포맷 등 -------------------------------------------------
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;


    sendfile        on;
    keepalive_timeout  65;


    # ----------------------------------------------------------------------
    # 1) upstream 정의 (http 블록 안!)
    # ----------------------------------------------------------------------
    upstream encore {
        server 127.0.0.1:8000;
    }


    # ----------------------------------------------------------------------
    # 2) 가상 서버 정의
    # ----------------------------------------------------------------------
    server {
        listen 80 default_server;
        listen [::]:80 default_server;


        # ---------- 정적 파일 ----------
        location /static/ {
            alias /home/play/workspace/django_test/mysite/static/;
        }


        # ---------- Django (Gunicorn) ----------
        location / {
            proxy_pass    http://encore;            # upstream 이름 사용
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

 

 

 

 

  • Gunicorn 단독 실행
    • 보통 python manage.py runserver 또는
      gunicorn --bind 0.0.0.0:8000 mysite.wsgi 형태로 실행
    • 이건 그냥 일반 프로세스가 특정 포트(8000 등)에 바인딩
    • SELinux는 "gunicorn이 8000포트 쓰는 건 괜찮다"라고 허용
  • Nginx 실행
    • 보통 80(HTTP), 443(HTTPS) 포트를 사용
    • SELinux 정책에서 “웹서버(Nginx)가 외부 네트워크 연결하거나 특정 디렉토리 접근”은 기본적으로 제한
    • 그래서 Nginx가 포트 열었는데도 접속 불가가 생길 수 있음

 

getenforce #리눅스에서 SELinux의 현재 동작 모드를 확인

📌 1. SELinux란?

  • Security-Enhanced Linux
  • 리눅스 커널에 붙은 보안 모듈
  • 파일 접근, 네트워크, 프로세스 실행 같은 걸 더 세밀하게 제어해줌
  • 보통 Red Hat, CentOS, Rocky Linux 계열에서 기본 활성화됨

👉 단순히 권한(rwx)으로만 제어하는 게 아니라, “이 프로세스가 이 파일에 접근할 수 있는가?” 같은 추가 정책을 적용

 

출력값은 3가지 중 하나:

  • Enforcing → SELinux 정책이 강제로 적용 중 (제일 빡셈)
  • Permissive → 위반을 기록만 하고 막지는 않음 (로그 확인용)
  • Disabled → 꺼져 있음 (아예 동작 안 함)

모드 전환(일시적):

sudo setenforce 0   # Permissive로 전환
sudo setenforce 1   # Enforcing으로 전환

설정 파일 변경(영구):

sudo vim /etc/selinux/config
#SELINUX=permissive 이걸로 변경

 

 

gunicorn --bind 0:8000 mysite.wsgi:application

📌 1. Gunicorn이 뭐야?

  • Gunicorn (Green Unicorn) = Python WSGI 서버
  • Django, Flask 같은 웹 프레임워크는 자체 개발 서버가 있는데, 이건 개발용이라 실제 서비스엔 적합하지 않음.
  • Gunicorn은 운영 환경에서 쓰는, 안정적이고 빠른 웹 서버.
  • Nginx 같은 리버스 프록시랑 자주 짝을 이룸.

📌 2. 옵션 설명

--bind 0:8000

  • --bind = 어떤 IP와 포트에 서버를 열지 지정
  • 0:8000 → 0.0.0.0:8000의 축약형
    • 0.0.0.0 = 모든 네트워크 인터페이스에서 접속 허용
    • :8000 = 8000번 포트에서 대기

👉 즉, 어디서든 내 서버IP:8000으로 접속 가능


mysite.wsgi:application

  • mysite = Django 프로젝트 디렉토리 이름
  • wsgi = Django가 만든 WSGI 엔트리 파일 (mysite/wsgi.py)
  • application = 그 안에 정의된 WSGI 애플리케이션 객체

 

이제 포트번호를 적지않고 serv1로 만 접속해도 웹서버로 접속돼소 웹서버에서 was를 불러 화면을 보여준다

 


📌 1. 데몬(daemon)이란?

  • 리눅스/유닉스에서 백그라운드에서 계속 돌아가는 프로세스
# ✅ Gunicorn을 systemd 서비스로 등록해서 재부팅해도 Django 서버 자동 실행되도록 설정

# 1) Gunicorn 실행 파일 위치 확인 (가상환경 안에 설치된 경로 확인)
which gunicorn   # 예: /home/play/workspace/django_test/venv/bin/gunicorn

# 2) 서비스 파일 생성 (/etc/systemd/system/mysite.service)
sudo vim /etc/systemd/system/mysite.service

# ---- mysite.service 내용 ----
[Unit]
Description=gunicorn daemon             # 서비스 설명
After=network.target                    # 네트워크 활성화 후 실행

[Service]
User=play                               # 실행할 사용자
Group=play                              # 실행 그룹
WorkingDirectory=/home/play/workspace/django_test/mysite/   # Django 프로젝트 경로
ExecStart=/home/play/workspace/django_test/venv/bin/gunicorn \
          --workers 2 \                 # 동시에 처리할 프로세스 수(멀티프로세스)
          --bind 0:8000 mysite.wsgi:application   # 모든 IP에서 8000포트로 실행

[Install]
WantedBy=multi-user.target              # 다중 사용자 모드에서 실행
# --------------------------------

# 3) systemd에 서비스 반영
sudo systemctl daemon-reload            # 서비스 파일 다시 읽기
sudo systemctl start mysite.service     # 서비스 즉시 실행
sudo systemctl enable mysite.service    # 재부팅 시 자동 실행 등록

# 4) Nginx도 부팅 시 자동 실행되도록 등록
sudo systemctl enable nginx

 

 

로그 보는 습관 길들이기