← 전체 글로 돌아가기

서버 운영

운영 서버에서만 앱이 안 돌 때

로컬에서는 완벽한데 서버에서는 에러가 나면, 서버의 시간대나 권한, 디스크 용량을 먼저 확인해야 한다.

서버에서만 앱이 안 되는 건 답답하다. 로컬과 서버의 차이가 뭔지 찾기 어렵기 때문이다. 하지만 체계적으로 확인하면 대부분 빨리 찾을 수 있다.

서버 리소스 상태 먼저 보기

앱이 안 된다고 바로 코드를 의심하기 전에, 서버 자체가 정상인지 본다.

# CPU와 메모리 사용량
htop

# 디스크 용량 확인
df -h

# 일반 프로세스들은 정상인가?
ps aux | head -20

메모리가 가득 찼거나 디스크 용량이 없으면, 앱이 정상이라도 돌 수 없다.

시간대 확인하기

로컬과 서버의 시간이 다르면 예상치 못한 에러가 날 수 있다.

# 현재 시간과 시간대 확인
date
timedatectl

# 타임존 설정
sudo timedatectl set-timezone Asia/Seoul

예약된 작업이 실행되지 않거나, 토큰이 갑자기 만료된다고 하면 시간대를 의심해본다.

파일 권한과 디렉토리 확인하기

# 앱 파일의 소유자와 권한
ls -la /opt/myapp/

# 로그 파일을 쓸 수 있는가?
ls -la /var/log/myapp/

# 임시 파일을 쓸 수 있는가?
ls -la /tmp

서버에서 파일을 쓰려고 하는데 권한이 없으면 에러가 난다. sudo chown -R user:group /opt/myapp 같은 명령으로 권한을 설정한다.

환경 변수 다시 확인하기

# 프로세스의 환경 변수
cat /proc/<pid>/environ | tr '\0' '\n' | grep -i 'api\|db\|secret'

# 또는 직접 확인
sudo -u app_user env | grep DATABASE

로컬에서는 .env 파일에서 읽지만, 서버에서는 시스템 환경 변수에서 읽을 수도 있다. 값이 다를 수 있다.

네트워크 연결 확인하기

# 데이터베이스에 연결되는가?
telnet db-host 5432

# Redis에 연결되는가?
redis-cli -h redis-host ping

# 외부 API에 접근할 수 있는가?
curl -v https://external-api.com/health

방화벽이 차단하고 있거나, 네트워크 설정이 다를 수 있다.

로그를 자세히 읽기

# 앱 시작 로그 보기
journalctl -u myapp -n 100

# 실시간 로그
journalctl -u myapp -f

# 특정 시간대 로그
journalctl -u myapp --since "2024-06-30 14:00:00" --until "2024-06-30 15:00:00"

로그에서 다음을 찾아본다:

  • "Connection refused": 데이터베이스/캐시 연결 실패
  • "Permission denied": 파일 권한 문제
  • "Disk quota exceeded": 디스크 가득 참
  • "Out of memory": 메모리 부족

로컬과 서버의 버전 비교

# 서버의 런타임 버전
node -v
python -version
java -version

# 의존성 버전
npm list | head -20
pip list | head -20

로컬에서는 Node 20을 쓰지만 서버에서는 Node 16을 쓸 수도 있다. 버전 차이로 인한 비호환성이 있을 수 있다.

한 가지씩 고쳐보기

여러 문제가 보인다면 하나씩 고친다.

  1. 권한 수정
  2. 환경 변수 재설정
  3. 앱 재시작
  4. 로그 다시 확인

한 번에 여러 개를 고치면 뭐가 효과가 있었는지 알기 어렵다.

앞으로의 배포 체크리스트

앱을 배포할 때 이걸 체크한다:

  1. 서버 시간대는 맞는가?
  2. 앱 파일 권한은 맞는가?
  3. 디스크 용량은 충분한가?
  4. 환경 변수는 설정됐는가?
  5. 데이터베이스에 연결되는가?
  6. 필수 포트는 열려 있는가?