Impermanence: NixOS'ta Her Boot'ta Sıfırlanan Bir Root
NixOS’un en özgün özelliklerinden biri, çoğu kullanıcının ilk duyduğunda “neden isteyeyim ki?” dediği bir şey: impermanence — kalıcısızlık.
Fikir basit: root dosya sistemi her boot’ta sıfırlanır. Sistem bir önceki oturumdan hiçbir iz taşımaz. Ne apt install kalıntıları, ne elle düzenlenmiş /etc/hosts, ne “şu an hatırlamıyorum ama çalışıyor” konfigürasyonları. Her boot, deklaratif konfigürasyonun tam yansıması.
Bu yazı teorik bir anlatı değil. Kendi kurulumumdaki gerçek disk yapısını, hangi verilerin kalıcı hangilerinin geçici olduğunu ve neden bu yapıyı tercih ettiğimi anlatıyor.
Disk Yapısı
Tek bir NVMe disk, etiket tabanlı bölümler:
| Mount | Tür | Btrfs subvol | Açıklama |
|---|---|---|---|
/ | tmpfs | — | Ephemeral root — RAM’de, boot’ta sıfırlanır |
/boot | FAT32 | — | EFI bölümü |
/nix | Btrfs | @nix | Nix store — kalıcı |
/home | Btrfs | @home | Kullanıcı dizini — kalıcı |
/persist | Btrfs | @persist | Sistem state — kalıcı |
hardware.nix dosyasındaki gerçek tanım:
fileSystems."/" = {
device = "none";
fsType = "tmpfs";
options = [ "defaults" "size=8G" "mode=755" ];
};
fileSystems."/nix"] = {
device = "/dev/disk/by-label/NIXOS";
fsType = "btrfs";
options = [ "subvol=@nix" "compress=zstd" "noatime" ];
neededForBoot = true;
};
fileSystems."/persist" = {
device = "/dev/disk/by-label/NIXOS";
fsType = "btrfs";
options = [ "subvol=@persist" "compress=zstd" "noatime" ];
neededForBoot = true;
};
Root için device = "none" ve fsType = "tmpfs" — disk değil, RAM. Her boot’ta boş başlar.
Ne Ephemeral, Ne Değil?
Bu kurulumda tam “everything ephemeral” yaklaşımı yok. Hibrit bir model:
Ephemeral (tmpfs, boot’ta sıfırlanır):
/etc— ama NixOS zaten bunu her boot’ta Nix konfigürasyonundan yeniden üretir/tmp,/run— zaten geçici olması beklenen dizinler- Herhangi bir “el ile eklendi” sistem değişikliği
Kalıcı:
/home/xmrah— Btrfs subvolume, kullanıcı dosyaları korunur/nix— Nix store, paketler ve generasyonlar/persist— açıkça persist edilmesi gereken sistem state
/home’un kalıcı olması bazı impermanence kurulumlarından farklı. Tam impermanence’ta home da tmpfs olur ve her dosya home.persistence ile açıkça tanımlanır. Bu daha radikal bir yaklaşım; şu an benim için gereğinden fazla.
Hangi Sistem Verileri Persist Ediliyor?
Root tmpfs olunca bir sorun çıkıyor: bazı servisler çalışma süresinde /var/lib ve /etc altına veri yazıyor — NetworkManager bağlantı profilleri, Docker volume’ları, makine ID’si gibi. Bunlar tmpfs’te kalırsa her boot’ta sıfırlanır.
nix-community/impermanence modülü bu sorunu çözüyor: belirtilen dizin ve dosyaları /persist altından bind-mount ederek kalıcı hale getiriyor.
Benim modules/core/impermanence.nix:
environment.persistence."/persist" = {
hideMounts = true;
directories = [
"/etc/NetworkManager/system-connections"
"/var/log"
"/var/lib/nixos"
"/var/lib/docker"
"/var/lib/libvirt"
"/var/lib/postgresql"
"/var/lib/private/open-webui"
"/var/lib/sddm"
"/var/cache/nix"
];
files = [
"/etc/machine-id"
];
};
hideMounts = true ile bu bind-mount’lar df -h çıktısında gizlenir — listeyi karmaşıklaştırmaz.
/etc/machine-id özellikle kritik: bu ID değişirse systemd journal’ı bozulur, bazı lisans mekanizmaları sıfırlanır, Tailscale yeniden auth ister. Bir kez üretilip /persist’te saklanıyor.
sops-nix: Neden SSH Key /persist’te?
sops-nix, NixOS secrets yönetimi için age şifrelemesi kullanıyor. Şifre çözme anahtarı SSH private key’i.
Şifre çözme boot sürecinde gerçekleşiyor — NixOS servisleri başlamadan önce. Ama bu noktada /home henüz mount edilmemiş. @home subvolume’u boot’un ilerleyen aşamalarında mount ediliyor.
Bu yüzden SSH anahtarı /home/xmrah/.ssh/ değil, /persist/xmrah/.ssh/ altında duruyor:
# modules/core/sops.nix
age.sshKeyPaths = [ "/persist/xmrah/.ssh/id_ed25519" ];
/persist ise neededForBoot = true ile işaretli — boot sürecinin erken aşamalarında mount ediliyor. Anahtar orada, boot sırasında ulaşılabilir.
Gerçekte Ne Kadar “Sıfırlanıyor”?
Şu anki disk durumu:
Filesystem Size Used Avail Mount
none 8,0G 70M 8,0G /
/dev/nvme0n1p3 899G 184G 714G /home
/dev/nvme0n1p3 899G 184G 714G /nix
/dev/nvme0n1p3 899G 184G 714G /persist
Root tmpfs’te 70MB — bunun büyük çoğunluğu boot sonrası NixOS’un /etc altına yazdıkları ve çalışan servislerin geçici dosyaları. Disk yazılmıyor.
Neden İstiyorum Bunu?
İki ana neden:
Sürüklenme (drift) olmuyor. Geleneksel Linux sistemlerinde zaman içinde “şimdilik böyle yapayım” kararları birikir. Bir yere bir şey eklenir, bir config düzenlenir, bir servis elle başlatılır ve unutulur. Sistem gerçekte ne olduğunu artık tam yansıtmıyor. Impermanence bunu imkânsız kılıyor — her boot deklaratif konfigürasyonun tam yansıması.
Temiz başlangıç garantisi. Yeni bir paket denerken veya servisi test ederken, sistemi pislettiğimi düşünmüyorum. Bir sonraki boot her şeyi geri alır. Persist etmek istediğim bir şeyi açıkça tanımlamam gerekiyor — bu da neyin gerçekten kalıcı olmaya değer olduğunu düşündürüyor.
NixOS, sistem konfigürasyonunu zaten deklaratif yönetiyor. Impermanence bunu runtime state’e kadar genişletiyor.
İlgili: NixOS: Kaostan Düzene Declarative Bir Yolculuk