☘️ DevTip

서버 자동화 쉘 스크립트 모음

nerowiki 2024. 9. 17. 14:10
728x90

서버에서 사용되는 서버 작업 자동화 쉘 스크립트 모음입니다.

start_server.sh

서버 시작을 도와주는 쉘 스크립트로 로그 파일 생성과 PID 관리 기능이 추가되어 있습니다
#!/bin/bash

# 애플리케이션 디렉토리로 이동
cd /root/neonadeuli-backend || { echo "디렉터리를 /root/neonadeuli-backend로 변경하지 못했습니다."; exit 1; }

# Log 디렉토리 설정
LOG_DIR="/root/log"
LOG_FILE="${LOG_DIR}/neonadeuli.log"
mkdir -p "${LOG_DIR}"

echo "Log directory: ${LOG_DIR}"
echo "Log file: ${LOG_FILE}"

# 기존 서버 프로세스 중지
if [ -f /root/log/server_pid.pid ]; then
    OLD_PID=$(cat /root/log/server_pid.pid)
    if ps -p ${OLD_PID} > /dev/null; then
        echo "PID: ${OLD_PID} 가 있는 기존 서버를 중지합니다."
        kill ${OLD_PID}
        rm /root/log/server_pid.pid
    else
        echo "PID: ${OLD_PID}로 기존 서버 프로세스를 찾을 수 없습니다..오래된 PID 파일을 제거해주세요."
        rm /root/log/server_pid.pid
    fi
else
    echo "기존 서버 프로세스를 찾을 수 없습니다."
fi


# Uvicorn 서버 시작
nohup uvicorn main:app --host 0.0.0.0 --port 443 \
  --ssl-keyfile /etc/letsencrypt/live/neonadeuli.life/privkey.pem \
  --ssl-certfile /etc/letsencrypt/live/neonadeuli.life/fullchain.pem \
  >> "${LOG_FILE}" 2>&1 &

# 시작된 프로세스 PID 저장
PID=$!

if [ -n "${PID}" ]; then
    echo "PID 번호 ${PID}로 서버가 구동되었습니다."
    echo "로그는 ${LOG_FILE} 이곳에 작성되었습니다."

    # PID를 파일에 저장 (나중에 서버 중지 시 사용 가능)
    echo ${PID} > /root/log/server_pid.pid
else
    echo "Failed to start the server."
    exit 1
fi

 

stop_server.sh

서버 종료를 도와주는 쉘 스크립트로 PID 관리와 종료 대기, 강제 종료 기능이 추가되어 있습니다.
#!/bin/bash

PID_FILE="/root/log/server_pid.pid"

# PID 파일에서 PID 읽기
if [ -f "$PID_FILE" ]; then
        PID=$(cat "$PID_FILE")
else
        # Uvicorn 프로세스 찾기
        PID=$(pgrep -f "uvicorn main:app")
fi

if [ -z "$PID" ]; then
        echo "현재 어떤 유니콘 서버도 동작하고 있지 않습니다."
        exit 0
fi

echo "현재 서버를 중지하는 중입니다. PID 번호는 $PID 입니다."

# 일반적인 종료 시도
kill $PID

# 프로세스가 종료될 때까지 대기 (최대 10초)
for i in {1..10}; do
    if ! kill -0 $PID 2>/dev/null; then
        echo "유비콘 서버가 정상적으로 종료되었습니다."
        [ -f "$PID_FILE" ] && rm "$PID_FILE"
        exit 0
    fi
    echo "서버가 종료되기를 기다리는 중입니다. ($i/10)"
    sleep 1
done

# 여전히 실행 중이라면 강제 종료
if kill -0 $PID 2>/dev/null; then
    echo "서버가 정상적으로 종료되지 않았습니다. 강제 종료를 시도합니다..."
    kill -9 $PID
    sleep 1
    if ! kill -0 $PID 2>/dev/null; then
        echo "유비콘 서버가 강제 종료되었습니다."
        [ -f "$PID_FILE" ] && rm "$PID_FILE"
    else
        echo "서버 종료에 실패했습니다. 수동으로 확인해 주세요."
    fi
fi

 

update_and_restart.sh

최신 코드와 라이브러리를 업데이트하고 서버를 재시작하는 쉘 스크립트입니다. 
#!/bin/bash

BASE_DIR="/root"

cd ${BASE_DIR}/neonadeuli-backend || { echo "/root/neonadeuli-backend로 디렉토리 변경을 실패했습니다."; exit 1; }



if git pull origin main; then
    echo "origin main 브랜치로부터 성공적으로 최신 코드를 pull 받았습니다."
else
    echo "최신 코드 pull 받기를 실패했습니다."
    exit 1
fi

if pip install -r requirements.txt; then
    echo "성공적으로 requirements 설치를 완료했습니다."
else
    echo "requirements 설치를 실패했습니다."
    exit 1
fi

if ${BASE_DIR}/stop_server.sh; then
    echo "성공적으로 server를 중지했습니다."
else
    echo "server 중지를 실패했습니다."
    exit 1
fi

if ${BASE_DIR}/start_server.sh; then
    echo "성공적으로 server를 구동했습니다."
else
    echo "server 구동을 실패했습니다."
    exit 1
fi

echo "$(date) 시각에 Server를 업데이트하고 재시작을 완료했습니다."


check_server_status.sh

CPU, 메모리 사용량, 최근 로그 15줄을 제공하는 서버 상태 체크 쉘 스크립트입니다.
#!/bin/bash

PID_FILE="/root/log/server_pid.pid"
LOG_FILE="/root/log/neonadeuli.log"

check_server_status() {
    PID=$(pgrep -f "uvicorn main:app")

    if [ -z "$PID" ]; then
        echo "서버가 실행 중이 아닙니다."
    else
        echo "서버가 실행 중입니다. (PID: $PID)"
        echo "CPU 사용량: $(ps -p $PID -o %cpu | tail -1)%"
        echo "메모리 사용량: $(ps -p $PID -o %mem | tail -1)%"
        echo "최근 로그:"
        tail -n 15 "$LOG_FILE"
    fi

    # PID 파일 확인
    if [ -f "$PID_FILE" ]; then
        FILE_PID=$(cat "$PID_FILE")
        if [ "$FILE_PID" != "$PID" ]; then
            echo "경고: PID 파일의 PID ($FILE_PID)가 실제 실행 중인 PID ($PID)와 다릅니다."
        fi
    else
        echo "경고: PID 파일이 존재하지 않습니다."
    fi
}

# 함수: 서버 포트 확인
check_server_port() {
    if netstat -tuln | grep :443 > /dev/null; then
        echo "포트 443이 열려있습니다."
    else
        echo "포트 443이 닫혀있습니다."
    fi
}

# 메인 실행
echo "서버 상태 확인 중..."
check_server_status
echo ""
check_server_port

 

rotate_logs.sh

로그 파일을 날짜에 따른 생성 및 삭제 관리를 도와주는 쉘 스크립트입니다.
#!/bin/bash

# Log 디렉토리 설정
LOG_DIR="/root/log"
LOG_FILE="${LOG_DIR}/neonadeuli.log"

# 현재 날짜를 이용하여 로그 파일 이름 생성
DATE=$(date +"%Y-%m-%d")
NEW_LOG_FILE="${LOG_DIR}/neonadeuli_${DATE}.log"

# 기존 로그 파일을 새로운 파일로 이동
if [ -f "${LOG_FILE}" ]; then
    echo "Rotating log file: ${LOG_FILE} to ${NEW_LOG_FILE}"
    mv "${LOG_FILE}" "${NEW_LOG_FILE}"
    # 새로운 로그 파일 생성
    touch "${LOG_FILE}"
else
    echo "Log file not found: ${LOG_FILE}"
fi

# 30일 이상 된 파일 삭제
find ${LOG_DIR} -name "neonadeuli_*.log" -type f -mtime +30 -delete

# 기존 서버 로그와 새로운 로그 파일을 연결
if [ -f /root/log/server_pid.pid ]; then
    PID=$(cat /root/log/server_pid.pid)
    echo "Sending USR1 signal to PID: ${PID} for log rotation"
    kill -USR1 ${PID}
else
    echo "Server PID file not found."
fi
더보기

크론탭에 다음과 같이 세팅하여 매일 자정마다 실행되도록 세팅

crontab -l : 예약된 작업리스트
crontab -e : 예약된 작업 수정
crontab -r : 예약된 작업 삭제
crontab -u 사용자명 : 루트관리자는 해당 사용자
crontab 파일을 보거나 삭제, 편집 가능
# Edit this file to introduce tasks to be run by cron.
# 
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
# 
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').
# 
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
# 
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
# 
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
# 
# For more information see the manual pages of crontab(5) and cron(8)
# 
# m h  dom mon dow   command
0 12 1 * * /user/bin/certbot renew --quiet

# 매일 자정에 로그 회전
0 0 * * * /root/rotate_logs.sh && /root/start_server.sh

# 서버 시작 (필요 시 주석 제거하여 사용, 최초 1회만 실행 필요
@reboot /root/start_server.sh

 

analyze_logs.sh

가장 최근 로그 파일 탐색 및 에러 분석하는 쉘 스크립트입니다.
#!/bin/bash

LOG_FILE="/root/log"

# 가장 최신의 로그 파일 찾기
LATEST_LOG=$(ls -t ${LOG_FILE}/neonadeuli_*.log | head -n1)

if [ -z "${LATEST_LOG}" ]; then
    echo "${LOG_FILE} 이라는 로그 파일이 존재하지 않습니다."
    exit 1
fi

echo "${LATEST_LOG} 이라는 로그 파일 분석 중"

echo "Error count in the last hour:"
grep "ERROR" ${LATEST_LOG} | grep -c "$(date -d '1 hour ago' +'%Y-%m-%d %H:')"

echo "Most frequent IP addresses:"
awk '{print $1}' ${LATEST_LOG} | sort | uniq -c | sort -nr | head -5

echo "Recent 404 errors:"
grep "404" ${LATEST_LOG} | tail -5

 

monitor_resource.sh

서버 CPU, 메모리, 디스크 사용량 분석 쉘 스크립트입니다.
#!/bin/bash

while true; do
    echo "-----$(date)-----"
    echo "CPU Usage: $(top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4}')%"
    echo "Memory Usage: $(free -m | awk 'NR==2{printf "%.2f%%", $3*100/$2 }')"
    echo "Disk Usage: $(df -h | awk '$NF=="/"{printf "%s", $5}')"
    sleep 60
done

 

security_check.sh

실패한 로그인 시도 기록과 열린 포트, 최근 시스템 업데이트 기록을 확인하는 쉘 스크립트입니다.
#!/bin/bash

echo "Checking for failed login attempts:"
grep "Failed password" /var/log/auth.log | tail -5

echo "Checking for open ports:"
netstat -tuln

echo "Checking for recent system updates:"
apt list --upgradable

 

backup_server.sh

백업 파일을 생성하는 쉘 스크립트입니다.
#!/bin/bash

BACKUP_DIR="/root/backups"
APP_DIR="/root/neonadeuli-backend"
DATE=$(date +"%Y%m%d_%H%M%S")

mkdir -p $BACKUP_DIR

tar -czf $BACKUP_DIR/app_backup_$DATE.tar.gz $APP_DIR

echo "Backup created: $BACKUP_DIR/app_backup_$DATE.tar.gz"