Mikro ERP SQL Server'a Web'den Güvenli Bağlantı: Cloudflare Tunnel Rehberi
Ofisteki Mikro ERP SQL Server'a web uygulamanızdan nasıl bağlanırsınız? Port açmadan, VPN olmadan Cloudflare Tunnel ile güvenli bağlantı kurma adımları.
Sorun: ERP Ofiste, Uygulama Bulutta
Web uygulamanız Vercel’de veya Cloudflare’da çalışıyor. Ama ERP sisteminiz (Mikro, Logo, Netsis…) şirket ofisindeki sunucuda, SQL Server üzerinde.
Bu ikisi nasıl konuşacak?
| Yaklaşım | Sorun |
|---|---|
| SQL Server’ı internete aç | 🔴 Güvenlik felaketi |
| VPN bağlantısı | 🟡 Karmaşık, yavaş |
| Her gün Excel aktar | 🟡 Eski veri, hatalı |
Çözüm: Cloudflare Tunnel
Cloudflare Tunnel, ofisteki sunucu ile bulut arasında şifreli bir tünel oluşturur. Sunucuda hiçbir port açmanız gerekmez.
Web Uygulaması → Cloudflare → Tünel → Ofisteki Proxy → SQL Server
(Bulut) (Güvenlik) (Şifreli) (Node.js) (Mikro ERP)
Güvenlik katmanları:
- Cloudflare Firewall — DDoS ve saldırı koruması
- API Key — Her istek doğrulanır
- Parametreli sorgular — SQL injection koruması
- Sadece SELECT — Veri değiştirme yasak
Nasıl Kurulur?
1. Sunucuya Cloudflare Tunnel Kurun
# cloudflared kurulumu
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o cloudflared
chmod +x cloudflared
# Tunnel oluştur
./cloudflared tunnel create erp-tunnel
./cloudflared tunnel route dns erp-tunnel erp-api.firma.com
Tunnel yapılandırması:
# config.yml
tunnel: TUNNEL_ID
ingress:
- hostname: erp-api.firma.com
service: http://localhost:3500
- service: http_status:404
2. Node.js Proxy Sunucusu
SQL Server’a doğrudan bağlanmak yerine, arada bir proxy katmanı kullanıyoruz. Bu proxy sadece SELECT sorgularına izin verir:
const express = require('express');
const sql = require('mssql');
const app = express();
// API Key kontrolü
function apiKeyKontrolu(req, res, next) {
const key = req.headers['x-api-key'];
if (key !== process.env.API_KEY) {
return res.status(401).json({ error: 'Yetkisiz' });
}
next();
}
// SQL Server bağlantısı
const pool = new sql.ConnectionPool({
server: 'localhost',
database: 'ERP_DB',
user: process.env.DB_USER,
password: process.env.DB_PASS,
pool: { max: 10, min: 2 },
});
pool.connect();
// Sorgu endpoint'i
app.post('/query', apiKeyKontrolu, async (req, res) => {
const { query, params } = req.body;
// GÜVENLİK: Sadece SELECT
if (!/^\s*SELECT/i.test(query)) {
return res.status(403).json({ error: 'Sadece SELECT sorgularına izin var' });
}
try {
const request = pool.request();
if (params) {
Object.entries(params).forEach(([key, value]) => {
request.input(key, value);
});
}
const result = await request.query(query);
res.json(result.recordset);
} catch (err) {
res.status(500).json({ error: 'Sorgu başarısız' });
}
});
app.listen(3500);
3. Web Uygulamasından API Çağrısı
async function erpSorgusu(sql, params) {
const response = await fetch('https://erp-api.firma.com/query', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': API_KEY,
},
body: JSON.stringify({ query: sql, params }),
});
return response.json();
}
// Kullanım
const cariler = await erpSorgusu(
'SELECT cari_kodu, cari_adi FROM CARI_HESAPLAR WHERE cari_kodu LIKE @prefix',
{ prefix: 'MRK%' }
);
Karşılaştığımız Sorunlar
Uzun Süren Sorgular
Cari yaşlandırma gibi ağır sorgular 3-4 dakika sürebilir. HTTP bağlantısı kopar. Çözüm: İsteği kabul edip arka planda çalıştırma, frontend’den polling ile sonucu alma.
Çoklu Veritabanı
Her şubenin ayrı Mikro veritabanı var. Şube parametresine göre doğru veritabanına bağlanma gerekiyor.
Türkçe Tarih Sorunu
SET LANGUAGE Turkish tarih formatlarını bozuyor. Detaylı yazımıza bakın.
Güvenlik Kontrol Listesi
Üretime almadan önce:
- API Key 64+ karakter ve rastgele mi?
- Sadece SELECT’e izin veriliyor mu?
- Parametreli sorgular kullanılıyor mu?
-
.envdosyası.gitignore’da mı? - Rate limiting aktif mi?
Bu mimariyle web uygulamanız ofisteki ERP verilerine güvenle erişir — hiç port açmadan, VPN kurmadan.
Bu yazı AstaFlow Case Study serisinin bir parçasıdır.