AI ile "Mission Impossible": 10 Yıllık Legacy Blogu Modernize Etmek
Bir blogu taşımak (migrate) kağıt üzerinde basit görünür: Yedeği al, yeni sunucuya yükle, çalıştır.
Ancak gerçek hayatta hiçbir zaman böyle olmaz. Özellikle de elinizde 10 yıldır güncellenmemiş, Ubuntu 14.04 üzerinde çalışan ve Ghost v0.5 (evet, sene 2014) kullanan bir sistem varsa.
Bu hafta sonu, DevOpsTR blogunu modernize ettik. Ama bunu ben yapmadım; Antigravity yaptı. Ben sadece çayımı içip "onaylıyorum" dedim.
İşte "Export/Import" butonlarının çalışmadığı, şifrelerin sıfırlanamadığı ve portların bloklandığı o kağıt üzerindeki basit işin arka planı.
1. Altyapı: Kodla Sunucu Kurmak
Eski sunucu ("Legacy") artık güvenlik yaması bile almıyordu. Yeni bir başlangıç lazımdı.
Antigravity'ye sadece "Bana DigitalOcean'da yeni bir sunucu aç" demedim. Ona API Access verdim.
O da gitti:
- DigitalOcean API'ı kullanarak Ubuntu 24.04 LTS bir droplet oluşturdu.
- SSH Key'lerimi otomatik tanımladı.
- Sunucuya girip Node.js v22, MySQL 8 ve Nginx kurulumlarını tek komutla halletti (
setup_ghost.sh). - Ghost-CLI ile
ghost installdiyerek tertemiz bir Ghost instance'ı ayağa kaldırdı. - HTTPS (SSL):
ghost setup sslkomutunu yöneterek Let's Encrypt sertifikasını saniyeler içinde kurdu.
Biz daha "hangi Node versiyonunu kuralım" diye düşünürken, o sunucuyu canlıya almıştı bile.
2. "Veriyi Alamıyoruz!": Tünel ve SQL Çözümü
Eski panelden "Export" almaya çalıştığımızda hüsrana uğradık. Panel hata veriyordu, API'lar cevap vermiyordu. Veri içeride hapis kalmıştı.
Çözüm: "Veriyi Zorla Almak"
Antigravity, eski sunucuya bir SSH Tüneli (SSH bağlantısı) üzerinden erişip, Ghost'un çalıştığı klasördeki ham veritabanı dosyasını (ghost.db - SQLite) ve resim klasörünü (content/images) söküp aldı.
# Antigravity'nin arka planda çalıştırdığı mantık
scp -r user@legacy-server:/var/www/ghost/content/data/ghost.db ./local-backup/
rsync -avz user@legacy-server:/var/www/ghost/content/images/ ./local-backup/images/
Ardından, 2014 model SQLite verisini, 2026 model Ghost'un anlayacağı JSON formatına çeviren özel bir Python scripti yazdı. Bu script, binary veriyi okuyup modern şemaya göre yeniden paketledi.
import sqlite3
import json
import time
def dict_factory(cursor, row):
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
conn = sqlite3.connect('legacy_ghost.db')
conn.row_factory = dict_factory
cursor = conn.cursor()
# 1. Eski DB'den "Published" durumdaki yazıları çek
cursor.execute("SELECT * FROM posts WHERE status != 'deleted'")
posts = cursor.fetchall()
# 2. Ghost 1.0 uyumlu JSON yapısını oluştur
data = {
"posts": posts,
"users": [], # Kullanıcılar eklendi
"tags": [] # Etiketler eklendi
}
export_structure = {
"db": [
{
"meta": {
"exported_on": int(time.time() * 1000),
"version": "1.0.0"
},
"data": data
}
]
}
# 3. Dosyayı kaydet
with open('ghost_migration.json', 'w') as f:
json.dump(export_structure, f, indent=4)
print(f"{len(posts)} yazı başarıyla dönüştürüldü.")
conn.close()
3. "Login Olamıyorum!": Email ve Şifre Paradoksu
Veriyi içeri attık, blog açıldı. Ama admin panele giremiyoruz!
- Eski şifreler hash uyumsuzluğu yüzünden çalışmıyor.
- "Şifremi Unuttum" diyoruz, ama sunucuda mail ayarı olmadığı için mail gitmiyor.
Tam bir kilitlenme (Deadlock) durumu.
Çözüm: Veritabanı Cerrahisi
Antigravity, MySQL veritabanına doğrudan bağlanıp, Admin kullanıcısının şifre hash'ini (bcrypt) manuel olarak güncelleyen bir SQL operasyonu yaptı.
-- Antigravity'nin ürettiği cerrahi müdahale
UPDATE users SET password='<yeni_hash>' WHERE email='<email_address>';
Bu sayede mail sistemine ihtiyaç duymadan "Backdoor" değil, "Frontdoor"dan giriş yaptık.
4. Final Boss: Email ve Port 25 Engel
Ghost'a girdik ama "Subscribe" ve "Newsletter" çalışmıyordu. Loglara baktığımızda ECONNREFUSED hatası görüyorduk.
DigitalOcean (ve modern bulutların çoğu), spam'i önlemek için yeni sunucularda Port 25'i (SMTP) bloklar.
Çözüm: Hibrit Mail Mimarisi
Antigravity burada devreye girip, API'lar üzerinden komple bir mail altyapısı kurdu:
- Brevo (ex. Sendinblue): Mailleri göndermek için.
- ImprovMX: "Geleni Yönlendirmek" için.
- DNS Otomasyonu: DigitalOcean DNS API'ını kullanarak SPF, DKIM ve DMARC kayıtlarını (
brevo-code...,v=spf1...) saniyeler içinde domainime ekledi.
Benim DNS paneline girip "TXT kaydı neydi?" diye bakmama bile gerek kalmadı.
Sonuç
Eskiden 3-4 gün süren, "Bu versiyon buna uymuyor" diye saç baş yolduran bu migrasyon süreci; doğru promptlar, API yetkileri ve Agentic AI yaklaşımıyla birkaç saatte bitti. Buna son zamanların popüler tabiriyle Andrej Karpathy'nin söylediği gibi "Vibecoding" de diyebiliriz; ben niyetimi (vibe) söyledim, Antigravity kodunu (code) yazdı.
Şu an okuduğunuz bu satırlar, o kaosun içinden Antigravity tarafından çekip kurtarılmış bir veritabanından geliyor.
Teknoloji geliştikçe işlerimiz zorlaşmıyor, sadece problemleri çözme yöntemlerimiz (ve hızımız) değişiyor.