omeryanbas.com

Ömer Yanbaş

Genel Müdür, Ticofab Yazılım

OperasyonWeb

Kontrol paneli ile nginx dosyanız çeliştiğinde

Kontrol panelleri vhost dosyasını kendi şablonundan üretir, elle yapılan değişiklik sertifika yenilemesinde silinir. Değişikliği nereye yazmak gerekir.

Haftalar önce yapılmış bir değişiklik ortada yok. Vhost dosyasına elle eklenen güvenlik başlıkları artık yanıtta görünmüyor, diskteki dosyada da yoklar ve o gün kimse deploy yapmadı. Buna karşılık dosyanın değiştirilme zamanı yeni, hatta en son giriş yapan kişiden daha yeni. Dosyayı hosting paneli yeniden yazdı, çünkü o dosyayı kendi malı sayıyor.

Gerçekte ne oluyor

Hosting paneli sitenizin yapılandırmasını config dosyasında tutmaz. Kendi veritabanında tutar: alan adı, doküman kökü, sertifika yolları, çalışma zamanı sürümü, arayüzdeki bir metin kutusuna yazılmış ek direktifler. nginx config dizinindeki dosya ise bir şablonun o veritabanı satırıyla birleştirilmiş çıktısıdır. Derlenmiş bir binary ile aynı anlamda bir artifact'tır ve onu elle düzenlemek, build çıktısını düzenlemektir.

Bu üretim insanların beklediğinden çok daha sık çalışır. Pratikte tetikleyiciler şunlar:

  1. Sertifika oluşturma ve sertifika yenileme. Panel yeni yolları vhost'a yazmak için dosyanın tamamını yeniden üretir.
  2. O site için arayüzde yapılan herhangi bir kayıt. Çalışma zamanı sürümünü değiştirmek ya da bir mail alias'ı eklemek gibi web sunucusuyla hiç ilgisi olmayan bir işlem de buna dahil.
  3. Alan adı alias'ı eklemek ya da silmek. Bu server_name değerini değiştirir, dolayısıyla dosyayı da.
  4. Panel güncellemesi. Yeni bir şablonla gelebilir ve makinedeki bütün siteleri baştan üretebilir.

Önemli olan yenileme, çünkü o bir zamanlayıcıyla çalışır. Değişiklik salı günü yapılır, site altı sekiz hafta doğru davranır, sonra kimsenin izlemediği bir zamanlanmış iş sabahın dördünde dosyayı yeniden yazar. Eksik davranış fark edildiğinde değişiklik o kadar geride kalmıştır ki kimse iki olayı birbirine bağlamaz. Değişiklik hiç çalışmamış gibi ya da onu başka bir şey bozmuş gibi görünür.

Panelin bunu yapmasının bir sebebi var ve sebep makul. Yüzlerce siteyi tek şablondan üretmek, sertifika yollarını tek yerden değiştirmek ve arayüzde yapılan bir ayarı bütün sitelere yansıtmak ancak dosyanın sahibi panel olduğunda mümkün olur. Yani buradaki çelişki bir hata değil, bir tasarım kararı. Sorun, o kararın sunucuya bağlanan kişiye hiçbir yerde anlatılmaması. Dosya sıradan bir config dosyası gibi görünür, sıradan bir editörle açılır, sıradan bir şekilde kaydedilir ve tek işareti çoğu zaman okunmadan geçilen ilk satırdır.

Üretim yalnızca sizin satırlarınızı düşürmekle de kalmayabilir. Include'ları sabit sırayla yazan bir şablon, sizin taşıdığınız her şeyi eski sırasına döndürür; şablonun tanımadığı direktifler ise çıktıda hiç yer almaz. Ortada birleştirme de yok, çakışma uyarısı da, neyin silindiğini söyleyen bir log satırı da.

Nasıl görülür

Önce üretilmiş dosyanın başını okuyun. Paneller neredeyse her zaman bir uyarı bırakır:

head -5 /etc/nginx/sites-enabled/ornek.com.conf
# # Bu dosya üretilmiştir. Yapılan değişiklikler bir sonraki güncellemede kaybolur.

Sonra zaman damgalarını kendi geçmişinizle karşılaştırın. Dosya sizin son girişinizden yeniyse onu yazan başka biri var demektir:

stat -c '%y %n' /etc/nginx/sites-enabled/*.conf
last -n 5

Şablonu bulmak için üretilmiş dosyadan kaynakta da geçmesi muhtemel, ayırt edici bir metin alın ve panelin kurulu olduğu dizinlerde arayın. Aramayı nginx dizininin dışında tutun ki çıktıda yalnızca kaynaklar kalsın:

grep -rl 'fastcgi_read_timeout' /opt /usr/local /usr/share 2>/dev/null | grep -v '/etc/nginx/'
# /usr/local/panel/templates/vhost_nginx.tpl

İçinde gerçek değerler yerine yer tutucular olan dosya şablondur. Onun yanında ya da panelin veri dizininde, site başına özel direktiflerin saklandığı yeri de bulursunuz. Asıl aradığınız şey odur.

Son doğrulama bilerek yapılır. Paneldeki siteyi hiçbir şey değiştirmeden kaydedin ve dosyayı izleyin:

sha256sum /etc/nginx/sites-enabled/ornek.com.conf
# arayüzde kaydet butonuna basın
sha256sum /etc/nginx/sites-enabled/ornek.com.conf

İki farklı hash, dosyanın her kayıtta yeniden üretildiği anlamına gelir. Artık soru değişikliğinizin kaybolup kaybolmayacağı değil, ne zaman kaybolacağıdır.

Çözüm

Dosyanın sahibi hangi katmansa onu kabul edin ve onunla güreşmeyi bırakın. Değişikliği koyabileceğiniz üç yer var, tercih sırasıyla.

Birincisi, çoğu panelin site başına sunduğu özel direktif alanı. Panel veritabanında durur ve her üretimde dosyaya yazılır, yani tasarımı gereği hayatta kalır. Ayrıca sizden sonraki kişinin bakacağı tek yer de orasıdır.

İkincisi, şablonun zaten ürettiği bir include dizini. Üretilmiş dosyada include /etc/nginx/custom/ornek.com.d/*.conf; gibi bir satır varsa oraya bir dosya bırakabilirsiniz, panel include satırını yazmaya devam eder:

# /etc/nginx/custom/ornek.com.d/headers.conf
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Bu include'un hangi seviyeye düştüğüne dikkat edin. Panel onu server seviyesinde değil bir location bloğunun içinde yazıyorsa, tek bir add_header'ın diğer bütün başlıkları düşürdüğü kuralla tanışmışsınız demektir.

Üçüncüsü, makinedeki bütün sitelere uygulanması gereken değişiklikler için şablonun kendisi. Şablonu düzenleyin, sonra bir üretim zorlayın ki dosya ile şablon aylar sonra tahmin edilemez bir anda değil, hemen o an aynı şeyi söylesin. Şablonun bir kopyasını versiyon kontrolünde tutun, çünkü panel güncellemesi onu değiştirecek ve o gün elinizde hatıra değil diff olsun istersiniz.

Hangi katmanı seçerseniz seçin, değişikliği kendini geri alabilen bir script ile uygulayın:

#!/bin/sh
set -e

target=/etc/nginx/custom/ornek.com.d/headers.conf
backup=/root/vhost-rollback-$(date +%Y%m%d%H%M%S).conf

[ -f "$target" ] && cp "$target" "$backup"
cp ./headers.conf "$target"

if nginx -t; then
  systemctl reload nginx
  echo "uygulandi"
else
  echo "config testi basarisiz, geri aliniyor"
  if [ -f "$backup" ]; then cp "$backup" "$target"; else rm -f "$target"; fi
  nginx -t && systemctl reload nginx
  exit 1
fi

Yedek, kendi dizininize zaman damgalı bir adla gider. Birden fazla kişinin ya da birden fazla projenin shell'i olduğu bir makinede paylaşılan bir dizine genel adla dosya koymak başlı başına bir kaza sebebidir.

Çalıştığını nasıl doğrularsınız

Değişikliğin bugün çalışıyor olması hiçbir şey kanıtlamaz. Bilmek istediğiniz şey, bir üretimden sonra da çalışıp çalışmadığı. Üretimi zorlayın, sonra hem dosyayı hem davranışı kontrol edin:

sha256sum /etc/nginx/sites-enabled/ornek.com.conf > /root/vhost.sha
# paneldeki siteyi kaydedin ya da sertifikayı yenileyin
sha256sum -c /root/vhost.sha
# /etc/nginx/sites-enabled/ornek.com.conf: FAILED

grep -c 'custom/ornek.com.d' /etc/nginx/sites-enabled/ornek.com.conf
# 1

curl -sI https://ornek.com/ | grep -ci 'strict-transport-security'
# 1

Hash'in değişmesi beklenen şey, panel dosyayı yeniden yazdı. Önemli olan include'un hâlâ orada olması ve başlığın hâlâ yanıtta olması. İkisi de bir yenilemeden sonra duruyorsa değişiklik doğru katmanda demektir.

Sonra bunu hafızadan çıkarıp kontrole çevirin. Siteyi isteyip zorunlu bir başlık eksikse haber veren küçük bir zamanlanmış iş, sessiz bir gerilemeyi mesaja dönüştürür ve günde bir isteğe mal olur.

Nelere dikkat etmeli

  • İnsanları en çok yakalayan tetikleyici sertifika yenilemesi, çünkü hem zamanlayıcıyla çalışır hem de başka şeylere dokunur. Yarım kalan bir yenileme, siteyi süresi dolmuş sertifikayla ya da yeni sertifikayı göstermeyen bir dosyayla bırakabilir. Aynı ailenin diğer tuzağı, yenilemenin ihtiyaç duyduğu dizini silen bir deploy adımıdır: sertifika yenilemeyi kıran rsync bayrağı tam olarak budur.
  • nginx -t geçmesi değişikliğinizin sağ kaldığı anlamına gelmez. Test söz dizimine bakar, sizin satırlarınızın silindiği bir dosyanın söz dizimi de gayet geçerlidir.
  • Bazı direktiflerde sıra önemlidir ve sırayı şablon belirler. Panel kendi add_header satırını ya da kendi location bloğunu sizinkinden sonra yazıyorsa kazanan sizinki olmaz.
  • Panel güncellemesinden sonra şablonu kendi kopyanızla diff'leyin, bir şeyin hâlâ geçerli olduğunu varsaymadan önce. Bütün siteleri aynı anda değiştiren üretim odur.
  • Dosyanın hangi katmana ait olduğunu, değişikliğin yanına, ekibinizin gerçekten okuduğu yere yazın. O dosyayı bir sonraki elle düzenleyecek kişi, baştaki uyarıyı hiç görmemiş biri olacak.

Bir araç tarafından üretilen her şey çıktıdır ve çıktı aracın malıdır. Bu sınıftaki sorunları önleyen alışkanlık, sunucuda herhangi bir dosyayı düzenlemeden önce tek bir soru sormak: bunu ne yazdı ve bir daha ne zaman yazacak. Cevap bir şablon ve bir zamanlayıcıysa değişiklik şablona, kontrol de zamanlanmış bir işe gider, sizin aklınıza değil. Doğru katmanı bulmanın bedeli bir kereye mahsus yirmi dakika, atlamanın bedeli ise iki ay sonra sebebi belirsiz biçimde ortaya çıkan bir gerileme.

Sorular ve cevaplar

nginx config değişikliğim neden kendi kendine kayboldu?
Çünkü o dosya üretilmiş bir dosya. Hosting paneli site tanımını kendi veritabanında saklar ve siteye dokunan her olayda vhost dosyasını şablondan yeniden üretir. Sertifika yenilemesi ve arayüzdeki her kayıt bu olaylara dahildir. Sizin değişikliğiniz çıktının içinde durduğu için bir sonraki üretimde üzerine yazıldı.
Panelin vhost'u hangi şablondan ürettiğini nasıl bulurum?
Önce üretilmiş dosyanın ilk satırlarına bakın; genelde "bu dosya üretilmiştir, elle değiştirmeyin" uyarısı olur. Sonra dosyadan ayırt edici bir metin parçası alın ve panelin kurulu olduğu dizinlerde arayın, nginx config dizinini aramanın dışında tutun. Eşleşen dosya şablondur.
Dosyayı immutable yapıp panelin yazmasını engelleyebilir miyim?
Engelleyebilirsiniz ama bu genelde değişikliğinizi korumak yerine paneli bozar. Başarısız bir üretim çoğu zaman başarısız bir sertifika yenilemesi demektir ve o da birkaç hafta sonra siteyi çok daha gürültülü biçimde düşürür. Değişikliği panelin okuduğu yere koymak daha doğru yoldur.
Config düzenledikten sonra nginx'i güvenli şekilde nasıl reload ederim?
Önce mevcut dosyayı benzersiz bir adla bir yere kopyalayın, değişikliği yazın, sonra nginx -t çalıştırın ve yalnızca test geçerse reload edin. Test başarısızsa kopyayı geri yazın, tekrar test edip reload edin. Bunu küçük bir script'e almak, hatalı bir düzenlemenin bedelini kesintiden saniyelere indirir.
Bir değişikliğin yeniden üretimden sağ çıktığını nasıl kanıtlarım?
Üretilen dosyanın hash'ini kaydedin, paneldeki siteyi kaydederek ya da sertifikayı yenileyerek bir üretim tetikleyin ve hash'i karşılaştırın. Sonra değişikliğin üretmesi gereken davranışı test edin, çünkü dosyanın sağ çıkması ile değişikliğin hâlâ çalışıyor olması aynı şey değildir.