AWS Lightsail 인스턴스 설정서버 업데이트 및 필수 패키지 설치Django 프로젝트 코드 클론Python 가상환경 설정 및 의존성 설치Django 프로젝트 설정Gunicorn 설정Systemd 서비스 파일 생성- Nginx 설정
- 방화벽 설정
- Django 정적 파일 수집
7번까지 진행이 된 상황이다. 계속 가보자.
처음에 GPT에게 질문했을 때에 8, 9, 10 단계에 대해 해주었던 답변은 이랬다.
8. Nginx 설정
- /etc/nginx/sites-available/<your-project-name> 파일을 생성하고 다음과 같이 설정합니다.
server {
listen 80;
server_name your-lightsail-ip or your-domain.com;
location / {
proxy_pass http://unix:/home/ubuntu/<your-project-directory>/gunicorn.sock;
}
location /static/ {
alias /home/ubuntu/<your-project-directory>/static/;
}
location /media/ {
alias /home/ubuntu/<your-project-directory>/media/;
}
}
- 링크 생성 및 Nginx 테스트:
sudo ln -s /etc/nginx/sites-available/<your-project-name> /etc/nginx/sites-enabled
sudo nginx -t
sudo systemctl restart nginx
9. 방화벽 설정
- Nginx가 HTTP 요청을 받을 수 있도록 방화벽을 설정합니다.
sudo ufw allow 'Nginx Full'
sudo ufw enable
10. Django 정적 파일 수집
- 마지막으로 정적 파일을 수집하여 서버에서 사용합니다.
python manage.py collectstatic
이제 서버에서 브라우저로 Lightsail IP 주소 또는 도메인에 접속하여 Django 앱이 잘 동작하는지 확인합니다.
그런데 7단계까지 진행하면서 누적된 정보들, 예를 들어서 서비스 파일이름이라던지, 소켓 파일이름, 그리고 각각의 파일들의 디렉토리 위치와 경로에 대한 정보들을 GPT가 알고 있다. 그러니 8,9,10 단계에 대해서 다시 물어볼 필요가 있다.
Nginx 설정 단계
- Nginx 설치
sudo apt install nginx
- Nginx 설정 파일 생성
- Nginx의 서버 블록을 설정하여 Gunicorn과 연결합니다
- 설정 파일을 /etc/nginx/sites-available/ 경로에 생성합니다. 예를 들어, mysite_nginx라는 이름으로 설정 파일을 만듭니다.
sudo nano /etc/nginx/sites-available/mysite_nginx
- Nginx 서버 블록 구성
- mysite_nginx 파일에 아래 내용을 입력합니다. 이때, server_name, root, proxy_pass 등을 프로젝트 경로와 서버에 맞게 수정이 필요합니다.
- 특히 proxy_pass 경로는 이전 단계에서 설정한 소켓 파일 mysite.sock 과 일치해야 합니다.
server {
listen 80;
server_name aichatbot-wyfamily.com; # 서버의 도메인 이름 또는 IP 주소로 수정
location / {
proxy_pass http://unix:/home/ubuntu/src/CodingProject/mysite/mysite.sock;
proxy_set_header Host $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;
}
location /static/ {
alias /home/ubuntu/src/CodingProject/mysite/static/; # Django의 static 파일 경로로 설정
}
location /media/ {
alias /home/ubuntu/src/CodingProject/mysite/media/; # Django의 media 파일 경로로 설정
}
}
- Nginx 설정 활성화
- 설정 파일을 저장한 후 sites-enabled 디렉토리에 심볼릭 링크를 만들어 Nginx에서 활성화합니다.
sudo ln -s /etc/nginx/sites-available/mysite_nginx /etc/nginx/sites-enabled
- 기본 설정 파일 비활성화
- Nginx의 기본 설정 파일을 비활성화합니다. 이 단계는 기존 설정과 충돌을 방지하기 위해 필요합니다.
sudo rm /etc/nginx/sites-enabled/default
- Nginx 설정 파일 구문 확인
- 설정 파일에 오류가 없는지 확인합니다. 오류가 없다면, syntax is ok 와 test is successful 메시지가 출력됩니다.
sudo nginx -t
- Nginx 재시작
- 설정을 적용하기 위해 Nginx를 재시작합니다.
sudo systemctl restart nginx
방화벽 설정 확인
- Nginx가 80번 포트(HTTP)를 사용하므로 방화벽에서 해당 포트를 열어야 합니다. 기본적으로는 Nginx가 자동으로 방화벽을 설정하지만, 수동으로 설정하려면 아래 명령을 사용합니다.
sudo ufw allow 'Nginx Full'
Nginx 테스트까지 완료했다.
방화벽 설정까지 완료
정적 파일 수집 (Collect Static file)
정적 파일 수집은 Django에서 사용되는 모든 CSS, JavaScript, 이미지 파일 등을 하나의 디렉토리에 모아주는 작업입니다. 이렇게 모인 정적 파일들은 Nginx를 통해 효율적으로 제공될 수 있습니다.
정적 파일이란?
정적 파일은 웹 페이지에서 자주 사용되는 변하지 않는 리소스 파일입니다. 예를 들어:
- CSS 파일: 웹 페이지의 스타일을 정의합니다. (예: 글자 크기, 색상, 배경 등)
- JavaScript 파일: 웹 페이지의 동작을 제어합니다. (예: 버튼 클릭 시 애니메이션 효과)
- 이미지 파일: 로고, 아이콘, 배경 이미지 등입니다.
이러한 파일들은 앱이 실행되는 동안 계속해서 변하지 않고 동일한 내용을 전달하기 때문에 "정적" 파일이라 부릅니다. 동적 파일과 비교하면, 동적 파일은 데이터베이스와 상호작용하거나 사용자 요청에 따라 내용이 달라질 수 있는 파일들을 말합니다.
정적 파일 수집의 필요성
Django에서는 여러 앱에서 다양한 정적 파일을 사용할 수 있는데, 이를 한 곳에 모아 관리하면 Nginx 같은 웹 서버가 효율적으로 제공할 수 있습니다. collectstatic 명령을 사용하면 Django가 모든 앱의 정적 파일을 한 디렉토리로 모아줍니다.
settings.py 파일 열기 및 수정
settings.py 파일을 열려면 다음과 같이 명령어를 입력하면 됩니다.
nano /home/ubuntu/src/CodingProject/mysite/mysite/settings.py
파일에서 확인해야 할 부분은 다음과 같습니다.
- STATIC_URL: 정적 파일의 URL 경로를 지정합니다.
- STATIC_ROOT: collectstatic 명령으로 정적 파일을 모아둘 최종 경로를 지정합니다.
- STATIC_ROOT는 정적 파일을 수집할 최종 경로입니다. 이 경로는 Django 프로젝트의 최상위 디렉토리에 설정하는 것이 일반적입니다.
- (선택 사항) MEDIA_URL 및 MEDIA_ROOT:
- 사용자가 업로드하는 파일(예: 프로필 사진 등)이 있다면 미디어 파일 경로도 설정합니다.
- 미디어 파일은 사용자가 업로드하는 파일이 있을 때만 설정이 필요합니다. 만약 Django 앱에서 업로드 기능이 없다면, MEDIA_URL과 MEDIA_ROOT 설정은 필요 없고, Nginx 설정 파일에서도 media 관련 location 설정을 생략해도 됩니다.
- 미디어 파일 경로를 미리 설정해두어도 전혀 문제 없습니다. 나중에 업로드 기능이 필요할 경우, 이미 설정이 되어 있으므로 바로 사용할 수 있어 편리합니다.
STATIC_URL = '/static/'
STATIC_ROOT = '/home/ubuntu/src/CodingProject/mysite/static/'
MEDIA_URL = '/media/'
MEDIA_ROOT = '/home/ubuntu/src/CodingProject/mysite/media/'
파일을 수정한 후에는 Ctrl + X, Y, Enter를 눌러 저장하고 종료합니다.
이렇게 설정을 완료하고 collectstatic 명령을 실행하면 Django가 정적 파일을 한 곳에 모아주어, Nginx가 효율적으로 정적 파일을 제공합니다.
정적 파일 수집 명령어 실행
- 가상환경을 활성화하고, Django 관리 명령어 collectstatic을 실행하여 정적 파일을 수집합니다.
source /home/ubuntu/src/CodingProject/venv/bin/activate
cd /home/ubuntu/src/CodingProject/mysite
python manage.py collectstatic
- 이 명령어를 실행하면 Django가 모든 앱의 정적 파일을 STATIC_ROOT 디렉토리에 복사해 둡니다.
여기까지 완료!
자, 이제 실제 도메인 주소를 입력해서 한 번 접속을 해보자!
502 Bad Gateway/ nginx/1.24.0 (Ubuntu)... 흠.. nginx의 버전 문제일려나? 아무튼 GPT에게 물어보자.
502 Bad Gateway 오류는 Nginx와 Gunicorn 간의 연결 문제일 가능성이 높습니다.
1. Gunicorn, Nginx 가 정상 작동 중인지 확인
2. 로그 파일 확인을 해보자 (Nginx와 Gunicorn의 로그 파일을 확인하여 구체적인 오류 메시지를 찾을 수 있다!)
sudo tail -f /var/log/nginx/error.log
sudo journalctl -u mysite_gunicorn
Nginx 의 로그 파일을 확인해보니, (13: Permission denied) 라는 오류가 보인다.
Nginx 로그의 (13: Permission denied) 오류는 Nginx가 Gunicorn의 소켓 파일에 접근할 권한이 부족하다는 뜻입니다. 이를 해결하려면 Gunicorn 소켓 파일의 권한을 수정하여 Nginx가 접근할 수 있도록 해야 합니다.
해결 방법
1. Gunicorn 소켓 파일의 권한 수정
먼저 Gunicorn 서비스 파일(mysite_gunicorn.service)을 열고, 소켓 파일의 권한을 수정하는 옵션을 추가합니다.파일을 열어 다음과 같이 수정합니다:
sudo nano /etc/systemd/system/mysite_gunicorn.service
-
[Service] 섹션에 다음 줄을 추가하여 소켓 파일의 권한을 설정합니다:
[Service]
...
ExecStart=/home/ubuntu/src/CodingProject/venv/bin/gunicorn --workers 3 --bind unix:/home/ubuntu/src/CodingProject/mysite/mysite.sock mysite.wsgi:application
...
# 소켓 파일의 소유권을 변경하여 Nginx가 접근할 수 있도록 설정
ExecStartPost=/bin/chmod 666 /home/ubuntu/src/CodingProject/mysite/mysite.sock
ExecStartPost 옵션을 사용하여 Gunicorn이 시작된 후 소켓 파일의 권한을 666으로 설정하여 모든 사용자(Nginx 포함)가 읽고 쓸 수 있도록 합니다.
2. 데몬 리로드 및 Gunicorn 서비스 재시작
변경 사항을 적용하기 위해 Systemd 데몬을 리로드하고 Gunicorn 서비스를 다시 시작합니다.
sudo systemctl daemon-reload
sudo systemctl restart mysite_gunicorn
3. Nginx 재시작
소켓 파일의 권한이 변경된 후, Nginx를 재시작하여 변경 사항을 반영합니다.
sudo systemctl restart nginx
ExecStartPost에서 너 말대로 하면, 모든 사용자에게 권한을 주는건데 그래도 괜찮은건가? 내가 이해를 제대로 한건지는 모르겠지만, 모든 사용자에게 권한을 줘도 되는거야?
좋은 질문입니다. 모든 사용자에게 권한을 주는 것은 보안상의 위험이 있을 수 있습니다. 특히 chmod 666은 읽기 및 쓰기 권한을 모든 사용자에게 허용하기 때문에, 서버에서 권한 관리를 엄격히 할 필요가 있는 경우에는 적절하지 않을 수 있습니다.
더 안전한 대안
대신, 소켓 파일의 소유자와 그룹을 Nginx와 Gunicorn이 공유하는 사용자/그룹으로 변경하는 것이 더 안전합니다.
소유자 및 그룹 설정 방법Gunicorn이 생성한 소켓 파일의 소유자와 그룹을 www-data(일반적으로 Nginx와 함께 사용되는 사용자 그룹)로 설정하는 방법입니다.mysite_gunicorn.service 파일을 열고 [Service] 섹션에 다음을 추가합니다:
[Service]
User=www-data
Group=www-data
ExecStart=/home/ubuntu/src/CodingProject/venv/bin/gunicorn --workers 3 --bind unix:/home/ubuntu/src/CodingProject/mysite/mysite.sock mysite.wsgi:application
이렇게 하면 Gunicorn이 소켓 파일을 생성할 때, 자동으로 www-data 그룹의 소유권을 가지게 되어 Nginx가 접근할 수 있습니다.
그러면, 기존에는
User = Ubuntu
였는데,
User = www-data 로 바꾼다는 것.
그러면, User = Ubuntu 였을때에는 왜 안 되는거였으며,
www-data의 뜻은 무엇인가?
약간 충격(?)적이라고 해야할까?
chat GPT가 하라는대로 했지만 전혀 해결이 되지 않았다.
전혀 해결이 안 되었다.
그래서 강의에서 알려주는대로 해보았다.
먼저 manage.py와 mysite.sock 이 있는 디렉토리에서 ls -l 을 입력하면
이런 식으로 나온다.
mysite.sock 의 경우에는 user와 group이 ubuntu/ www-data 로 나온다.
접근 권한이라는게 100퍼센트 이해가 된 건 아니지만, 계속 나아가보자면,
nginx의 경우에는 gunicorn에 접근 권한이 없다고 했는데, nginx 의 user 가 무엇인지 확인을 해보자.
sudo nano /etc/nginx/nginx.conf
확인을 해보면, 맨 위에 user www-data; 라고 되어 있다.
소켓 파일의 user가 ubuntu로 되어 있으니,
nginx의 user도 ubuntu로 해주면 문제가 해결되지 않을까 라고 힌트를 주었다.
그래서 변경했더니, 문제가 해결되었다.
그래도 어쨌든 해결되었으니 다음 단계로!
502 에러는 사라지고 not found가 뜬다. 에러는 해결이 된 것.
not found 는, 지정된 게 없어서 그런것이니 큰 문제는 아니다.
/admin 을 했더니 잘 작동하는 걸 볼 수 있다. 휴우....
일단, 왜 작동을 안 한 것인지 정리를 좀 하고 넘어가야, 배우는게 있다고 한다. 정리를 해보자면,
Django - (Gunicorn) - Nginx
gunicorn은 인터페이스고, Nginx를 통해서 접속을 해서 사용자가 Gunicorn을 통해서 Django에 접속하는 방식으로 배포 환경을 구성을 했다.
하지만 무슨 에러가 났냐면,
gunicorn이 생성한 .sock 에 nginx가 접근 권한이 없다 : 13 Permission denied 라는 리눅스 에러가 났다.
이걸 해결하기 위해서, .sock 의 파일의 권한을 확인했다.
파일을 생성하고 소유한 사람 (user) - ubuntu
소속 Group www-data
라고 되어있었다.
* .sock 파일에서 srwxrwxrwx 라고 쓰여져 있는게 있는데, r : read / w: write / x: execute / 읽고 쓰고 실행하는 모든 권한이 다 부여가 되어 있다는 뜻으로 이해하자. 맨 앞에 있는 첫번째 문자는 파일 유형을 의미하며 s 는 파일의 유형이 socket 임을 나타낸다. 일반 파일은 -, 디렉토리는 d, 심볼릭 링크는 l 등으로 표시된다.
* .sock 파일은 **인터프로세스 통신(IPC)**을 위해 사용되는 파일로, 주로 Nginx와 같은 웹 서버에서 백엔드 서버와 통신할 때 사용됩니다. 이 소켓 파일을 통해 웹 서버와 애플리케이션 서버가 빠르게 데이터를 주고받을 수 있는 통로가 마련됩니다.
nginx.conf (nginx가 시작되는 configuration 파일)에서는
user www-data 가 쓰여져있었다. (★ user ubuntu 로 변경해서 해결했다)
user www-data 는 group www-data 에 속해있다.
www-data 란? :
www-data는 일반적으로 웹 서버 소프트웨어, 특히 Apache나 Nginx와 같은 웹 서버에서 사용되는 유저 및 그룹 이름입니다. 이 계정은 웹 서버 프로세스를 실행하는 사용자로, 보안 측면에서 중요한 역할을 합니다.
주요 목적은 다음과 같습니다:
보안 격리: www-data 계정을 사용하여 웹 서버가 일반 사용자의 권한으로 실행되지 않도록 합니다. 이로 인해 서버에 침입자가 들어와도 시스템의 다른 영역에 접근할 수 없도록 격리하는 효과가 있습니다.
권한 관리: www-data 계정에 특정 디렉터리나 파일의 접근 권한을 제한하여, 웹 서버만 해당 파일을 읽거나 쓰는 등의 작업을 할 수 있도록 설정할 수 있습니다.
파일 소유: 웹 애플리케이션이 파일을 생성하거나 수정할 때, 해당 파일의 소유자를 www-data로 설정하여 웹 서버의 접근성을 관리합니다.
따라서 www-data는 보안을 유지하면서 서버가 정상적으로 동작하도록 돕는 역할을 합니다.
원래라면, nginx.conf 에서 user www-data 라고 하면,
.sock 에 접근이 가능해야 한다.
.sock 의
소속 Group www-data 라고 했는데, 이건 user www-data 를 포함하는 더 큰 영역이라고 한다.
그러니까, 그 그룹에 들어가는 거면 read/write/execute가 가능해야 하는데 그렇게 되지가 않았다.
nginx.conf
user www-data --> ubuntu
로 변경하니까, 소속 그룹으로는 접근이 안 되고, 소유한 사람으로는 접근이 되더라 라는 과정이었다.
그런데, 원래는 소속 그룹으로도 접근이 되야 한다는 뜻이다.
왜? user www-data 는 group www-data 에 속하고, 그룹에 속하면, 읽고 쓰고 실행하는게 다 가능하다고 했다.
그런데 왜 안 될걸까?
이걸 막은 건, 보안 프로그램이다.
리눅스 보안 프로그램인 SELinux 도 있고,
AppArmor 라는 것이 있다고 한다. Ubuntu Instance 생성하면 최신 버전에 AppArmor 라는게 있다고 함.
AppArmor가 문제를 일으킨 거라고 한다.
여기서 해결한 방법은 nginx.conf의 user ubuntu로 해서 nginx의 권한을 높이는 방식으로 해결했지만,
AppArmor를 disable 해서 보안을 비활성화하는 방법도 있다고 함.
GPT가 도움 주기 힘든 영역이, 최신 버전에 대한 정보가 없을 때.
그리고 다음에는 진짜 끝까지 더더더 검색도 많이 해보고 공식 docs도 가보는 활동까지 해보자!