İçindekiler
- 1 Ofiste Küçük Bir Sorun, Büyük Bir Aydınlanma: Tek VPS’te WordPress’i Nasıl Derli Toplu Koştururuz?
- 2 Mimarinin Fotoğrafı: Küçük Kutular, Net Sorumluluklar
- 3 Traefik ile Reverse Proxy: HTTPS, Yönlendirmeler ve Etiketlerle Büyü Yapmak
- 4 docker-compose.yml: WordPress + PHP-FPM, Nginx (App), MariaDB ve Traefik
- 5 İlk Çalıştırma: Küçük Kontroller, Büyük Rahatlık
- 6 Veriler, Yedekler, Güncellemeler: Gece Uykunuzu Kaçırmayan Rutin
- 7 Performans ve Ölçek: Küçük Dokunuşlarla Büyük Fark
- 8 Nginx’i Reverse Proxy Olarak Kullanmak: Ne Zaman, Nasıl?
- 9 Güvenlik ve Şeffaflık: En Az İzin, Net Loglar, Sakin Geceler
- 10 Sorun Giderme: Küçük Hatalar Nasıl Hızla Yakalanır?
- 11 Kaynaklar ve Küçük Notlar
- 12 Kapanış: Tek VPS’te Üretim Disiplini, Rahat Bir Nefes
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.
