Docker ile sunucu yönetimi artık kaçınılmaz bir gerçek. Ama OpenLiteSpeed’i container ortamında çalıştırmak, bazı sysadmin’lerin düşündüğünden daha fazla nüans barındırıyor. Hem performans hem de yönetim kolaylığı açısından doğru yapılandırıldığında, OLS + Docker kombinasyonu production ortamlar için gerçekten güçlü bir seçenek haline geliyor. Bu yazıda sıfırdan başlayarak production’a hazır bir OpenLiteSpeed Docker kurulumu yapacağız.
Neden OpenLiteSpeed ve Docker Birlikte?
OpenLiteSpeed’in Apache ve Nginx’e kıyasla sunduğu performans avantajları zaten iyi biliniyor. PHP-FPM yerine LiteSpeed SAPI kullanması, özellikle WordPress gibi PHP ağırlıklı uygulamalarda çok ciddi fark yaratıyor. Docker ise bize izolasyon, taşınabilirlik ve kolay ölçekleme imkanı veriyor.
İkisini birleştirdiğimizde şunları elde ediyoruz:
- Hızlı deployment: Yeni bir site kurmak dakikalar meselesi
- Kolay rollback: Image versiyonlama sayesinde sorunlu güncellemelerden hızla dönebiliyorsunuz
- Kaynak izolasyonu: Her uygulama kendi container’ında çalışıyor
- Geliştirme-production paritesi: Dev ortamınız production ile birebir aynı
Tek dezavantaj olarak şunu söyleyeyim: OLS’nin web tabanlı admin paneli container ortamında biraz farklı davranıyor. Bunu da ele alacağız.
Ön Hazırlık ve Gereksinimler
Sisteminizde Docker ve Docker Compose kurulu olmalı. Ben bu yazıda Ubuntu 22.04 üzerinde Docker 24.x ile çalışıyorum. Aşağıdaki komutlarla versiyonları kontrol edin:
docker --version
docker compose version
Proje dizin yapımızı şöyle oluşturalım:
mkdir -p ~/ols-docker/{config,logs,html,certs,php}
cd ~/ols-docker
Bu yapı önemli. Her şeyi düzgün mount etmezsek container restart sonrasında konfigürasyonlarımız uçar, bu da production’da felaket demek.
Temel Docker Compose Dosyası
Önce basit çalışan bir yapıyla başlayalım, sonra üstüne inşa ederiz. Aşağıdaki docker-compose.yml dosyasını oluşturun:
cat > ~/ols-docker/docker-compose.yml << 'EOF'
version: '3.8'
services:
openlitespeed:
image: litespeedtech/openlitespeed:latest
container_name: ols_webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "7080:7080"
volumes:
- ./html:/var/www/vhosts/localhost/html
- ./config/vhosts:/usr/local/lsws/conf/vhosts
- ./config/httpd_config.conf:/usr/local/lsws/conf/httpd_config.conf
- ./logs:/usr/local/lsws/logs
- ./certs:/etc/letsencrypt
environment:
- TZ=Europe/Istanbul
- OLS_ADMIN_PASS=GucluBirSifre123!
networks:
- ols_network
networks:
ols_network:
driver: bridge
EOF
Port 7080, OLS admin paneline erişim için gerekli. Production’da bu portu dışarıya açmamanızı, sadece localhost üzerinden erişmenizi öneririm. Firewall kurallarıyla kısıtlayın.
Özel Dockerfile ile Image Oluşturma
Resmi image iyi bir başlangıç noktası ama çoğu zaman özelleştirme gerekiyor. PHP extension’ları eklemek, özel modüller yüklemek veya security hardening yapmak istediğinizde kendi image’ınızı build etmeniz gerekiyor.
cat > ~/ols-docker/Dockerfile << 'EOF'
FROM litespeedtech/openlitespeed:latest
# Gerekli paketleri kur
RUN apt-get update && apt-get install -y
curl
wget
unzip
git
&& rm -rf /var/lib/apt/lists/*
# PHP eklentilerini kur (lsphp81 üzerinde)
RUN apt-get update && apt-get install -y
lsphp81-common
lsphp81-mysql
lsphp81-curl
lsphp81-imagick
lsphp81-redis
lsphp81-intl
lsphp81-opcache
&& rm -rf /var/lib/apt/lists/*
# OLS için PHP yolunu ayarla
RUN ln -sf /usr/local/lsws/lsphp81/bin/lsphp /usr/local/bin/lsphp
# Özel OLS konfigürasyonu
COPY config/httpd_config.conf /usr/local/lsws/conf/httpd_config.conf
# Sağlık kontrolü
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3
CMD curl -f http://localhost/lscheck || exit 1
EXPOSE 80 443 7080
CMD ["/usr/local/lsws/bin/lswsctrl", "start"]
EOF
Şimdi bu image’ı build edelim:
cd ~/ols-docker
docker build -t ols-custom:1.0 .
httpd_config.conf Temel Yapılandırması
Bu dosya OLS’nin kalbi. Container’a mount edeceğimiz konfigürasyon dosyasını oluşturalım:
mkdir -p ~/ols-docker/config
cat > ~/ols-docker/config/httpd_config.conf << 'EOF'
serverName localhost
user nobody
group nogroup
priority 0
inMemBufSize 60M
swappingDir /tmp/lshttpd/swap
autoFix503 1
gracefulRestartTimeout 300
mime conf/mime.properties
showVersionNumber 0
adminEmails [email protected]
errorlog logs/error.log {
useServer 1
logLevel ERROR
rollingSize 10M
keepDays 30
compressArchive 1
}
accesslog logs/access.log {
useServer 0
logFormat "%h %l %u %t "%r" %>s %b"
logHeaders 5
rollingSize 10M
keepDays 30
compressArchive 1
}
tuning {
maxConnections 10000
maxSSLConnections 10000
connTimeout 300
maxKeepAliveReq 10000
keepAliveTimeout 5
sndBufSize 0
rcvBufSize 0
maxReqURLLen 32768
maxReqHeaderSize 65536
maxReqBodySize 2047M
maxDynRespHeaderSize 32768
maxDynRespSize 2047M
maxCachedFileSize 4096
totalInMemCacheSize 20M
totalMMAPCacheSize 40M
useSendfile 1
fileETag 28
enableGzipCompress 1
enableBrCompress 4
compressibleTypes default
gzipCompressLevel 6
brCompressLevel 4
}
EOF
showVersionNumber 0 satırına dikkat edin. Bu, security açısından önemli. OLS versiyonunuzu response header’larında yayınlamak istemezsiniz.
WordPress ile Gerçek Dünya Örneği
Şimdi işin pratik kısmına gelelim. Production’da en sık karşılaşılan senaryo: WordPress + MySQL + Redis + OpenLiteSpeed. Tam stack’i Docker Compose ile ayağa kaldıralım:
cat > ~/ols-docker/docker-compose-wordpress.yml << 'EOF'
version: '3.8'
services:
openlitespeed:
build:
context: .
dockerfile: Dockerfile
container_name: ols_web
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- wordpress_data:/var/www/vhosts/wordpress/html
- ./config/vhosts/wordpress.conf:/usr/local/lsws/conf/vhosts/wordpress/vhconf.conf
- ./logs/ols:/usr/local/lsws/logs
- ./certs:/etc/letsencrypt
environment:
- TZ=Europe/Istanbul
depends_on:
- mysql
- redis
networks:
- wp_network
mysql:
image: mysql:8.0
container_name: ols_mysql
restart: unless-stopped
volumes:
- mysql_data:/var/lib/mysql
- ./config/mysql/my.cnf:/etc/mysql/conf.d/custom.cnf
environment:
- MYSQL_ROOT_PASSWORD=rootsifre123
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wpuser
- MYSQL_PASSWORD=wpsifre456
- TZ=Europe/Istanbul
networks:
- wp_network
redis:
image: redis:7-alpine
container_name: ols_redis
restart: unless-stopped
command: redis-server --requirepass redissifre789 --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- redis_data:/data
networks:
- wp_network
phpmyadmin:
image: phpmyadmin:latest
container_name: ols_phpmyadmin
restart: unless-stopped
ports:
- "127.0.0.1:8080:80"
environment:
- PMA_HOST=mysql
- PMA_PORT=3306
depends_on:
- mysql
networks:
- wp_network
volumes:
wordpress_data:
mysql_data:
redis_data:
networks:
wp_network:
driver: bridge
EOF
PhpMyAdmin’i sadece 127.0.0.1:8080‘e bind ettiğimize dikkat edin. Bu şekilde dışarıdan erişim engellenmiş oluyor, SSH tunnel üzerinden ulaşıyorsunuz.
Virtual Host Konfigürasyonu
WordPress için virtual host dosyasını oluşturalım:
mkdir -p ~/ols-docker/config/vhosts/wordpress
cat > ~/ols-docker/config/vhosts/wordpress/vhconf.conf << 'EOF'
docRoot $VH_ROOT/html/
vhDomain yourdomain.com
vhAliases www.yourdomain.com
adminEmails [email protected]
enableGzip 1
enableIpGeo 0
index {
useServer 0
indexFiles index.php, index.html
autoIndex 0
}
scripthandler {
add lsapi:lsphp81 php
}
accessControl {
allow *
}
rewrite {
enable 1
autoLoadHtaccess 1
rules <<<END_RULES
RewriteEngine On
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
END_RULES
}
context / {
location $DOC_ROOT/
allowBrowse 1
rewrite {
enable 1
}
}
vhssl {
keyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem
certFile /etc/letsencrypt/live/yourdomain.com/fullchain.pem
certChain 1
sslProtocol 24
ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
enableECDHE 1
renegProtection 1
sslSessionCache 1
enableTicket 0
}
EOF
Container Yönetimi ve Günlük Operasyonlar
Stack’i ayağa kaldırmak için:
cd ~/ols-docker
docker compose -f docker-compose-wordpress.yml up -d
# Logları takip et
docker compose -f docker-compose-wordpress.yml logs -f openlitespeed
# OLS'yi container içinde yeniden başlat (tam restart değil, graceful)
docker exec ols_web /usr/local/lsws/bin/lswsctrl restart
# Container'a shell ile bağlan
docker exec -it ols_web bash
# PHP versiyon kontrolü
docker exec ols_web /usr/local/lsws/lsphp81/bin/php -v
OLS’nin en güzel özelliklerinden biri graceful restart. Apache’deki apachectl gracefull gibi, mevcut bağlantıları kesmeden yeni worker’ları başlatıyor. Container ortamında bu özellikten faydalanmak için container’ı tamamen durdurmak yerine yukarıdaki lswsctrl restart komutunu kullanın.
SSL Sertifikası ve Let’s Encrypt Entegrasyonu
Production’da HTTPS kaçınılmaz. Certbot’u ayrı bir container olarak çalıştıralım:
# Certbot ile sertifika al
docker run --rm
-v ~/ols-docker/certs:/etc/letsencrypt
-v ~/ols-docker/html/certbot:/var/www/html
certbot/certbot certonly
--webroot
--webroot-path=/var/www/html
--email [email protected]
--agree-tos
--no-eff-email
-d yourdomain.com
-d www.yourdomain.com
Sertifika yenileme için cron job ekleyin:
# Crontab'a ekle
crontab -e
# Şu satırı ekleyin:
0 3 * * * docker run --rm -v ~/ols-docker/certs:/etc/letsencrypt -v ~/ols-docker/html/certbot:/var/www/html certbot/certbot renew --quiet && docker exec ols_web /usr/local/lsws/bin/lswsctrl restart
Performans Tuning ve Cache Yapılandırması
LiteSpeed Cache, OLS’nin en güçlü silahı. Container ortamında da aktif edebiliriz:
cat >> ~/ols-docker/config/vhosts/wordpress/vhconf.conf << 'EOF'
module cache {
storagePath /tmp/lscache
ls_enabled 1
}
context exp:php {
location SCRIPT_FILENAME
handler lsapi:lsphp81
addDefaultCharset off
}
EOF
Container başlangıcında cache dizinini oluşturmak için entrypoint script yazalım:
cat > ~/ols-docker/docker-entrypoint.sh << 'EOF'
#!/bin/bash
set -e
# Cache dizini oluştur
mkdir -p /tmp/lscache
chown -R nobody:nogroup /tmp/lscache
# Log dizinleri
mkdir -p /usr/local/lsws/logs
touch /usr/local/lsws/logs/error.log
touch /usr/local/lsws/logs/access.log
# OLS başlat
exec /usr/local/lsws/bin/lswsctrl start
# Foreground'da tut
tail -f /usr/local/lsws/logs/error.log
EOF
chmod +x ~/ols-docker/docker-entrypoint.sh
Dockerfile’ı bu script’i kullanacak şekilde güncelleyin:
# Dockerfile'a ekle
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
Güvenlik Sertleştirme
Container’ı root olmayan bir kullanıcıyla çalıştırmak ve gereksiz yetenekleri kaldırmak önemli:
cat > ~/ols-docker/docker-compose-secure.yml << 'EOF'
version: '3.8'
services:
openlitespeed:
image: ols-custom:1.0
container_name: ols_web_secure
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./html:/var/www/vhosts/localhost/html:ro
- ./config:/usr/local/lsws/conf:ro
- ./logs:/usr/local/lsws/logs
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
- CHOWN
- SETUID
- SETGID
read_only: false
tmpfs:
- /tmp
- /run
environment:
- TZ=Europe/Istanbul
deploy:
resources:
limits:
cpus: '2.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 256M
networks:
- secure_network
networks:
secure_network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
EOF
cap_drop: ALL ile tüm Linux capabilities’leri kaldırıyoruz, sonra sadece ihtiyaç duyduklarını geri ekliyoruz. no-new-privileges:true ise container içindeki süreçlerin privilege escalation yapmasını engelliyor.
Sorun Giderme
Container ortamında OLS ile çalışırken karşılaşılan yaygın sorunlar ve çözümleri:
403 Forbidden hatası:
# Dosya izinlerini kontrol et
docker exec ols_web ls -la /var/www/vhosts/
# nobody kullanıcısına izin ver
docker exec ols_web chown -R nobody:nogroup /var/www/vhosts/localhost/html
PHP çalışmıyor:
# lsphp process'ini kontrol et
docker exec ols_web ps aux | grep lsphp
# OLS hata loglarını incele
docker exec ols_web tail -50 /usr/local/lsws/logs/error.log
# PHP handler konfigürasyonunu kontrol et
docker exec ols_web cat /usr/local/lsws/conf/httpd_config.conf | grep -A5 lsphp
Container restart sonrası konfigürasyon kaybı: Bu en sık yapılan hata. Tüm kritik dizinleri volume olarak mount ettiğinizden emin olun. Özellikle /usr/local/lsws/conf/ ve /usr/local/lsws/admin/conf/ dizinlerini unutmayın.
Admin paneline erişim sorunu:
# Admin şifreyi sıfırla
docker exec ols_web /usr/local/lsws/admin/misc/admpass.sh
# Admin servisinin çalışıp çalışmadığını kontrol et
docker exec ols_web ss -tlnp | grep 7080
Multi-Site Yapılandırması
Birden fazla web sitesi çalıştırıyorsanız, her site için ayrı virtual host dizini oluşturun ve ana konfigürasyona ekleyin:
# Site dizin yapısı
mkdir -p ~/ols-docker/config/vhosts/{site1,site2,site3}
# Her site için vhconf.conf dosyası oluşturun
# httpd_config.conf'a virtual host tanımları ekleyin
cat >> ~/ols-docker/config/httpd_config.conf << 'EOF'
virtualhost site1 {
vhRoot /var/www/vhosts/site1/
configFile conf/vhosts/site1/vhconf.conf
allowSymbolLink 1
enableScript 1
restrained 1
}
virtualhost site2 {
vhRoot /var/www/vhosts/site2/
configFile conf/vhosts/site2/vhconf.conf
allowSymbolLink 1
enableScript 1
restrained 1
}
listener HTTP {
address *:80
secure 0
map site1 yourdomain1.com, www.yourdomain1.com
map site2 yourdomain2.com, www.yourdomain2.com
}
listener HTTPS {
address *:443
secure 1
map site1 yourdomain1.com, www.yourdomain1.com
map site2 yourdomain2.com, www.yourdomain2.com
}
EOF
Sonuç
OpenLiteSpeed’i Docker ortamında çalıştırmak, başlangıçta biraz öğrenme eğrisi gerektiriyor. Özellikle konfigürasyon dosyalarının doğru mount edilmesi, PHP handler’ların ayarlanması ve cache yapılandırması dikkat istiyor. Ama bir kez çalışır hale getirdiğinizde, elde ettiğiniz deployment hızı ve esneklik gerçekten değer.
Özellikle vurgulamak istediğim birkaç nokta: Volume mount’larınızı asla ihmal etmeyin, admin panelini internete açmayın ve security_opt ile cap_drop ayarlarını production’da mutlaka kullanın. Multi-site yapılandırmalarında virtual host listener mapping’lerini dikkatli yapın, yanlış mapping ciddi baş ağrısına yol açabiliyor.
Nginx veya Apache’den OLS’ye geçiş yapıyorsanız, rewrite kurallarının davranışı bazı edge case’lerde farklı olabiliyor. Geçiş sürecinde mutlaka staging ortamında test edin. LiteSpeed Cache eklentisi WordPress için tartışmasız en iyi cache çözümü, bu kombinasyonu bir kez production’da görünce neden bu kadar popüler olduğunu anlıyorsunuz.
Bu yapıyı CI/CD pipeline’ınıza entegre etmek, image’larınızı registry’de versiyonlamak ve Kubernetes’e taşımak da bir sonraki adımlar olarak değerlendirilebilir. Sorularınız olursa yorum kısmında belirtin.