SSD Nodes Learn 🎉 VPS $5.50/aydan başlayan
Rehberler Matt ConnorYazan Matt Connor

VPS Uzerinde Docker ile Zitadel Kurulumu

Zitadel kurulumu icin gereken 4 CPU ve 8GB RAM gereksinimlerini, Postgres, masterkey, TLS ve SMTP yapilandirmalarini ogrenin. Guncelleme sirasinda veritabani risklerini engelleyin.

Bir VPS üzerinde Zitadel self-host etmek için gerekenler

Bir VPS üzerinde Zitadel self-host etmek için bir Docker sunucusu, sunucuya yönlendirilmiş genel bir DNS adı, PostgreSQL ve yaklaşık 8 GB RAM ile 4 CPU çekirdeği gereklidir. Zitadel bir kimlik sağlayıcıdır (identity provider). OIDC (OpenID Connect) ve SAML (security assertion markup language) üzerinden token yayınlar; böylece diğer servisleriniz kendi kullanıcı listelerini tutmak zorunda kalmaz. Kurulum bir curl ve bir docker compose up içerir. Sistemin sürekliliğini belirleyen temel bileşenler masterkey, veritabanı kullanıcısı, SMTP (simple mail transfer protocol), yedekleme ve ilk yükseltme işlemidir.

Aşağıdaki tüm adımlar Ubuntu 24.04, Compose eklentisine sahip Docker Engine 24 veya daha yeni bir sürüm ve sunucuya halihazırda yönlendirilmiş auth.example.com gibi bir alan adının mevcut olduğunu varsayar.

Zitadel ne kadar VPS kaynağına ihtiyaç duyar?

Zitadel belgelerindeki Compose hızlı başlangıç kılavuzu 2 GB RAM talep eder. Bu değer bir dizüstü bilgisayar içindir. Zitadel'in üretim kılavuzu farklı rakamlar yayınlamaktadır.

ChartZitadel's own published sizing guidance, August 2026
The data behind this chart
[
  {
    "config": "Process floor, no load",
    "cpu_cores": 0.5,
    "ram_gb": 0.5
  },
  {
    "config": "Single node, reduced setup",
    "cpu_cores": 4,
    "ram_gb": 8
  },
  {
    "config": "HA node, logs and metrics on",
    "cpu_cores": 4,
    "ram_gb": 16
  }
]

Bunlar çalışan bir sunucudan alınan ölçümler değil, yayınlanmış önerilerdir. Bunları problemin genel çerçevesi olarak değerlendirin. Zitadel sürecinin kendisi küçüktür; boşta yaklaşık 0.5 GB RAM tüketir. İşlemci çekirdekleri, kasıtlı olarak yavaş tutulan parola karma (hashing) işlemleri içindir; bu nedenle ani giriş istekleri CPU kullanımında sıçramaya neden olur. PostgreSQL maliyetin diğer yarısını oluşturur: aynı kılavuz saniyede 100 istek için yaklaşık bir çekirdek ve çekirdek başına 4 GB RAM öngörür. İkisini birleştirdiğinizde, kılavuzun tek bir düğüm için belirttiği 4 çekirdek ve 8 GB değerine, günlükleme ve metrikler etkinleştirildiğinde ise düğüm başına 16 GB değerine ulaşırsınız.

Dolayısıyla 2 GB bir VPS bu yığını başlatacaktır ancak bu değer, projenin gerçek bir kullanım için önerdiğinin altındadır. Giriş yapma işlemi, diğer tüm servislerin bağımlı olduğu servistir. Bu servis kapandığında, ona güvenen hiçbir uygulama kullanıcı kabul etmez. Kimlik doğrulama için 8 GB RAM harcamak istemediğinize karar vermek makul bir yaklaşımdır ve bu kararı bir geçiş işleminden sonra vermekten çok daha ucuzdur. Keycloak, Authentik ve Zitadel karşılaştırması, her birinin bellek ve operasyonel iş yükü açısından maliyetini ele alır; kendi kendine barındırılan bir Authentik sunucusu ise daha küçük sunucular için genellikle tercih edilen çözümdür.

Stack'i alın ve bir sürümü sabitleyin

mkdir zitadel-compose && cd zitadel-compose
curl -fsSLO https://raw.githubusercontent.com/zitadel/zitadel/main/deploy/compose/docker-compose.yml
curl -fsSLO https://raw.githubusercontent.com/zitadel/zitadel/main/deploy/compose/.env.example
cp .env.example .env
chmod 600 .env

Bu dosya, fiilen çalıştıracağınız dört servisi tanımlar. Traefik, reverse proxy görevi görür: trafiği yola göre yönlendirir ve aşağıda yer alan katmanla birlikte TLS (transport layer security) sonlandırmasını gerçekleştirir. zitadel-api, 8080 numaralı portta çalışan Go binary dosyasıdır. zitadel-login, /ui/v2/login adresinde sunulan giriş arayüzüdür. postgres ise her şeyi barındırır. Bir Redis önbelleği ve bir OpenTelemetry toplayıcısı, Compose profillerinin arkasında aynı dosyada yer alır ve siz talep edene kadar kapalı kalırlar.

Henüz docker compose up komutunu çalıştırmayın. İlk başlatma işlemi örneği oluşturur ve aşağıdaki bazı ayarlar, daha sonra ekstra işlem yapılmadan değiştirilemez.

Kopyaladığınız .env dosyası kendi imaj etiketlerini sabitler:

ZITADEL_VERSION=v4.16.0
TRAEFIK_IMAGE=traefik:v3.7.7
POSTGRES_IMAGE=postgres:17.10-alpine

Mevcut v4 sürümü, 14 Ağustos 2026 tarihinde yayınlanan v4.17.1'dir. ZITADEL_VERSION değişkenini çalıştırmak istediğiniz sürüme ayarlayın ve en güncel sürümü takip etmek yerine v4 hattında kalın. Yukarıdaki curl, main dalından docker-compose.yml imajını çeker; bu dal herhangi bir sürüme sabitlenmemiştir. Bu nedenle her iki dosyanın kopyasını bir git deposuna commit edin. Aksi takdirde, gelecek ay yeni bir sunucuda aynı komutu çalıştırdığınızda farklı bir dosya ile karşılaşırsınız ve nelerin değiştiğini anlayamazsınız.

Postgres'e özel bir kullanıcı ve gerçek bir parola atayın

Dağıtılan .env, Zitadel'i PostgreSQL'e süper kullanıcı olarak ve postgres parolasıyla bağlar:

POSTGRES_ADMIN_USER=postgres
POSTGRES_ADMIN_PASSWORD=postgres
ZITADEL_DATABASE_POSTGRES_DSN=postgresql://postgres:postgres@postgres:5432/zitadel?sslmode=disable

Buradaki sıkılaştırma adımında bir tuzak bulunmaktadır. Zitadel belgeleri POSTGRES_ZITADEL_PASSWORD değerini .env dosyasına eklemenizi söyler, ancak temel docker-compose.yml bu değişkeni hiçbir zaman okumaz; bu nedenle ayarı değiştirmek hiçbir sonucu değiştirmez. Sadece POSTGRES_ADMIN_PASSWORD değerini değiştirmek ise bağlantıyı koparır, çünkü parola aynı zamanda DSN (veri kaynağı adı) dizisinin içinde açıkça yazılıdır. DSN, Zitadel'in nasıl bağlanacağına karar veren satırdır.

.env.example içindeki yorumlar durumu açıkça belirtir: bir DSN yapılandırıldığında Zitadel bu kullanıcıyı doğrudan kullanır ve sizin için yetkisiz bir kullanıcı oluşturmaz; bu nedenle rolün ilk başlatmadan önce var olması gerekir. Bir parola oluşturun, Postgres'i kendi başına başlatın ve rolü tanımlayın.

tr -dc A-Za-z0-9 </dev/urandom | head -c 32; echo

docker compose --env-file .env -f docker-compose.yml up -d postgres

docker compose --env-file .env -f docker-compose.yml exec -T postgres \
  psql -U postgres -d postgres <<'SQL'
CREATE ROLE zitadel LOGIN PASSWORD 'the-password-you-generated';
ALTER DATABASE zitadel OWNER TO zitadel;
SQL

docker compose --env-file .env -f docker-compose.yml exec -T postgres \
  psql -U postgres -d zitadel -c 'ALTER SCHEMA public OWNER TO zitadel;'

Bu psql çağrıları, resmi Postgres imajının güvendiği yerel soket üzerinden container içinde çalışır, bu yüzden parola sormazlar. Önemli olan sahiplik kısmıdır. PostgreSQL 15 ve sonraki sürümlerde, basit bir GRANT ALL PRIVILEGES ON DATABASE komutu artık bir rolün public şemasında tablo oluşturmasına izin vermez; bu nedenle Zitadel'in kurulum aşaması, şemalarını oluştururken izin hatası nedeniyle başarısız olur. Rolü veritabanının ve şemanın sahibi yapmak bu sorunu önler.

Şimdi DSN'i yeni role yönlendirin ve dosya içindeyken gerçek bir yönetici parolası belirleyin:

POSTGRES_ADMIN_PASSWORD=a-32-character-random-string
ZITADEL_DATABASE_POSTGRES_DSN=postgresql://zitadel:the-password-you-generated@postgres:5432/zitadel?sslmode=disable

Postgres yalnızca özel Compose ağı üzerinden erişilebilir olduğundan ve portu hiçbir zaman ana makineye açılmadığından sslmode=disable burada sorun yaratmaz. İlk tam başlatmadan sonra, rolün verilerinin gerçekten sahibi olup olmadığını kontrol edin:

docker compose exec -T postgres psql -U zitadel -d zitadel -c '\dn'

Bu komut bir eventstore şeması ve bir projections şeması listelemelidir. Boş bir liste, kurulum aşamasının o noktaya hiç ulaşmadığı anlamına gelir; API container günlüğü bunun nedenini gösterecektir.

Masterkey ve kaybedilmesinin maliyeti

Zitadel, gizli verileri depolamadan önce şifreler: client secret'lar, kimlik sağlayıcı kimlik bilgileri, SMTP parolası, tek kullanımlık parola (OTP) tohumları ve makine anahtarları. Masterkey, tüm bunların kilidini açar. Tam olarak 32 karakter uzunluğundadır ve belgeler sonuç konusunda nettir: şifrelenmiş verilere erişimi kaybetmeden bu anahtar değiştirilemez.

Bir tane oluşturun ve .env içindeki yer tutucu satırı değiştirin:

tr -dc A-Za-z0-9 </dev/urandom | head -c 32; echo

İkinci bir satır eklemek yerine ZITADEL_MASTERKEY=MasterkeyNeedsToHave32Characters satırını düzenleyin. Compose, yinelenen bir anahtarın son tanımını dikkate alır; bu nedenle ekleme yapmak teknik olarak çalışsa da, iki masterkey satırı içeren bir dosya, dosyayı daha sonra okuyacak kişi için bir tuzaktır.

Şimdi bu anahtarın nerede durduğunu düşünün. Compose dosyası, API container'ını şu şekilde başlatır:

command: start-from-init --masterkey "${ZITADEL_MASTERKEY}"

Bu nedenle masterkey, container komut satırında yer alır ve docker inspect, Docker socket'ine erişebilen herkese bu değeri gösterir. Tek yöneticili bir VPS üzerinde bu kabul edilebilir bir takastır ve .env üzerindeki mod, dosyayı disk üzerinde koruyan şeydir. Eğer bu kabul edilebilir değilse, anahtarı bir dosya olarak mount edin ve değeri süreç argümanlarının dışında tutan --masterkeyFile /run/secrets/zitadel-masterkey seçeneğini kullanın.

İlk başlatmadan önce masterkey'i parola yöneticinize kopyalayın. Veritabanı dökümünde görünmez; bu nedenle farklı bir masterkey ile geri yüklenen bir döküm, kendi gizli verilerini okuyamayan bir örnek oluşturur. Anahtarı, dökümü içeren arşivden başka bir yerde saklayın; böylece çalınan bir yedekleme hem şifrelenmiş verileri hem de onun anahtarını aynı anda içermez.

İlk başlatmadan önce harici alan adını ayarlayın

ZITADEL_DOMAIN, .env içinde ZITADEL_EXTERNALDOMAIN değerini besler ve bu, kullanıcılarınızın tarayıcıya yazdığı isimdir. Zitadel; OIDC sağlayıcısını, giriş arayüzü temel URI adresini, SAML uç noktalarını ve ilk yöneticinin giriş adını bu değerden türetir; dolayısıyla bu sadece görsel bir ayar değildir.

ZITADEL_DOMAIN=auth.example.com
ZITADEL_EXTERNALPORT=443
ZITADEL_EXTERNALSECURE=true

Zitadel, hangi örneğe (instance) eriştiğinizi Host başlığından anlar. Eğer bu başlık, sistemin bildiği bir alan adı ile eşleşmezse, her istek aynı yanıtı alır:

ID=QUERY-1kIjX Message=Instance not found

Bu, kendi sunucusunda Zitadel barındıran kullanıcıların karşılaştığı en yaygın hatadır ve neredeyse her zaman iki durumdan birine işaret eder. Ya ZITADEL_DOMAIN tarayıcıda girdiğiniz isimle aynı değildir ya da ön taraftaki bir proxy, Host değerini upstream adresine göre yeniden yazıyordur. Sunucuya alan adı yerine IP adresi ile erişmek de bu hataya yol açar.

Bu değerleri daha sonra değiştirebilirsiniz. Ancak Zitadel'in değişikliği algılaması için kurulum aşamasını yeniden çalıştırması gerekir ve halihazırda kaydettiğiniz tüm uygulamalar eski yönlendirme URI adreslerini korur. Nihai ismi en başta belirlemek, daha sonra taşımaktan çok daha zahmetsizdir.

Let's Encrypt katmanı ile TLS sonlandırma

Halka açık bir alan adı için Zitadel'in Let's Encrypt katmanını ekleyin. Bu katman, Traefik'i ACME (otomatik sertifika yönetimi ortamı) HTTP sınamasına geçirir ve yayınlanan portları 80 ve 443 ile değiştirir; bu nedenle sunucuda başka hiçbir servis bu portları kullanamaz.

curl -fsSLO https://raw.githubusercontent.com/zitadel/zitadel/main/deploy/compose/docker-compose.mode-letsencrypt.yml
echo 'LETSENCRYPT_EMAIL=ops@example.com' >> .env

Bu katman ayrıca API container'ı üzerinde ZITADEL_EXTERNALPORT: 443 ve ZITADEL_EXTERNALSECURE: true ayarlarını yapılandırır; bu sayede genel URL ile Zitadel'in kendi oluşturduğu URL'ler birbiriyle uyumlu hale gelir. HTTP sınaması bu kayıt olmadan başarısız olacağından, işleme başlamadan önce A kaydının çözümlendiğinden emin olunmalıdır.

TLS sonlandırmasını halihazırda nginx veya bir yük dengeleyici üzerinde yapıyorsanız, bunun yerine docker-compose.mode-external-tls.yml kullanın ve TRAEFIK_TRUSTED_IPS değerini proxy'nizin istek gönderdiği aralıklarla ayarlayın. Traefik yalnızca bu listedeki adreslerden gelen X-Forwarded-* başlıklarını dikkate alır; yanlış bir değer, iletilen protokolün reddedilmesine ve Zitadel'in bir HTTPS sitesi için http:// URL'leri oluşturmaya başlamasına neden olur.

Bir upstream proxy'nin Zitadel için katı kurallara tabi iki görevi vardır. API gRPC tabanlı olduğu için backend ile HTTP/2 üzerinden haberleşmelidir. Ayrıca Host başlığını X-Forwarded-Proto: https ile birlikte değiştirmeden iletmelidir. Zitadel'in kendi nginx örneği bu yapıyı göstermektedir:

server {
    listen 443 ssl;
    http2 on;
    ssl_certificate     /etc/certs/selfsigned.crt;
    ssl_certificate_key /etc/certs/selfsigned.key;
    location /ui/v2/login {
        proxy_pass http://login-external-tls:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
    }
    location / {
        grpc_pass grpc://zitadel-external-tls:8080;
        grpc_set_header Host $host;
        grpc_set_header X-Forwarded-Proto https;
    }
}

Buradaki upstream isimleri Zitadel'in test kurulumundaki container'lardır, bunları kendi kurulumunuzdakilerle değiştirin. Zitadel'i 443 dışında bir porttan sunuyorsanız, portun başlık ile birlikte iletilmesi için grpc_set_header Host $host:$server_port; kullanın. Yapılandırmanın geri kalanı standart bir sanal sunucu ayarıdır ve satır satır nginx reverse proxy yapılandırması dokümanı, Zitadel'e özel olmayan kısımları açıklamaktadır.

İlk yönetici ve parola değişikliğini zorunlu kılma

İlk başlatma işlemi bir instance, bir organizasyon ve bir insan yönetici oluşturur. Giriş adı zitadel-admin@ artı zitadel. artı harici alan adınızdan oluşur; dolayısıyla ZITADEL_DOMAIN=auth.example.com ile sonuç şöyledir:

zitadel-admin@zitadel.auth.example.com

Siz kendinizinkini belirlemediğiniz sürece parola Password1! değerindedir. Zitadel'in varsayılan ayarı ilk girişte parola değişikliğini zorunlu kılmaktır ve sunulan compose dosyası bu varsayılanı şu şekilde geçersiz kılar:

ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORDCHANGEREQUIRED: false

Bu satır .env dosyasından okunmak yerine docker-compose.yml içinde sabit kodlanmıştır, bu nedenle kendi değerlerinizi küçük bir katman dosyasına ekleyin. Bu dosyayı docker-compose.local.yml olarak adlandırın:

services:
  zitadel-api:
    environment:
      ZITADEL_FIRSTINSTANCE_ORG_HUMAN_EMAIL_ADDRESS: you@example.com
      ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD: "a-long-temporary-password"
      ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORDCHANGEREQUIRED: "true"

Compose, herhangi bir -f bayrağı olmadan çalıştırıldığında yalnızca docker-compose.override.yml dosyasını yükler; Zitadel kılavuzundaki her komut ise bu özelliği devre dışı bırakan -f bayrağını kullanır. Sürekli uzayan bayrak listelerini tekrarlamak yerine, dosya listesini .env içinde sabitleyin:

COMPOSE_FILE=docker-compose.yml:docker-compose.mode-letsencrypt.yml:docker-compose.local.yml

Şimdi başlatın:

docker compose pull
docker compose up -d --wait

--wait, sağlık kontrolleri başarılı olana kadar komutu bekletir. API container'ı bu aşamaya ulaşamazsa, Compose dependency failed to start: container zitadel-compose-zitadel-api-1 is unhealthy hatasıyla durur ve docker compose logs zitadel-api dosyasında hata nedeni yer alır. İlk başlatmada bu neden genellikle anahtar uzunluğu veya veritabanı DSN bilgisidir.

https://auth.example.com/ui/console adresinden giriş yapın, parolayı değiştirin ve başka bir şey oluşturmadan önce bu hesap için ikinci bir doğrulama faktörü etkinleştirin. Her ZITADEL_FIRSTINSTANCE_* değeri yalnızca ilk instance oluşturulurken geçerlidir. Instance bir kez oluştuktan sonra, bu değerleri düzenlemek hiçbir etki yaratmaz.

SMTP çalışana kadar parola sıfırlama işleminin sonuçsuz kalmasının nedeni

E-posta gönderemeyen bir kimlik sağlayıcı, haftalarca fark edilmeyecek bir şekilde bozuk kalır. Zitadel; kullanıcı davetleri, adres doğrulama, parola sıfırlama bağlantıları, tek kullanımlık kodlar ve alan adı sahiplik bildirimleri için e-posta gönderir. SMTP sağlayıcısı yapılandırılmadığında, Konsol işlemi tamamlanmış gibi raporlar ancak mesaj, gönderilecek yeri olmayan bir bildirim işleyicisine (notification worker) iletilir. Varsayılan ayarlar bu işleyiciye MaxAttempts: 3 ve MaxTtl: 5m değerlerini atadığı için, sistem birkaç dakika boyunca birkaç kez yeniden deneme yapar ve ardından durur. Bağlantıyı bekleyen kişiye hiçbir bildirim gitmez.

Yapılandırmayı Konsol üzerinde, https://auth.example.com/ui/console/settings altındaki örnek (instance) ayarlarından yapın. SMTP sağlayıcısı formu; gönderen e-posta adresi, gönderen adı, ana makine (host) ve port, kullanıcı adı, SMTP parolası ve TLS anahtarı ister. Kaydetmeden önce formdaki test düğmesini kullanın; bu düğme gerçek bir mesaj gönderir, böylece mesajın ulaşıp ulaşmadığını anında görürsünüz.

ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_HOST ve benzeri ortam değişkenleri de mevcuttur. Bunlar, bir örnek oluşturulduğunda geçerli olur. Hali hazırda çalışan bir yığında (stack) bu değişkenlerin etkisi yoktur, bu nedenle mevcut bir örnek için en doğru yer Konsol'dur.

Bir VPS üzerinden gönderim yaparken dikkat edilmesi gereken iki husus vardır, çünkü hatalar genellikle burada oluşur. Çoğu sağlayıcı yeni hesaplarda 25 numaralı giden portu engeller, bu nedenle alıcının posta sunucusuna doğrudan gönderim, anlamlı bir hata vermeden zaman aşımına uğrar. Bunun yerine 587 numaralı port üzerinden kimlik doğrulamalı bir aktarıcı (relay) kullanın. Ayrıca gönderen alan adı için SPF (sender policy framework) ve DKIM (domainkeys identified mail) kayıtlarını yayınlayın; aksi takdirde sıfırlama bağlantısı spam klasörüne düşer ve bu durum kullanıcıya e-posta hiç gönderilmemiş gibi görünür.

Kimseyi davet etmeden önce sistemi test edin. Geçici bir kullanıcı oluşturun, parola sıfırlama isteğinde bulunun ve mesajın ulaştığını doğrulayın. Eğer ulaşmazsa, docker compose logs -f zitadel-api SMTP hatasını belirtir. SMTP parolası veritabanında şifrelenmiş olarak saklanır; bu da ana anahtarın (masterkey) sizin için koruduğu bir diğer veridir.

Postgres ve masterkey verilerini ayrı ayrı yedekleyin

Zitadel'in bildiği her şey PostgreSQL içinde yer alır. Bu verilerin şifresini çözen öğe ise masterkey dosyasıdır. Bu iki veriyi birbirinden farklı iki konuma yedekleyin.

Önce veritabanı dökümünü alın:

sudo install -d -m 700 /srv/zitadel-backups
docker compose exec -T postgres \
  pg_dump -U postgres -Fc zitadel > "/srv/zitadel-backups/zitadel-$(date +%F).dump"

-Fc, verileri dışa aktarırken sıkıştıran ve pg_restore tarafından seçici olarak okunabilen özel bir formattır. exec -T, terminal bağlantısını keser; bu, işlemin terminali olmayan bir cron görevi üzerinden çalıştırılması nedeniyle önemlidir.

Ardından, verileri şifreleyen ve tekilleştiren restic kullanarak bu dizini sunucu dışına aktarın:

export RESTIC_REPOSITORY="sftp:backup@backup.example.com:/srv/restic/zitadel"
export RESTIC_PASSWORD_FILE=/root/.restic-password
restic init
restic backup /srv/zitadel-backups
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune

restic init yalnızca ilk gün, bir kez çalıştırılır. Döküm komutunu ve son iki komutu /usr/local/bin/zitadel-backup.sh dosyasına ekleyin ve her gece çalışacak şekilde ayarlayın:

0 3 * * * /usr/local/bin/zitadel-backup.sh

.env dosyasını ve kullandığınız tüm compose dosyalarını git üzerinde yedekleyin. Masterkey, bu kuralın istisnasıdır. Bu anahtar, parola yöneticinizde ve bu restic deposundan farklı ikinci bir konumda tutulmalıdır; çünkü veritabanını ve şifre çözme anahtarını aynı arşivde tutmak, şifreli bir sistemin yedekleme amacını ortadan kaldırır.

Geri yüklemesini yapmadığınız bir yedekleme, sadece bir tahmindir. Aynı sunucuda geçici bir veritabanına geri yükleme yapın ve kontrol edin:

docker compose exec -T postgres createdb -U postgres zitadel_restore_test
docker compose exec -T postgres pg_restore -U postgres -d zitadel_restore_test \
  < /srv/zitadel-backups/zitadel-2026-08-21.dump
docker compose exec -T postgres psql -U postgres -d zitadel_restore_test -c '\dt eventstore.*'
docker compose exec -T postgres dropdb -U postgres zitadel_restore_test

eventstore şemasındaki tabloların listelenmesi, dökümün başarılı olduğunu gösterir. Şemanın bulunamadığına dair bir hata mesajı, yedeğin hatalı olduğu anlamına gelir; bunu, herhangi bir veri kaybı yaşamadığınız bir günde fark etmiş olursunuz. Compose yığınlarını yedekleme ve yükseltme için genel yöntem, burada neredeyse hiç değişiklik yapılmadan uygulanabilir; masterkey dosyasını aynı arşivin dışında tutmak, Zitadel'e özgü tek farktır.

Zitadel'i örneği kaybetmeden yükseltmek

Yükseltme işlemi, .env sürümünün güncellenmesi ve ardından şu iki komutun çalıştırılmasıdır:

docker compose pull
docker compose up -d --wait

İkinci komutu, kullanıcıların giriş yaptığı bir sistemde çalıştırmadan önce ne işe yaradığını anladığınızdan emin olun. Container komutu olan start-from-init, servis başlamadan önce init ve setup aşamalarını çalıştırır; setup aşaması ise veritabanı migrasyonlarını kapsar. Dolayısıyla sürüm yükseltme işlemi, container başladığında canlı veritabanınız üzerinde otomatik olarak şema migrasyonlarını çalıştırır ve bu sırada --wait, sağlık kontrolünün (healthcheck) geçmesini bekler. Yukarıda bahsedilen geri yükleme testinin isteğe bağlı olmamasının temel nedeni budur.

Yükseltme işleminden hemen önce güncel bir veritabanı dökümü alın. Dün gece alınan döküm, güncel durumla aynı değildir.

Ana sürüm atlaması yapmayın. v3 sürümünden v4 sürümüne geçmek için önce v3.4.1 veya daha yeni bir sürüme geçiş yapılmış olmalıdır. v4 sürümü eski OIDC imzalama anahtarlarını kaldırdığı için, eski anahtarlarla imzalanmış token'lar geçiş yapıldığı anda doğrulanamaz hale gelir. Zitadel teknik bülteni A-10017 bu durumu açıklar; çözüm ise, eski token'ların süresi dolana kadar yeni v3 sürümünü bir süre çalıştırmaktır.

Setup aşamasını docker compose logs -f zitadel-api ile izleyin. Büyük bir eventstore üzerindeki migrasyonlar dakikalar sürebilir ve Traefik, sağlık kontrolü geçene kadar API'ye yönlendirme yapmayacaktır; bu nedenle site bu süre zarfında kapalı kalır. Bu durumu sürpriz olarak değil, planlı bir şekilde yönetin.

Geri alma (rollback) işlemi, sadece eski etiketi (tag) geri getirmekten ibaret değildir. Migrasyonlar bir kez çalıştırıldığında, eski binary dosyası karşılaştığı şema yapısını anlayamaz; bu nedenle geri alma işlemi, dökümün geri yüklenmesi anlamına gelir. Örnek üzerinde gerçek kullanıcılar bulunmaya başladığında, init ve setup işlemlerini başlatma sürecinden ayrı adımlar olarak çalıştıran docker-compose.prodlike.yml overlay yapısına geçin. Böylece migrasyon, container yeniden başlatılmasının bir yan etkisi olmak yerine, tetiklediğiniz ve izlediğiniz kontrollü bir işlem haline gelir.

Yeni kimlik sağlayıcınıza neyi işaret etmelisiniz

Console üzerinde bir proje oluşturun ve ardından içinde bir uygulama tanımlayın. Modern tüm yapılar için OIDC seçeneğini tercih edin; Zitadel size bir client ID, bir client secret ve https://auth.example.com/.well-known/openid-configuration adresinde bir discovery document sunacaktır. Single sign-on destekleyen çoğu self-hosted yazılım tam olarak bu bilgilere ihtiyaç duyar.

Pek çok yazılım bu desteği sunmaz veya yalnızca ücretli sürümlerinde destekler. İlk durum için, uygulamanın önünde oauth2-proxy kullanımı, herhangi bir HTTP servisini Zitadel tarafından korunabilir hale getirir. İkinci durum için, self-hosted uygulamalarda SSO maliyeti, henüz ödeme yapmadığınız bir özellik üzerine geçiş planlamadan önce okunmalıdır.

FAQ

Kendi kendine barındırılan (self-hosted) Zitadel ne kadar RAM ve CPU gerektirir?

Zitadel üretim kılavuzu, kısıtlı bir kurulum çalıştıran tek bir düğüm için yaklaşık 4 CPU çekirdeği ve 8 GB RAM; günlük kaydı ve metrikler açıkken düğüm başına 16 GB RAM önermektedir. PostgreSQL için ayrı bir bütçe ayrılmalıdır; bu da saniyede 100 istek için yaklaşık bir çekirdek ve çekirdek başına 4 GB RAM anlamına gelir. Compose hızlı başlangıç kurulumu 2 GB altında başlar; bu miktar denemeler için yeterli olsa da, diğer servislerin bağımlı olduğu bir sistem için projenin önerdiği değerlerin altındadır.

Zitadel ana anahtarını (masterkey) kaybedersem ne olur?

Bu anahtarla şifrelenmiş her şey şifreli kalır. İstemci sırları, kimlik sağlayıcı kimlik bilgileri, SMTP parolası ve tek kullanımlık parola (OTP) tohumlarının şifresi çözülemez ve anahtar sonradan değiştirilemez. Veritabanı dökümü tek başına çalışan bir örneği geri yükleyemez, çünkü döküm şifreli metni içerir ancak anahtarı içermez. Ana anahtarı, dökümü içeren yedekten ayrı bir yerde, bir parola yöneticisinde saklayın. Her ikisi de kaybolursa, tek seçenek örneği sıfırdan yeniden oluşturmaktır.

Zitadel parola sıfırlama e-postaları neden hiç ulaşmıyor?

Çünkü bir SMTP sağlayıcısı yapılandırılmamıştır veya yapılandırılan sağlayıcı teslimat yapamıyordur. Zitadel her bildirimi varsayılan olarak üç deneme yapan bir işçiye (worker) kuyruklar ve her iki durumda da Console üzerinde başarı raporu verir; bu nedenle hata sessizce gerçekleşir. SMTP sağlayıcısını örnek ayarları altında yapılandırın ve o formdaki, gerçek bir ileti gönderen test düğmesini kullanın. Bir VPS üzerinden gönderim yapıyorsanız, çoğu sağlayıcı 25 numaralı giden portu engellediği için 587 numaralı portta kimlik doğrulamalı bir aktarıcı (relay) kullanın ve postanın spam olarak filtrelenmemesi için gönderen alan adı adına SPF ve DKIM kayıtlarını yayınlayın.

Kurulumdan sonra Zitadel dış alan adını değiştirebilir miyim?

Evet, ancak yalnızca .env dosyasını düzenleyerek değil. ZITADEL_EXTERNALDOMAIN, ZITADEL_EXTERNALPORT ve ZITADEL_EXTERNALSECURE değerlerini değiştirin, ardından Zitadel'in değişikliği algılaması için kurulum aşamasını yeniden çalıştırmasına izin verin. Daha önce kaydettiğiniz uygulamalar eski yönlendirme URI'lerini korur ve elle güncellenmeleri gerekir; ayrıca Host başlığı Zitadel'in bildiği bir alan adıyla eşleşmeyen her istek Instance not found yanıtını alır. İlk başlatmadan önce nihai alan adını seçmek tüm bu süreçten kaçınmanızı sağlar.