n8n ile Slack Bildirim Otomasyonu Nasıl Kurulur
Geçen hafta gece yarısı bir production veritabanının disk dolduğunu sabah işe geldiğimde öğrendim. Monitoring vardı, alertler kuruluydu ama Slack’e düşmesi gereken bildirim bir şekilde takılmıştı. O gün kendi kendime “bir daha olmayacak” dedim ve n8n ile sağlam bir Slack bildirim altyapısı kurdum. Bu yazıda o süreçte öğrendiklerimi paylaşıyorum.
n8n Nedir, Neden Slack Bildirimleri İçin Kullanmalısınız?
n8n, açık kaynaklı, self-hosted çalışabilen bir iş akışı otomasyonu aracı. Zapier veya Make (eski adıyla Integromat) gibi düşünebilirsiniz ama farkı şu: kendi sunucunuzda çalıştırıyorsunuz, verileriniz dışarı çıkmıyor ve lisans maliyeti yok. Özellikle Türkiye’deki şirketler için KVKK uyumu açısından bu ciddi bir avantaj.
Slack bildirimleri için n8n’i tercih etmemin ana sebeplerinden biri, tek bir araçtan onlarca farklı trigger (tetikleyici) ve aksiyon yönetebilmeniz. Webhook’tan mı veri geldi? Cron job mu çalışacak? HTTP endpoint mi dinleyeceksiniz? Hepsi n8n’in native özellikleri.
Kurulum: Docker ile 10 Dakikada Ayağa Kaldırın
Ben production ortamda Docker Compose ile çalıştırıyorum. Basit bir docker-compose.yml ile başlayalım:
mkdir -p ~/n8n-stack && cd ~/n8n-stack
cat > docker-compose.yml << 'EOF'
version: "3.8"
services:
n8n:
image: docker.n8n.io/n8nio/n8n:latest
restart: always
ports:
- "5678:5678"
environment:
- N8N_HOST=n8n.sirketiniz.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- NODE_ENV=production
- WEBHOOK_URL=https://n8n.sirketiniz.com/
- GENERIC_TIMEZONE=Europe/Istanbul
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=admin
- N8N_BASIC_AUTH_PASSWORD=guclu_sifreniz_buraya
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=db_sifreniz
volumes:
- n8n_data:/home/node/.n8n
depends_on:
- postgres
postgres:
image: postgres:15
restart: always
environment:
- POSTGRES_USER=n8n
- POSTGRES_PASSWORD=db_sifreniz
- POSTGRES_DB=n8n
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
n8n_data:
postgres_data:
EOF
docker-compose up -d
SQLite yerine PostgreSQL kullanmanızı kesinlikle öneririm. Özellikle iş akışı geçmişi ve execution logları büyüdüğünde SQLite’ın performansı düşüyor. Bunu acı tecrübeyle öğrendim.
Kurulum sonrası http://sunucu_ip:5678 adresine gidin, hesabınızı oluşturun ve başlayın.
Slack Uygulama Yapılandırması
n8n’den Slack’e mesaj gönderebilmek için önce bir Slack uygulaması oluşturmanız gerekiyor.
api.slack.com/apps adresine gidin, “Create New App” deyin, “From scratch” seçin. Uygulama adını ve workspace’i belirledikten sonra sol menüden “OAuth & Permissions” bölümüne gelin.
“Bot Token Scopes” kısmına şu izinleri ekleyin:
- chat:write: Mesaj göndermek için zorunlu
- chat:write.public: Bot’un üye olmadığı kanallara mesaj atabilmek için
- channels:read: Kanal listesini okumak için
- files:write: Dosya ve attachment göndermek istiyorsanız
Ardından “Install to Workspace” butonuna basın ve oluşan Bot User OAuth Token‘ı kopyalayın. xoxb- ile başlayan bu token’ı güvenli bir yere kaydedin.
n8n arayüzünde sol menüden Credentials bölümüne gidin, “Add Credential” deyin, Slack arayın. Token’ı yapıştırın ve test edin. Bağlantı başarılıysa artık iş akışlarınızda Slack node’unu kullanabilirsiniz.
Senaryo 1: Sunucu Disk Kullanımı Alarmı
İlk gerçek dünya senaryomuz: sunuculardaki disk kullanımını her saat kontrol et, %80’i geçenleri Slack’e bildir.
Bu senaryo için bir Cron trigger, bir SSH node ve bir Slack node kullanacağız. Ama önce sunucudan veriyi çeken script’i hazırlayalım:
#!/bin/bash
# /usr/local/bin/disk_check.sh
# Bu script JSON çıktısı üretir, n8n bunu parse eder
THRESHOLD=80
HOSTNAME=$(hostname -f)
TIMESTAMP=$(date -Iseconds)
df -h --output=source,pcent,target | tail -n +2 | while read -r filesystem percent mountpoint; do
# Yüzde işaretini kaldır
usage=${percent//%/}
if [ "$usage" -ge "$THRESHOLD" ] 2>/dev/null; then
echo "{"hostname":"$HOSTNAME","filesystem":"$filesystem","mountpoint":"$mountpoint","usage":$usage,"threshold":$THRESHOLD,"timestamp":"$TIMESTAMP"}"
fi
done
chmod +x /usr/local/bin/disk_check.sh
# Test et
/usr/local/bin/disk_check.sh
n8n tarafında iş akışını şöyle kuruyorum:
Cron Node ayarı:
- Trigger: Her saat başı
- Cron Expression:
0
SSH Node ayarı için önce sunucu credential’ı oluşturuyorsunuz (IP, kullanıcı adı, SSH key), ardından komut alanına şunu yazıyorsunuz:
/usr/local/bin/disk_check.sh 2>/dev/null || echo "SCRIPT_ERROR"
SSH node çıktısını parse etmek için bir Function Node ekliyorum:
// n8n Function Node - SSH çıktısını parse et
const output = $input.first().json.stdout || '';
if (output === 'SCRIPT_ERROR' || output.trim() === '') {
return [];
}
const alerts = [];
const lines = output.trim().split('n');
for (const line of lines) {
try {
const parsed = JSON.parse(line);
alerts.push({ json: parsed });
} catch (e) {
// Geçersiz satırları atla
continue;
}
}
// Hiç alert yoksa workflow'u durdur
if (alerts.length === 0) {
return [];
}
return alerts;
Son olarak Slack Node:
- Resource: Message
- Operation: Post
- Channel:
#infrastructure-alerts - Text alanı:
:warning: *Disk Kullanım Alarmı*
*Sunucu:* {{ $json.hostname }}
*Dosya Sistemi:* {{ $json.filesystem }}
*Bağlama Noktası:* {{ $json.mountpoint }}
*Kullanım:* {{ $json.usage }}% (Eşik: {{ $json.threshold }}%)
*Zaman:* {{ $json.timestamp }}
Lütfen en kısa sürede kontrol edin.
Senaryo 2: Webhook ile CI/CD Pipeline Bildirimleri
İkinci senaryo biraz daha karmaşık ama production’da çok işe yarıyor. GitLab veya Jenkins’ten gelen webhook’ları alıp Slack’e formatlı mesaj atıyoruz.
n8n’de Webhook Node oluşturun:
- HTTP Method: POST
- Path:
cicd-notifications - Authentication: Header Auth (güvenlik için)
Webhook URL’niz şöyle görünecek: https://n8n.sirketiniz.com/webhook/cicd-notifications
GitLab tarafında proje ayarlarından Webhooks bölümüne gidin, bu URL’yi ekleyin ve “Pipeline events” ile “Job events” kutucuklarını işaretleyin. Header authentication için X-Webhook-Token header’ı ekleyin.
Webhook’u alan n8n akışında bir Switch Node ile pipeline durumuna göre yönlendirme yapıyorum:
// Switch Node koşulları:
// Değer: {{ $json.body.object_attributes.status }}
// Kural 1: success -> Başarı kanalına
// Kural 2: failed -> Alert kanalına
// Kural 3: running -> İsteğe bağlı bildirim
Başarısız pipeline için Slack mesajı daha detaylı olmalı. İşte Slack node’un mesaj yapısı (JSON modunda):
{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Pipeline Başarısız! :rotating_light:"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Proje:*n{{ $json.body.project.name }}"
},
{
"type": "mrkdwn",
"text": "*Branch:*n{{ $json.body.object_attributes.ref }}"
},
{
"type": "mrkdwn",
"text": "*Tetikleyen:*n{{ $json.body.user.name }}"
},
{
"type": "mrkdwn",
"text": "*Pipeline ID:*n#{{ $json.body.object_attributes.id }}"
}
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Pipeline'a Git"
},
"url": "{{ $json.body.object_attributes.url }}"
}
]
}
]
}
Bu yapıda Slack’in Block Kit formatını kullanıyoruz. Düz metin yerine bu format çok daha okunaklı mesajlar üretiyor.
Senaryo 3: Veritabanı Yedek Doğrulama Bildirimi
Üçüncü senaryo ekibimizde gerçekten kullandığımız bir otomasyon. Her gece veritabanı yedeği alınıyor, sabah n8n bu yedeğin başarılı olup olmadığını kontrol edip Slack’e rapor atıyor.
#!/bin/bash
# /usr/local/bin/backup_verify.sh
BACKUP_DIR="/var/backups/postgresql"
EXPECTED_MIN_SIZE=104857600 # 100MB minimum beklenti
TODAY=$(date +%Y%m%d)
BACKUP_FILE="$BACKUP_DIR/backup_${TODAY}.dump"
# Sonuç yapısı
if [ ! -f "$BACKUP_FILE" ]; then
echo "{"status":"missing","file":"$BACKUP_FILE","message":"Yedek dosyasi bulunamadi"}"
exit 1
fi
ACTUAL_SIZE=$(stat -c%s "$BACKUP_FILE")
ACTUAL_SIZE_MB=$((ACTUAL_SIZE / 1048576))
if [ "$ACTUAL_SIZE" -lt "$EXPECTED_MIN_SIZE" ]; then
echo "{"status":"too_small","file":"$BACKUP_FILE","size_mb":$ACTUAL_SIZE_MB,"message":"Yedek boyutu beklenenden kucuk"}"
exit 1
fi
# pg_restore ile dogrulama (sadece toc kontrol)
if pg_restore --list "$BACKUP_FILE" > /dev/null 2>&1; then
echo "{"status":"success","file":"$BACKUP_FILE","size_mb":$ACTUAL_SIZE_MB,"message":"Yedek dogrulandi"}"
else
echo "{"status":"corrupt","file":"$BACKUP_FILE","size_mb":$ACTUAL_SIZE_MB,"message":"Yedek bozuk veya okunamıyor"}"
exit 1
fi
n8n akışında bu script’in çıktısına göre iki farklı Slack mesajı gidiyor. Başarılı durumda #devops-daily kanalına yeşil bir bildirim, başarısız durumda #critical-alerts kanalına kırmızı bir alarm ve aynı anda ilgili kişilere DM atılıyor.
DM göndermek için Slack node’da channel alanına kullanıcının Slack ID’sini yazabilirsiniz (U0XXXXXXX formatında). Kullanıcı ID’sini Slack’te profiline tıklayıp “Copy member ID” ile alabilirsiniz.
Hata Yönetimi ve Retry Mekanizması
Bu kısma çok dikkat edin. n8n’de hata yönetimi yapmadan kurulan akışlar, sessizce başarısız oluyor ve siz haberdar olmuyorsunuz. Bu da monitoring kuruyorum derken başka bir kör nokta yaratmak demek.
Her iş akışı için Error Workflow tanımlayın. n8n ayarlarından global bir error workflow belirleyebilir ya da her workflow’a özel hata akışı atayabilirsiniz.
Hata yakalama için workflow ayarlarında “On Error” bölümünde “Error Workflow” seçeneğini kullanın. Hata workflow’u şöyle kuruyorum:
// Error Workflow - Function Node
const error = $input.first().json;
const message = {
channel: '#n8n-errors',
text: `:sos: *n8n İş Akışı Hatası*nn*Workflow:* ${error.workflow.name}n*Node:* ${error.node.name}n*Hata:* ${error.error.message}n*Zaman:* ${new Date().toLocaleString('tr-TR', {timeZone: 'Europe/Istanbul'})}`
};
return [{ json: message }];
Slack node’a bağlayın ve artık n8n’nin kendi hataları da Slack’e düşüyor.
Retry ayarları için node’a sağ tıklayın, “Settings” bölümünde “Retry On Fail” seçeneğini aktif edin. Max tries için 3, wait between tries için 60 saniye makul değerler.
Ortam Değişkenleri ve Güvenlik
Slack token’larını, SSH şifrelerini veya API anahtarlarını workflow içine direkt yazmayın. n8n’nin Credentials sistemi bunun için var ama bazen workflow’dan değişkene ihtiyaç duyuyorsunuz.
n8n, .env dosyasından veya environment variable’lardan değer okuyabiliyor:
# docker-compose.yml'e ekleyin
environment:
- N8N_CUSTOM_ENV_SLACK_WEBHOOK=https://hooks.slack.com/services/xxx/yyy/zzz
- [email protected]
Workflow içinde bu değerlere erişmek için Function Node’da:
// Environment variable'dan değer okuma
const webhookUrl = $env.SLACK_WEBHOOK;
const alertEmail = $env.ALERT_EMAIL;
// Kullanım
return [{
json: {
webhookUrl: webhookUrl,
email: alertEmail
}
}];
Webhook endpoint’lerinizi mutlaka authentication ile koruyun. Production’da açık webhook URL’leri ciddi güvenlik açığı. Header authentication için n8n’de “Header Auth” credential oluşturun ve webhook node’a bağlayın.
n8n’yi Nginx Arkasına Almak
Production’da n8n’yi direkt expose etmeyin. Nginx reverse proxy arkasına alın:
# /etc/nginx/sites-available/n8n
server {
listen 443 ssl http2;
server_name n8n.sirketiniz.com;
ssl_certificate /etc/letsencrypt/live/n8n.sirketiniz.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/n8n.sirketiniz.com/privkey.pem;
# n8n'nin büyük webhook payload'ları göndermesi için
client_max_body_size 50m;
location / {
proxy_pass http://localhost:5678;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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;
proxy_cache_bypass $http_upgrade;
# WebSocket timeout (n8n editor için gerekli)
proxy_read_timeout 86400;
}
}
Slack Mesaj Formatlama İpuçları
Deneyimle öğrendiğim birkaç şey:
- Emoji kullanın ama aşırıya kaçmayın.
:rotating_light:kritik,:white_check_mark:başarı,:warning:uyarı için iyi çalışıyor - @channel veya @here kullanmak istiyorsanız mesaj metnine
veyayazın - Kod bloğu için backtick kullanın:
komut“ veya çok satır için üç backtick - Önemli bilgileri bold yapın, ama her şeyi bold yapmayın; okuma güçleşiyor
Zaman bilgisi göstermek için her zaman İstanbul timezone’unu kullanıyorum. n8n’nin $now objesi UTC döndürüyor, düzeltmek için:
// Türkiye saatine çevirme
const now = new Date();
const turkishTime = now.toLocaleString('tr-TR', {
timeZone: 'Europe/Istanbul',
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
return [{ json: { timestamp: turkishTime } }];
Workflow Export ve Backup
Kurduğunuz workflow’ları düzenli olarak export edin. n8n arayüzünden export JSON formatında geliyor. Bunu Git repo’ya commit etmek iyi bir pratik:
#!/bin/bash
# /usr/local/bin/n8n_backup.sh
# Her gün çalıştır, workflow'ları Git'e commit et
N8N_URL="https://n8n.sirketiniz.com"
BACKUP_DIR="/opt/n8n-backups"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"
# n8n API üzerinden tüm workflow'ları çek
curl -s -u "admin:sifreniz"
"${N8N_URL}/api/v1/workflows"
-H "Accept: application/json"
> "${BACKUP_DIR}/workflows_${DATE}.json"
# Git commit
cd "$BACKUP_DIR"
git add .
git commit -m "n8n workflow backup - $DATE" --allow-empty
git push origin main 2>/dev/null || true
echo "Backup tamamlandi: workflows_${DATE}.json"
Sonuç
n8n ile Slack bildirimleri kurmak başta karmaşık görünüyor ama bir kez oturup temel yapıyı kurduğunuzda sistem kendini tekrarlayan bir hal alıyor. Yeni bir senaryo eklemeniz gerektiğinde mevcut workflow’ları kopyalayıp üzerinde değişiklik yapıyorsunuz.
Benim için en büyük fayda şu oldu: ekipte herkes hangi sistemin ne durumda olduğunu Slack’ten takip edebiliyor. Junior mühendisler sunuculara SSH açmak zorunda kalmıyor, sabah Slack’i açtıklarında gece ne olduğunu görüyorlar. Bu hem onboarding sürecini hızlandırıyor hem de operasyonel yükü azaltıyor.
Self-hosted olması da kritik. Birkaç yıl önce bir SaaS otomasyon aracı kullanıyorduk, fiyatlandırma politikasını değiştirdiklerinde ciddi bir maliyet şokuyla karşılaştık. n8n ile o risk yok. Sunucu maliyeti dışında sıfır lisans gideri.
Başlamak için disk alarm senaryosundan gidin. Basit, sonucu hemen görüyorsunuz ve motivasyonu yüksek tutuyor. Oradan diğer entegrasyonlara genişletebilirsiniz.
