인프런 커뮤니티 질문&답변

ktsfrank님의 프로필 이미지
ktsfrank

작성한 질문수

파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)

00-00 GitHub 저장소 안내

nginx, gunicorn, daphne 기반 배포 관련하여 질문 좀 드릴게요

작성

·

459

·

수정됨

0

안녕하세요~

현재까지 공개된 강의 내용과 무관한 질문이지만, 도통 문제 해결 방향을 잡지 못하고 있어 글 남겨 봅니다. ><

DRF, Channels, React로 만든 앱을 nginx, gunicorn, daphne 기반으로 배포하려는데, 막힌 지점에서 벗어나질 못하고 있습니다 ㅜ

nginx, gunicorn, daphne 모두 정상적으로 동작하고 있는 것 같은데, nginx 설정 파일에 등록한 127.0.0.1로 접속하면 "사이트에 연결할 수 없음, 127.0.0.1에서 연결을 거부했습니다"라는 화면이 나옵니다.

  • 문제 해결을 위해 추가적으로 살펴봐야 부분에 관해 조언을 해주신다면 너무 감사드리겠습니다!

    • 한 가지 찝찝한 부분은, react오 django 프로젝트 폴더를 담고 있는 폴더의 경로는 home/kiwitter인데 home/ubuntu/kiwitter/처럼 현재 제 우분투 환경의 사용자를 중간에 추가해야 진행 시 오류가 발생하지 않더라고요. 가상환경 사용과 관련있는 것 같은데, 어쨌든 그래서 경로 입력 시 home/ubuntu/kiwitter/처럼 중간에 사용자명을 추가하는 방식을 사용하고 있는데, 혹시 지금 문제가 이것과 관련이 있을까 싶어 말씀드립니다.

  • 배포 시 React와 Django 프로젝트가 정상적으로 동작하는지 각각 따로 확인하는 방법이 있을까요? Django도 지금처럼 http와 웹소켓으로 클라이언트 요청이 들어오는 경우에 각각의 동작 여부를 개별적으로 살펴볼 수 있는 방법이 있나요? 배포 관련 지식이 없는 데다 하나씩 단계적으로 정상 동작 여부를 점검하지도 못하니 배포의 늪에서 벗어나는 게 더 힘드네요,,

  • 파이썬 사랑방에는 모든 게시물이 관리자의 승인을 받아야 되나요? 아니면 가령 일정 등급 이상이 되면 승인 없이 게시물을 자유롭게 올릴 수 있나요? 여기서 질문 드린 부분을 처음에는 페북 파이썬 사랑방 그룹에 질문했었는데 관리자의 검토가 필요하다는 안내를 보고 궁금해서 여쭤봅니다.

 

프로젝트 폴더 구조

(venv) ubuntu@Ubuntu:~/kiwitter$
├── kiwitter_backend
│   ├── chats
│   ├── db.sqlite3
│   ├── kiwitter_backend
│   ├── kiwitter.sock
│   ├── log
│   ├── manage.py
│   ├── secrets.json
│   ├── staticfiles
│   ├── tweets
│   └── users
├── kiwitter_frontend
│   ├── build
│   ├── node_modules
│   ├── package.json
│   ├── package-lock.json
│   ├── public
│   ├── README.md
│   └── src
├── requirements.txt
└── venv
    ├── bin
    ├── include
    ├── lib
    ├── lib64 -> lib
    └── pyvenv.cfg

 

nginx, gunicorn, daphne 동작 상태

<sudo systemctl status nginx 명령어 출력 결과>

<ps aux | grep gunicorn의 출력 결과>

<ps aux | grep daphne의 출력 결과>

nginx, gunicorn, daphne 관련 설정 파일

</etc/nginx/sites-available/kiwitter>

upstream django_server {
    server unix:/home/ubuntu/kiwitter/kiwitter_backend/kiwitter.sock; # Gunicorn 소켓 파일 위치
}

upstream channels_layer {
    server localhost:6379; # Daphne 서버 주소 및 포트
}

server {
    listen 80;
    server_name 127.0.0.1; # 실제 도메인 또는 공용 IP 주소로 변경

    # React 앱이 위치한 경로
    location / {
        root /home/ubuntu/kiwitter/kiwitter_frontend/build/;
        try_files $uri $uri/ /index.html;
    }

    location = /favicon.ico { access_log off; log_not_found off; }

    location /static/ {
        alias /home/ubuntu/kiwitter/kiwitter_backend/staticfiles/; # STATIC_ROOT 경로
    }

    location /media/ {
        alias /home/ubuntu/kiwitter/kiwitter_backend/media/; # MEDIA_ROOT 경로
    }

    # API 요청을 Django로 프록시
    location /api/ {
        proxy_pass http://django_server;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # Django admin 페이지 및 기타 Django 경로
    location /admin/ {
        proxy_pass http://django_server;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # WebSocket 요청 처리를 위한 설정
    location /ws/ {
        proxy_pass http://channels_layer;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

</etc/systemd/system/gunicorn.service>

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/kiwitter/kiwitter_backend
ExecStart=/home/ubuntu/kiwitter/venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/kiwitter/kiwitter_backend/kiwitter.sock kiwitter_backend.wsgi:application

[Install]
WantedBy=multi-user.target

</etc/supervisor/conf.d/channels.conf>

[fcgi-program:asgi]
socket=tcp://localhost:8000
directory=/home/ubuntu/kiwitter/kiwitter_backend

command=/home/ubuntu/kiwitter/venv/bin/daphne -u /run/daphne/daphne%(process_num)d.sock --fd 0 --access-log - --proxy-headers kiwitter_backend.asgi:application

numprocs=2

process_name=asgi%(process_num)d

autostart=true
autorestart=true

stdout_logfile=/home/ubuntu/kiwitter/kiwitter_backend/log/asgi.log
redirect_stderr=true

Django settings.py

... 생략

ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '').split(',')
# .env 관련 부분 -> ALLOWED_HOSTS=127.0.0.1,localhost

... 생략

CSRF_TRUSTED_ORIGINS = [
    'http://127.0.0.1:8000', 'http://127.0.0.1',
    'http://localhost:8000', 'http://localhost',
]

... 생략

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],  # Redis 서버 주소
        },
    },
}

 

답변 3

1

이진석님의 프로필 이미지
이진석
지식공유자

윈도우에서 VM은 VirtualBox로 설치하셨나요?

윈도우에서 브라우저로 127.0.0.1 주소로 접속하신 거죠?
VirtualBox 내의 VM은 현재 사용하시는 윈도우와는 별도의 네트워크를 가집니다.
그러니 윈도우에서 127.0.0.1 으로 접속을 시도하시면, VirtualBox 내의 VM에 접속을 시도하지 않습니다.

윈도우에서 127.0.0.1 으로 접속을 시도하셨을 때, 해당 VM으로 접속이 될려면
VirtualBox에서 포트포워딩 설정으로
윈도우의 127.0.0.1:8000 으로의 요청을 지정 VM으로 전달이 되도록 해주셔야 합니다.

ktsfrank님의 프로필 이미지
ktsfrank
질문자

아~~~!!

네 VirtualBox로 우분투 설치하고 윈도우에서 브라우저로 접속했습니다.

정작 가장 중요한 부분은 알지도 모른 채 애먼 데서 계속 힘 빼고 있을 뻔 했네요.

포트포워딩 설정 찾아봐서 한 번 잘 해보겠습니다.

너무 감사드려요!

1

이진석님의 프로필 이미지
이진석
지식공유자

그리고, ubuntu 유저 권한으로 장고 서버를 구동하시는 데, ubuntu 유저가 권한이 없는 /home/kiwitter 와 같은 경로에서는 읽기/쓰기/실행 등의 권한이 없어서 서버 구동에 실패하실 수 있습니다.

보통 컴퓨터를 쓰실 때에는 권한에 대해서 잘 몰라도 되지만, 리눅스 서버에서는 특정 파일/디렉토리에 대한 적절한 읽기/쓰기/실행이 없어서 접근이나 명령이 실패하는 경우가 아주 많습니다.

권한이 어려우실 때에는 처음에는 root 로 실행해보셨다가, 구동에 성공하시고나서 특정 유저 권한으로 변경해보시는 것도 좋습니다.

--

그리고 유닉스 소켓으로 서버를 구동하신 경우도, curl 를 통해서도 유닉스 소켓으로 접속을 테스트해보실 수도 있습니다.

ktsfrank님의 프로필 이미지
ktsfrank
질문자

빠른 답변 너무 감사드립니다!

덕분에 살펴볼 부분도 알게 되고 이것저것 해보면서 현재 문제에 대한 이해도가 조금이나마 올라갔갔네요 ㅎ

하지만 아직 문제를 해결하진 못했습니다. ㅜ
실습은 제 윈도우 os 노트북에 vm으로 우분투 설치해서 진행 하고 있습니다.

조언해주신 대로 nginx와 gunicorn 모두 유닉스 소켓 대신 http를 사용하도록 수정하고 다시 시도해봤는데 여전히 nginx에 등록한 ip(127.0.0.1)로 접속이 안됩니다.

이상한 게, nginx, gunicorn, daphne가 모두 동작 중인데 curl로 요청을 보내면 응답으로 500 Internal Server Error 이 돌아옵니다.

또 말씀하신 "root 로 실행" 부분은 제가 이해를 충분히 하진 못했지만, gunicorn 등을 실행할 때 sudo /home/ubuntu/kiwitter/venv/bin/gunicorn (추가 옵션) 처럼 해보라는 말씀으로 이해해서 ls -l /home/ubuntu/kiwitter/venv/bin/gunicorn으로 살펴보니 이미 읽기, 쓰기, 실행 권한이 모두 있더라고요.

혹시 React 문제인가 싶어 127.0.0.1/admin으로 장고 어드민 페이지로 접속해보았으나 마찬가지로 "사이트에 연결할 수 없음" 화면이 나타나고, 장고에 문제가 있나 해서 장고 쉘로 모델 객체 만들어 보니 정상적으로 동작하더라고요.

 

허허 쉽지가 않네요,,

혹시 짚이시는 부분이 있으시다면 공유해주세요~

 

nginx. gunicorn, daphne 동작 상태

<nginx 동작 상태>
image<gunicorn 동작 상태>
image<daphne 동작 상태>
image<curl 요청에 대한 서버 응답>
image

프로젝트 폴더 구조

(venv) ubuntu@Ubuntu:~/kiwitter$
├── kiwitter_backend
│   ├── chats
│   ├── db.sqlite3
│   ├── kiwitter_backend
│   ├── kiwitter.sock
│   ├── log
│   ├── manage.py
│   ├── secrets.json
│   ├── staticfiles
│   ├── tweets
│   └── users
├── kiwitter_frontend
│   ├── build
│   ├── node_modules
│   ├── package.json
│   ├── package-lock.json
│   ├── public
│   ├── README.md
│   └── src
├── requirements.txt
└── venv
    ├── bin
    ├── include
    ├── lib
    ├── lib64 -> lib
    └── pyvenv.cfg


수정한 nginx.conf, gunicorn.service 파일

<nginx.conf: unix 소켓 -> http 사용으로 변경>

upstream django_server {
    server 127.0.0.1:8001;
}

upstream channels_layer {
    server localhost:6379; # Daphne 서버 주소 및 포트
}

server {
    listen 80;
    server_name 127.0.0.1; # 실제 도메인 또는 공용 IP 주소로 변경

    # React 앱이 위치한 경로
    location / {
        root /home/ubuntu/kiwitter/kiwitter_frontend/build/;
        try_files $uri $uri/ /index.html;
    }

    location = /favicon.ico { 
        access_log off; 
        log_not_found off; 
    }

    location /static/ {
        alias /home/ubuntu/kiwitter/kiwitter_backend/staticfiles/; # STATIC_ROOT 경로
    }

    location /media/ {
        alias /home/ubuntu/kiwitter/kiwitter_backend/media/; # MEDIA_ROOT 경로
    }

    # API 요청을 Django로 프록시
    location /api/ {
        proxy_pass http://django_server;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # Django admin 페이지 및 기타 Django 경로
    location /admin/ {
        proxy_pass http://django_server;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # WebSocket 요청 처리를 위한 설정
    location /ws/ {
        proxy_pass http://127.0.0.1:8002;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

<gunicorn.service: 변경 내용 없음>

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/kiwitter/kiwitter_backend
ExecStart=/home/ubuntu/kiwitter/venv/bin/gunicorn --access-logfile - --workers 3 --bind 0.0.0.0:8001 kiwitter_backend.wsgi:application

[Install]
WantedBy=multi-user.target

<channels.conf: http 사용으로 변경>

[program:asgi]

command=/home/ubuntu/kiwitter/venv/bin/daphne -b 0.0.0.0 -p 8002 kiwitter_backend.asgi:application



# Directory where your site's project files are located

directory=/home/ubuntu/kiwitter/kiwitter_backend



# Number of processes to startup, roughly the number of CPUs you have

numprocs=2



# Give each process a unique name so they can be told apart

process_name=asgi%(process_num)d



# Automatically start and recover processes

autostart=true

autorestart=true



# Choose where you want your log to go

stdout_logfile=/home/ubuntu/kiwitter/kiwitter_backend/log/asgi.log

redirect_stderr=true

1

이진석님의 프로필 이미지
이진석
지식공유자

안녕하세요.

  1. 웹브라우저로 접속하시는 컴퓨터가 서버를 구동하는 우분투 리눅스이신가요? 아니면 다른 컴퓨터이신가요? 어디에 있는 서버이신가요?

  1. daphne 서버를 유닉스 소켓말고 아이피/포트드로 구동하시고, daphne 서버에 http 접속을 확인하시고, 그 후에 nginx를 통해서도 http로 리버스 프록시를 연결해보시면 어떤가요? // 유닉스 소켓은 권한 이슈가 있을 수도 있습니다.

http 연결부터 확인하신 후에 웹소켓을 확인해보세요.

ktsfrank님의 프로필 이미지
ktsfrank

작성한 질문수

질문하기