Cron Job Permission Denied Hatası ve Çözümü

Sorun GidermeYayın: Güncellendi: 11 dk okumaHazırlayan: cronjob.com.tr Editörleri

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:

  1. 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ı.
  2. Kullanıcı ve Grup (UID/GID) Yetki Uyuşmazlığı: Örneğin görevin www-data kullanıcısının crontab'ında tanımlanmış olması fakat betiğin yalnızca root veya ubuntu kullanıcısı tarafından okunabilir izinlere (0700) sahip olması.
  3. 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ı.
  4. 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
Güvenlik İlkesi: İzin sorununu çözmek amacıyla asla 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:

  1. 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
  2. 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:

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 →

İlgili Rehberler