Teknoloji

WordPress’i Docker ile Konteynerize Etmek: Tek VPS’te Traefik/Nginx Reverse Proxy ile Üretim Mimarisi Nasıl Kurulur?

Ofiste Küçük Bir Sorun, Büyük Bir Aydınlanma: Tek VPS’te WordPress’i Nasıl Derli Toplu Koştururuz?

Hiç WordPress sitenizi tek bir VPS’e taşırken “bunu daha temiz, daha düzenli ve güvenli nasıl yaparım?” diye uzun uzun düşündünüz mü? Ben bir akşam tam da bu soruyla boğuşurken, sunucuda bir WordPress, bir veritabanı, bir de önünde bir ters vekil (reverse proxy) derken her şeyin birbirine karıştığını fark ettim. Klasik kurulumda dizin izinleri, PHP ayarları, SSL yenilemeleri ve yedeklemeler derken küçük bir değişiklik bile domino taşı gibi her şeyi etkileyebiliyor. O gün kendime “Bunu konteynerlerle, gözüm arkada kalmadan, üretim ortamı disiplininde toparlayamaz mıyım?” diye sordum.

İşte bu yazıda, tek bir VPS üzerinde WordPress’i Docker ile konteynerize edip, önüne Traefik ya da Nginx reverse proxy koyarak üretim şartlarına yakışır bir mimariyi adım adım kuracağız. Mesela şöyle düşünün: Her parça kendi kutusunda, bağımlılıklar şeffaf, güncellemeler kontrollü, SSL otomatik ve loglar tertemiz. Ben hem pratikte uyguladığım örnek dosyaları hem de yolda görebileceğiniz küçük tümsekleri anlatacağım. En sonda da güncelleme ve yedekleme stratejisiyle güvenle uyumanızı sağlayacak birkaç tatlı tavsiye bırakacağım.

Mimarinin Fotoğrafı: Küçük Kutular, Net Sorumluluklar

Bir an gözünüzün önüne getirin: Tek bir VPS, üstünde Docker Engine, onun üzerinde üç ana oyuncu. Önde trafiği karşılayan reverse proxy (Traefik veya Nginx), ortada WordPress uygulaması (PHP-FPM olarak), arkada da veritabanı. Hepsi kendi konteynerinde, kendi hayatlarını yaşıyor. Network olarak iki küçük sahne var; edge sahnesinde reverse proxy dışarıya bakıyor, backend sahnesinde WordPress ile veritabanı sakin sakin konuşuyor. Veriler kalıcı volume’larda duruyor, logs ve config’ler repo’da sakince takip ediliyor.

Böyle olunca sihirli birkaç şey oluyor. Birincisi, sorun olduğunda suçluyu bulmak kolaylaşıyor. İkincisi, güncelleme yapmak güç gösterisine dönüşmüyor; imajı değiştir, servisi yeniden başlat, mis gibi. Üçüncüsü, güvenlik sınırları netleşiyor; dışarı sadece reverse proxy bakıyor, veritabanı kapalı bir arka sokakta yaşıyor. Dördüncüsü, taşıması kolay; yarın başka bir VPS’e geçmek isterseniz, dosyalarınızın ve .env’inizin peşinden gitmeniz çoğu zaman yetiyor.

Traefik ile Reverse Proxy: HTTPS, Yönlendirmeler ve Etiketlerle Büyü Yapmak

Traefik’i özellikle tek VPS senaryosunda seviyorum; Docker etiketleriyle konuşuyor, servisleri otomatik keşfediyor ve TLS sertifikalarını kendi alıyor. Bir kere doğru kurdunuz mu, yeni bir servis eklemek için çoğu zaman sadece birkaç label yazmanız yeterli oluyor. HTTP’den HTTPS’e yönlendirme, HSTS, sıkıştırma gibi detayları da ayar dosyasında toparlayabilirsiniz. En güzeli de, loglar net ve anlaşılır.

Eğer DNS tarafında ACME doğrulamasını merak ediyorsanız, ACME challenge türlerini sakin sakin anlattığım yazı tam yerine oturuyor. Sertifika sağlayıcısında aksaklıkları yedekli yönetmek isterseniz de ACME otomasyonunda yedekli CA kurma rehberini göz atmalık notlar listesine ekleyin.

Traefik’in etiket tabanlı yaklaşımıyla tanışmak için resmi Traefik belgeleri iyi bir başlangıç. Ben burada pratik, çalışır bir örnek üzerinden ilerleyeceğim. Etiketleri okuyabilen bir göz, sistemin niyetini de hemen okuyor, bu güzel bir his.

docker-compose.yml: WordPress + PHP-FPM, Nginx (App), MariaDB ve Traefik

Ön Hazırlık: .env ve küçük ayarlar

Ben yapılandırmaları olabildiğince .env’e almayı seviyorum. Böylece repo’yla kimlik bilgilerinin yolunu ayırmak kolaylaşıyor. Aşağıdaki gibi basit bir .env dosyası iyi bir start:

DOMAIN=example.com
[email protected]
DB_PASSWORD=supersecret
DB_ROOT_PASSWORD=evenmoresecret

Bir de PHP için upload ve memory limitini tatlı bir noktaya çekmek için küçük bir ini dosyası açıyorum:

; uploads.ini
file_uploads = On
memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300

Compose dosyası: Servisleri sahneye alalım

Gelelim asıl dosyaya. Aşağıdaki örnek, tek bir VPS’te Traefik’i reverse proxy olarak kullanıyor; WordPress’i PHP-FPM ile çalıştırıp Nginx’i uygulama sunucusu gibi konumlandırıyor. MariaDB de arkada, sessiz ve derinden:

version: "3.9"

services:
  traefik:
    image: traefik:v2.11
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.le.acme.tlschallenge=true
      - --certificatesresolvers.le.acme.email=${ACME_EMAIL}
      - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
    ports:
      - 80:80
      - 443:443
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - letsencrypt:/letsencrypt
    networks:
      - edge

  db:
    image: mariadb:10.11
    environment:
      - MYSQL_DATABASE=wordpress
      - MYSQL_USER=wp
      - MYSQL_PASSWORD=${DB_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - backend

  wordpress:
    image: wordpress:6.6-fpm
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=wp
      - WORDPRESS_DB_PASSWORD=${DB_PASSWORD}
      - WORDPRESS_DB_NAME=wordpress
    volumes:
      - wp_data:/var/www/html
      - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini:ro
    depends_on:
      db:
        condition: service_healthy
    networks:
      - backend

  web:
    image: nginx:1.25-alpine
    volumes:
      - wp_data:/var/www/html:ro
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - wordpress
    labels:
      - traefik.enable=true
      - traefik.http.routers.wp.rule=Host(`${DOMAIN}`)
      - traefik.http.routers.wp.entrypoints=websecure
      - traefik.http.routers.wp.tls.certresolver=le
      - traefik.http.services.wp.loadbalancer.server.port=80
      - traefik.http.routers.wp.middlewares=wp-https-redirect
      - traefik.http.middlewares.wp-https-redirect.redirectscheme.scheme=https
    networks:
      - edge
      - backend

volumes:
  db_data:
  wp_data:
  letsencrypt:

networks:
  edge:
  backend:

Bu dosyada dikkatinizi çekecek nokta şu: Traefik dış dünyaya bakıyor, Nginx içerde 80’de dinliyor ve PHP-FPM’e fastcgi geçiş yapıyor. Traefik’in TLS işini üstlenmesi işleri ciddi basitleştiriyor. Etiketlerle tek domain’e route ettik; isterseniz alt alanlar veya farklı siteler için çoğaltmanız çok kolay.

Nginx tarafı: PHP-FPM’e nazikçe pas atmak

Nginx konteyneri, statik dosyaları hızlıca sunarken, dinamik istekleri PHP-FPM’e iletiyor. Bunun için basit bir Nginx yapılandırması yeterli:

server {
  listen 80 default_server;
  server_name ${DOMAIN};

  root /var/www/html;
  index index.php index.html;

  location / {
    try_files $uri $uri/ /index.php?$args;
  }

  location ~ .php$ {
    include fastcgi_params;
    fastcgi_pass wordpress:9000;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }

  location ~* .(jpg|jpeg|png|gif|css|js|ico|svg)$ {
    expires 7d;
    add_header Cache-Control "public, no-transform";
  }
}

Burada fastcgi_pass wordpress:9000 ifadesi, PHP-FPM’in konteyner adını kullanarak erişildiğini anlatıyor. Yani basitçe söylemek gerekirse Nginx “dinamiği” WordPress’e atıyor, WordPress de PHP-FPM ile işi pişiriyor. Statikler Nginx’ten fırlıyor, dinamikler sakin sakin arka mutfakta hazırlanıyor.

İlk Çalıştırma: Küçük Kontroller, Büyük Rahatlık

İlk ayağa kaldırmada adımlar genelde şöyle akıyor. Önce .env’i doldurun, sonra volume’ların boş olduğuna emin olun. Ardından compose’u çalıştırın. Ben bu noktada bir docker compose pull ile imajların güncelini çekmeyi ve sonra docker compose up -d ile servisleri kalkındırmayı seviyorum. İlk dakikalarda Traefik sertifika almaya çalışacak, loglarında ACME ile ilgili birkaç satır görebilirsiniz. Domain DNS’inin doğru IP’yi gösterdiğini test etmeyi unutmayın.

WordPress kurulum ekranına ulaştığınızda “tamam” hissi gelir. Fakat acele etmeyin; medya yükleyin, küçük bir yazı yayınlayın, bir de kalıcı bağlantıları değiştirip yeniden kaydedin. Bunlar küçük ama sık karşılaşılan problemlerin görünür olmasını sağlar. Bir sorun yakalarsanız “docker compose logs -f web” ve “docker compose logs -f wordpress” ile iki tarafta da anında iz sürün.

Veriler, Yedekler, Güncellemeler: Gece Uykunuzu Kaçırmayan Rutin

Veritabanı volume’u kritik. MariaDB’nin db_data volume’u sizin altın kasanız. WordPress’in wp_data volume’u ise içerikler, temalar ve eklentilerle dolu gardırobunuz. İkisini de düzenli yedekleyin. Ben uygulama tutarlı yedekleri seviyorum; özellikle veritabanı tarafında küçük bir dondurma/çözme pratiğiyle pırıl pırıl dump’lar alabilirsiniz. Uygulama-tutarlı yedek alma rehberindeki pratik adımlar bu konuda işinizi çok kolaylaştırır.

Basit bir örnek olarak, günlük bir dump ile anlık kopya alabilirsiniz:

docker exec -i $(docker compose ps -q db) 
  mysqldump -uwp -p${DB_PASSWORD} --databases wordpress 
  | gzip > backups/wp-$(date +%F).sql.gz

Bu komutu zamanlamak için isterseniz cron, isterseniz systemd timer kullanın. Hangi durumda hangisi daha temiz olur sorusunu merak ediyorsanız, cron mu systemd Timer mı yazımda kulağa küpe olacak öneriler var. Güncelleme tarafında ise, WordPress çekirdeğini ve eklentileri düzenli tutarken PHP 8.x yükseltmelerinde dikkat edilmesi gerekenleri şu kapsamlı kontrol listesine bakarak adım adım yönetebilirsiniz.

Performans ve Ölçek: Küçük Dokunuşlarla Büyük Fark

Tek VPS senaryosunda mucize beklemek yerine doğru ayarlarla ferah bir kullanım hedefleyin. Nginx tarafında statiklere uzun süreli cache başlıkları vermek, PHP-FPM’de havuz değerlerini sitenizin ritmine göre ayarlamak, WordPress tarafında iyi bir önbellek eklentisi kullanmak çok işe yarıyor. Bazı projelerde Redis ekleyip oturum ve obje cache’i hızlandırmak hoş sonuç veriyor; ama bu kararı site trafiğine ve eklenti ekosistemine göre verin.

Güncelleme ve dağıtım tarafında da konforlu bir akış kuralım. Yeni bir tema güncellemesi ya da önemli bir eklenti değişikliği yapacaksanız, “kademeli” geçirmek iyi hissettirebilir. Traefik’te ağırlıklandırılmış servislerle küçük bir kanarya akışı kurmak mümkün; bu mantığı ve geri dönüş yollarını canary dağıtımı rehberinde uzun uzun anlattım. Tek VPS’te bile küçük ölçekte kontrollü geçişler huzur veriyor.

Nginx’i Reverse Proxy Olarak Kullanmak: Ne Zaman, Nasıl?

Traefik hoşunuza gitmedi mi, ya da yıllardır Nginx’ten vazgeçemiyor musunuz? Dert değil. Nginx’i de reverse proxy olarak kullanıp SSL’i burada sonlandırabilirsiniz. Sertifikaları certbot ile yenileyip Nginx’e teslim etmek ve arka tarafta yine “web” ve “wordpress” konteynerleriyle konuşmak gayet mümkün. Mimarinin genel akışı değişmiyor; sadece TLS yenileme ve yönlendirmeleri Nginx tarafına almış oluyorsunuz.

Ben Nginx yaklaşımında iki şeye dikkat ediyorum. Birincisi, sertifika yenileme jobs’larını temiz yazmak; ikincisi, konfigürasyon parçalarını modüler tutmak. Yarın bir domain daha eklerseniz, bir dosya kopyalayarak çoğaltmak kadar basit olsun istiyorum. “Tek VPS, tek reverse proxy, birden çok site” deseni bu şekilde acısız büyüyor. Bu mimaride de Docker Compose mantığı aynen geçerli; sadece Traefik yerine Nginx konuşuyor.

Güvenlik ve Şeffaflık: En Az İzin, Net Loglar, Sakin Geceler

Tek VPS’te güvenlik çizgilerini basit ama sıkı tutmak büyük fark yaratıyor. Dışarıya sadece reverse proxy’yi açın, veritabanını private network’te tutun, host’tan konteynerlere erişimi daraltın. Günlükleri ayrı dosyalara yönlendirmek, container bazlı log rotasyonu yapmak ve gerektiğinde merkezi bir dizine aktarmak, sorun anında altın değerinde. Doğru TLS etki alanını seçmek ve sertifika otomasyonunu sağlama almak için az önce bahsettiğim ACME yazılarını el altında tutun, bir de domain/TLS ayarlarını belgeleyin ki bir ay sonra “bunu nasıl yapmıştım” demeyesiniz.

WordPress yönetici panelinde iki faktörlü doğrulama eklentileri kullanmak, XML-RPC’yi sınırlamak ve gereksiz eklentileri hayatınızdan çıkarmak da görünenden daha çok işe yarar. Reverse proxy tarafında gerçek istemci IP’lerini doğru ilettiğinizden emin olun ki güvenlik eklentileriniz doğru günlük tutsun. Küçük not: SSL yenileme ve doğrulamalarda takıldığınızda, bazen sadece logları dikkatle okumak bile çözümü gösterir.

Sorun Giderme: Küçük Hatalar Nasıl Hızla Yakalanır?

“Site açılıyor ama yükleme tuşu dönüyor” mu? Genellikle PHP upload limitleri ya da Nginx’deki body size sınırı akla gelir; uploads.ini ve Nginx ayarlarını kontrol edin. “SSL aldı ama yönlendirme yok” diyorsanız, Traefik etiketlerinde middleware tanımının doğru geçtiğinden emin olun. “Beyaz sayfa” gördüğünüzde, önce WordPress hatalarını açın, sonra “web” ve “wordpress” container loglarına bakın; çoğu zaman bir eklenti veya tema sıkıştırması ipucu verir.

Bir de veritabanı bağlantı hataları. Bu durumda WORDPRESS_DB_HOST değerini, kullanıcı/parola eşleşmesini ve MariaDB healthcheck durumunu kontrol edin. Eğer veritabanı ilk kurulumdan sonra başlıyorsa, host makinedeki disk alanı ve inode değerleri de bazen görünmez kahramanlar olur. Kısacası, sakince loglara bakın, ağ yapılandırmasına ve volume’lara göz atın; genellikle ilk 10 dakikada ışık yanar.

Kaynaklar ve Küçük Notlar

Compose dünyasına yeni adım atıyorsanız, Docker Compose rehberi hızlıca elinizi ısıtır. WordPress imajında hangi tag’ler, hangi ortam değişkenleri var diye merak ederseniz WordPress resmi Docker imajı sayfası kısa yoldur. Traefik’i ilk kez deniyorsanız da az önce verdiğim Traefik belgeleri fazla uzatmadan işin özüne götürüyor. Bazen bir örnek dosya, bir de log ekranı görmek tüm sis perdesini aralar.

Kapanış: Tek VPS’te Üretim Disiplini, Rahat Bir Nefes

Bir VPS üzerinde WordPress’i Docker ile taşıyıp, önüne Traefik ya da Nginx koyduğunuzda, düzen bir anda kendini belli ediyor. Her bileşen kendi alanında; güncellemeler öngörülebilir, yedekler tekrarlanabilir, sorunlar izlenebilir oluyor. Mesela şöyle düşünün: Yarın PHP versiyonunu yükseltmek istediniz; imaj etiketini değiştirip doğrulama adımlarıyla küçük bir tur atıyorsunuz ve her şey kontrolünüz altında ilerliyor. Bu his, uzun vadede en büyük kazanç.

Pratik bir kapanış listesi bırakayım: .env kayıtlarınızı temiz tutun, volume’ları düzenli yedekleyin, loglarınızı toplayın, TLS otomasyonunu güvenceye alın ve yönetici panelinde gereksiz eklentileri hayatınızdan çıkarın. Küçük adımlar, büyük huzur. Umarım bu yolculuk sizi de benim gibi “oh be” dedirten bir düzene götürür. Sorularınız olursa, yorumlarda buluşuruz; bir dahaki yazıda görüşmek üzere.

Sıkça Sorulan Sorular

Doğru ayarlarsanız olumsuz bir etki yerine düzen ve öngörülebilirlik kazanırsınız. Nginx statikleri hızlıca sunar, PHP‑FPM doğru havuz değerleriyle rahatlar, veritabanı da ayrı konteynerde huzurla çalışır.

Traefik etiketlerle otomasyon sağlar, Nginx ise alışıldık yapılandırmalarla ilerler. Hangisine aşina iseniz onunla başlayın; ikisiyle de tek VPS’te üretime yakışır bir mimari kurabilirsiniz.

Veritabanı dump’ını günlük alın, WordPress volume’unu düzenli arşivleyin. İşleri otomatikleştirmek için cron veya systemd timer tercih edin, yedekleri farklı bir depoya kopyalamayı ihmal etmeyin.