Statik Sitenizi VPS’e Otomatik Olarak Nasıl Yüklersiniz?

08.11.2024

Statik bir siteyi barındırmak dünyanın en kolay şeyi. Bir sürü statik html dosyasından oluştuğu için, dosyalarınızı FTP ile yüklemek gibi basit bir yol izleyebilirsiniz. Fakat yaptığınız her değişiklikte, bütün bu dosyaları tek tek bir yerlere yüklemek ölümcül olacaktır.

Bu çileli süreçle uğraşmak istemeyenler için Netlify, Vercel, Cloudflare Pages gibi alternatif platformlar var. Bu platformlar temel olarak şunu yapıyor:

  1. Siteniz için kullandığınız SSG’ye ait dosyaları barındırdığınız Github reponuzu tanımlıyorsunuz.
  2. Yaptığınız değişiklikleri, Github reponuza pushladığınız (ittirdiğiniz?) zaman:
    1. Güncel dosyaları repodan çekiyor.
    2. Bu dosyaları kullanarak, sitenizi oluşturuyor.
    3. Yeni sitenizi yayına alıyor.

Bu adımları izleyerek, sitemizi kendi sunucumuza deploy eden bir sistem oluşturabiliriz.

Zero Downtime Deployment

Sitenize ait kaynak kodlarınızı /var/www/site.com/’da bulundurduğunuzu ve kullandığınız SSG de sitenizi /var/www/site.com/dist/ dizinine oluşturduğunu varsayıyorum. Kullandığınız SSG, sitenizin büyüklüğü ve sunucunuzun donanımına göre bu build adımı bir kaç dakika sürebilir. Bu süreçte dist dizini içerisinde değişiklikler yapılıyor olduğu için, sitenizdeki bazı sayfalar ya da sitenizin tamamı ziyaretçilere erişilemez durumda olabilir.

Sitenizin oluşturulma ve yayına alınması sürecinde, erişilemez duruma gelmemesine zero downtime deployment deniliyor.

  1. Sitenizi /var/www/site.com/builds/current/ dizininden yayınlayacaksınız.
  2. Kullandığınız SSG, buildlerini /var/www/site.com/builds/dists/ dizinine yeni bir klasör oluşturarak oluşturacak. Yeni dizinin özgün bir isme sahip olabilmesi için, o anki zaman kullanılır; örneğin builds/dists/20241108_022248/.
  3. Build adımı tamamlandıktan sonra yeni buildinizin barındığı builds/dists/20241108_022248 dizinine builds/current dizininden link oluşturacaksınız. Yani builds/current dizini her zaman en güncel buildin bulunduğu dizine işaret eden bir kısayol olacak.
  4. Depolama alanınızın gereksiz şekilde şişmemesi için, builds/dists dizinindeki en yeni X adet build harici tüm dizinler silinir.

Sitenizin oluşturulması sürecinde sitenizi ziyaret edenler bir önceki versiyonu görecekler. Siteniz oluşturulduktan sonra yeni versiyonu görmeye başlayacaklar.

Sürecin otomatikleştirilmesi

Bu adımları otomatikleştiren bir script yazdım. Bu scripti /var/www/site.com/deploy.sh olarak kaydedebilirsiniz. Scriptin .gitignoreda bulunduğuna emin olun.

#!/bin/bash

# Build Directory
BUILDS_DIR="./builds"
ORIGINALS_DIR="dists"
CURRENT_SYMLINK="current"


# Origin'deki değişiklikleri çek
git fetch origin

# Local ile fark var mı kontrol et
if [ "$(git rev-parse HEAD)" != "$(git rev-parse @{u})" ]; then
    echo "Origin'de değişiklikler var, güncel dosyalar çekiliyor..."

    # Komutları && ile chain haline getir ki adımlardan biri hata verirse devam edilmesin.
    git pull origin && \
    TIMESTAMP=$(date +"%Y%m%d_%H%M%S") && \
    NEW_DIR="$BUILDS_DIR/$ORIGINALS_DIR/$TIMESTAMP" && \
    pnpm install && pnpm build --silent --outDir "$NEW_DIR" && \
    ln -snf "./$ORIGINALS_DIR/$TIMESTAMP" "$BUILDS_DIR/$CURRENT_SYMLINK"

    if [ $? -eq 0 ]; then
        # xarg ile başlayan son komut tehlikeli, önceki adımlarda verilen dizinleri siliyor.
        # Ne yaptığını bilmiyotsan sakın bulaşma. Eski buildleri elle silebilirsin.
        # Eğer son 3 build harici silinsin istiyorsan aşağıdaki satırın başındaki # işaretini kaldır.
        # ls -1d $BUILDS_DIR/$ORIGINALS_DIR/* | sort | head -n -3 | xargs -r rm -rf

        echo "Başarıyla tamamlandı."
    else
        echo "Adımların birinde hata oluştu."
    fi
else
    echo "Origin'de değişiklik yok, iptal."
fi

Script içerisindeki pnpm install && pnpm build --silent --outDir "$NEW_DIR" kısmı Astro 🡥’ya göre yazıldı. Kullandığınız SSG’ye uygun build komutu yazabilirsiniz.

Peki yaptığınız değişiklikleri Github reponuza pushladıktan sonra, sitenizi barındıran sunucu bu değişikliklerden nasıl haberdar olacak?

Webhook: “Repo Güncellendi”

Webhook, sunucunuzun dışında olan olayların sunucunuza bildirilebilmesi için kullanılan bir teknolojidir. Github reponuza yeni commitlerin pushlanması ya da Telegram kanalınıza yeni mesaj gönderilmesi bu olaylara örnek olarak gösterilebilir.

Github sizin seçebileceğiniz çeşitli olayları belirttiğiniz bir webhook’a gönderebiliyor.

Github webhook tanımlama ekranı

Sunucuya gönderilecek webhook istemlerini alıp işleyebilmek için adnanh/webhook 🡥 uygulamasını kullanıyorum. Bu uygulama varsayılan olarak 9000 portunu dinliyor.

Ubuntu 24.04’te kolayca kurulabiliyor:

$ sudo apt-get install webhook -y

Bu uygulama ayarlarını hooks.json dosyasını okuyarak yapıyor. Dolayısıyla bir yere geçerli bir hooks.json oluşturmanız gerekiyor.

$ cd /var/www
$ touch hooks.json

Github’ın gönderdiği push eventlerini kullanmak için gerekli örnek hooks.json:

[
	{
		"id": "site-deploy",
		"execute-command": "/var/www/site.com/deploy.sh",
		"command-working-directory": "/var/www/site.com",
		"parse-parameters-as-json": [
			{
				"source": "payload",
				"name": "payload"
			}
		],
		"trigger-rule": {
			"and": [
				{
					"match": {
						"type": "payload-hmac-sha1",
						"secret": "GITHUB_WEBHOOK_SECRET",
						"parameter": {
							"source": "header",
							"name": "X-Hub-Signature"
						}
					}
				},
				{
					"match": {
						"type": "value",
						"value": "refs/heads/master",
						"parameter": {
							"source": "payload",
							"name": "ref"
						}
					}
				}
			]
		}
	}
]

Örnek dosya şu varsayımları yapıyor:

  • "id": "site-deploy" : Bu ID, webhookunuza http://site.com:9000/hooks/site-deploy URL’sinden erişilebilir olmasını tanımlıyor.
  • GITHUB_WEBHOOK_SECRET : Github’da webhook’unuzu tanımlarken oluşturduğunuz gizli tutmanız gereken rasgele ve uzun bir şifre.
  • parse-parameters-as-json : Github webhook’unuz verileri JSON olarak gönderecek şekilde ayarlandı.
  • refs/heads/master : Github reponuzdaki ana branch’inizin adı master.

Kurduğumuz webhook uygulamasını çalıştırmak için:

$ webhook -port 9000 -hooks /var/www/hooks.json -hotreload -verbose

SSH bağlantınızı kestikten sonra da çalışmasını istiyorsanız:

$ nohup webhook -port 9000 -hooks /var/www/hooks.json -hotreload -verbose &

Not: Sunucunuz yeniden başlatıldığı zaman webhook uygulaması otomatik olarak çalışmayacaktır. Tekrar aynı komutu kullanabilirsiniz.

Sonuç olarak

Yaptığınız değişiklikleri Github reponuza pushladığınız zaman, bir değişiklik olduğunu sunucunuza bildiren bir webhook kullanıyoruz. Bu webhook da sitenizi yeniden oluşturacak deploy.sh scriptini çalıştırıyor.

Bu sayede hem dosyalarınızı sunucuya elle yüklemekten kurtuluyorsunuz hem de sitenizin oluşturulması sürecinde ziyaretçi kaybı yaşamıyorsunuz.