Bu sitenin de çalıştığı sunucu, uzun süre doğrudan donanım üzerinde kurulu bir Ubuntu Server'dı. Virtualmin ile yönetiliyor, Apache ve MariaDB ile iki alan adı yayınlıyordu. Ağustos 2026'da bu makineyi, verilerine dokunmadan Proxmox VE üzerinde bir sanal makineye dönüştürdüm (P2V, physical-to-virtual).
Taşımanın kendisi bir öğleden sonra sürdü. Asıl zaman alan, taşımadan sonra üst üste çıkan ve her biri bir öncekini gizleyen dört hata oldu. Bu yazıda hem kurulumu hem de bu hataları nasıl bulduğumu anlatıyorum.
Başlangıç durumu ve hedef
- Donanım: Ubuntu'nun kurulu olduğu bir SATA disk ve boş bir NVMe disk.
- Ağ: Sunucunun internete tek çıkışı bir USB Wi-Fi kartı. Kablolu bağlantı yok.
- Servisler: Virtualmin, Apache (iki site, Let's Encrypt sertifikaları), MariaDB.
- Hedef: Aynı makinede başka sanal makineler de çalıştırabilmek, sunucuyu yedeklenebilir hâle getirmek ve bunu yaparken mevcut sistemi yeniden kurmamak.
1. Proxmox'u ayrı diske kurmak ve disk passthrough
Proxmox'u boş NVMe diske kurdum. Ubuntu'nun bulunduğu SATA diske kurulum sırasında hiç dokunulmadı. Bu, en önemli güvenlik ağıydı: bir şey ters giderse Proxmox diskini çıkarıp makineyi eskisi gibi Ubuntu'dan açabilirdim.
Diski bir imaja kopyalamak yerine, fiziksel diskin tamamını sanal makineye bağladım (disk passthrough). Diski /dev/sda gibi bir adla değil, kalıcı kimliğiyle bağlamak önemli; çünkü disk sırası açılışta değişebilir:
# Diskin kalıcı kimliğini bul (sda/sdb sırası açılışta değişebilir)
ls -l /dev/disk/by-id/ | grep -v part
# Diskin tamamını VM'e bağla
qm set 100 -scsi0 /dev/disk/by-id/<disk-kimligi>
Ubuntu UEFI modunda kurulu olduğu için sanal makinenin de UEFI (OVMF) ile açılması gerekiyordu. Varsayılan SeaBIOS ile sistem önyükleme bulamadı; firmware'i OVMF'ye çevirip bir EFI diski ekleyince Ubuntu sanal ortamda açıldı:
qm set 100 -bios ovmf -efidisk0 local-lvm:1,efitype=4m,pre-enrolled-keys=0
qm set 100 -boot order=scsi0
2. Wi-Fi köprülenmez: NAT ile izole bir ağ
Proxmox'ta sanal makineler genelde fiziksel ağ kartına bağlı bir Linux köprüsüne (vmbr0) takılır ve yerel ağdan doğrudan IP alır. Wi-Fi'de bu çalışmaz: istemci modundaki bir Wi-Fi kartı, erişim noktasına kendi MAC adresi dışındaki çerçeveleri gönderemez. Bu yüzden köprüye bağlı sanal makinenin trafiği modeme ulaşmaz.
Çözüm, Proxmox'u sanal makineler için küçük bir yönlendiriciye çevirmekti:
- Hiçbir fiziksel karta bağlı olmayan bir köprü (
vmbr0,10.10.10.1/24). Sanal makine bu ağda10.10.10.2adresini alıyor ve ağ geçidi olarak Proxmox'u kullanıyor. - Sanal makinenin internete çıkışı için MASQUERADE (kaynak NAT).
- Dışarıdan gelen web trafiği için DNAT ile port yönlendirme.
/etc/network/interfaces içindeki ilgili bölüm şöyle (Wi-Fi arayüzünün adı burada wlan0; kendi sisteminizdeki adı ip a ile bulabilirsiniz):
auto vmbr0
iface vmbr0 inet static
address 10.10.10.1/24
bridge-ports none
bridge-stp off
bridge-fd 0
post-up echo 1 > /proc/sys/net/ipv4/ip_forward
post-up iptables -t nat -A POSTROUTING -s '10.10.10.0/24' -o wlan0 -j MASQUERADE
post-down iptables -t nat -D POSTROUTING -s '10.10.10.0/24' -o wlan0 -j MASQUERADE
post-up iptables -t nat -A PREROUTING -i wlan0 -p tcp --dport 80 -j DNAT --to 10.10.10.2:80
post-down iptables -t nat -D PREROUTING -i wlan0 -p tcp --dport 80 -j DNAT --to 10.10.10.2:80
post-up iptables -t nat -A PREROUTING -i wlan0 -p tcp --dport 443 -j DNAT --to 10.10.10.2:443
post-down iptables -t nat -D PREROUTING -i wlan0 -p tcp --dport 443 -j DNAT --to 10.10.10.2:443
Modemdeki port yönlendirmesini de sunucunun eski fiziksel IP'si yerine Proxmox'un Wi-Fi IP'sine çevirdim. Böylece zincir şu hâle geldi: Modem → Proxmox (Wi-Fi) → DNAT → Ubuntu VM → Apache.
Kâğıt üzerinde her şey hazırdı. Pratikte hiçbir şey çalışmıyordu.
3. Hata 1: SSH sessizce yanlış makineye gidiyor
Belirti: Proxmox'a yerel ağdan SSH ile bağlanmaya çalıştığımda Permission denied (publickey) alıyordum. Proxmox'un sshd_config dosyasında yaptığım hiçbir değişikliğin etkisi olmuyordu.
Sebep: SSH'ı dışarıdan sanal makineye yönlendiren kural yalnızca arayüze göre eşleşiyordu:
post-up iptables -t nat -A PREROUTING -i wlan0 -p tcp --dport 22 -j DNAT --to 10.10.10.2:22
Bu kural, Wi-Fi arayüzüne gelen her 22 numaralı port isteğini yakalıyordu: modemden gelen dış trafiği de, yerel ağdaki bilgisayarımdan doğrudan Proxmox'a giden bağlantıyı da. DNAT, PREROUTING aşamasında yani yönlendirme kararından önce çalıştığı için paket Proxmox'un kendi SSH servisine hiç uğramadan sanal makineye gidiyordu. Yani aslında hep Ubuntu'ya bağlanıyordum ve Ubuntu'da parola ile giriş kapalı olduğu için publickey hatası alıyordum. Düzenlediğim dosya hiç devreye girmiyordu.
Çözüm: Kurala bir kaynak filtresi ekledim. Yerel ağdan gelen bağlantılar artık Proxmox'ta kalıyor, yalnızca dışarıdan gelenler sanal makineye gidiyor:
post-up iptables -t nat -A PREROUTING -i wlan0 ! -s 192.168.1.0/24 -p tcp --dport 22 -j DNAT --to 10.10.10.2:22
post-down iptables -t nat -D PREROUTING -i wlan0 ! -s 192.168.1.0/24 -p tcp --dport 22 -j DNAT --to 10.10.10.2:22
Küçük bir tuzak: Bu satırı önce sed ile değiştirmeye çalıştım ve komut hiçbir hata vermeden hiçbir şey yapmadı. Sebebi, çift tırnak içindeki ! karakterinin bash'te geçmiş genişletmesini (history expansion) tetiklemesiydi. Satırı nano ile elle düzenleyince sorun kalmadı. Ayrıca bu düzenlemeyi SSH yerine Proxmox web arayüzündeki konsoldan yaptım; çünkü SSH oturumu da aynı hatalı yönlendirmeye takılabiliyordu.
Yeniden başlattıktan sonra istemcideki eski host anahtarını silip gerçekten doğru makineye bağlandığımı hostname çıktısıyla doğruladım:
# Windows tarafında eski host anahtarını temizle
ssh-keygen -R 192.168.1.120
ssh root@192.168.1.120 hostname
4. Hata 2: firewalld kuralları var ama uygulanacağı arayüz yok
Belirti: Proxmox'tan sanal makineye curl http://10.10.10.2 denediğimde No route to host alıyordum. Apache çalışıyordu, portlar firewalld'de açıktı.
Sebep: firewall-cmd --list-all çıktısında her şey doğru görünüyordu, tek bir satır hariç:
$ sudo firewall-cmd --list-all
public (default, active)
interfaces:
services: ... http https ssh ...
ports: ... 80/tcp 443/tcp 22/tcp
interfaces: satırı boştu. Sanal makinedeki ağ kartı (ens18) hiçbir bölgeye (zone) bağlı değildi. Kurallar tanımlıydı ama hiçbir arayüze uygulanmıyordu; trafik reddediliyor ve istemci tarafında No route to host olarak görünüyordu.
Çözüm:
sudo firewall-cmd --permanent --zone=public --add-interface=ens18
sudo firewall-cmd --reload
sudo firewall-cmd --get-active-zones
# Host'tan test
curl -sI http://10.10.10.2
HTTP/1.1 200 OK
Server: Apache
Ayarın kalıcı olduğundan emin olmak için sanal makineyi bir kez yeniden başlatıp testi tekrarladım.
5. Hata 3: 443 portu TLS yerine düz HTTP döndürüyor
Belirti: Siteyi dışarıdan açtığımda tarayıcı ERR_SSL_PROTOCOL_ERROR veriyordu, curl ise wrong version number diyordu. Bu aslında iyi bir işaretti: Paket modemden Apache'ye kadar ulaşıyordu, yani ağ zinciri artık çalışıyordu. Sorun Apache'nin içindeydi.
Sebep: Virtualmin, sitelerin VirtualHost tanımlarını sunucunun eski fiziksel IP adresine sabitlemişti (<VirtualHost 192.168.1.119:443>). Sanal makinenin yeni adresi 10.10.10.2 olunca bu tanımlar hiçbir isteğe eşleşmedi. 443'e gelen istekleri SSL'siz bir varsayılan VirtualHost karşıladı ve TLS el sıkışması yerine düz HTTP cevabı döndü.
Bunu görmenin en kolay yolu apache2ctl -S; hangi IP ve port için hangi VirtualHost'un tanımlı olduğunu listeler:
curl -skI https://10.10.10.2
sudo apache2ctl -S 2>&1 | grep -E ':443|:80'
Çözüm: VirtualHost'ları belirli bir IP yerine * olacak şekilde düzelttim (dosyaların yedeklerine dokunmadan):
cd /etc/apache2/sites-available
sudo sed -i 's/192\.168\.1\.119/*/g' ardamuratsoybahceci.com.tr.conf emrekapukaya.com.tr.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
Syntax OK ve yeniden yüklemeden sonra iki site de HTTPS ile açıldı. Dış erişimi test ederken bir not: Çoğu ev modemi NAT hairpin desteklemez. Aynı ev ağındayken kendi dış IP'nize bağlanmayı denerseniz bağlantı düşebilir. Bu testi telefonda Wi-Fi kapalıyken mobil veriyle yaptım.
6. Hata 4: MariaDB başlamıyor
Belirti: Yeniden başlatmadan sonra systemctl --failed listesinde tek bir servis kaldı: MariaDB. Günlükte SSL anahtarıyla ilgili bir hata vardı.
Sebep: Yapılandırma üç SSL dosyasını gösteriyordu, ama diskte yalnızca anahtar dosyası vardı:
$ ls -la /etc/mysql/mysql-ssl.key /etc/mysql/mysql-ssl.crt
ls: cannot access '/etc/mysql/mysql-ssl.crt': No such file or directory
-rw------- 1 mysql mysql 1708 ... /etc/mysql/mysql-ssl.key
$ sudo grep -rn "ssl" /etc/mysql/mariadb.conf.d/
50-server.cnf:97:ssl_ca = /etc/mysql/mysql-ssl.ca
50-server.cnf:98:ssl_key = /etc/mysql/mysql-ssl.key
50-server.cnf:99:ssl_cert = /etc/mysql/mysql-ssl.cert
Sertifika ve CA dosyaları olmadan MariaDB SSL'i kuramıyor ve hiç başlamıyordu. Veritabanını yalnızca aynı makinedeki siteler (localhost) kullandığı için SSL'e gerek yoktu.
Çözüm: 50-server.cnf dosyasında bu üç satırı yorum satırına çevirdim ve servisi başlattım:
#ssl_ca = /etc/mysql/mysql-ssl.ca
#ssl_key = /etc/mysql/mysql-ssl.key
#ssl_cert = /etc/mysql/mysql-ssl.cert
sudo systemctl start mariadb
sudo systemctl status mariadb --no-pager | head -5
Veritabanına uzaktan şifreli bağlanılacak olsaydı doğru çözüm, satırları kapatmak değil, eksik sertifikaları yeniden üretmek olurdu.
Sonuç ve çıkardığım dersler
Sunucu artık Proxmox üzerinde bir sanal makine. Aynı donanımda başka sanal makineler de çalışıyor ve iki site de HTTPS ile yayında. Bu süreçten aklımda kalanlar:
- Katman katman ilerle. Her hata bir sonrakini gizliyordu. Önce yönlendirmeyi, sonra güvenlik duvarını, sonra web sunucusunu, en son veritabanını ayrı ayrı doğruladım.
curl -sI,ss -tlnp,firewall-cmd --list-allveapache2ctl -Sen çok kullandığım komutlardı. - Hata mesajı iyi haber olabilir.
No route to host'tanERR_SSL_PROTOCOL_ERROR'a geçmek, paketin bir katman daha ileri gittiği anlamına geliyordu. - DNAT kurallarında kaynak filtresini unutma. Arayüze göre eşleşen bir kural, beklemediğin trafiği de yakalar ve bunu sessizce yapar.
- Taşımada IP'ye bağlı her şeyi listele. VirtualHost tanımları, modemdeki yönlendirmeler ve güvenlik duvarı bölgeleri eski adrese ya da eski arayüze göre ayarlanmış olabilir.
- Geri dönüş yolunu koru. Orijinal diske hiç yazmadan çalışmak, her denemeyi rahatça yapabilmemi sağladı.
Sıradaki adım: Passthrough ile bağlanan fiziksel diskte Proxmox snapshot alamıyor. Diski Proxmox'un kendi depolamasına taşıyıp snapshot desteği eklemeyi planlıyorum.