Ana Sayfa Hakkımda Dersler Blog MikrofondaOn The Mic İletişim Projeler Yakında
DerslerLessons DEPLOY · C#

Shared Hosting'de Secret Yönetimi — web.config Yöntemi Secret Management on Shared Hosting — web.config Approach

9 dk okuma 9 min read · Emre Ulutabak
1
Neden appsettings.json yetmez? Why isn't appsettings.json enough?

DB şifreni, mail hesabını, JWT anahtarını bir yere yazman gerekiyor. Ama nereye?

appsettings.json ilk akla gelen yer. Kolay, hızlı. Ama büyük bir riski var: bu dosya kaynak kodunla birlikte Git'e gider. GitHub'a push edersen, şifreler herkese açık olur. Takım çalışmasında da herkes görebilir.

Peki Azure Key Vault, HashiCorp Vault, Secret Manager gibi araçlar? Bunlar harika çözümler — ama shared hosting'de erişim yok. SSH yok, root yok, servis kurma yok.

Çözüm basit ama etkili: web.config içindeki environmentVariables bloğu.

You need to write your DB password, mail credentials, and JWT key somewhere. But where?

appsettings.json is the first thing that comes to mind. Easy, fast. But there is a big risk: this file goes to Git along with your source code. If you push to GitHub, the passwords are exposed to everyone. In team settings, everyone can see them too.

What about tools like Azure Key Vault, HashiCorp Vault, Secret Manager? These are great solutions — but there is no access on shared hosting. No SSH, no root, no service installation.

The solution is simple but effective: the environmentVariables block inside web.config.

💡
appsettings.json Git'e gider. Şifre koyma. web.config'i .gitignore'a ekle veya production'da ayrı tut. appsettings.json goes to Git. Don't put passwords there. Add web.config to .gitignore or keep it separate in production.
2
web.config environmentVariables web.config environmentVariables

web.config dosyası sunucuda yaşar, Git'e gitmez. İçine koyduğun environment variable'lar, ASP.NET Core'un configuration sistemine otomatik olarak eklenir ve appsettings.json'daki aynı key'leri ezer.

The web.config file lives on the server and does not go to Git. The environment variables you put inside it are automatically added to ASP.NET Core's configuration system and override the same keys in appsettings.json.

xml
<aspNetCore processPath="dotnet" arguments=".\MyApp.dll"
            stdoutLogEnabled="false"
            stdoutLogFile=".\logs\stdout"
            hostingModel="outofprocess">
  <environmentVariables>

    <!-- DB bağlantısı — şifre burada, appsettings.json'da değil -->
    <environmentVariable name="ConnectionStrings__DefaultConnection"
      value="Server=.\SQLEXPRESS;Database=MyDb;User Id=sa;Password=Sifre123;TrustServerCertificate=True;" />

    <!-- Mail sunucusu ayarları -->
    <environmentVariable name="EmailSettings__SmtpServer" value="smtp.brevo.com" />
    <environmentVariable name="EmailSettings__Port"       value="587" />
    <environmentVariable name="EmailSettings__Username"   value="kullanici@ornek.com" />
    <environmentVariable name="EmailSettings__Password"   value="MailSifresi" />

    <!-- JWT — private key dosyasının yolu -->
    <environmentVariable name="Jwt__PrivateKeyPath" value="private.key" />

  </environmentVariables>
</aspNetCore>
💡
TrustServerCertificate=True: shared hosting'de SQL Server SSL sertifika doğrulaması sorun çıkarır. Bu olmadan bağlantı hatası alırsın. TrustServerCertificate=True: SQL Server SSL certificate validation causes issues on shared hosting. Without this, you will get a connection error.
3
XML ve JSON escape farkı XML vs JSON escape difference

Connection string yazarken sık karşılaşılan bir hata: JSON'da çalışan connection string XML'de çalışmıyor.

Sebebi basit: JSON'da backslash (\) özel karakterdir, kendisini temsil etmek için \\ yazmak gerekir. XML'de ise backslash özel karakter değildir — olduğu gibi \ yazılır.

A common mistake when writing connection strings: a connection string that works in JSON doesn't work in XML.

The reason is simple: in JSON, backslash (\) is a special character — you need to write \\ to represent it. In XML, backslash is not a special character — you write it as \ directly.

json
// appsettings.json — JSON'da \\ gerekir
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=.\\SQLEXPRESS;Database=MyDb;..."
  }
}
xml
<!-- web.config — XML'de tek \ yeterli -->
<environmentVariable name="ConnectionStrings__DefaultConnection"
  value="Server=.\SQLEXPRESS;Database=MyDb;..." />
💡
XML'de tek \, JSON'da çift \\. Bunu karıştırırsan bağlantı kurulamaz ama hata mesajı seni yanıltabilir. Single \ in XML, double \\ in JSON. If you mix these up, the connection fails but the error message might be misleading.
4
CopyToPublishDirectory ayarı CopyToPublishDirectory setting

dotnet publish çalıştığında hangi dosyaların publish çıktısına dahil edileceği .csproj dosyasından kontrol edilir.

İki önemli kural:

  • appsettings.Production.json ve appsettings.Development.jsonNever — bu dosyalar sırlar içerebilir, publish çıktısına gitmesin.
  • private.key gibi dosyalarAlways — uygulama bu dosyaya ihtiyaç duyuyor, publish çıktısında olmalı.

When dotnet publish runs, which files are included in the publish output is controlled from the .csproj file.

Two important rules:

  • appsettings.Production.json and appsettings.Development.jsonNever — these files may contain secrets, they should not go into the publish output.
  • Files like private.keyAlways — the application needs this file, it must be in the publish output.
xml
<!-- .csproj -->
<ItemGroup>
  <!-- Sırlar içerebilir — publish'e gitmesin -->
  <Content Update="appsettings.Production.json">
    <CopyToPublishDirectory>Never</CopyToPublishDirectory>
  </Content>
  <Content Update="appsettings.Development.json">
    <CopyToPublishDirectory>Never</CopyToPublishDirectory>
  </Content>

  <!-- JWT imzalamak için gerekli — publish'e gitsin -->
  <Content Include="private.key">
    <CopyToPublishDirectory>Always</CopyToPublishDirectory>
  </Content>
</ItemGroup>
5
stdoutLogEnabled — production log stdoutLogEnabled — production log

Production'da site açılmıyorsa ya da garip hatalar varsa ne yaparsın? SSH yok, Visual Studio debugger yok. Tek çözüm: log.

stdoutLogEnabled attribute'u true yapılırsa uygulama çıktısı logs/ klasörüne yazılır. Hatayı bul, düzelt, sonra tekrar false yap.

What do you do when the site won't start in production or you get strange errors? No SSH, no Visual Studio debugger. The only solution: logs.

When the stdoutLogEnabled attribute is set to true, the application output is written to the logs/ folder. Find the error, fix it, then set it back to false.

xml
<!-- Normalde: production'da kapalı -->
<aspNetCore stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" ... />

<!-- Hata ayıklarken: aç, hatayı bul, kapat -->
<aspNetCore stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" ... />
💡
stdoutLogEnabled=true yaptıktan sonra siteye bir istek gönder, sonra FTP'den logs/ klasörüne bak. Hata mesajı orada. After setting stdoutLogEnabled=true, send a request to the site, then check the logs/ folder via FTP. The error message is there.
💡
Hata bulduktan sonra stdoutLogEnabled'ı tekrar false yap. Açık kalırsa log dosyaları disk doldurana kadar büyür. After finding the error, set stdoutLogEnabled back to false. If left open, log files grow until they fill the disk.
6
Mini quiz Mini quiz
MİNİ QUIZ MINI QUIZ
appsettings.Production.json için CopyToPublishDirectory değeri ne olmalıdır? What should the CopyToPublishDirectory value be for appsettings.Production.json?
Always — her zaman publish'e gitsin Always — always include in publish
Never — publish çıktısına gitmesin Never — do not include in publish output
PreserveNewest — değiştiyse gitsin PreserveNewest — include if changed
Bu ayar .csproj'da yapılamaz This setting cannot be made in .csproj