Slack Incoming Webhook으로 서버 상태 알람 구축하기
디스크 사용량, CPU, 메모리 등 서버 이상 징후를 Slack으로 실시간 알람 받는 방법을 단계별로 설명합니다.
1. 개요 및 아키텍처
왜 Incoming Webhook인가?
Slack과 서버를 연동하는 방법은 여러 가지가 있지만, Incoming Webhook은 가장 빠르고 간단한 방법입니다.
| 방식 | 복잡도 | 양방향 통신 | 적합한 용도 |
|---|---|---|---|
| Incoming Webhook | 낮음 | 단방향 (서버 → Slack) | 알람, 모니터링 |
| Slack Bot Token (API) | 중간 | 양방향 | 명령어 처리, 인터랙션 |
| Socket Mode | 높음 | 양방향 | 실시간 이벤트 처리 |
단순 서버 알람 목적이라면 Incoming Webhook으로 충분합니다.
전체 아키텍처
┌─────────────────────────────────┐
│ Linux Server │
│ │
│ [monitor.sh] (crontab 5분마다) │
│ │ │
│ 디스크/CPU/메모리 체크 │
│ │ 임계값 초과 시 │
│ ▼ │
│ curl POST 요청 │
└──────────────┬──────────────────┘
│ HTTPS
▼
┌─────────────────────────────────┐
│ Slack API Server │
│ hooks.slack.com/services/... │
└──────────────┬──────────────────┘
│
▼
┌─────────────────────────────────┐
│ Slack Channel (#alerts) │
│ 디스크 사용량 경고! │
│ /dev/sda1: 83% 사용 중 │
└─────────────────────────────────┘
2. Slack 앱(봇) 생성
2-1. Slack API 대시보드 접속
https://api.slack.com/apps 에 접속한 뒤, Slack 계정으로 로그인합니다.
2-2. 새 앱 만들기
Create New App 클릭
생성 방식 선택
팝업에서 From scratch 를 선택합니다.
앱 이름 및 워크스페이스 설정
App Name : server-monitor-bot (원하는 이름으로 변경 가능)
Workspace : (알람을 받을 Slack 워크스페이스 선택)
Create App 버튼을 클릭하면 앱이 생성됩니다.
3. Incoming Webhook 활성화 및 URL 발급
3-1. Incoming Webhooks 메뉴 이동
앱 설정 페이지 좌측 메뉴에서 Incoming Webhooks 를 클릭합니다.
3-2. Webhook 활성화
페이지 상단의 토글을 On 으로 변경합니다.
Activate Incoming Webhooks
[ OFF ] → [ ON ]
3-3. Webhook URL 생성
페이지 하단의 Add New Webhook to Workspace 버튼을 클릭합니다.
채널 선택 화면이 나타나면 알람을 받을 채널을 선택합니다.
Post to: # server-alerts ← 미리 채널을 만들어두는 것을 권장
허용 버튼 클릭 후, Webhook URL이 생성됩니다.
Webhook URL 예시:
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
⚠️ 이 URL은 외부에 절대 노출하지 마세요. URL만 있으면 누구나 메시지를 발송할 수 있습니다.
Copy 버튼으로 URL을 복사해 안전한 곳에 보관합니다.
3-4. Webhook 동작 확인 (빠른 테스트)
터미널에서 아래 명령어로 즉시 테스트할 수 있습니다.
curl -X POST \
-H 'Content-type: application/json' \
--data '{"text":"✅ Webhook 연결 테스트 성공!"}' \
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX
Slack 채널에 메시지가 도착하면 정상입니다.
4. Slack 채널에 봇 연동
Incoming Webhook을 생성할 때 채널을 선택했다면, 봇은 해당 채널에 자동으로 연동됩니다.
4-1. 봇 프로필 설정 (선택 사항)
앱 설정 페이지에서 Basic Information → Display Information 섹션으로 이동합니다.
App name : 서버 모니터
Short desc : 서버 디스크/CPU/메모리 상태 알람 봇
App icon : (서버 또는 경고 아이콘 이미지 업로드)
Background : #D32F2F (빨간색 계열 추천)
Save Changes 클릭.
4-2. 다른 채널에도 알람 보내기
하나의 앱에서 채널별로 Webhook URL을 여러 개 생성할 수 있습니다.
# server-alerts→ 디스크/CPU/메모리 경고# critical-alerts→ 서버 다운, 심각한 오류# info-logs→ 일반 상태 리포트
각 채널마다 Add New Webhook to Workspace 를 반복하여 URL을 발급받으면 됩니다.
5. 서버 모니터링 스크립트 작성
5-1. 환경 설정 파일 생성
Webhook URL은 스크립트에 직접 넣지 말고 별도 파일로 관리합니다.
# /etc/server-monitor/config.env
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX"
SLACK_WEBHOOK_CRITICAL="https://hooks.slack.com/services/T00000000/B00000000/YYYYYYYY"
# 임계값 설정
DISK_THRESHOLD=80 # 디스크 사용량 80% 초과 시 알람
CPU_THRESHOLD=90 # CPU 사용률 90% 초과 시 알람
MEM_THRESHOLD=85 # 메모리 사용률 85% 초과 시 알람
# 서버 식별자
SERVER_NAME="web-server-01"
SERVER_ENV="production" # production / staging / dev
# 파일 권한 설정 (소유자만 읽기)
sudo chmod 600 /etc/server-monitor/config.env
sudo chown root:root /etc/server-monitor/config.env
5-2. 메인 모니터링 스크립트
#!/bin/bash
# /usr/local/bin/server-monitor.sh
# ─── 설정 로드 ───────────────────────────────────────────
source /etc/server-monitor/config.env
# ─── Slack 메시지 전송 함수 ──────────────────────────────
send_slack() {
local webhook_url="$1"
local payload="$2"
curl -s -X POST \
-H 'Content-type: application/json' \
--data "$payload" \
"$webhook_url" > /dev/null 2>&1
}
# ─── 경고 메시지 포맷 함수 ───────────────────────────────
build_alert_payload() {
local emoji="$1"
local title="$2"
local message="$3"
local color="$4" # good(녹색) / warning(노란색) / danger(빨간색)
cat <<EOF
{
"attachments": [
{
"color": "$color",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "$emoji $title",
"emoji": true
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*서버*\n\`$SERVER_NAME\`"
},
{
"type": "mrkdwn",
"text": "*환경*\n\`$SERVER_ENV\`"
},
{
"type": "mrkdwn",
"text": "*시각*\n$(date '+%Y-%m-%d %H:%M:%S')"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "$message"
}
}
]
}
]
}
EOF
}
# ─── 1. 디스크 사용량 체크 ───────────────────────────────
check_disk() {
# 각 마운트 포인트의 사용률 확인 (tmpfs 제외)
while IFS= read -r line; do
usage=$(echo "$line" | awk '{print $5}' | tr -d '%')
mount=$(echo "$line" | awk '{print $6}')
device=$(echo "$line" | awk '{print $1}')
if [ "$usage" -gt "$DISK_THRESHOLD" ]; then
local payload
payload=$(build_alert_payload \
"🚨" \
"디스크 사용량 경고" \
"*${device}* (\`${mount}\`) 사용률: *${usage}%*\n임계값: ${DISK_THRESHOLD}% 초과" \
"danger")
send_slack "$SLACK_WEBHOOK_URL" "$payload"
fi
done < <(df -h --output=source,size,used,avail,pcent,target | \
grep -vE '^(Filesystem|tmpfs|udev|overlay)')
}
# ─── 2. CPU 사용률 체크 ──────────────────────────────────
check_cpu() {
# 1분 평균 CPU idle 값으로 사용률 계산
local cpu_idle
cpu_idle=$(top -bn1 | grep "Cpu(s)" | awk '{print $8}' | tr -d '%')
local cpu_usage
cpu_usage=$(echo "100 - $cpu_idle" | bc | awk '{printf "%.0f", $1}')
if [ "$cpu_usage" -gt "$CPU_THRESHOLD" ]; then
# Top 5 프로세스 수집
local top_proc
top_proc=$(ps aux --sort=-%cpu | head -6 | tail -5 | \
awk '{printf "%s\\t%s%%\\t%s\\n", $1, $3, $11}')
local payload
payload=$(build_alert_payload \
"⚠️" \
"CPU 사용률 경고" \
"*현재 CPU 사용률: ${cpu_usage}%*\n임계값: ${CPU_THRESHOLD}% 초과\n\n*Top 프로세스:*\n\`\`\`${top_proc}\`\`\`" \
"warning")
send_slack "$SLACK_WEBHOOK_URL" "$payload"
fi
}
# ─── 3. 메모리 사용률 체크 ───────────────────────────────
check_memory() {
local mem_total mem_used mem_usage
mem_total=$(free -m | awk '/^Mem:/{print $2}')
mem_used=$(free -m | awk '/^Mem:/{print $3}')
mem_usage=$(echo "scale=0; $mem_used * 100 / $mem_total" | bc)
if [ "$mem_usage" -gt "$MEM_THRESHOLD" ]; then
local mem_total_g mem_used_g mem_free_g
mem_total_g=$(free -h | awk '/^Mem:/{print $2}')
mem_used_g=$(free -h | awk '/^Mem:/{print $3}')
mem_free_g=$(free -h | awk '/^Mem:/{print $4}')
local payload
payload=$(build_alert_payload \
"🔴" \
"메모리 사용률 경고" \
"*현재 메모리 사용률: ${mem_usage}%*\n임계값: ${MEM_THRESHOLD}% 초과\n\n총 메모리: ${mem_total_g} | 사용 중: ${mem_used_g} | 여유: ${mem_free_g}" \
"danger")
send_slack "$SLACK_WEBHOOK_URL" "$payload"
fi
}
# ─── 4. 실행 ─────────────────────────────────────────────
check_disk
check_cpu
check_memory
# 스크립트 실행 권한 부여
chmod +x /usr/local/bin/server-monitor.sh
6. Crontab으로 자동 실행 등록
6-1. Crontab 편집
sudo crontab -e
6-2. 스케줄 등록
# 서버 모니터링 - 5분마다 실행
*/5 * * * * /usr/local/bin/server-monitor.sh >> /var/log/server-monitor.log 2>&1
# 매일 오전 9시 일일 리포트 발송 (별도 스크립트)
0 9 * * * /usr/local/bin/daily-report.sh >> /var/log/server-monitor.log 2>&1
6-3. 로그 로테이션 설정
로그 파일이 과도하게 커지지 않도록 logrotate를 설정합니다.
# /etc/logrotate.d/server-monitor
/var/log/server-monitor.log {
daily
rotate 14
compress
missingok
notifempty
create 0640 root root
}
7. 알람 메시지 커스터마이징 (Block Kit)
Slack의 Block Kit을 사용하면 버튼, 이미지, 구분선 등을 넣은 풍부한 메시지를 만들 수 있습니다.
7-1. Block Kit Builder
https://app.slack.com/block-kit-builder 에서 메시지를 시각적으로 디자인할 수 있습니다.
7-2. 실제 알람 메시지 예시 (디스크 경고)
{
"attachments": [
{
"color": "#FF0000",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "🚨 디스크 사용량 경고",
"emoji": true
}
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": "*서버*\n`web-server-01`" },
{ "type": "mrkdwn", "text": "*환경*\n`production`" },
{ "type": "mrkdwn", "text": "*시각*\n2025-04-29 14:35:00" },
{ "type": "mrkdwn", "text": "*사용률*\n`83%` (임계값: 80%)" }
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*/dev/sda1* (`/`) 파티션의 디스크 사용량이 임계값을 초과했습니다.\n즉시 불필요한 파일을 정리하거나 디스크를 확장하세요."
}
},
{ "type": "divider" },
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "🤖 server-monitor-bot | 자동 알람"
}
]
}
]
}
]
}
7-3. 심각도별 색상 코드
| 심각도 | 색상 코드 | 사용 예시 |
|---|---|---|
| 정상 (Info) | #36A64F (녹색) |
복구 알람, 일일 리포트 |
| 주의 (Warning) | #FFA500 (주황) |
CPU 80% 초과 등 |
| 위험 (Critical) | #FF0000 (빨간) |
디스크 90%, 서버 다운 등 |
8. 테스트 및 검증
8-1. 스크립트 수동 실행
# 직접 실행하여 Slack 알람 확인
sudo /usr/local/bin/server-monitor.sh
# 로그 확인
tail -f /var/log/server-monitor.log
8-2. 임계값을 낮춰 강제 트리거
실제 테스트 시에는 임계값을 낮춰 알람이 발생하도록 유도할 수 있습니다.
# config.env에서 임시로 임계값 변경
DISK_THRESHOLD=1 # 1%로 낮춰서 무조건 알람 발생
테스트 후 반드시 원래 값으로 복원합니다.
8-3. Webhook URL 직접 테스트
# 간단한 텍스트 메시지 테스트
curl -X POST \
-H 'Content-type: application/json' \
--data '{
"text": "✅ 서버 모니터링 봇 연결 테스트",
"attachments": [{
"color": "#36A64F",
"text": "Webhook 연동이 정상적으로 완료되었습니다."
}]
}' \
$SLACK_WEBHOOK_URL
9. 보안 주의사항
⚠️ Webhook URL 보안
- Webhook URL은 GitHub, GitLab 등 버전 관리 시스템에 절대 커밋하지 마세요
.gitignore에config.env또는*.env를 반드시 추가하세요- 환경변수 또는 AWS Secrets Manager, HashiCorp Vault 같은 비밀 관리 시스템 사용을 권장합니다
# .gitignore 예시
config.env
.env
*.secret
⚠️ Webhook URL 유출 시 대응
URL이 노출되었다면 즉시 아래 순서로 조치하세요.
- https://api.slack.com/apps → 해당 앱 선택
Incoming Webhooks→ 유출된 URL 오른쪽Delete클릭Add New Webhook to Workspace로 새 URL 발급- 서버의
config.env에 새 URL로 업데이트
⚠️ 알람 폭풍(Alert Storm) 방지
동일한 알람이 5분마다 계속 발송되는 것을 방지하기 위해 쿨다운 파일 방식을 사용하세요.
# 스크립트 내 쿨다운 처리 예시
COOLDOWN_DIR="/tmp/server-monitor-cooldown"
mkdir -p "$COOLDOWN_DIR"
send_with_cooldown() {
local alert_key="$1" # 예: "disk_/dev/sda1"
local cooldown_min=60 # 60분 이내 동일 알람 재발송 안 함
local cooldown_file="$COOLDOWN_DIR/${alert_key//\//_}"
if [ -f "$cooldown_file" ]; then
local last_sent now diff
last_sent=$(cat "$cooldown_file")
now=$(date +%s)
diff=$(( (now - last_sent) / 60 ))
if [ "$diff" -lt "$cooldown_min" ]; then
return 0 # 쿨다운 중, 발송 생략
fi
fi
# 알람 발송 후 타임스탬프 저장
send_slack "$SLACK_WEBHOOK_URL" "$2"
date +%s > "$cooldown_file"
}
마무리
이 가이드를 따라 구성하면 아래와 같은 모니터링 환경을 갖추게 됩니다.
- ✅ Slack 앱(봇) 생성 및 Incoming Webhook URL 발급
- ✅ 채널별 알람 라우팅 (경고/심각 분리)
- ✅ 디스크 / CPU / 메모리 임계값 기반 자동 알람
- ✅ Crontab으로 5분 주기 자동 실행
- ✅ 쿨다운으로 알람 폭풍 방지
- ✅ Webhook URL 보안 관리
필요에 따라 네트워크 트래픽 모니터링, 프로세스 감시, 외부 URL Health Check 등의 체크 항목을 추가하여 확장할 수 있습니다.
참고: Slack API 공식 문서 → https://api.slack.com/messaging/webhooks