~/yazilar/dokploy-ile-kendi-sunucunda-paas

Dokploy ile kendi sunucunda küçük bir PaaS

8 dk okuma

Bilgi işlemde sık gelen bir istek var: bir bölümün ya da bir proje ekibinin küçük bir web uygulaması hazır, bir yere konması gerekiyor. Arkasında bir veritabanı, önünde bir alan adı ve sertifika olacak. Yılda birkaç kez güncellenecek. Bunun için Kubernetes kümesi kurmak fazla, elle Compose dosyası ve Traefik label'ı yazmak ise her seferinde aynı işi tekrar etmek ve "bunu en son kim, nasıl deploy etmişti" sorusuyla yaşamak demek.

Dokploy bu aradaki boşluğa oturuyor. Kendi sunucuna kurduğun açık kaynak bir panel: arkada Docker Swarm ve Traefik kullanıyor, önde de Heroku ya da Vercel'e benzeyen bir arayüz veriyor. Repodan ya da hazır bir image'dan uygulama çıkarmak, alan adı bağlamak, Let's Encrypt sertifikası almak, veritabanı açmak ve yedeklemek panelden yapılıyor. Traefik yazısında label'larla elle kurduğumuz yapının hazır, arayüzlü hali gibi düşünebilirsin.

Ne zaman mantıklı, ne zaman değil

Bence Dokploy şu durumlarda iyi bir seçim:

  • Birkaç ile birkaç düzine arası küçük web uygulaması, iç araç ya da öğrenci projesi
  • Uygulamaları deploy edecek kişilerin Docker'ı az bildiği, ama bir panelde "Deploy" düğmesine basmayı kabul ettiği ekipler
  • Tek sunucu ya da birkaç sunucu, kesintiye birkaç dakika tahammülü olan servisler

Yüksek erişilebilirlik şartı varsa başka bir şeye bakardım. Dokploy birden fazla sunucuyu yönetebiliyor ama panelin kendisi tek bir sunucuda duruyor ve küme yönetimi Kubernetes kadar olgun değil. Kurumda zaten çalışan bir Kubernetes ve GitOps düzeni varsa yanına ikinci bir platform koymak da işi bölüyor. Kişisel veri işleyen, denetime tabi uygulamalarda ise panel güvenliği ve yedekler tamamen sende kalıyor, o sorumluluğu taşıyabileceğinden emin olmadan başlama.

Bir de şunu hesaba kat: Dokploy hızlı gelişen bir proje. Menü adları, özellikler ve varsayılanlar sürümden sürüme değişiyor. Bu yazıdaki ekran adlarını kendi kurduğun sürümle karşılaştır.

Panelin bir özelliği daha var ki baştan bilmek gerekiyor: Dokploy Docker soketine tam erişimle çalışıyor. Panelde yönetici olan biri sunucuda pratikte root. Panel girişini SSH girişi kadar ciddiye al.

Ön koşullar

  • Sadece bu iş için açılmış, Ubuntu Server'ın güncel LTS sürümü kurulu temiz bir sanal makine. Üzerinde Docker ya da başka bir web sunucusu olmasın.
  • En az 2 GB RAM ve 30 GB disk. Uygulamalar sunucuda build edileceği için bence 4 GB RAM daha rahat.
  • Genel bir IP. Örneklerde 203.0.113.10 kullanıyorum.
  • DNS'te panel.example.com ve uygulamalar için kayıtlar, ya da *.apps.example.com gibi bir wildcard kayıt.
  • Kurum güvenlik duvarında 80 ve 443 portlarının bu sunucuya açık olması. Let's Encrypt sertifikası için 80 portu dışarıdan erişilebilir olmalı.
  • SSH sıkılaştırma yazısındaki ayarlar yapılmış olsun.

Kurulum

Dokploy'un dokümantasyonu kurulumu şu komutla veriyor:

curl -sSL https://dokploy.com/install.sh | sh

Bu script root olarak çalışmak zorunda. Docker kuruyor, Swarm başlatıyor, ağ oluşturuyor ve sistem servislerini ayağa kaldırıyor. Bu kadar yetkiyle çalışacak bir şeyi okumadan çalıştırmıyorum:

curl -sSL https://dokploy.com/install.sh -o dokploy-install.sh
less dokploy-install.sh

Script'te baktığım şeyler kabaca şunlar: root kontrolü, 80, 443 ve 3000 portlarının boş olup olmadığının kontrolü, Docker'ın resmi kurulum script'iyle kurulması, docker swarm init, dokploy-network adında bir overlay ağ ve Dokploy'un kendi veritabanı (PostgreSQL), Redis, Traefik ve panel container'ları. Beklemediğin bir şey görmüyorsan çalıştır:

sudo sh dokploy-install.sh

Sunucunun birden fazla ağ arayüzü varsa Swarm'ın yanlış IP'yi duyurmasını önlemek için script ADVERTISE_ADDR ortam değişkenini kabul ediyor. Tek arayüzlü bir sanal makinede buna gerek yok.

Kurulum birkaç dakika sürüyor ve sonunda panel adresini yazıyor:

Congratulations, Dokploy is installed!
Wait 15 seconds for the server to start
Please go to http://203.0.113.10:3000

Neyin çalıştığına bakıyorum:

sudo docker service ls
sudo docker ps --format '{{.Names}}\t{{.Ports}}'
ID         NAME               MODE         REPLICAS   IMAGE
...        dokploy            replicated   1/1        dokploy/dokploy:...
...        dokploy-postgres   replicated   1/1        postgres:...
...        dokploy-redis      replicated   1/1        redis:...

dokploy-traefik   0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, ...

Yönetici hesabı ve 3000 portu

Panele ilk giren kişi yönetici hesabını oluşturuyor. Kurulumla kayıt arasındaki birkaç dakika boyunca http://203.0.113.10:3000 adresine internetten ulaşabilen herkes bu hesabı senden önce açabilir. Bu riski kapatmak için 3000 portunu kurum güvenlik duvarında sadece yönetim ağına açıyorum.

Burada sunucudaki UFW'ye güvenme. Docker'a giriş yazısında anlattığım sebeple UFW'de 3000 kapalı görünse bile port dışarıdan erişilebilir kalıyor. Önünde bir kurum güvenlik duvarı yoksa bu pencereyi kapatmanın kolay bir yolu yok, kurulum biter bitmez hesabı açmak gerekiyor.

Hesabı açarken IP üzerinden düz HTTP kullanmak yerine SSH tüneli açıyorum. Böylece yönetici parolası ağda açık gitmiyor:

# kendi bilgisayarında
ssh -L 3000:127.0.0.1:3000 deploy@203.0.113.10

Tünel açıkken tarayıcıda http://localhost:3000 adresine gidip yönetici hesabını oluşturuyorum. Parola için uzun, parola yöneticisinden üretilmiş bir değer kullan. Hesap açılır açılmaz profil ayarlarından iki aşamalı doğrulamayı açıyorum.

Panelin alan adı ve HTTPS

Panel şu an düz HTTP ile ve IP üzerinden çalışıyor. Giriş parolası ağda açık gidiyor. Önce DNS'te panel.example.com için 203.0.113.10 adresine bir A kaydı açıyorum, sonra panelde sunucu ayarlarına giriyorum:

  1. Settings altında web sunucusu ayarlarını aç.
  2. Alan adı olarak panel.example.com yaz.
  3. Let's Encrypt için e-posta adresini gir. Let's Encrypt süre sonu uyarılarını 2025'te bıraktı, yenilemeyi takip etmek için sertifika bitiş tarihini izleme sistemine ekle.
  4. HTTPS'i ve sertifika sağlayıcısı olarak Let's Encrypt'i seç, kaydet.

Bir dakika kadar sonra kontrol ediyorum:

curl -sI https://panel.example.com | head -3
HTTP/2 200
content-type: text/html; charset=utf-8
...

Bu çalıştıktan sonra 3000 portunun açık durmasına gerek yok. Panel artık Traefik arkasından, 443 üzerinden geliyor. Portu Swarm servisinden kaldırıyorum:

sudo docker service update \
  --publish-rm "published=3000,target=3000,mode=host" dokploy

Sonra başka bir makineden deniyorum:

curl -m 5 http://203.0.113.10:3000
curl: (28) Connection timed out after 5001 milliseconds

Bağlantı reddedilmeli ya da zaman aşımına uğramalı. Sırayı ters yapma: alan adı ve sertifika çalışmadan portu kapatırsan panele hiçbir yoldan giremezsin. Öyle bir durumda portu SSH ile geri açabilirsin:

sudo docker service update \
  --publish-add "published=3000,target=3000,mode=host" dokploy

Panel güvenliği için iki şey daha yapıyorum. Ekipten başkaları da panele girecekse herkese ayrı kullanıcı açıyorum ve yetkileri sadece ilgili projelerle sınırlıyorum. Bir de Dokploy'un kendi güncellemelerini takip ediyorum. Panel internete açık bir yönetim arayüzü, güvenlik düzeltmeleri geldiğinde beklememek gerekiyor.

İlk uygulama

İlk denemeyi repo bağlamadan, hazır bir image ile yapıyorum. Gelen istekteki başlıkları ekrana basan traefik/whoami bunun için iyi, HTTPS'in doğru sonlandığını da gösteriyor.

  1. Projects altında deneme adında bir proje oluştur.
  2. Projenin içinde Create Service ile bir Application ekle, adı whoami olsun.
  3. Uygulamanın genel ayarlarında kaynak (provider) olarak Docker'ı seç ve image olarak traefik/whoami:v1.10.1 yaz. Kaydet.
  4. Deploy düğmesine bas. Deployment sekmesinden logları izleyebilirsin.

Image'ı etiketiyle yazdım, etiket vermezsen Dokploy da latest çekiyor.

Container çalışıyor ama henüz dışarıdan ulaşılamıyor. DNS'te whoami.apps.example.com için 203.0.113.10 adresine kayıt açtıktan (ya da wildcard kaydın varsa hiçbir şey yapmadan) sonra uygulamanın Domains sekmesine geçiyorum:

  • Host: whoami.apps.example.com
  • Path: /
  • Container Port: 80
  • HTTPS: açık
  • Certificate: Let's Encrypt

Kaydedince Dokploy arka planda Traefik için yönlendirme kuralını yazıyor. Container port, uygulamanın container içinde dinlediği port. Sunucuda hiçbir portu dışarı açmıyorsun, trafik Traefik üzerinden Docker ağı içinden geliyor.

curl -s https://whoami.apps.example.com/
Hostname: 4f1c2a9b7e3d
IP: 127.0.0.1
IP: 10.0.1.15
RemoteAddr: 10.0.1.4:51234
GET / HTTP/1.1
Host: whoami.apps.example.com
User-Agent: curl/...
X-Forwarded-For: 198.51.100.25
X-Forwarded-Host: whoami.apps.example.com
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Real-Ip: 198.51.100.25

X-Forwarded-Proto: https satırı TLS'in Traefik'te sonlandığını ve uygulamaya iç ağdan düz HTTP ile ulaştığını gösteriyor. Kendi uygulaman yönlendirme ya da çerez ayarlarında bu başlığa güvenecekse ayarlarında proxy'ye güven seçeneğini açman gerekecek.

Takılınabilecek yerler

Sertifika gelmiyor, tarayıcı Traefik'in varsayılan sertifikasını gösteriyor

Let's Encrypt doğrulaması başarısız olmuş demektir. En sık sebep 80 portunun dışarıdan kapalı olması. Kurumun güvenlik duvarında sadece 443'ü açtıysan HTTP doğrulaması çalışmaz. İkinci sebep DNS kaydının henüz yayılmamış olması: dig +short whoami.apps.example.com doğru IP'yi dönmüyorsa beklemek gerekiyor. Traefik'in logları sebebi açıkça yazıyor:

sudo docker logs dokploy-traefik 2>&1 | grep -i acme | tail -5

Sunucu sadece kurum içinden erişilebilir bir ağdaysa Let's Encrypt'in HTTP doğrulaması hiç çalışmaz. O durumda kurumun kendi sertifikasını panelden yüklemek ya da DNS doğrulaması kullanmak gerekiyor.

Alan adı açılıyor ama 404 page not found ya da Bad Gateway geliyor

404, Traefik'in bu host için kural bulamadığını gösteriyor. Domains sekmesindeki host adında yazım hatası var mı bak. Bad Gateway ise kural var ama arkadaki container'a ulaşılamıyor: container port yanlış girilmiş ya da uygulama çöktü. Önce uygulamanın loglarına bak.

Let's Encrypt limitlerine takılmak

Aynı alan adı için kısa sürede çok sayıda başarısız deneme yaparsan Let's Encrypt geçici olarak reddetmeye başlıyor. DNS ve güvenlik duvarı tarafı doğrulanmadan HTTPS'i açıp kapatıp denemek bu sınırı hızla tüketiyor.

Disk doluyor

Her deploy yeni bir image demek ve eskileri kendiliğinden silinmiyor. Repodan build alan uygulamalarda build önbelleği de birikiyor. Ne kadar yer kapladığını görmek için:

sudo docker system df

Dokploy'un ayarlarında kullanılmayan image ve build önbelleğini düzenli temizleyen bir seçenek var, açık olduğundan emin ol. Diski izleme sistemine eklemek ise her durumda gerekli.

Sunucuda başka bir şey 80 ya da 443'ü tutuyordu

Kurulum script'i bunu baştan kontrol edip duruyor. Sunucuda daha önce nginx ya da Apache kurulmuşsa kaldırmak ya da Dokploy'u temiz bir makineye kurmak gerekiyor. Ben ikincisini öneririm: Dokploy sunucuyu sahipleniyor, yanına başka iş koymak sorun çıkarıyor.

Şimdiki haliyle her güncellemede panele girip "Deploy"a basmak gerekiyor. Bunu push'a bağlamak, yanına veritabanı ve sunucu dışına giden yedekler eklemek sıradaki iş.

Sıradaki yazı: Dokploy'da otomatik deploy, veritabanı ve yedekler