OpenLiteSpeed ile Docker Ortamında Çalıştırma

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.

Yorum yapın