macOS 15 Sequoia’da Apache başlamıyor ya da başladıktan hemen sonra kapanıyorsa sebebi tahminle değil, dört soruyu sırayla yanıtlayarak bulmak gerekir: hangi httpd çalışıyor, yapılandırma geçerli mi, port kimde ve hata günlüğü ne diyor. macOS’ta sistemle gelen Apache ile Homebrew’dan kurulan Apache yan yana bulunabildiği için bu sorular, iki kurulumun birbirine karıştığı noktayı da ortaya çıkarır.
Yazı önce iki kurulumun farkını, ardından teşhis akışını, hata mesajına göre hedefli düzeltmeleri ve PHP’yi mod_php ya da PHP-FPM ile bağlamayı ele alır. Yapılandırma dosyasındaki her değişiklik yedek alınarak ve sed ile hedefli biçimde yapılır; dosyanın üzerine yazılmaz.
macOS’ta iki ayrı Apache
macOS, /usr/sbin/httpd konumunda kendi Apache’siyle gelir. Bu kurulum, launchd’nin org.apache.httpd etiketiyle yönettiği bir arka plan servisi (daemon) olarak çalışır; launchd, Linux’taki systemd servis birimlerinin macOS’taki karşılığıdır. brew install httpd ise ikinci, bağımsız bir Apache kurar. İki kurulum farklı dosyalar kullanır:
| Sistem Apache’si | Homebrew httpd | |
|---|---|---|
| Program | /usr/sbin/httpd, /usr/sbin/apachectl | /opt/homebrew/bin/httpd, /opt/homebrew/bin/apachectl |
| Ana yapılandırma | /etc/apache2/httpd.conf | /opt/homebrew/etc/httpd/httpd.conf |
| Hata günlüğü | /var/log/apache2/error_log | /opt/homebrew/var/log/httpd/error_log |
| Varsayılan port | 80 | 8080 (SSL için 8443) |
| Başlatma | sudo /usr/sbin/apachectl start (launchd) | brew services start httpd |
| PHP modülü | yok | brew install php ile ayrıca kurulur |
Homebrew, httpd’nin sudo olmadan çalışabilmesi için varsayılan portları 8080 ve 8443 yapar; bu, formülün kurulum notunda yazar. Tablodaki Homebrew yolları Apple Silicon içindir, Intel Mac’lerde önek /usr/local’dır. Kabuk komutlarında öneki elle yazmak yerine "$(brew --prefix)" kullanmak iki mimaride de doğru yolu verir. Yapılandırma dosyasının içinde ise kabuk ifadesi çalışmaz; oraya brew --prefix çıktısındaki gerçek yol yazılır.
Bir ayrıntı daha önemlidir: brew shellenv kurulumu /opt/homebrew/bin dizinini PATH’in başına ekler. Bu durumda yalnız apachectl ya da httpd yazmak Homebrew’un programını çalıştırır. Sistem Apache’sine komut verirken tam yolu (/usr/sbin/apachectl) kullanın.
Teşhis akışı
1. Hangi httpd kurulu, hangisi çalışıyor
# PATH'te bulunan tüm httpd ve apachectl kopyaları
which -a httpd apachectl
# Çalışan httpd süreçleri, tam yol ve argümanlarıyla
pgrep -lf httpd
# Homebrew servisleri: kullanıcı ve root düzeyi ayrı listelenir
brew services list
sudo brew services list
pgrep çıktısındaki yol hangi kurulumun çalıştığını gösterir: /usr/sbin/httpd sistem Apache’sidir, /opt/homebrew/opt/httpd/bin/httpd -D FOREGROUND Homebrew servisidir. brew services start servisi kullanıcının ~/Library/LaunchAgents dizinine kaydeder ve oturum açılışında başlatır; sudo brew services start ise /Library/LaunchDaemons altına kaydeder ve sistem açılışında root olarak başlatır. httpd iki listede birden görünüyorsa aynı Apache iki kez başlatılıyordur ve ikinci kopya portu alamaz.
2. Yapılandırma geçerli mi
# Homebrew httpd
"$(brew --prefix)/bin/httpd" -t
# Sistem Apache'si
/usr/sbin/httpd -t
-t yalnız yapılandırmayı ayrıştırır, sunucuyu başlatmaz. Sonuç ya Syntax OK ya da hatalı dosya ve satır numarasıdır. Hangi yapılandırma dosyasının ve hangi MPM’nin (Multi-Processing Module) kullanıldığını -V gösterir:
"$(brew --prefix)/bin/httpd" -V | grep -E 'SERVER_CONFIG_FILE|Server MPM'
AH00558: httpd: Could not reliably determine the server's fully qualified domain name satırı yalnız bir uyarıdır ve Apache’nin başlamasını engellemez. Homebrew yapılandırmasındaki #ServerName www.example.com:8080 satırını ServerName localhost:8080 yapmak uyarıyı kaldırır.
3. Port kimde
sudo lsof -nP -iTCP:80 -sTCP:LISTEN
sudo lsof -nP -iTCP:8080 -sTCP:LISTEN
Burada sudo gereklidir: sistem Apache’si root olarak çalışır ve lsof yetkisiz çağrıldığında başka kullanıcıların soketlerini göstermez, port boş görünür. -nP ad ve port çözümlemesini kapatır, -sTCP:LISTEN yalnız dinleyen soketleri listeler. Çıktıdaki COMMAND, PID ve USER sütunları portu tutan süreci gösterir. Bu süreç Apache değilse ya onu kendi aracıyla durdurun ya da Apache’yi başka bir porta alın. Süreci sinyalle sonlandırmanız gerekiyorsa önce SIGTERM gönderin; adımlar kill ve PID yazısında anlatılıyor.
4. Hata günlüğü ne diyor
tail -n 50 "$(brew --prefix)/var/log/httpd/error_log"
tail -n 50 /var/log/apache2/error_log
Homebrew’un httpd servis tanımı standart hata çıktısını bir dosyaya yönlendirmez. Günlük dosyası açılmadan önce oluşan hatalar bu yüzden hiçbir yerde görünmeyebilir. Böyle bir durumda servisi durdurup Apache’yi ön planda başlatmak hatayı doğrudan terminale yazar; Ctrl+C ile kapatılır:
brew services stop httpd
"$(brew --prefix)/opt/httpd/bin/httpd" -D FOREGROUND
5. Güncellemeden sonra sistem yapılandırması değişti mi
Sistem Apache’sini kullanıyorsanız macOS’un varsayılan yapılandırma kopyası /etc/apache2/original/httpd.conf konumunda durur. Güncellemeden sonra kendi değişikliklerinizin yerinde olup olmadığını iki dosyayı karşılaştırarak görebilirsiniz:
diff /etc/apache2/original/httpd.conf /etc/apache2/httpd.conf
Çıktı boşsa yapılandırma varsayılan hâldedir. Önceki ayarlarınız kaybolduysa onları yedeğinizden satır satır geri taşıyın; varsayılan dosyanın tamamını eski bir kopyayla değiştirmek yeni sürümün eklediği satırları siler.
Hata mesajına göre çözüm
Port başka bir süreçte: Address already in use
Günlükte Address already in use ve could not bind to address birlikte görünüyorsa port başka bir süreçtedir. macOS’ta iki tipik neden vardır: sistem Apache’si 80’de çalışırken Homebrew httpd de 80’e alınmıştır ya da Homebrew httpd hem kullanıcı hem root düzeyinde servis olarak kayıtlıdır.
# Sistem Apache'sini durdurur. macOS'un apachectl betiği bunu
# launchctl unload -w ile yaptığı için servis açılışta yeniden başlamaz.
sudo /usr/sbin/apachectl stop
# Root düzeyindeki Homebrew servis kaydını kaldırır
sudo brew services stop httpd
# Homebrew httpd'yi kullanıcı düzeyinde başlatır ve oturum açılışına kaydeder
brew services start httpd
brew services start servisi oturum açılışına zaten kaydeder. Aynı servisi ayrıca sudo ile başlatmak ikinci bir kopya üretir ve Homebrew dizininde root sahipliğinde dosyalar bırakabilir.
Yetki hatası: Permission denied
Permission denied ile could not bind to address birlikte görünüyorsa Apache, root yetkisi olmadan 1024 altındaki bir porta bağlanmaya çalışıyordur. macOS’ta bu kısıt Mojave’den beri tüm adresleri dinleyen soketler (Listen 80) için kalktı; belirli bir adrese bağlanmak (Listen 127.0.0.1:80) ise hâlâ root yetkisi ister. Apple bu davranışı resmî olarak belgelemedi: değişikliği bir Apple DTS mühendisi geliştirici forumunda doğruladı, belirli adres kısıtını da aynı konudaki kullanıcı raporları anlatıyor. Ekim 2026’da macOS 27’de yapılan denemede de 0.0.0.0:81 ve [::]:81 root olmadan bağlandı, 127.0.0.1:81 ise Permission denied verdi.
En basit çözüm Homebrew’un varsayılanı olan 8080’e dönmektir. Önce yedek alın, sonra yalnız ilgili satırı değiştirin:
conf="$(brew --prefix)/etc/httpd/httpd.conf"
# Zaman damgalı yedek
cp -p "$conf" "$conf.$(date +%Y%m%d-%H%M%S).bak"
# Yalnız "Listen 80" ve "Listen <adres>:80" satırlarını 8080'e çevirir
sed -i '' -E 's/^([[:space:]]*Listen[[:space:]]+([0-9.]+:)?)80$/\18080/' "$conf"
# Sonucu ve sözdizimini doğrula
grep -nE '^[[:space:]]*Listen' "$conf"
"$(brew --prefix)/bin/httpd" -t
macOS’taki BSD sed, -i seçeneğinden sonra bir yedek uzantısı bekler; boş dize ('') ek dosya oluşturmadan yerinde düzenler. Desen satır başına (^) ve sonuna ($) bağlı olduğu için zaten Listen 8080 olan satıra dokunmaz. Elle düzenlemek isterseniz yine önce cp -p ile yedek alın.
Hata günlük dosyasının kendisi için geliyorsa (could not open error log file), httpd daha önce root olarak çalışmış ve günlük dosyalarını root sahipliğinde bırakmış olabilir; kullanıcı olarak başlayan httpd bu dosyalara yazamaz. Sahipliği kontrol edin, root ise kendi kullanıcınıza geri verin:
ls -l "$(brew --prefix)/var/log/httpd"
sudo chown "$(id -un)" "$(brew --prefix)"/var/log/httpd/*_log
MPM çakışması: More than one MPM loaded
httpd -t şu çıktıyı veriyorsa yapılandırmada birden fazla MPM yüklüdür:
AH00534: httpd: Configuration error: More than one MPM loaded.
Homebrew httpd varsayılan olarak prefork MPM’sini yükler. Eski performans rehberlerindeki LoadModule mpm_worker_module satırını bunun yanına eklemek bu hatayı verir. Yüklü MPM satırlarını listeleyin:
grep -nE '^[[:space:]]*LoadModule mpm_' "$(brew --prefix)/etc/httpd/httpd.conf"
Birden fazla satır çıkıyorsa yalnız birini bırakıp diğerlerini # ile yorum satırına çevirin. mod_php kullanıyorsanız kalması gereken mpm_prefork_module’dür.
PHP modülü yüklenmiyor
Kısaltılmış örnek çıktı:
httpd: Syntax error on line 534 of /opt/homebrew/etc/httpd/httpd.conf: Cannot load /usr/local/lib/httpd/modules/libphp.so into server: dlopen(...)
Bu hata, LoadModule satırındaki yolun var olmayan bir dosyayı gösterdiği anlamına gelir. Olası nedenler: Apple Silicon bir Mac’e taşınmış Intel dönemi /usr/local/... yolu, güncellemeyle silinen sürümlü bir Cellar yolu (Cellar/php/<sürüm>/...) ya da brew unlink php sonrasında kaybolan bir bağlantı. brew info php çıktısındaki notta yazan opt/php yolu bu değişikliklerden etkilenmez; dosyanın var olduğunu şöyle doğrulayabilirsiniz:
ls -l "$(brew --prefix php)/lib/httpd/modules/libphp.so"
Günlükte Apache is running a threaded MPM, but your PHP Module is not compiled to be threadsafe görünüyorsa mod_php, event veya worker MPM ile birlikte yüklenmiştir. Homebrew PHP’si thread-safe derlenmediği için ya prefork’a dönün ya da aşağıdaki PHP-FPM yöntemine geçin.
PHP’yi Apache’ye bağlamak
macOS’un kendi Apache’si PHP modülü içermez. Yerel PHP geliştirmesi için aşağıdaki iki yöntem Homebrew httpd’yi esas alır.
Yöntem 1: mod_php ve prefork
brew install php sonrasında brew info php çıktısındaki notlar (caveats) Apache için gereken satırları verir. Bu satırları yapılandırma dosyasının sonuna eklemek ve DirectoryIndex satırını hedefli olarak değiştirmek yeterlidir:
conf="$(brew --prefix)/etc/httpd/httpd.conf"
cp -p "$conf" "$conf.$(date +%Y%m%d-%H%M%S).bak"
# >> dosyanın sonuna ekler; tek > dosyanın tamamını siler
cat >> "$conf" <<EOF
# PHP: brew info php notlarındaki satırlar
LoadModule php_module $(brew --prefix php)/lib/httpd/modules/libphp.so
<FilesMatch \.php\$>
SetHandler application/x-httpd-php
</FilesMatch>
EOF
# Dizin isteğinde önce index.php aranır
sed -i '' -E 's/^([[:space:]]*DirectoryIndex) index\.html$/\1 index.php index.html/' "$conf"
"$(brew --prefix)/bin/httpd" -t && brew services restart httpd
Heredoc tırnaksız olduğu için $(brew --prefix php) yazma anında gerçek yola (/opt/homebrew/opt/php/...) çevrilir; \$ ise $ karakterini olduğu gibi bırakır. opt/php yolu PHP güncellemelerinde değişmez. php@8.3 gibi sürümlü bir formül kullanıyorsanız brew --prefix php@8.3 yazın.
PHP’nin çalıştığını yeni bir test dosyasıyla doğrulayın, işiniz bitince dosyayı silin:
printf '<?php echo PHP_VERSION, PHP_EOL;\n' > "$(brew --prefix)/var/www/surum.php"
curl -s http://localhost:8080/surum.php
rm "$(brew --prefix)/var/www/surum.php"
Yöntem 2: PHP-FPM ve event MPM
PHP-FPM, PHP’yi Apache’den ayrı bir süreç havuzunda çalıştırır; Apache, .php isteklerini mod_proxy_fcgi ile bu havuza iletir. Böylece Apache, mod_php ile kullanılamayan event MPM’sini kullanabilir.
# php-fpm'i kullanıcı servisi olarak başlatır; varsayılan havuz 127.0.0.1:9000'de dinler
brew services start php
lsof -nP -iTCP:9000 -sTCP:LISTEN
conf="$(brew --prefix)/etc/httpd/httpd.conf"
cp -p "$conf" "$conf.$(date +%Y%m%d-%H%M%S).bak"
sed -i '' -E \
-e 's/^(LoadModule mpm_prefork_module)/#\1/' \
-e 's/^#(LoadModule mpm_event_module)/\1/' \
-e 's/^#(LoadModule proxy_module )/\1/' \
-e 's/^#(LoadModule proxy_fcgi_module )/\1/' \
-e 's/^(LoadModule php_module)/#\1/' \
-e 's#SetHandler application/x-httpd-php$#SetHandler "proxy:fcgi://127.0.0.1:9000"#' \
"$conf"
"$(brew --prefix)/bin/httpd" -t && brew services restart httpd
Bu sed komutu prefork’u kapatıp event MPM’sini, mod_proxy ve mod_proxy_fcgi modüllerini açar, mod_php’yi devre dışı bırakır ve önceki yöntemde eklenen FilesMatch bloğunu FPM’ye yönlendirir. Blok hiç eklenmediyse önceki bölümdeki cat >> adımını SetHandler "proxy:fcgi://127.0.0.1:9000" satırıyla kullanın. FPM havuzunun dinlediği adres $(brew --prefix)/etc/php/<sürüm>/php-fpm.d/www.conf dosyasındaki listen satırındadır.
macOS 15 ve sonrası için not
Yazı macOS 15 Sequoia için yazıldı. Yollar ve komutlar Ekim 2026’da macOS 27.0 üzerinde, sistem Apache’si 2.4.67 ve Homebrew httpd 2.4.68 ile salt okunur kontroller ve httpd -t kullanılarak yeniden denetlendi. Bu sürümde sistem Apache’si hâlâ /usr/sbin/httpd olarak geliyor ve prefork kullanıyor; apachectl start ve stop hâlâ launchctl load -w ve unload -w çağırıyor; varsayılan yapılandırma kopyası /etc/apache2/original/ altında duruyor. Servis başlatma adımları bu sürümde ayrıca denenmedi. Büyük bir macOS güncellemesinden sonra teşhis akışını baştan çalıştırmak, eski bir rehberdeki yolları doğrulamadan uygulamaktan daha güvenilirdir.
Sonuç
macOS’ta Apache başlamadığında hangi kurulumun çalıştığına, yapılandırmanın geçerli olup olmadığına, portu kimin tuttuğuna ve error_log’a sırayla bakın; düzeltmeyi sorunun göründüğü adıma göre seçin. Yerel PHP geliştirmesi için Homebrew httpd’yi 8080’de kullanıcı servisi olarak çalıştırmak, sistem Apache’sini kapalı tutmak ve yapılandırma değişikliklerini yedek alıp sed ile hedefli yapmak iki kurulumun çakışmasını önler. Sistem Apache’si statik dosya sunmak için yeterlidir; PHP, MPM seçimi veya birden fazla PHP sürümü gerekiyorsa Homebrew kurulumu daha kontrollüdür.