> For the complete documentation index, see [llms.txt](https://docs.kangal.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kangal.dev/tr/gateway/custom-domains.md).

# Custom domain

Custom domain, müşteriye ait bir hostname'i Kangal gateway'e veya Developer Portal'a bağlar. Akış DNS sahipliğini doğrular, certificate üretir, certificate ve SNI kaynaklarını oluşturur ve target binding'i kaydeder.

DNS kayıtları ve serving edge operator tarafından yönetilir. Hostname'i duyurmadan önce Kangal akışını ve DNS/ingress değişikliğini birlikte planlayın.

## Akış özeti

1. Tam hostname için bir custom-domain kaynağı oluşturun.
2. Üretilen DNS TXT ownership kaydını yayınlayın.
3. Kangal üzerinden kaydı doğrulayın.
4. Certificate worker'ın certificate materyalini ve SNI eşlemesini oluşturmasını bekleyin.
5. Hostname trafik kaydını yayınlayın ve serving edge'i yapılandırın.
6. Public certificate ile uygulama response'unu doğrulayın.

DNS verifier ownership kayıtlarını salt okunur olarak kontrol eder. Müşterinin DNS zone'unda kayıt oluşturma, değiştirme ve silme işlemleri kendi DNS yönetim süreci üzerinden yapılır.

## Gereksinimler

* Aynı tenant içinde mevcut bir gateway.
* Kangal Admin API veya Console için administrator erişimi.
* Authoritative DNS zone'da TXT ve trafik kaydı oluşturma izni.
* Çalışan bir custom-domain certificate worker.
* Public certificate için cert-manager çalışan Kubernetes cluster, yapılandırılmış issuer, DNS-01 solver erişimi ve etkin production issuance guard'ları.
* Üretilen certificate'ı sunabilen ve hostname'i seçilen gateway ya da portal'a iletebilen ingress veya edge listener.

Hostname tam bir FQDN olmalıdır. Kangal büyük/küçük harfi normalize eder, sondaki noktayı kaldırır ve internationalized domain adlarını IDNA biçimine dönüştürür. Wildcard, IP adresi, `localhost`, tek label içeren adlar, 63 karakterden uzun label'lar ve `-` ile başlayan veya biten label'lar reddedilir. Normalize edilmiş bir hostname deployment genelinde tek bir custom-domain veya manuel SNI kaynağı tarafından yönetilir.

## Target ve provider seçimi

### Target

| Değer     | Kullanım                                                                                                   |
| --------- | ---------------------------------------------------------------------------------------------------------- |
| `gateway` | Hostname'i gateway proxy trafiğine gönderir.                                                               |
| `portal`  | Hostname'i tenant Developer Portal'a gönderir. Binding, portal path olarak `/portal/{tenant_id}` kaydeder. |

### DNS verification provider

| Değer        | Configuration                                                                                           | Davranış                                               |
| ------------ | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| `manual`     | `dns_provider_config` içinde isteğe bağlı `nameservers` listesi ve 1 ile 15 arasında `timeout_seconds`. | TXT kaydını DNS üzerinden çözümler.                    |
| `cloudflare` | `dns_provider_config` içinde `zone_id`, `dns_credentials` içinde `api_token`.                           | Eşleşen TXT kayıtlarını Cloudflare API üzerinden okur. |

Cloudflare credential'ı, seçilen zone'un DNS kayıtları için read yetkisine sahip olmalıdır. Kangal saklanan credential değerlerini korur ve response'lardan redact eder. Least-privilege token kullanın ve credential politikanıza göre düzenli olarak rotate edin.

### Certificate provider

| Değer          | Kullanım                                                 | Davranış                                                                                                                                                                                   |
| -------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `test-ca`      | Local, development ve akış testi.                        | Kangal private test CA'sından 1 ile 90 gün geçerli ECDSA certificate üretir. Browser ve public client'lar bu certificate'a varsayılan olarak güvenmez. `validity_days` varsayılanı 30'dur. |
| `cert-manager` | Kubernetes üzerinde staging veya production certificate. | `cert-manager.io/v1` Certificate oluşturur ve sonuçtaki TLS Secret'ı okur.                                                                                                                 |

`cert-manager` için `acme_config`; `namespace`, `issuer_name`, `issuer_kind`, `issuer_group`, `duration` ve `renew_before` alanlarını kabul eder. Varsayılanlar sırasıyla pod namespace'i veya `default`, `letsencrypt-staging`, `ClusterIssuer`, `cert-manager.io`, `2160h` ve `360h` değerleridir.

`dry_run` varsayılan olarak `true` değeridir. `cert-manager` dry-run işlemi TLS Secret oluşturmadan Kubernetes admission kontrolünü doğrular. İlk staging kontrolünde dry-run kullanın; production guard'ları etkinleştirdikten sonra doğrulanmış domain'i `dry_run: false` ile yeniden çalıştırın. `test-ca` provider yalnızca production dışı ortamlarda kullanılmalıdır.

## Domain oluşturma

### Console adımları

1. Bir gateway açın ve **Custom domains** bölümünü seçin.
2. **Add domain** seçeneğini seçin.
3. Tam hostname'i girin.
4. **Gateway** veya **Portal** seçin.
5. DNS verification provider'ı seçip configuration alanlarını girin.
6. Local test için **Test CA**, Kubernetes için **cert-manager** seçin.
7. İlk cert-manager admission kontrolünde dry-run seçeneğini etkin bırakın.
8. Domain'i oluşturun ve üretilen TXT adını ve değerini kaydedin.

### Admin API: manual DNS ve test CA

```bash
export KANGAL_ADMIN_URL="https://control.example.com"
export KANGAL_TOKEN="replace-with-admin-token"
export KANGAL_TENANT_ID="tenant_123"
export KANGAL_GATEWAY_ID="gateway_123"

curl -sS -X POST \
  "$KANGAL_ADMIN_URL/api/v1/admin/gateways/$KANGAL_GATEWAY_ID/custom-domains" \
  -H "Authorization: Bearer $KANGAL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tenant_id": "'"$KANGAL_TENANT_ID"'",
    "hostname": "api.example.com",
    "target": "gateway",
    "dns_provider": "manual",
    "dns_provider_config": {
      "timeout_seconds": 5
    },
    "acme_provider": "test-ca",
    "acme_config": {
      "validity_days": 30
    },
    "dry_run": true
  }'
```

Yeni kaynak `pending_dns` durumunda başlar ve şu alanları döndürür:

* `_kangal-verification.api.example.com` gibi bir `challenge_record_name`
* `kangal-domain-verification=` ile başlayan `challenge_value`
* oluşturulduktan 24 saat sonrasını gösteren `challenge_expires_at`
* `challenge_version`

Challenge değerini domain sahipliği kanıtı olarak koruyun ve yalnızca amaçlanan hostname için yayınlayın.

### Admin API: Cloudflare ve cert-manager

```bash
curl -sS -X POST \
  "$KANGAL_ADMIN_URL/api/v1/admin/gateways/$KANGAL_GATEWAY_ID/custom-domains" \
  -H "Authorization: Bearer $KANGAL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tenant_id": "'"$KANGAL_TENANT_ID"'",
    "hostname": "portal.example.com",
    "target": "portal",
    "dns_provider": "cloudflare",
    "dns_provider_config": {
      "zone_id": "replace-with-zone-id"
    },
    "dns_credentials": {
      "api_token": "replace-with-read-token"
    },
    "acme_provider": "cert-manager",
    "acme_config": {
      "namespace": "kangal",
      "issuer_name": "letsencrypt-staging",
      "issuer_kind": "ClusterIssuer"
    },
    "dry_run": true
  }'
```

## Ownership kaydını yayınlama ve doğrulama

Dönen ad ve değerle tam bir TXT kaydı oluşturun. DNS provider'lar zone adını otomatik ekleme konusunda farklı davranabilir; devam etmeden önce provider üzerindeki son FQDN'i kontrol edin.

Authoritative görünürlüğü doğrulayın:

```bash
dig +short TXT _kangal-verification.api.example.com
```

Ardından Kangal üzerinden doğrulayın:

```bash
export KANGAL_DOMAIN_ID="domain_123"

curl -sS -X POST \
  "$KANGAL_ADMIN_URL/api/v1/admin/gateways/$KANGAL_GATEWAY_ID/custom-domains/$KANGAL_DOMAIN_ID/verify?tenant_id=$KANGAL_TENANT_ID" \
  -H "Authorization: Bearer $KANGAL_TOKEN"
```

Başarılı response eşleşen TXT değerlerini ve certificate job ID'sini içerir. Challenge bir kez tüketilir; sonraki certificate işlemleri doğrulanmış domain state'ini kullanır.

24 saatlik challenge, domain `pending_dns` veya `verification_failed` durumundayken sona ererse challenge'ı rotate edin:

```bash
curl -sS -X POST \
  "$KANGAL_ADMIN_URL/api/v1/admin/gateways/$KANGAL_GATEWAY_ID/custom-domains/$KANGAL_DOMAIN_ID/challenge?tenant_id=$KANGAL_TENANT_ID" \
  -H "Authorization: Bearer $KANGAL_TOKEN"
```

Yeniden doğrulamadan önce eski TXT değerini yeni challenge ile değiştirin.

## Certificate üretimini izleme

Domain, ownership ve certificate işlemlerini açıklayan şu status değerlerinden geçer:

| Status                         | Anlamı                                                       | Operator işlemi                                                 |
| ------------------------------ | ------------------------------------------------------------ | --------------------------------------------------------------- |
| `pending_dns`                  | Ownership TXT kaydı bekleniyor.                              | Kaydı yayınlayın ve doğrulayın.                                 |
| `verifying`                    | DNS verification devam ediyor.                               | Verification işleminin tamamlanmasını bekleyin.                 |
| `verification_failed`          | TXT kaydı bulunamadı, farklı, süresi dolmuş veya okunamıyor. | DNS'i düzeltin veya süresi dolmuş challenge'ı rotate edin.      |
| `issuance_pending` / `issuing` | Certificate işi sırada veya çalışıyor.                       | Certificate worker ve issuer'ı izleyin.                         |
| `issuance_failed`              | Certificate üretimi tamamlanamadı.                           | Provider configuration'ı düzeltin ve retry işlemini çalıştırın. |
| `active`                       | Certificate, SNI ve target binding kaydedildi.               | Serving edge'i yapılandırın ve doğrulayın.                      |
| `renewal_due` / `renewing`     | Renewal sırada veya çalışıyor.                               | Worker ve issuer'ı izleyin.                                     |
| `renewal_failed`               | Renewal tamamlanamadı; önceki binding seçili kalır.          | Hatayı giderin ve renewal isteğini yeniden gönderin.            |

`last_error`, certificate ID'leri, expiry, renewal zamanı ve alert'leri incelemek için domain'i okuyun:

```bash
curl -sS \
  "$KANGAL_ADMIN_URL/api/v1/admin/gateways/$KANGAL_GATEWAY_ID/custom-domains/$KANGAL_DOMAIN_ID?tenant_id=$KANGAL_TENANT_ID" \
  -H "Authorization: Bearer $KANGAL_TOKEN"
```

Console etkin işleri düzenli olarak yeniler. Otomasyon için get işlemini backoff ile poll edin; domain `active`, `issuance_failed` veya `renewal_failed` durumuna ulaştığında poll işlemini sonlandırın.

## cert-manager dry-run işlemini production'a geçirme

Public certificate üretmeden önce:

1. cert-manager'ı kurun ve çalışan DNS-01 solver ile hedef `Issuer` veya `ClusterIssuer` kaynağını yapılandırın.
2. Staging issuer'ı, certificate chain'i, ingress route'u ve rollback sürecini doğrulayın.
3. Helm `customDomainAutomation.allowPublicAcme: true` ve `customDomainAutomation.dryRun: false` değerlerini ayarlayın.
4. Deployment configuration üzerinden worker/API environment guard'ı `CUSTOM_DOMAIN_ALLOW_PUBLIC_ACME=true` olarak ayarlayın.
5. Dry-run admission kontrolü tamamlanan doğrulanmış domain için retry isteği gönderin.

```bash
curl -sS -X POST \
  "$KANGAL_ADMIN_URL/api/v1/admin/gateways/$KANGAL_GATEWAY_ID/custom-domains/$KANGAL_DOMAIN_ID/retry?tenant_id=$KANGAL_TENANT_ID" \
  -H "Authorization: Bearer $KANGAL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "promote_after_staging_validation",
    "dry_run": false
  }'
```

Deployment ve request guard'larının ikisi de yanlışlıkla public ACME issuance başlatılmasını önler. Account registration, DNS-01 solver değişiklikleri, CAA policy, propagation ve ACME rate-limit yönetimini cert-manager ile yapılandırılmış issuer üzerinde yönetin.

## Trafiği yayınlama ve edge'i yapılandırma

`active` durumundaki domain Kangal certificate, SNI ve binding kayıtlarına sahiptir. Serving path'i şu adımlarla tamamlayın:

1. Hostname için gereken `A`, `AAAA` veya `CNAME` kaydını oluşturun. Ownership TXT kaydı yerine gerçek ingress veya load-balancer adresini kullanın.
2. Ingress veya edge'i hostname ile üretilen TLS Secret ya da certificate materyalini kullanacak şekilde yapılandırın.
3. Gateway target'larını data-plane proxy listener'a, portal target'larını kayıtlı tenant portal path'ine iletin.
4. Edge configuration'ı uygulayın ve DNS propagation'ı bekleyin.
5. SNI, certificate trust, hostname routing ve uygulama davranışını test edin.

Kangal Helm chart kullanırken release-time ingress binding'lerini hostname ve `tlsSecretName` ile tanımlayın. Database binding ile ingress release configuration'ın ikisini de birlikte uygulayın.

DNS ve TLS'i doğrulayın:

```bash
dig +short api.example.com

openssl s_client -connect api.example.com:443 \
  -servername api.example.com -showcerts </dev/null

curl -i https://api.example.com/health
```

Test CA private trust kullanır. Test-CA hostname'i için CA'yı test client'ın trust store'una ekleyin veya yalnızca test ortamına özel trust seçeneğini kullanın. Test CA'yı public production trust anchor olarak dağıtmayın.

## Renewal

Kangal renewal zamanını certificate expiry tarihinden 30 gün veya certificate ömrünün üçte birinden küçük olan süreyi çıkararak planlar. Expiry alert seviyeleri şöyledir:

* 30 gün içinde `warning`
* 7 gün içinde `critical`
* expiry tarihinde veya sonrasında `expired`

Gerektiğinde erken renewal isteği gönderin:

```bash
curl -sS -X POST \
  "$KANGAL_ADMIN_URL/api/v1/admin/gateways/$KANGAL_GATEWAY_ID/custom-domains/$KANGAL_DOMAIN_ID/renew?tenant_id=$KANGAL_TENANT_ID" \
  -H "Authorization: Bearer $KANGAL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"reason": "scheduled_operator_rotation"}'
```

Renewal yalnızca certificate üretilmiş domain için kabul edilir. Başarılı işlem yeni managed certificate oluşturur ve activation sonrasında SNI/binding'i yeni certificate'a geçirir. Renewal tamamlanamazsa önceki certificate binding seçili kalır; expiry tarihini bir sonraki retry planıyla birlikte değerlendirin.

## Custom domain silme

Kangal kaynağını silin:

```bash
curl -sS -X DELETE \
  "$KANGAL_ADMIN_URL/api/v1/admin/gateways/$KANGAL_GATEWAY_ID/custom-domains/$KANGAL_DOMAIN_ID?tenant_id=$KANGAL_TENANT_ID" \
  -H "Authorization: Bearer $KANGAL_TOKEN"
```

Silme işlemi managed SNI ve binding kayıtlarını kaldırır, etkin domain job'larını iptal eder ve managed certificate'ı retired olarak işaretler. Ardından trafik kaydını, ownership TXT kaydını, Helm/ingress binding'ini ve dış DNS veya certificate sisteminde tutulan provider kaynaklarını kendi yönetim sürecinizle kaldırın.

## Güvenlik gereksinimleri

* Least-privilege DNS credential kullanın ve yalnızca custom-domain credential alanında veya deployment secret store'da saklayın.
* Admin API'yi tenant bazında sınırlandırın; bearer token'ları, audit verisini, database backup'larını ve encryption key'lerini koruyun.
* Test ortamlarında production ACME guard'larını kapalı tutun.
* Public issuance öncesinde CAA kayıtlarını ve issuer account sahipliğini inceleyin.
* Ownership challenge'ı tüketilene veya süresi dolana kadar hassas veri olarak yönetin.
* Certificate worker'ı, job retry'larını, expiry alert'lerini ve public certificate'ı bağımsız olarak izleyin.

## Sorun giderme

### Verification TXT değeri bulamıyor

Son record adını doğrulayın, yanlışlıkla eklenen tırnakları kaldırın, authoritative nameserver'ı doğrudan sorgulayın ve propagation'ı bekleyin. Özel `nameservers` kullanıyorsanız her değerin resolver tarafından kabul edilen bir adres olduğunu doğrulayın.

### Cloudflare verification başarısız

`zone_id`, token geçerliliği, zone read yetkisi ve tam TXT record adını kontrol edin. Kangal Cloudflare kayıtlarını okur; verification öncesinde TXT kaydını DNS yönetim akışınızla oluşturun.

### Verification `409` döndürüyor

Başka bir verification çalışıyor olabilir veya challenge değişmiş, süresi dolmuş ya da tüketilmiş olabilir. En güncel domain state'ini okuyun. Yalnızca pending veya failed ownership challenge'ı rotate edin.

### Dry-run sonrasında public certificate üretilmedi

cert-manager dry-run Kubernetes admission kontrolünü yapar. Staging doğrulaması tamamlanıp iki production guard da etkinleştirildikten sonra `dry_run: false` ile `retry` çağrısı yapın.

### cert-manager issuance pending durumunda kalıyor

Üretilen Certificate kaynağını, cert-manager event'lerini, issuer readiness'i, DNS-01 solver kayıtlarını, CAA policy'yi ve TLS Secret'ı inceleyin. Son hata ayrıntısını domain'in `last_error` alanında kontrol edin.

### Domain active ancak hostname erişilemiyor

Trafik DNS kaydını, load-balancer adresini, ingress host ve TLS Secret'ı, data-plane erişimini ve release durumunu kontrol edin. Kangal kaynaklarıyla dış serving path'in birlikte uygulandığını doğrulayın.

### Public endpoint eski certificate'ı sunuyor

`certificate_id`, `previous_certificate_id`, issuer Secret, ingress binding ve tüm load-balancer listener'larını karşılaştırın. Renewal sonrasında edge'in reload olduğunu ve DNS'in eski environment'a yönlenmediğini doğrulayın.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kangal.dev/tr/gateway/custom-domains.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
