İçeriğe atla
HexaTransfer
Bloga dön
Teknik incelemeler

Yaratın Your Own Dosya Transferi Service: Dev Eğitim

Oluşturun a dosya transfer service from scratch. Backend API design, storage integration, ve user interface development tutorial.

Kendi dosya transfer hizmetinizi oluşturmak için beş parçaya ihtiyacınız var: dosyaları tarayıcıda dilimleyip isteğe bağlı olarak şifreleyen bir ön uç, yükleme oturumları oluşturan ve depolama URL'lerini ön imzalayan bir REST API, S3 uyumlu nesne depolaması (Cloudflare R2, Backblaze B2 veya MinIO), küçük bir meta veri veritabanı (SQLite veya Postgres) ve TLS 1.3 ters proxy. Node 22, Fastify ve Vite ile yaklaşık 600 satır kodda WeTransfer tarzı bir hizmet gönderebilir ve orta trafikte tüm şeyi aylık 150-500 TL'ye barındırabilirsiniz.

Önce Depolama Katmanını Seçme

Depolama ekonomisi, bir dosya transfer hizmetini başarıya taşır ya da çöküşe götürür. AWS S3, GB çıkış başına 0,09 $ talep eder; bu da 1.000 kez paylaşılan popüler 2 GB'lık bir indirmenin yalnızca bant genişliğinde size 180 dolara mal olduğu anlamına gelir. Cloudflare R2, çıkış için sıfır ve depolanan GB başına 0,015 $ alır. Backblaze B2, GB çıkış başına 0,01 $ ve depolanan GB başına 0,006 $ alır. Ücretsiz katmanlı bir transfer hizmeti için R2 açık seçimdir. MinIO, zaten boşta olan bant genişliğiniz ve diskleriniz varsa kendi donanımınızda S3 semantiğini kendi kendine barındırmanızı sağlar.

İstemcilerin sunucunuz üzerinden değil doğrudan depolamaya yükleme ve indirme yapması için ön imzalı URL'ler kullanın. Bu, API'nizi bant genişliği yerine CPU sınırlı tutar.

API Yüzeyini Taslaklamak

API'yi küçük tutun. Beş uç nokta, ihtiyacınız olanın %95'ini karşılar:

  • POST /sessions — yükleme oturumu oluştur, kimlik ve ön imzalı çok parçalı URL'ler döndür
  • POST /sessions/:id/complete — çok parçalı yüklemeyi sonuçlandır, paylaşım URL'si döndür
  • GET /shares/:id — dosya meta verilerini döndür (boyut, son kullanma, kalan indirmeler)
  • GET /shares/:id/download — ön imzalı indirme URL'si döndür
  • DELETE /shares/:id — sahibinin erken iptal etmesine izin ver (iptal belirteci gerektirir)

POST /sessions'a agresif biçimde hız sınırı uygulayın — saat başına IP başına 20 yeterlidir. Tüm uç noktalar JSON döndürür, Cache-Control: no-store kullanır ve HTML sayfalarında Content-Security-Policy ayarlar.

Fastify ile Arka Ucu Bağlamak

Fastify, uğraşmadan JSON şema doğrulaması, makul günlükleme ve çekirdek başına 30 bin istek/sn sağlar. Minimal bir POST /sessions:

fastify.post('/sessions', {
  schema: {
    body: {
      type: 'object', required: ['size'],
      properties: {
        size: { type: 'integer', minimum: 1, maximum: 10737418240 },
        contentType: { type: 'string', maxLength: 120 }
      }
    }
  }
}, async (req) => {
  const id = nanoid(16);
  const key = `blobs/${id}`;
  const upload = await s3.createMultipartUpload({
    Bucket: 'transfers', Key: key, ContentType: req.body.contentType
  });
  const partCount = Math.ceil(req.body.size / (8 * 1024 * 1024));
  const urls = await Promise.all(
    Array.from({ length: partCount }, (_, i) =>
      getSignedUrl(s3, new UploadPartCommand({
        Bucket: 'transfers', Key: key, UploadId: upload.UploadId, PartNumber: i + 1
      }), { expiresIn: 3600 }))
  );
  db.prepare('INSERT INTO sessions VALUES (?, ?, ?, ?)')
    .run(id, upload.UploadId, key, Date.now());
  return { id, uploadId: upload.UploadId, partUrls: urls };
});

10 GB tavan, 8 MB parça, 1 saatlik URL geçerliliği. Trafik karışımınıza göre ayarlayın.

Yükleme Kullanıcı Arayüzü Oluşturma

Vite artı React artı sıfır UI kütüphanesi sizi yaklaşık 150 satırda çalışan bir sürükle-bırak işlevine ulaştırır. Kritik parça yükleme işçisidir: özel bir Web Worker başlatın, File tanıtıcısını ve parça URL'lerini ona verin; her parçayı 3 eşzamanlılıkla PUT etmesini sağlayın. Ana iş parçacığı tepkili kalır, ilerleme güncellemeleri postMessage aracılığıyla gelir.

// worker.js
self.onmessage = async ({ data: { file, partUrls } }) => {
  const partSize = 8 * 1024 * 1024;
  const etags = [];
  for (let i = 0; i < partUrls.length; i++) {
    const blob = file.slice(i * partSize, (i + 1) * partSize);
    const res = await fetch(partUrls[i], { method: 'PUT', body: blob });
    etags[i] = res.headers.get('etag');
    self.postMessage({ type: 'progress', done: i + 1, total: partUrls.length });
  }
  self.postMessage({ type: 'done', etags });
};

PBKDF2 (600.000 iterasyon, SHA-256) aracılığıyla bir anahtar türeten ve PUT'tan önce her parçayı AES-256-GCM üzerinden saran bir parola alanı ekleyin. Bu, hizmetinizi sunucu tarafı şifreli yerine E2EE hizmetine dönüştürür.

Veritabanı Şemasını Tasarlama

better-sqlite3 aracılığıyla SQLite, göz kırpmadan on milyonlarca satırı halleder. Şemayı yalın tutun:

CREATE TABLE sessions (
  id TEXT PRIMARY KEY, upload_id TEXT, object_key TEXT, created_at INTEGER
);
CREATE TABLE shares (
  id TEXT PRIMARY KEY, object_key TEXT, size_bytes INTEGER,
  content_type TEXT, expires_at INTEGER, max_downloads INTEGER,
  download_count INTEGER DEFAULT 0, revocation_token TEXT
);
CREATE INDEX idx_shares_expires ON shares(expires_at);

Kullanıcı tablosu yok, e-posta yok, IP günlüğü yok. Bu kasıtlı bir seçimdir — KVKK uyumluluğunu neredeyse önemsiz hale getirir. Gecelik cron, süresi dolan satırları ve S3 nesnelerini siler:

const expired = db.prepare('SELECT object_key FROM shares WHERE expires_at < ?').all(Date.now());
for (const { object_key } of expired) {
  await s3.deleteObject({ Bucket: 'transfers', Key: object_key });
}
db.prepare('DELETE FROM shares WHERE expires_at < ?').run(Date.now());

Paylaşım Bağlantıları ve İndirmeleri Uygulama

İstemci tarafı şifreleme eklediğinizde paylaşım URL'leri https://uygulamaniz.com/f/abc123#k=<base64anahtar> gibi görünür. Parça, anahtarı sunucu günlüklerinden uzak tutar. İndirme sayfası /shares/abc123'ü alır, ön imzalı bir S3 URL'si alır, baytları doğrudan R2'den akıtır, tarayıcıda şifresini çözer ve sonucu StreamSaver.js'e veya Dosya Sistemi Erişim API'sine iletir.

Content-Disposition: attachment; filename*=UTF-8''kodlanmış-ad ayarı, tarayıcının dosyayı satır içi oluşturmak yerine kaydetme iletişim kutusunu tetiklemesini sağlar. Bu, aksi takdirde tarayıcı bağlamında betik çalıştırabilen PDF'ler, HTML dosyaları ve SVG için önem taşır.

Kötüye Kullanıma Karşı Sertleştirme

Dosya transfer hizmetleri kötüye kullananları çeker. Üç kategori bekleyin: kötü amaçlı yazılım dağıtımı, kimlik avı yük barındırma ve telif hakkı ihlalli yüklemeler. Etki sırasına göre hafifletmeler: IP başına yüklemelere hız sınırı uygulayın, minimum boyut gereksinimi belirleyin (10 KB'ın altı neredeyse her zaman önemsizdir), şifreli metnin SHA-256'sını hesaplayın ve bilinen-kötü karmalar denylist'e göre kontrol edin, ücretsiz kötüye kullanım bildirimi formu sağlayın. Şifresi çözülmüş içerikte ClamAV yalnızca anahtara sahip olduğunuzda çalışır ki bu E2EE'yi bozar — doğru yanıt içerikten bağımsız hız sınırları artı duyarlı kaldırmadır.

Her ön imzalı URL'yi kısa TTL ile imzalayın (maksimum 1 saat) ve oturumları Secure; HttpOnly; SameSite=Strict çerezinde saklanan tarayıcı tarafından oluşturulan geçici bir belirtece bağlayın.

Ucuz Dağıtım ve Çalıştırma

Tek bir Hetzner CX22 sunucusu (2 vCPU, 4 GB RAM, aylık yaklaşık 200 TL), Fastify + SQLite + Caddy ters proxy çalıştırır ve binlerce aktif kullanıcıyı kaldırır. Caddy, Let's Encrypt aracılığıyla TLS 1.3'ü otomatik olarak sağlar. DDoS koruması ve ücretsiz WAF için Cloudflare'i önüne koyun. Uptime Kuma (ücretsiz, kendi barındırmalı) ile izleyin ve journald tarafından yakalanan stdout'a günlük kaydedin.

Coğrafi yedeklilik için SQLite'ı Litestream ile R2'ye çoğaltın ve ikinci bölgeyi aynı nesne deposuna yönlendirin. Yük devretme DNS düzeyindedir. Tüm felaket kurtarma stratejiniz tek sayfaya sığar.

Yukarıdaki yaklaşımın tamamı HexaTransfer'in nasıl inşa edildiğini yansıtır — Fastify API, R2 depolama, tarayıcıda Web Crypto, SQLite meta verileri, hesap yok. hexatransfer.com'da deneyin — ücretsiz, hesap gerekmez, maksimum 10 GB.

v1'de Atlayabilecekleriniz

v1'de hesap, ekip veya klasör oluşturmayın. E-posta teslimi eklemeyin. Video önizleme veya resim küçük resimleri uygulamayın (ikisi de sunucunun düz metni görmesini zorlar). Web sürümü mobil Safari'de sağlam olmadan bir mobil uygulama göndermayın. Erken dosya transfer klonlarını öldüren özellik genişlemesi her zaman aynı desendi: hesaplar, ardından depolama kotaları, ardından ödeme, ardından ekip planları ve bir anda Dropbox ile rekabet ediyorsunuzdur. Yüzeyi küçük tutun ve kriptografiyi sıkı tutun.

Uçtan uca şifreleme ile büyük dosyaları güvenle gönderin

Uçtan uca şifreleme ile 10 GB'a kadar dosya ücretsiz aktarın. Hesap gerekmez. Dosyalarınız yüklenmeden önce tarayıcınızda şifrelenir — başka kimse okuyamaz.

Dosya gönder