Basit, güvenli ve yalnızca .png dosyaları servis eden bir HTTPS statik görsel sunucusu.
Fastify üzerinde çalışır; hostname whitelist, streaming, ETag/Last-Modified ve şüpheli istek loglama özelliklerine sahiptir.
Öne Çıkanlar
- 🔒 HTTPS (kendi sertifikanızı kullanın)
- 🧰 Host whitelist (Host / X-Forwarded-Host doğrulaması)
- 📦 Streaming (daha az bellek tüketimi)
- 🗃️ ETag + Last-Modified (304 yanıtları, basit cache)
- 🧯 Path traversal ve uzantı filtrelemesi
- 📝
logs/access.logiçine şüpheli istek logları
- Gereksinimler
- Kurulum
- Dizin Yapısı
- Yapılandırma
- Çalıştırma
- Kullanım
- Loglar
- Geliştirme & Lokal Test
- Sık Karşılaşılanlar
- Reverse Proxy/CDN Notları
- systemd Servis Örneği
- Lisans
- Node.js 18+ (önerilen: 20 LTS)
npm,pnpmya dayarn
Proje ESM (ECMAScript Modules) kullanır.
# Projeyi indir
git clone https://github.com/JustL0/image-server.git
cd image-server
# Paketleri kur
npm iimage-server/
├─ server.js # ya da server.mjs (ESM)
├─ images/ # .png dosyalarınızı buraya koyun
├─ ssl/
│ ├─ origin.key # özel anahtar
│ └─ origin.crt # sertifika (chain ile birlikte)
└─ logs/
└─ access.log # şüpheli istek logları (otomatik oluşur)
logs/klasörü ilk çalıştırmada otomatik yaratılır.
server.js içinde:
const ALLOWED_HOSTS = new Set([
'subdomain.domain.com',
'www.domain.com'
// Lokal test için şunları ekleyebilirsiniz:
// 'localhost',
// '127.0.0.1'
]);- Sunucu yalnızca bu hostname’lerle gelen istekleri kabul eder.
- Lokal geliştirme için
localhostveya127.0.0.1ekleyin (bkz. Geliştirme & Lokal Test).
ssl/origin.key ve ssl/origin.crt dosyalarını yerleştirin.
Üretimde gerçek sertifika kullanın. Lokal geliştirmede self-signed oluşturabilirsiniz.
OpenSSL (Git Bash/WSL/WSL2):
openssl req -x509 -newkey rsa:2048 -nodes -keyout ssl/origin.key -out ssl/origin.crt -days 365 \
-subj "/CN=localhost"Tarayıcıda uyarı görebilirsiniz; lokalde test için normaldir.
Varsayılan: Cache-Control: public, max-age=86400 (1 gün).
server.js içinde ihtiyacınıza göre değiştirin:
.header('Cache-Control', 'public, max-age=86400')node server.mjsVarsayılan adres:
https://0.0.0.0:2096
Başarı mesajı:
Image server listening on https://0.0.0.0:2096
- PNG görüntüleme:
GET /<dosya>.png
Örnekler:
https://www.domain.com:2096/logo.pnghttps://subdomain.domain.com:2096/path/to/elephant.png
Sadece .png uzantısına izin verilir. Diğer uzantılar (.jpg, .ico, vs.) ve directory traversal denemeleri 404/403 ile sonuçlanır.
HEAD istekleri otomatik desteklenir (Fastify GET için HEAD de üretir).
cURL örnekleri:
# Doğrudan
curl -vk https://subdomain.domain.com:2096/elephant.png -o /dev/null
# Lokal IP ile ama Host header ayarlayarak
curl -vk https://127.0.0.1:2096/elephant.png -H "Host: subdomain.domain.com" -o /dev/nullŞüpheli istekler logs/access.log içine yazılır.
Örnek (lokalde görülen çıktı):
2025-09-01T07:11:22.880Z [SUSPICIOUS] reason=invalid_host:127.0.0.1 ip=127.0.0.1 path=/ headers={"host":"127.0.0.1:2096",...}
2025-09-01T07:12:51.192Z [SUSPICIOUS] reason=invalid_host:127.0.0.1 ip=127.0.0.1 path=elephant.png headers={"host":"127.0.0.1:2096",...}
2025-09-01T07:12:58.659Z [SUSPICIOUS] reason=invalid_extension ip=127.0.0.1 path=favicon.ico headers={...}
Olası reason değerleri:
invalid_host:<host>: Host whitelist dışı.invalid_extension:.pngdışında bir uzantı (örn:favicon.ico).path_traversal:..vb. ileimages/dışına çıkma denemesi.decode_error: URL decode hatası.stat_error: Dosya bilgisi okunamadı (yok veya izin).read_stream_error: Okuma/stream sırasında hata.invalid_method: GET/HEAD dışındaki HTTP metodu.
Tarayıcıyla https://127.0.0.1:2096/elephant.png gibi bir URL açtığınızda Host header 127.0.0.1 olacağı için whitelist’e takılırsınız (logda invalid_host:127.0.0.1 görürsünüz).
Seçenekler:
-
Whitelist’e ekle
const ALLOWED_HOSTS = new Set([ 'localhost', '127.0.0.1', 'subdomain.domain.com', 'www.domain.com' ]);
-
curl ile Host header ayarla
curl -vk https://127.0.0.1:2096/elephant.png -H "Host: subdomain.domain.com" -o /dev/null -
hosts dosyası ile domain → 127.0.0.1
- Windows:
C:\Windows\System32\drivers\etc\hosts - Linux/macOS:
/etc/hosts
İçerik örneği:
127.0.0.1 subdomain.domain.comSonra tarayıcıdan:
https://subdomain.domain.com:2096/elephant.png - Windows:
-
FST_ERR_DUPLICATED_ROUTE: Method 'HEAD' already declared
Fastify GET için otomatik HEAD oluşturur. Ekstrafastify.head()yazdıysanız kaldırın ya da Fastify’iexposeHeadRoutes: falseile başlatıp kendi HEAD rotanızı tutun. -
Tarayıcı
favicon.icoistiyor, logdainvalid_extensiongörünüyor
Sadece.pngservis ediliyor.favicon.icoistekleri 404/loglanır. İsterseniz.icodesteği ekleyin veya favicon’u.pngolarak verin. -
Sertifika uyarısı
Self-signed sertifika lokalde normaldir. Üretimde geçerli sertifika kullanın.
trustProxy: trueaçıktır. Proxy/CDN arkasında gerçek IP için gereklidir.- Host doğrulaması
X-Forwarded-Host→Hostsırasıyla yapılır. Proxy’nizinX-Forwarded-Host’u doğru aktardığından emin olun. - CDN/Proxy health check’leri HEAD isteği atabilir; desteklidir.
- Cloudflare gibi bir CDN kullanıyorsanız, Origin Sertifikası ile
ssl/origin.crt/origin.keyyerleştirip kullanabilirsiniz.
Linux üzerinde servis olarak koşmak için:
/etc/systemd/system/image-server.service
[Unit]
Description=image-server
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/image-server
ExecStart=/usr/bin/node server.js
Restart=always
User=www-data
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now image-server
sudo systemctl status image-serverMIT