n8n ile FTP ve SFTP Dosya Transfer Otomasyonu
Dosya transferi otomasyonu, sysadmin hayatının en can sıkıcı ama bir o kadar da kritik parçalarından biri. Yıllarca cron job’larla, bash script’leriyle, “şimdi çalıştı mı çalışmadı mı” diye monitör başında beklediğiniz anlar olmuştur muhtemelen. n8n bu noktada gerçekten fark yaratıyor: görsel iş akışı tasarımı, zengin node ekosistemi ve özellikle FTP/SFTP entegrasyonları sayesinde saatler süren script yazımını dakikalara indirmeniz mümkün.
Bu yazıda n8n’in FTP ve SFTP node’larını gerçek dünya senaryolarıyla ele alacağız. Sadece “şuraya bağlan, dosyayı al” düzeyinde değil, hata yönetimi, dosya filtreleme, arşivleme, bildirim entegrasyonu gibi prodüksiyon ortamlarında ihtiyaç duyacağınız her şeyi konuşacağız.
n8n FTP/SFTP Node’larına Genel Bakış
n8n’de FTP ve SFTP işlemleri için iki ayrı node bulunuyor: FTP node’u klasik FTP ve FTPS protokollerini desteklerken, SFTP node’u SSH tabanlı güvenli transfer için kullanılıyor. 2024 itibarıyla her iki node da şu operasyonları destekliyor:
- Download: Uzak sunucudan dosya indirme
- Upload: Uzak sunucuya dosya yükleme
- List: Dizin içeriğini listeleme
- Delete: Uzak sunucudan dosya silme
- Rename: Dosya veya dizin yeniden adlandırma
- Create Folder: Yeni dizin oluşturma
Credential tarafında SFTP için SSH key authentication da destekleniyor, bu da prodüksiyon ortamlarında parola bazlı erişimden kaçınmanızı sağlıyor.
Credential Yapılandırması
n8n arayüzünden Credentials > New Credential > SFTP yolunu izlediğinizde şu alanlarla karşılaşıyorsunuz:
- Host: Sunucu adresi
- Port: Varsayılan 22 (SFTP için)
- Username: Kullanıcı adı
- Authentication Type: Password veya Private Key
- Private Key: PEM formatında SSH private key
- Passphrase: Key passphrase (varsa)
SSH key ile bağlantı kurarken private key’i doğru formatta girmeniz önemli. n8n, OpenSSH formatını tercih ediyor. Eğer PuTTYgen ile ürettiyseniz, önce OpenSSH formatına dönüştürmeniz gerekiyor:
# PuTTY ppk formatını OpenSSH'a dönüştürme
puttygen mykey.ppk -O private-openssh -o mykey_openssh
# Ya da doğrudan OpenSSH key pair üretimi
ssh-keygen -t ed25519 -C "[email protected]" -f n8n_sftp_key
# Public key'i hedef sunucuya ekle
ssh-copy-id -i n8n_sftp_key.pub -p 22 [email protected]
Senaryo 1: Muhasebe Raporlarının Otomatik Toplanması
Diyelim ki tedarikçi firmaların her gün gece yarısı SFTP sunucularına attığı fatura ve irsaliye dosyalarını toplamanız gerekiyor. 5 farklı tedarikçi, 5 farklı SFTP sunucusu, her biri farklı dizin yapısı. Bunu elle yapmak hem zaman kaybı hem de hata riski.
İş akışının mantığı şöyle: Sabah 06:00’da tetikleyici çalışır, her tedarikçi için ayrı SFTP bağlantısı kurulur, önceki gün tarihli dosyalar listelenir, indirilir, merkezi bir konuma kopyalanır ve muhasebe ekibine bildirim gönderilir.
Workflow içindeki List operasyonu için SFTP node’unun döndürdüğü veriyi filtrelemek amacıyla bir Code node kullanıyoruz:
// Code node - Önceki güne ait dosyaları filtreleme
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
yesterday.setHours(0, 0, 0, 0);
const today = new Date();
today.setHours(0, 0, 0, 0);
const filteredFiles = items[0].json.map(file => {
const fileDate = new Date(file.modifyTime * 1000);
return {
json: {
...file,
isYesterday: fileDate >= yesterday && fileDate < today
}
};
}).filter(item => item.json.isYesterday && item.json.name.endsWith('.pdf'));
return filteredFiles.length > 0 ? filteredFiles : [{ json: { isEmpty: true } }];
Dosyaları indirdikten sonra yerel bir staging dizinine kaydetmek için Execute Command node’u kullanabiliriz:
# n8n host'unda dosyaları organize etme
# Bu komut Execute Command node'unda çalışır
SUPPLIER="{{ $json.supplierName }}"
DATE=$(date -d "yesterday" +%Y%m%d)
TARGET_DIR="/data/invoices/${SUPPLIER}/${DATE}"
mkdir -p "${TARGET_DIR}"
echo "${TARGET_DIR}"
Senaryo 2: FTP Sunucusuna Raporların Otomatik Yüklenmesi
Birçok kurumsal müşteri hala FTP bazlı entegrasyon istiyor. Özellikle bankaların, sigortacıların ve devlet kurumlarının sistemleri bunu gerektiriyor. Gece üretilen raporları sabah 05:00’te onların FTP sunucusuna göndermek tipik bir senaryo.
Burada dikkat edilmesi gereken nokta: Upload operasyonunda n8n, dosya içeriğini binary data olarak bekliyor. Eğer bir önceki node’dan metin verisi geliyorsa, önce dönüştürmeniz gerekiyor.
Raporu bir veritabanından çekip FTP’ye yükleyen basit bir senaryo için Code node ile binary dönüşümü:
// Veritabanından gelen JSON veriyi CSV'ye çevirip binary'e dönüştürme
const rows = items.map(item => item.json);
if (rows.length === 0) {
return [{ json: { error: 'No data to export' } }];
}
// CSV header
const headers = Object.keys(rows[0]).join(',');
// CSV rows
const csvRows = rows.map(row =>
Object.values(row).map(val => {
if (val === null || val === undefined) return '';
const str = String(val);
return str.includes(',') ? `"${str}"` : str;
}).join(',')
);
const csvContent = [headers, ...csvRows].join('n');
// Binary data olarak döndür
return [{
json: { filename: `report_${new Date().toISOString().split('T')[0]}.csv` },
binary: {
data: {
data: Buffer.from(csvContent, 'utf-8').toString('base64'),
mimeType: 'text/csv',
fileName: `report_${new Date().toISOString().split('T')[0]}.csv`
}
}
}];
FTP node’unda Upload yaparken File Path alanına /reports/{{ $json.filename }} yazmanız ve Binary Property alanına data girmeniz yeterli.
Senaryo 3: SFTP ile Senkronizasyon ve Arşivleme
Prodüksiyon ortamlarında sık karşılaştığım bir ihtiyaç: iki SFTP sunucusu arasında belirli dizinlerin senkronize edilmesi. Bunu n8n’de “SFTP’den al, işle, diğer SFTP’ye at” şeklinde kurabilirsiniz.
Ama daha ilginç olan senaryo: indirilen dosyaları kaynak sunucuda arşiv klasörüne taşımak, böylece bir sonraki çalışmada aynı dosyayı tekrar işlememe garantisi sağlamak.
// Arşivlenecek dosyalar için path oluşturma
// Kaynak: /incoming/reports/rapor.xlsx
// Hedef: /archive/2024/01/rapor.xlsx
const sourceFile = items[0].json;
const fileName = sourceFile.name;
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
return [{
json: {
sourcePath: `/incoming/reports/${fileName}`,
archivePath: `/archive/${year}/${month}/${fileName}`,
fileName: fileName,
processedAt: now.toISOString()
}
}];
Bu path bilgileriyle önce dosyayı indirin, sonra hedef SFTP’ye yükleyin, ardından kaynak sunucudaki Rename operasyonuyla dosyayı arşiv dizinine taşıyın. Delete yerine Rename kullanmak, bir şeyler ters gittiğinde geri dönüş imkanı tanıdığı için çok daha güvenli.
Hata Yönetimi ve Retry Mekanizmaları
n8n’de hata yönetimi konusunda birçok ekip iş akışını kuruyor, çalışıyor, mutlu; ama ilk ciddi hata geldiğinde panikliyor. SFTP bağlantısı zaman aşımına uğradı mı? Uzak sunucu bakımda mı? Disk doldu mu? Bunların hepsini önceden düşünmek gerekiyor.
n8n’in Error Trigger node’u bu konuda temel savunma hattınız. Herhangi bir workflow hata verdiğinde bu trigger’ı tetikleyen ayrı bir “hata yönetimi workflow’u” kurabilirsiniz.
Bağlantı hatalarını handle eden bir yapı için Settings sekmesinde her SFTP node’u için On Error ayarını Continue olarak setleyip sonraki node’da kontrol edebilirsiniz:
// SFTP operasyonu sonrası hata kontrolü
const sftpResult = items[0];
// n8n hata durumunda error property ekler
if (sftpResult.json.error || sftpResult.error) {
const errorMessage = sftpResult.json.error?.message ||
sftpResult.error?.message ||
'Unknown SFTP error';
return [{
json: {
success: false,
errorMessage: errorMessage,
timestamp: new Date().toISOString(),
retryRequired: true
}
}];
}
return [{
json: {
success: true,
filesProcessed: sftpResult.json.length || 1,
timestamp: new Date().toISOString()
}
}];
Retry için n8n’in built-in retry özelliğini kullanabilirsiniz. Node ayarlarında Retry On Fail aktif edin, Max Tries değerini 3, Wait Between Tries değerini 5000ms (5 saniye) olarak ayarlayın. Geçici ağ sorunları için bu çoğu zaman yeterli oluyor.
Kritik transferler için Slack veya e-posta bildirimi eklemek şart. Başarısız transfer bildirim mesajı için:
// Slack mesajı oluşturma - hata durumunda
const errorDetails = items[0].json;
const message = {
text: `:red_circle: *SFTP Transfer Hatası*`,
blocks: [
{
type: "section",
text: {
type: "mrkdwn",
text: `*Workflow:* ${errorDetails.workflowName || 'FTP Automation'}n*Hata:* ${errorDetails.errorMessage}n*Zaman:* ${errorDetails.timestamp}n*Sunucu:* ${errorDetails.host || 'Bilinmiyor'}`
}
}
]
};
return [{ json: message }];
Büyük Dosyalar ve Performans
SFTP üzerinden büyük dosya transferlerinde n8n’in bellek yönetimini göz önünde bulundurmak gerekiyor. n8n, binary verileri varsayılan olarak belleğe alıyor. Birkaç GB’lık dosyalar için bu sorun yaratabilir.
n8n 1.x versiyonlarıyla birlikte gelen Binary Data Mode ayarı bu konuda kritik. Environment değişkenlerinden N8N_DEFAULT_BINARY_DATA_MODE=filesystem olarak ayarladığınızda, binary veriler disk üzerinde geçici dosya olarak tutulur:
# n8n Docker environment ayarları
# docker-compose.yml veya .env dosyanıza ekleyin
N8N_DEFAULT_BINARY_DATA_MODE=filesystem
N8N_BINARY_DATA_TTL=60
# Geçici binary dosyaların tutulacağı dizin
N8N_BINARY_DATA_STORAGE_PATH=/home/node/.n8n/binaryData
# Maksimum payload boyutu (varsayılan 16mb, büyük dosyalar için artırın)
N8N_PAYLOAD_SIZE_MAX=100
Docker Compose ile n8n kuruyorsanız volume mount’a dikkat edin:
# docker-compose.yml
version: '3.8'
services:
n8n:
image: n8nio/n8n:latest
ports:
- "5678:5678"
environment:
- N8N_DEFAULT_BINARY_DATA_MODE=filesystem
- N8N_BINARY_DATA_TTL=60
- N8N_PAYLOAD_SIZE_MAX=100
- N8N_BINARY_DATA_STORAGE_PATH=/home/node/.n8n/binaryData
volumes:
- n8n_data:/home/node/.n8n
- /data/transfer_staging:/data/staging
restart: unless-stopped
volumes:
n8n_data:
Dinamik SFTP Bağlantıları
Bazen credential’ları iş akışı içinde dinamik olarak belirlemeniz gerekebilir. Örneğin müşteri bazlı SFTP hesapları yönetiyorsanız, müşteri ID’sine göre farklı sunuculara bağlanmak isteyebilirsiniz.
n8n’de bu durumu yönetmenin pratik yolu, bağlantı bilgilerini bir veritabanında veya n8n’in kendi static data özelliğinde tutmak, sonra HTTP Request node’u veya Code node’u ile çözmek:
// Müşteri bazlı SFTP config çözümleme
// Bu veriyi gerçekte bir DB'den veya secrets manager'dan çekmelisiniz
const customerConfigs = {
'CUSTOMER_001': {
host: '10.0.1.50',
port: 22,
username: 'transfer_c001',
remotePath: '/uploads/invoices'
},
'CUSTOMER_002': {
host: '10.0.1.51',
port: 2222,
username: 'transfer_c002',
remotePath: '/incoming'
}
};
const customerId = items[0].json.customerId;
const config = customerConfigs[customerId];
if (!config) {
throw new Error(`Customer config not found for: ${customerId}`);
}
return [{
json: {
...items[0].json,
sftpConfig: config
}
}];
Credential’ları tamamen dinamik yönetmek için n8n’in HTTP Request node’u ile kendi yazdığınız bir credential API’sine bağlanmak veya HashiCorp Vault entegrasyonu kurmak daha güvenli bir yaklaşım.
Monitoring ve Logging
Prodüksiyon ortamında çalışan SFTP otomasyonlarını izlemek için n8n’in yerleşik execution logları yeterli olmayabilir. Özellikle compliance gereksinimleri olan ortamlarda hangi dosyanın ne zaman transfer edildiğinin kaydını tutmak önemli.
Her başarılı transferi bir log tablosuna yazan basit bir yapı:
// Transfer log kaydı oluşturma
// Bu çıktıyı PostgreSQL node'una veya başka bir DB'ye yazabilirsiniz
const transferDetails = items[0].json;
return [{
json: {
transfer_id: `TRF_${Date.now()}`,
source_host: transferDetails.sourceHost,
destination_host: transferDetails.destHost,
file_name: transferDetails.fileName,
file_size_bytes: transferDetails.fileSize || 0,
transfer_direction: transferDetails.direction || 'download',
status: transferDetails.success ? 'SUCCESS' : 'FAILED',
error_message: transferDetails.errorMessage || null,
started_at: transferDetails.startTime || new Date().toISOString(),
completed_at: new Date().toISOString(),
workflow_id: $workflow.id,
execution_id: $execution.id
}
}];
Bu log verisini n8n’in PostgreSQL, MySQL ya da MongoDB node’larından biriyle doğrudan yazabilirsiniz. Ayrıca Grafana ile görselleştirip transfer hacimlerini, başarı oranlarını ve ortalama transfer sürelerini takip edebilirsiniz.
Güvenlik Konuları
SFTP otomasyonlarında güvenlik genellikle sonradan düşünülen bir konu oluyor, oysa baştan doğru kurgulanması çok daha az baş ağrısı yaratıyor.
Pratik güvenlik önerileri:
- Dedicated transfer user kullanın: Her otomasyon için ayrı, kısıtlı yetkili bir kullanıcı.
chrootile sadece transfer dizinine erişim verin. - SSH key rotation: n8n credential’larını periyodik olarak güncelleyin. Eski keyleri hemen iptal edin.
- IP whitelist: Mümkünse n8n sunucusunun IP adresini hedef SFTP’de whitelist’e alın.
- Transfer dizinini izleyin: İndirilip işlenmeyi bekleyen dosyalar için boyut limiti koyun.
- n8n credential şifrelemesi:
N8N_ENCRYPTION_KEYenvironment değişkenini güçlü bir değerle setleyin ve bu değeri güvenli bir yerde saklayın.
# Kısıtlı SFTP kullanıcısı oluşturma (hedef sunucuda)
sudo useradd -m -s /usr/sbin/nologin sftpuser_n8n
sudo mkdir -p /data/sftp/n8n_uploads
sudo chown root:root /data/sftp
sudo chmod 755 /data/sftp
sudo chown sftpuser_n8n:sftpuser_n8n /data/sftp/n8n_uploads
# sshd_config'e eklenecek chroot konfigürasyonu
cat >> /etc/ssh/sshd_config << 'EOF'
Match User sftpuser_n8n
ChrootDirectory /data/sftp
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
EOF
sudo systemctl restart sshd
Sonuç
n8n’in FTP/SFTP entegrasyonları, yıllardır cron job ve bash script karmalarıyla yönetilen dosya transfer süreçlerini görselleştirilebilir, izlenebilir ve yönetilebilir hale getiriyor. Tedarikçi entegrasyonlarından iç raporlama süreçlerine, legacy sistem köprülemesinden merkezi arşivlemeye kadar geniş bir yelpazede kullanılabiliyor.
Burada anlattıklarımdan çıkaracağınız en önemli birkaç ders var: Hata yönetimini baştan kurun, büyük dosyalar için binary data mode’u filesystem’e alın, transfer loglarını mutlaka tutun ve güvenlik için dedicated kullanıcılar kullanın.
n8n sürekli gelişen bir araç ve SFTP node’una yeni özellikler eklenmeye devam ediyor. Özellikle community node’ları arasında daha gelişmiş SFTP kütüphanelerini kullanan alternatifler var. Ama çoğu ihtiyaç için built-in node’lar fazlasıyla yeterli. Küçük bir workflow ile başlayın, çalıştığını görün, sonra üzerine inşa edin. “Önce çalışan, sonra mükemmel” prensibi n8n otomasyonlarında gerçekten işe yarıyor.
