Uzun ömürlü altyapıyı yönetmenin doğru yolu deklaratiftir. Ortamında staging URL'leri, webhook alıcıları ve kiracı başına proxy'ler varsa, ekip her yeni servis eklediğinde bir runbook'tan curl POST /api/v1/proxies yapmak istemezsin. Bunu cloud kaynaklarının yanında bir main.tf'de istiyorsun — terraform plan diff'i göstersin, terraform apply değişikliği uygulasın.
Kısa özet: Nodetonet REST API'si tamamen betiklenebilir. İki standart Terraform primitifi — okuma için hashicorp/http ve yazma için local-exec'li null_resource — özel bir sağlayıcı beklemeden bugün mobil proxy'leri, dönen proxy havuzlarını ve HTTP tünellerini kod olarak yönetmeni sağlar.
Proxy'leri neden kod olarak yönetmeli?
Altyapıyı-kod-olarak (IaC) yaklaşımı sadece bir DevOps trendi değil — proxy yoğun iş yükleri için gerçek operasyonel sorunları çözer:
- Tekrarlanabilirlik. Staging ve production proxy'leri aynı repo'da tanımlıdır. Yeni bir ekip üyesi
terraform applyçalıştırır ve dakikalar içinde özdeş bir stack elde eder. - Drift tespiti. Biri panelden bir tünel ekleyip belgelemeyi unutursa, sonraki
terraform planeksikliği gösterir. - Denetim izi. Her proxy oluşturma, güncelleme ve silme işlemi yazar, zaman damgası ve mesajıyla bir git commit'tir — panel aktivite logunu kaydırmaktan çok daha iyidir.
- CI/CD entegrasyonu. Bir mikro-servis ekleyen pull request, aynı akışta incelenen ve birleştirilen o servisin ihtiyaç duyduğu proxy veya tüneli de sağlar.
Nodetonet'in perde arkasında trafiği nasıl yönlendirdiğine dair bağlam için Nodetonet trafiği nasıl yönlendirir yazısına bak. Terraform'a dalmadan önce REST API temellerini öğrenmek için ilk REST API çağrın rehberini oku.
1 · Minimum providers bloğu
http, built-in null ve (isteğe bağlı) unique subdomain ekleri için random'a ihtiyacın var. Private registry yok, plugin kurulum dansı yok:
terraform {
required_version = ">= 1.6"
required_providers {
http = { source = "hashicorp/http", version = "~> 3.4" }
null = { source = "hashicorp/null", version = "~> 3.2" }
random = { source = "hashicorp/random", version = "~> 3.6" }
}
}
variable "nodetonet_token" {
type = string
sensitive = true
}
locals {
api_base = "https://nodetonet.com/api/v1"
headers = {
Authorization = "Bearer ${var.nodetonet_token}"
Content-Type = "application/json"
}
}
Token'ı TF_VAR_nodetonet_token=$NTN_TOKEN terraform apply ile geç veya mevcut secret backend'inde sakla (AWS Secrets Manager, Vault, Doppler) ve bir data source ile çek. API token'ını hesabından API Anahtarları bölümünden oluşturabilirsin — şifre gibi davran: Terraform'da sensitive, kasanda sakla, asla versiyon kontrolüne koyma.
2 · Proxy oluşturma
"Oluşturma" yarısı iki provisioner'lı bir null_resource: create'te local-exec POST /api/v1/proxies çağırır, destroy'da local-exec DELETE çağırır. İşin püf noktası dönen id'yi yakalamak — destroy'un ne silineceğini bilmesi gerekir. triggers ve küçük bir state dosyası kullanıyoruz:
resource "random_string" "sub_suffix" {
length = 6
upper = false
special = false
}
resource "null_resource" "tunnel_api" {
triggers = {
subdomain = "api-${random_string.sub_suffix.result}"
port = 8080
state_dir = "${path.module}/.terraform-nodetonet"
}
provisioner "local-exec" {
command = <<-EOT
mkdir -p ${self.triggers.state_dir}
RESP=$(curl -fsS -X POST ${local.api_base}/proxies \
-H "Authorization: Bearer ${var.nodetonet_token}" \
-H "Content-Type: application/json" \
-d '{
"subdomain": "${self.triggers.subdomain}",
"target_host": "127.0.0.1",
"target_port": ${self.triggers.port}
}')
echo "$RESP" > ${self.triggers.state_dir}/${self.triggers.subdomain}.json
EOT
}
provisioner "local-exec" {
when = destroy
command = <<-EOT
ID=$(jq -r .id ${self.triggers.state_dir}/${self.triggers.subdomain}.json)
curl -fsS -X DELETE \
-H "Authorization: Bearer ${var.nodetonet_token}" \
https://nodetonet.com/api/v1/proxies/$ID
rm -f ${self.triggers.state_dir}/${self.triggers.subdomain}.json
EOT
}
}
triggers input'ları Terraform state'ine hashler. Sonraki plan'da port'u değiştirirsen Terraform drift'i algılar ve create provisioner'ını tekrar çalıştırır — yeni port'la API'mizi çağırır. Bu gerçek bir "update" değil (yok eder ve yeniden oluşturur) ama ephemeral tüneller için gayet yeterli.
3 · State okuma — http data source
Okumalar için (state'i değiştirmemesi gereken her şey için) http daha temiz. Proxy'leri listele, dışarıda oluşturduğun birinin URL'ini bul veya başka bir kaynağa input olarak ver:
data "http" "proxies" {
url = "${local.api_base}/proxies"
request_headers = local.headers
}
locals {
proxies = jsondecode(data.http.proxies.response_body)
}
output "all_urls" {
value = [for p in local.proxies : p.url]
}
Bunu yukarıdaki null_resource ile eşleştirerek az önce oluşturduğun proxy'nin URL'ini içeren output'lar yap:
locals {
created = jsondecode(file(
"${null_resource.tunnel_api.triggers.state_dir}/${null_resource.tunnel_api.triggers.subdomain}.json"
))
}
output "tunnel_url" {
value = local.created.url
}
output "tunnel_id" {
value = local.created.id
}
4 · Hepsini bir araya getirmek — tam bir main.tf
Kopyala/yapıştır, terraform init && terraform apply çalıştır ve başka yerde tanımlayacağın bir servise yönlendirilmiş bir tünelle kal:
terraform {
required_version = ">= 1.6"
required_providers {
null = { source = "hashicorp/null", version = "~> 3.2" }
random = { source = "hashicorp/random", version = "~> 3.6" }
}
}
variable "nodetonet_token" { type = string, sensitive = true }
variable "service_port" { type = number, default = 3000 }
variable "service_name" { type = string }
resource "random_string" "suffix" {
length = 6, upper = false, special = false
}
resource "null_resource" "tunnel" {
triggers = {
name = "${var.service_name}-${random_string.suffix.result}"
port = var.service_port
}
provisioner "local-exec" {
command = "curl -fsS -X POST https://nodetonet.com/api/v1/proxies -H 'Authorization: Bearer ${var.nodetonet_token}' -H 'Content-Type: application/json' -d '{"subdomain":"${self.triggers.name}","target_port":${self.triggers.port}}' | tee ${path.module}/.tunnel-${self.triggers.name}.json"
}
provisioner "local-exec" {
when = destroy
command = "curl -fsS -X DELETE -H 'Authorization: Bearer ${var.nodetonet_token}' https://nodetonet.com/api/v1/proxies/$(jq -r .id ${path.module}/.tunnel-${self.triggers.name}.json) && rm -f ${path.module}/.tunnel-${self.triggers.name}.json"
}
}
output "url" {
value = jsondecode(file("${path.module}/.tunnel-${null_resource.tunnel.triggers.name}.json")).url
}
terraform apply -var="service_name=stripe-test" ile çalıştır. terraform destroy ile yok et — when = destroy provisioner'ı DELETE çağırır.
5 · Dönen proxy havuzlarını Terraform ile yönetmek
Tek tünellerin ötesinde, Nodetonet'in dönen proxy havuzları (token grupları olarak adlandırılır) da API üzerinden yönetilebilir. Token grubu, istemcilerin tek bir uç nokta aracılığıyla bağlandığı adlandırılmış bir mobil cihaz havuzudur — Nodetonet, cihaz çevrimdışı olduğunda otomatik yük devretme ile round-robin veya en-az-bağlantı seçimi kullanarak bir cihaz seçer.
Aynı null_resource deseni geçerlidir. Bir grup oluştur, dönen grup id'sini sakla, müşteri başına kimlik bilgileri oluştururken ona başvur. API, aşağı akış tüketicilerine verdiğin proxy uç noktasını, kullanıcı adını ve şifreyi döndürür. Bu, birden çok müşteri için proxy yöneten ekiplerin — örneğin beyaz etiket bayi hesapları aracılığıyla — tüm müşteri topolojisini versiyon kontrolüne alabilme yoludur.
Terraform yazmadan önce token gruplarının ve havuzlarının kavramsal bir özetini görmek için token grupları: havuz oluşturma yazısına bak.
6 · DIY vs resmi sağlayıcı — karşılaştırma
Dürüst olalım: null_resource yaklaşımı çalışıyor ama güzel değil. Gerçek bir sağlayıcının gerisinde kaldığı ve gayet yeterli olduğu yerler:
| Yetenek | null_resource + curl (bugün) | Resmi sağlayıcı (yol haritası) |
|---|---|---|
| Kaynak oluşturma / silme | Evet, local-exec ile | Evet, yerel kaynak yaşam döngüsü |
| Mevcut durumu okuma | Evet, http data source ile | Evet, tipli data source'lar |
| Drift tespiti | Kısmi — trigger'lar değişiklikleri hashler, panel düzenlemelerini değil | Tam — refresh bant dışı değişiklikleri tespit eder |
| Yerinde güncellemeler (PATCH) | Hayır — yok et + yeniden oluştur | Evet, alan-bazlı granülarite |
| İnsan tarafından okunabilir plan diff'leri | Minimal ("will be replaced") | Tam alan-bazlı diff |
| Tipli kaynak şeması | Hayır — ham JSON stringleri | Evet — doğrulanmış girdiler |
| Terraform Cloud ile çalışır | Evet, uzak state geçici çözümüyle | Evet, yerel olarak |
| Gerekli harici araçlar | Runner'da curl, jq | Hiçbiri |
1–5 uzun ömürlü tünel yönetiyorsan DIY yaklaşımı gayet yeterli. Çoklu kiracı boyunca 50+ kaynak yönetiyorsan gerçek sağlayıcıyı bekle — veya support@nodetonet.com'a ulaş ve kullanım durumunu anlat; kurumsal zaman çizelgeleri esnektir.
7 · Resmi Terraform sağlayıcısı yol haritasında
Terraform provider · 2026 4. çeyrek. Yayınlandığında yukarıdaki tüm main.tf'in eşdeğeri şu olur:
provider "nodetonet" {
token = var.nodetonet_token
}
resource "nodetonet_proxy" "api" {
subdomain = "stripe-test"
target_host = "127.0.0.1"
target_port = 3000
}
output "url" {
value = nodetonet_proxy.api.url
}
Altta aynı REST API; sağlayıcı sadece düzgün drift algılama, yerinde PATCH ve tipli şema ile sarar. null_resource desenini kullanan mevcut main.tf dosyaları çalışmaya devam edecek — birer birer geçiş yapabilirsin.
8 · CI/CD entegrasyon ipuçları
Curl yaklaşımını otomasyonda çalıştırırken ekiplerin takıldığı birkaç pratik detay:
- State dosyası kalıcılığı. Create provisioner tarafından yazılan
.tunnel-*.jsondosyaları,applyile sonraki herhangi birdestroyçalıştırması arasında hayatta kalmalıdır. Kısa ömürlü CI runner'larında (GitHub Actions, GitLab CI) hem Terraform state'ini hem de JSON cache'ini uzak bir backend'de sakla (S3, GCS, Terraform Cloud). Doğru JSON'u bulamayan yeni bir runner'da destroy, doğru DELETE'i çağıramayacak. - Secret yönetimi.
TF_VAR_nodetonet_token'ı maskelenmiş bir CI değişkeni olarak ayarla. Loglara asla yazdırma —curl -fsSkullan (sessiz, hata üretirse fail) ve provisioner shell'lerindeset -x'ten kaçın. - İdempotency. Bir create provisioner yarıda başarısız olursa,
terraform apply'i yeniden çalıştırmak API'yi tekrar çağıracak. Önce cache dosyasını kontrol ederek veya POST etmeden önce mevcut subdomain içinGET /api/v1/proxiessorgulayarak koruma sağla. - İzleme. Apply sonrası, tünelin erişilebilir olduğunu doğrulamak için Nodetonet'in tünel sağlığı izleme özelliğini kullan ve uzun süreli kapalı kalma için nöbet rotasyonuna bir uyarı ekle.
Hemen başla
Yukarıdaki main.tf'i yapıştır, token'ını ayarla ve terraform apply çalıştır. İlk bildirgesel proxy'n iki dakika uzakta. Soruların mı var? İletişim'i ziyaret et, discord.gg/nodetonet'e katıl ya da belirli özellikler için daha derin rehberler için blog'a göz at. Python'la proxy oluşturmayı betiklemek istersen, Python ile programatik tünel oluşturma'ya bak.