Linux sunucularda zamanlanmış görev yapılandırması sırasında en sık karşılaşılan ve can sıkan sorunların başında Permission denied (Erişim reddedildi) hatası gelir. Çoğu zaman bir betik terminalde manuel olarak çalıştırıldığında sorunsuz tamamlanır; ancak aynı betik crontab listesine eklendiğinde sessizce çöker ya da sistem günlüklerine yürütme izin hatası fırlatır. Zamanlama mekanizmasının temellerini tazelemek isterseniz cron job nedir rehberimizi inceleyebilirsiniz.
Geliştiricilerin ilk refleksi genellikle hedef dosyaya kontrolsüzce chmod 777 vermek olur. Oysa Permission denied hatası yalnızca dosyanın çalıştırma bayrağından kaynaklanmaz. Dosyanın bulunduğu ebeveyn (üst) dizinlerdeki geçiş (traverse/execute) izinlerinin eksikliği, crontab kullanıcısı ile dosya sahibinin (UID/GID) uyuşmaması, Windows ortamında düzenlenen dosyalardaki CRLF satır sonları, log dosyasına yazma engelleri veya SELinux/AppArmor güvenlik kalkanları bu hatayı tetikleyebilir.
Sistem genelindeki otomasyon mantığını anlattığımız Linux cron job ve genel arıza teşhislerini topladığımız cron job çalışmıyor rehberlerinden farklı olarak bu makalede; dosya izinlerinin anatomisini, üst dizin geçiş mekanizmasını, kullanıcı yetkilendirme modellerini ve kalıcı çözüm adımlarını teknik derinliğiyle masaya yatırıyoruz.
Cron'da "Permission Denied" Hatasının 4 Temel Nedeni
Cron servisi, komutları kullanıcının zengin interaktif oturumundan bağımsız, kısıtlı ve izole bir alt kabuk (subshell) ortamında çalıştırır. İzin reddi hatalarının arkasında yatan 4 temel teknik etken şunlardır:
- Yürütme (Execute) ve Geçiş (Traverse) İzni Eksikliği: Betik dosyasının kendisinde
+xçalıştırma izni bulunmaması veya betiğin yer aldığı klasör yolundaki üst dizinlerden herhangi birinde yürütme/geçiş bitinin kapalı olması. - Kullanıcı ve Grup (UID/GID) Yetki Uyuşmazlığı: Örneğin görevin
www-datakullanıcısının crontab'ında tanımlanmış olması fakat betiğin yalnızcarootveyaubuntukullanıcısı tarafından okunabilir izinlere (0700) sahip olması. - Hedef Log ve Çalışma Dizinlerine Yazma Engeli: Betiğin kendi içinde üretilen çıktıların veya yönlendirme yapılan log dosyasının (
>> /var/log/app.log) standart kullanıcı tarafından açılamaması. - Windows Satır Sonu Karakterleri (CRLF) ve Shebang Bozulması: Betiğin Windows işletim sisteminde düzenlenip Linux'a aktarılması sonucu ilk satırdaki yorumlayıcı yoluna
\r(^M) karakterinin eklenmesi ve kabuğun yorumlayıcıyı çalıştıramaması.
Adım Adım Çözüm 1: Dosya ve Dizin İzinleri (chmod ve chown)
İzin sorunlarını çözmeye başlarken ilk kontrol edilmesi gereken nokta, çalıştırılacak dosyanın ve bu dosyaya giden dizin ağacının izin yapısıdır.
Script Dosyasına Çalıştırma İzni Verme (chmod +x)
Bir dosyanın kabuk betiği olarak doğrudan yürütülebilmesi için üzerinde çalıştırma (execute) bitinin aktif olması gerekir. Dosyanın mevcut izinlerini ls -l /yol/betik.sh komutuyla incelediğinizde kullanıcı haklarında -rwxr-xr-x (0755) yapısını görmelisiniz:
# Betiğe güvenli çalıştırma izni verin:
chmod 755 /home/kullanici/scripts/yedek.sh
# Veya yalnızca çalıştırma bitini ekleyin:
chmod +x /home/kullanici/scripts/yedek.sh
chmod 777 kullanmayın. 777 izni, sistemdeki diğer tüm servislerin ve kullanıcıların o betiğin içeriğini değiştirmesine (yazmasına) olanak tanır. Bu durum saldırganların betik içine zararlı komutlar enjekte etmesiyle sonuçlanabilir. Sistem güvenliği kurallarımız hakkında detaylı bilgi için cron job güvenlik rehberimizi inceleyebilirsiniz.
Üst Dizin Geçiş İzinleri (Execute Bit Kontrolü)
Linux dosya sistemlerinde en sık gözden kaçan kural dizin geçiş izinleridir (POSIX directory traversal). Bir dosyanın kendisi 0777 iznine sahip olsa dahi, o dosyanın bulunduğu dizin yolundaki tüm üst klasörlerde görevi çalıştıran kullanıcının x (execute/search) izni olmak zorundadır. Dizinler üzerindeki x biti, işletim sistemine o dizinin içine girme (traverse etme) yetkisi verir.
Örneğin betiğiniz /home/ahmet/projeler/script.sh konumundaysa ve görevi www-data kullanıcısı çalıştırıyorsa; hem /home/ahmet hem de /home/ahmet/projeler dizinlerinde www-data kullanıcısına kullanıcı, grup veya ACL üzerinden x izni verilmelidir. Eğer /home/ahmet dizini 0700 (yalnızca ahmet erişebilir) olarak kilitliyse, www-data kullanıcısı dosyanın varlığını bile sorgulayamaz ve çekirdek seviyesinde Permission denied hatası üretilir.
Adım Adım Çözüm 2: Crontab Kullanıcısı ve Yetki Seviyeleri (root vs www-data)
Linux sistemlerinde her kullanıcının kendine ait bağımsız bir crontab tablosu bulunur. Görevi hangi kullanıcının çalıştırdığını doğru tespit etmek izin hatalarını çözmenin anahtarıdır:
| Komut / Konum | Çalıştıran Kullanıcı | Kullanım Alanı |
|---|---|---|
crontab -e |
Komutu yürüten oturum kullanıcısı | Kullanıcıya ait ev dizini betikleri |
sudo crontab -e |
root | Sistem seviyesi, servis yeniden başlatma, disk işlemleri |
sudo crontab -u www-data -e |
www-data (Nginx / Apache kullanıcısı) | Web uygulaması periyodik görevleri, cache temizliği |
/etc/crontab veya /etc/cron.d/ |
Satırda belirtilen 6. alandaki kullanıcı | Paket otomasyonları ve merkezi yönetim |
Bir web uygulaması görevi hazırlıyorsanız, dosya sahipliğini ve grubunu ilgili web kullanıcısına devretmelisiniz:
# Dosya sahibini www-data olarak ayarlayın:
sudo chown www-data:www-data /var/www/html/scripts/cron_gorev.sh
sudo chmod 750 /var/www/html/scripts/cron_gorev.sh
Farklı dağıtımların servis ve kullanıcı yapılarını karşılaştırmak için Ubuntu cron job kılavuzumuzdaki dizin hiyerarşisine bakabilirsiniz.
Adım Adım Çözüm 3: Log Dosyası Yazma Hakları ve Yönlendirmeler
Crontab satırlarında çıktıların kaybolmaması için çoğunlukla çıktı yönlendirmesi (redirection) kullanılır. Ancak yönlendirilen log dosyasının kendisi veya yazıldığı dizin yazma iznine sahip değilse, betik çalışmaya dahi başlayamadan kabuk tarafından Permission denied hatası fırlatılır:
# Hatalı kullanım: Standart kullanıcının /var/log içine yazmaya çalışması
0 * * * * /home/kullanici/script.sh >> /var/log/uygulama.log 2>&1
Linux sistemlerinde /var/log/ dizini varsayılan olarak yalnızca root kullanıcısının yazma yetkisine sahiptir. Standart bir kullanıcının bu alana doğrudan yeni dosya açması işletim sistemi tarafından engellenir. Bu sorunu çözmek için iki yöntem mevcuttur:
- Log Dosyasını Kullanıcının Kendi Dizinine Yönlendirin: En pratik ve temiz yöntem, çıktıları kullanıcının tam yetkili olduğu ev dizinine almaktır:
0 * * * * /home/kullanici/script.sh >> /home/kullanici/logs/uygulama.log 2>&1 - Log Dosyasını Önceden Oluşturup Yetki Tanımlayın: Eğer mutlaka
/var/log/altında tutulması gerekiyorsa, dosya root tarafından oluşturulup sahipliği kullanıcıya verilmelidir:sudo touch /var/log/uygulama.log sudo chown kullanici:kullanici /var/log/uygulama.log sudo chmod 644 /var/log/uygulama.log
Adım Adım Çözüm 4: Windows Satır Sonu (CRLF) ve Shebang Sorunları
Geliştiricilerin Windows ortamında (VS Code, Notepad++ vb.) yazdığı veya git üzerinden Windows satır sonlarıyla (\r\n - CRLF) sunucuya aktardığı kabuk betikleri kafa karıştırıcı bir izin hatası doğurur. Betiğin en başında #!/bin/bash yazılı olsa bile, Linux çekirdeği ilk satırın sonundaki \r karakterini komutun bir parçası kabul eder ve şu meşhur hatayı üretir:
/bin/bash^M: bad interpreter: No such file or directory
Bu hata mesajındaki sorun dosya izinleriyle ilgili değil, çekirdeğin /bin/bash\r isimli var olmayan bir dosyayı çalıştırmaya çalışmasıdır. Çözüm için dosyayı Linux (LF) satır sonu formatına dönüştürmelisiniz:
# dos2unix aracı ile dönüştürün:
sudo apt install dos2unix -y # Debian/Ubuntu
# veya sudo dnf install dos2unix -y # RHEL/CentOS
dos2unix /home/user/script.sh
# Veya sed kullanarak \r karakterlerini temizleyin:
sed -i 's/\r$//' /home/user/script.sh
Gerçek Kod Örnekleri
Aşağıdaki betikler, sistem yöneticilerinin sunucularındaki izin karmaşasını tek komutla denetlemesi ve otomatik onarması için tasarlanmıştır.
Script ve Log İzinlerini Standartlaştıran Onarım Scripti
Bu Bash betiği, belirtilen bir otomasyon klasöründeki tüm betiklerin ve log dosyalarının izinlerini güvenli kurumsal standartlara (betikler için 0755, loglar için 0644) getirir ve dosya sahipliklerini hizalar:
#!/usr/bin/env bash
set -euo pipefail
TARGET_DIR="/opt/cron_tasks"
APP_USER="deployer"
APP_GROUP="deployer"
echo "[*] Dizin denetleniyor: ${TARGET_DIR}"
if [[ ! -d "${TARGET_DIR}" ]]; then
echo "[!] Hedef dizin mevcut değil: ${TARGET_DIR}" >&2
exit 1
fi
# Dizin izinlerini ayarla (üst dizin geçiş hakkı: 0755)
echo "[+] Dizin geçiş izinleri 0755 olarak yapılandırılıyor..."
find "${TARGET_DIR}" -type d -exec chmod 755 {} +
# Tüm shell betiklerine çalıştırma hakkı (0755) ver
echo "[+] Betik çalıştırma izinleri (0755) atanıyor..."
find "${TARGET_DIR}" -type f -name "*.sh" -exec chmod 755 {} +
# Log dosyalarını güvenli okuma-yazma (0644) moduna al
echo "[+] Log dosyası izinleri (0644) eşitleniyor..."
find "${TARGET_DIR}" -type f -name "*.log" -exec chmod 644 {} +
# Dosya sahipliklerini doğru kullanıcıya aktar
if id "${APP_USER}" >/dev/null 2>&1; then
echo "[+] Sahiplik ${APP_USER}:${APP_GROUP} olarak güncelleniyor..."
chown -R "${APP_USER}:${APP_GROUP}" "${TARGET_DIR}"
fi
echo "[OK] İzin standardizasyonu başarıyla tamamlandı."
ls -la "${TARGET_DIR}"
Üst Dizinlerdeki Traverse İzinlerini Denetleyen Bash Scripti
Bir betik izin hatası verdiğinde, kök dizinden (/) başlayarak betiğe kadar giden tüm ebeveyn klasörlerde yürütme (x) izninin bulunup bulunmadığını test eden teşhis betiği:
#!/usr/bin/env bash
set -euo pipefail
TARGET_FILE="${1:-}"
if [[ -z "${TARGET_FILE}" ]]; then
echo "Kullanım: $0 /tam/dosya/yolu/betik.sh" >&2
exit 1
fi
REAL_PATH="$(realpath "${TARGET_FILE}" 2>/dev/null || echo "${TARGET_FILE}")"
echo "=== Dizin Ağacı İzin Denetimi: ${REAL_PATH} ==="
CURRENT_DIR="$(dirname "${REAL_PATH}")"
while [[ "${CURRENT_DIR}" != "/" ]]; do
PERMS="$(ls -ld "${CURRENT_DIR}" | awk '{print $1, $3, $4}')"
echo "[Klasör] ${CURRENT_DIR} -> ${PERMS}"
# Geçerli kullanıcı için execute izni kontrolü
if [[ ! -x "${CURRENT_DIR}" ]]; then
echo " [UYARI] ${CURRENT_DIR} dizininde geçerli kullanıcı için traverse (+x) izni bulunmuyor!"
fi
CURRENT_DIR="$(dirname "${CURRENT_DIR}")"
done
echo "[Klasör] / -> $(ls -ld / | awk '{print $1, $3, $4}')"
echo "=== Denetim Tamamlandı ==="
Sık Karşılaşılan Hatalar ve Çözümleri
Sistem yöneticilerinin cron günlüğünde veya konsolda karşılaştığı 4 kritik permission denied hatası:
1. /bin/sh: /home/user/script.sh: Permission denied
Nedeni: Betik dosyasının kendisinde yürütme izni (execute bit) bulunmamaktadır ya da betiğin üst dizinlerinden biri diğer kullanıcıların geçişine kapalıdır.
Çözümü: Dosyaya çalıştırma hakkı tanıyın: chmod +x /home/user/script.sh. Sorun çözülmezse üst dizinlerin izinlerini chmod 755 /home/user komutuyla güncelleyin.
2. /bin/bash^M: bad interpreter: No such file or directory
Nedeni: Dosya Windows metin düzenleyicilerinde kaydedildiği için satır sonlarında \r\n karakterleri kalmıştır. Kabuk, /bin/bash\r yorumlayıcısını bulamadığı için dosyanın bulunamadığını raporlar.
Çözümü: Dosyayı Linux satır sonu formatına çevirin: dos2unix /home/user/script.sh veya sed -i -e 's/\r$//' /home/user/script.sh.
3. crontab spool dizinine erişilemiyor
Nedeni: Kullanıcının crontab -e komutunu çalıştırırken spool dizinine erişememesidir. Ubuntu'da /var/spool/cron/crontabs, RHEL'de ise /var/spool/cron dizini yetkileri bozulmuştur ya da crontab ikili dosyasının dağıtıma özgü SUID/SGID izinleri bozulmuştur.
Çözümü: Paketin dağıtıma özgü sahiplik ve izinlerini geri yükleyin. Ubuntu/Debian crontab komutu SGID kullanır; rastgele SUID vermeyin. Ubuntu/Debian için sudo apt install --reinstall cron, RHEL için sudo rpm --restore cronie komutunu kullanın.
4. cannot create /var/log/my_cron.log: Permission denied
Nedeni: Crontab görevindeki standart çıktı yönlendirmesi (>> /var/log/my_cron.log) standart bir kullanıcının yetkisiyle root sahipliğindeki bir dizine yeni dosya oluşturmaya çalışmaktadır.
Çözümü: Log dosyasını kullanıcının ev dizinine taşıyın veya dosyayı önceden root ile oluşturup sahibini değiştirin: sudo touch /var/log/my_cron.log && sudo chown kullanici:kullanici /var/log/my_cron.log.
cronjob.com.tr ile HTTP Tabanlı Alternatif Kurulum (İzin Kargaşasını Sıfırlama)
Sunucu üzerinde yerel cron betikleriyle çalışmak; chmod, chown, UID/GID eşleşmeleri, üst dizin geçiş izinleri, SELinux etiketleri ve dosya kilitleme mekanizmaları nedeniyle ciddi bir operasyonel yük oluşturur. Tek bir yanlış izin bayrağı kritik yedekleme veya faturalandırma işlerinin günlerce durmasına yol açabilir.
Yerel crontab yapılandırmasını azaltmanın pratik bir yolu, periyodik görevlerinizi web uygulamanızın (Nginx/Apache) doğal çalışma ortamında bir HTTP uç noktası olarak sunmak ve bu adresi cronjob.com.tr üzerinden güvenle tetiklemektir. Böylece işlemler web sunucusu kullanıcısının izinleriyle yürütülür; hedef dosya ve dizinlerin bu kullanıcıya gerekli erişimi sağlaması gerekir.
Örneğin bir PHP uç noktası tasarlayarak görevinizi koruma altına alabilirsiniz:
<?php
// /var/www/html/api/cron-tetikleyici.php
declare(strict_types=1);
// Yalnızca cronjob.com.tr tarafından iletilen gizli anahtarı doğrula
$authHeader = $_SERVER['HTTP_X_CRON_AUTH'] ?? '';
$secretKey = '9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d';
if (!hash_equals($secretKey, $authHeader)) {
http_response_code(403);
echo json_encode(['durum' => 'engellendi', 'mesaj' => 'Geçersiz yetki anahtarı.']);
exit;
}
// Güvenle yürütülecek iş mantığı (Veritabanı optimizasyonu, fatura kesimi vb.)
$basariliIslem = 24;
http_response_code(200);
header('Content-Type: application/json');
echo json_encode([
'durum' => 'basarili',
'islenen' => $basariliIslem,
'calisma_zamani' => date('c')
]);
cronjob.com.tr dış tetikleme altyapısının sağladığı kolaylıklar:
- Ücretsiz Kullanım: Kayıt sırasında kredi kartı talep edilmez, ücretsiz olarak hemen başlayabilirsiniz.
- Kolay Zamanlama: 1 dakikadan başlayan hazır aralıklar veya standart 5 alanlı cron ifadeleri ile tam esneklik sunulur. Europe/Istanbul veya dilediğiniz saat dilimi tanımlanabilir.
- Gelişmiş HTTP Ayarları: GET, POST, PUT, PATCH, DELETE, HEAD ve OPTIONS metotları desteklenir; yukarıdaki örnekte olduğu gibi özel HTTP başlıkları (Header), istek gövdesi ve HTTP Basic Auth gönderilebilir.
- Güvenilir Zaman Aşımı (Timeout): 1 dakikalık işlerde 55 saniye, 2 dakikalık işlerde 115 saniye, 5 dakika ve üzeri veya cron ifadeli görevlerde 290 saniyeye kadar bekleme süresi tanınır.
- Kesintisiz İzleme ve Uyarılar: HTTP 200–399 harici yanıtlar veya bağlantı hataları istek sırasında tespit edilir. Belirlediğiniz ardışık hata eşiği (varsayılan 3) aşıldığında e-posta uyarısı alırsınız; görev düzeldiğinde toplam kesinti süresini belirten e-posta iletilir. Aynı iş için bildirimler arasında en az 60 dakika bulunur.
- Ayrıntılı 7 Günlük Kayıtlar: Her çalışmanın HTTP durum kodu, yanıt süresi, hata ayrıntısı ve yanıt gövdesinin ilk ~64 KB'ı 7 gün boyunca izleme panelinde saklanır.
Sıkça Sorulan Sorular (SSS)
chmod 777 vermek sorunu güvenli çözer mi?
Hayır, chmod 777 izni sistemdeki tüm kullanıcılara okuma, yazma ve çalıştırma yetkisi tanıdığı için ciddi bir güvenlik açığı yaratır; yürütülebilir betiklere 755 veya 750, log dosyalarına ise 644 veya 640 izinleri verilmelidir.
Terminalde çalışan script cron'da neden Permission Denied verir?
Terminalde betiği kendi kullanıcı hesabınız ve tam ortam değişkenlerinizle çalıştırırken; cron servisi kısıtlı bir alt kabuk ortamında ve görevin eklendiği crontab kullanıcısının (örneğin www-data veya nobody) yetkileriyle çalıştırır.
Script içindeki shebang satırı izin hatasına sebep olur mu?
Evet, betiğin ilk satırındaki shebang (#!) yolu hatalıysa, belirtilen yorumlayıcı mevcut değilse veya çalıştırma iznine sahip değilse işletim sistemi Permission denied veya bad interpreter hatası üretir.
Root crontab'ında Permission Denied alınabilir mi?
Evet, noexec bayrağı taşıyan bir disk bölümündeki dosya doğrudan çalıştırılıyorsa veya SELinux/AppArmor politikaları işlemi engelliyorsa root kullanıcısı da Permission denied alabilir. Salt okunur dosya sistemine yazma ise genellikle Read-only file system hatası üretir.
Sonuç
Cron'da Permission Denied hatasını çözmek için dosya izinleri, üst dizin geçiş hakları, görev kullanıcısı, bağlama seçenekleri ve SELinux/AppArmor politikaları birlikte kontrol edilmelidir. Sunucuda karmaşık izin yapılarıyla uğraşmak istemediğinizde cronjob.com.tr servisinin HTTP tabanlı tetikleme altyapısıyla görevlerinizi HTTP üzerinden tetikleyebilirsiniz.
Hemen Ücretsiz Cron Job Oluşturun
chmod/chown ve üst dizin traverse karmaşasını azaltmak için görevi web kullanıcısının HTTPS uç noktasına taşıyıp cronjob.com.tr ile zamanlayın; başarısız yanıtlarda e-posta, her çalışmada 7 günlük log. Ücretsizdir; kayıtta kredi kartı istenmez.
Ücretsiz Başla →