Açık Kaynak Uygulamalar

    React Projesini Sunucuya Yükleme: build Klasörünü Yayına Alma

    React uygulamasının build çıktısını hosting veya sunucuya yükleyip yönlendirme sorunlarını çözmeyi anlatır.

    12 dk okuma Güncellendi: 11 Ağustos 2026

    React projesini sunucuya yükleme konusunda Türkçe arattığınızda karşınıza çıkan neredeyse her sonuç sizi tek bir yere götürür: bir bulut platformuna hesap açın, deponuzu bağlayın, gerisi otomatik. Peki elinizde zaten bir cPanel hostingi varsa, projeyi kendi alan adınızda ve kendi sunucunuzda yayınlamak istiyorsanız? İşte oradan sonrası Türkçe kaynaklarda büyük ölçüde boş. Bu boşluğun en görünür sonucu da şu meşhur şikâyettir: "Site açılıyor, menüdeki linklere tıklayınca sayfalar geliyor, ama bir iç sayfada F5'e basınca 404 alıyorum."

    Bu yazıda React uygulamasını klasik bir paylaşımlı hostinge ve kendi sunucunuza yüklemenin tamamını anlatıyorum. npm run build çıktısının ne olduğunu ve neden node_modules yüklemeniz gerekmediğini, hangi dosyaların nereye gideceğini, sayfa yenilendiğinde 404 alınmasının teknik sebebini ve bunun Apache tarafında .htaccess, Nginx tarafında try_files ile nasıl çözüldüğünü, projeyi bir alt dizinde (siteadi.com/panel gibi) yayınlarken homepage ve basename ayarlarının nasıl kurulacağını, API adreslerinin ortam değişkenleriyle nasıl yönetileceğini ve Next.js gibi sunucu tarafı çalışan projelerde tablonun neden tamamen değiştiğini adım adım göreceksiniz.

    build Klasörü Nedir, Sunucuya Tam Olarak Ne Yüklenir#

    React projesinde sunucuya yüklenecek şey kaynak kodunuz değil, derlenmiş çıktıdır. npm run build komutu src klasöründeki JSX, modern JavaScript ve CSS dosyalarını tarayıcıların anlayacağı sade dosyalara dönüştürür, hepsini küçültür ve tek bir klasöre koyar.

    npm install
    npm run build
    

    Çıktı klasörünün adı kullandığınız araca göre değişir ve bu ayrım önemlidir:

    AraçÇıktı klasörüTipik dosyalar
    Create React Appbuild/index.html, static/js/, static/css/
    Vitedist/index.html, assets/
    Next.js (statik dışa aktarım)out/index.html ve sayfa klasörleri
    Next.js (standart).next/Sunucu gerektirir, statik yüklenmez

    Bir Create React App projesinde build klasörünün içi kabaca şöyle görünür:

    build/
    ├── index.html
    ├── favicon.ico
    ├── manifest.json
    ├── robots.txt
    ├── asset-manifest.json
    └── static/
        ├── css/main.8f3a21c4.css
        ├── js/main.6b7d9e02.js
        └── media/logo.5d5d9eef.svg
    

    Sunucuya yüklenecek olan bu klasörün içeriğidir. src, public, node_modules, package.json sunucuya gitmez. Özellikle node_modules klasörünü yüklemeye çalışmak yeni başlayanların düştüğü klasik hatadır: içinde on binlerce küçük dosya vardır, FTP ile yüklemesi saatler sürer ve hiçbir işe yaramaz, çünkü o paketlerin içeriği zaten build çıktısına derlenmiştir. Statik hosting söz konusu olduğunda sunucuda Node.js çalışmasına da gerek yoktur; hosting yalnızca hazır HTML, CSS ve JS dosyalarını servis eder.

    Dosya isimlerindeki main.6b7d9e02.js gibi rastgele görünen parçalara dikkat edin. Bunlar içerik damgasıdır ve her derlemede içerik değiştiğinde değişir; sayesinde tarayıcı eski dosyayı önbellekten getirmez. Bu yüzden yeni bir sürüm yüklerken eski static klasörünü silmek, yeni derlemenin tamamen geçtiğinden emin olmanın en kolay yoludur.

    Adım Adım: cPanel Hostinge React Yükleme#

    Aşağıdaki adımlar CRA veya Vite ile üretilmiş, tamamen tarayıcıda çalışan bir React uygulaması içindir.

    1. Yerelde derleyin. Proje klasöründe npm run build çalıştırın. Komut hatasız bitmeli; uyarılar sorun değil, hatalar sorundur.
    2. Çıktıyı sıkıştırın. build (veya dist) klasörünün içine girip tüm dosyaları seçin ve bir zip yapın. Klasörün kendisini paketlerseniz sunucuda fazladan bir dizin oluşur ve site alt dizine kayar.
    3. cPanel → Dosya Yöneticisi → public_html klasörüne girin. Ayarlar'dan "Show Hidden Files" seçeneğini açın, çünkü birazdan .htaccess dosyasını göreceksiniz.
    4. Klasörü temizleyin. Hosting karşılama sayfası (default.html gibi) varsa silin. Eski bir sürüm varsa static/assets klasörünü ve index.html dosyasını silin.
    5. Zip'i yükleyip sunucuda açın. Upload → dosyayı seçin → yükleme bitince dizine dönüp zip'e sağ tıklayın ve Extract deyin. Zip'i sunucuda açmak, FTP ile yüzlerce dosya taşımaktan kat kat hızlıdır; derleme çıktısında yüzlerce küçük parça dosya olabilir.
    6. Zip dosyasını silin. İşi bittiğinde sunucuda durmasının hiçbir faydası yok.
    7. .htaccess dosyasını oluşturun. Bir sonraki bölümdeki içerik olmadan site yarım çalışır.
    8. Alan adınızı açın ve Ctrl+F5 yapın.

    Bu noktada ana sayfa açılıyor olmalı. Açılmıyorsa public_html içinde doğrudan index.html görüp görmediğinize bakın; tek bir build klasörü görüyorsanız 2. adımı yanlış yapmışsınızdır, o klasörün içeriğini bir üst dizine taşıyın.

    Sayfayı Yenileyince 404 Alıyorum: Sorunun Gerçek Sebebi#

    React uygulamasında iç sayfayı yenilediğinizde 404 almanızın sebebi, tarayıcının sunucudan gerçekten var olmayan bir dosya istemesidir. Bu, React'in hatası değil, tek sayfa uygulaması (SPA) mimarisinin doğal sonucudur.

    Şöyle işler: siteye siteadi.com adresinden girdiğinizde sunucu index.html dosyasını gönderir, tarayıcıda React başlar ve React Router adres çubuğunu yönetmeye başlar. Menüden "Hakkımızda" bağlantısına tıkladığınızda sunucuya hiçbir istek gitmez; React sadece adres çubuğunu siteadi.com/hakkimizda olarak günceller ve ilgili bileşeni ekrana basar. Şimdi F5'e bastığınızda ya da o adresi doğrudan yazdığınızda tarayıcı sunucuya "bana /hakkimizda yolunu ver" der. Sunucu bunu bir dosya isteği sanır, public_html/hakkimizda diye bir dosya veya klasör arar, bulamaz ve 404 döner.

    Çözüm, sunucuya şunu söylemektir: "İstenen yol gerçekten bir dosya veya klasör değilse, index.html'i gönder; gerisini JavaScript halleder."

    Apache tarafında public_html/.htaccess dosyasına şunu yazın:

    <IfModule mod_rewrite.c>
      RewriteEngine On
      RewriteBase /
    
      # Gerçekten var olan dosya veya klasörse dokunma
      RewriteCond %{REQUEST_FILENAME} -f [OR]
      RewriteCond %{REQUEST_FILENAME} -d
      RewriteRule ^ - [L]
    
      # Geri kalan her yolu index.html'e ver
      RewriteRule ^ index.html [L]
    </IfModule>
    

    Buradaki iki RewriteCond satırı kritiktir. Onlar olmadan static/js/main.js isteği de index.html'e yönlenir; tarayıcı JavaScript beklerken HTML alır ve konsolda Uncaught SyntaxError: Unexpected token '<' hatası görürsünüz. Bu hata mesajını gördüğünüzde nedeni aramayın, doğrudan bu iki koşulun eksik olduğuna bakın. .htaccess dosyasını sıfırdan oluşturma ve düzenleme ayrıntıları htaccess dosyası oluşturma yazısında anlatılıyor.

    Nginx kullanan bir sunucudaysanız .htaccess hiç okunmaz; aynı işi sunucu bloğunda yaparsınız:

    server {
        listen 80;
        server_name siteadi.com www.siteadi.com;
        root /var/www/siteadi.com;
        index index.html;
    
        location / {
            try_files $uri $uri/ /index.html;
        }
    
        location /static/ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }
    

    try_files $uri $uri/ /index.html; satırı tam olarak Apache tarafındaki üç kuralın karşılığıdır: önce dosya, sonra klasör, ikisi de yoksa index.html. Değişikliği yaptıktan sonra nginx -t ile yapılandırmayı doğrulayıp systemctl reload nginx demeyi unutmayın.

    Projeyi Alt Dizinde Yayınlama: homepage ve basename#

    Uygulamayı alan adının kökünde değil de siteadi.com/panel gibi bir alt dizinde yayınlayacaksanız iki ayrı ayar yapmanız gerekir ve bunlardan sadece birini yapmak siteyi beyaz ekranda bırakır.

    Birinci ayar — varlık yolları. Derleme sonrası index.html içindeki JS/CSS bağlantıları varsayılan olarak /static/js/... şeklinde, yani kökten başlar. Alt dizine koyduğunuzda tarayıcı bu dosyaları siteadi.com/static/js/... adresinde arar, orada yoktur, sayfa bomboş açılır ve konsol 404 dolar. Create React App'te package.json içine şunu ekleyin:

    {
      "homepage": "/panel"
    }
    

    Vite kullanıyorsanız karşılığı vite.config.js içindedir:

    export default defineConfig({
      base: "/panel/",
    });
    

    İkinci ayar — router. React Router'a da uygulamanın kökünün nerede başladığını söylemeniz gerekir, aksi halde /panel yolunu tanımayıp boş sayfa gösterir:

    <BrowserRouter basename="/panel">
      <App />
    </BrowserRouter>
    

    Üçüncü ayar — sunucu. .htaccess dosyasını public_html/panel/ içine koyun ve RewriteBase değerini düzeltin:

    RewriteEngine On
    RewriteBase /panel/
    RewriteCond %{REQUEST_FILENAME} -f [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^ - [L]
    RewriteRule ^ index.html [L]
    

    Üçünü birden yapmadan alt dizin kurulumu çalışmaz. Belirtilerden hangi ayarın eksik olduğunu anlayabilirsiniz:

    BelirtiEksik olan
    Sayfa bembeyaz, konsolda static dosyaları için 404homepage / base
    Dosyalar yükleniyor ama ekran boş, hata yokbasename
    Ana sayfa açılıyor, iç sayfa yenileyince 404.htaccess / RewriteBase
    JS dosyası yerine HTML geliyor (Unexpected token '<')RewriteCond satırları

    API Adresleri ve Ortam Değişkenleri#

    Yerelde çalışırken API adresiniz muhtemelen http://localhost:8000 gibi bir şeydir ve bu adres derleme çıktısının içine gömülür. Sunucuya yükledikten sonra uygulama hâlâ ziyaretçinin kendi bilgisayarındaki 8000 portuna istek atmaya çalışır; ağ sekmesinde ERR_CONNECTION_REFUSED görürsünüz.

    Doğru yaklaşım adresi ortam değişkeninden okumaktır. Create React App'te değişken adı REACT_APP_ ile, Vite'ta VITE_ ile başlamak zorundadır:

    # .env.production
    REACT_APP_API_URL=https://api.siteadi.com
    
    const api = process.env.REACT_APP_API_URL;
    

    Burada iki şeyi hiç unutmayın. Birincisi: ortam değişkenleri derleme anında gömülür, çalışma anında okunmaz. Dosyayı değiştirdiyseniz yeniden npm run build almanız ve yeni çıktıyı yüklemeniz şarttır; sunucudaki dosyayı elle düzeltmeye çalışmayın. İkincisi: bu değerlerin tamamı tarayıcıya iner, yani gizli değildir. API anahtarı, veritabanı şifresi, ödeme sağlayıcı gizli anahtarı gibi şeyleri asla bir React ortam değişkenine koymayın; onlar sunucu tarafında durur.

    Bir de karışık içerik tuzağı var: siteniz HTTPS ile açılırken API adresiniz http:// ile başlıyorsa tarayıcı isteği engeller ve konsola "Mixed Content" uyarısı basar. API'niz de HTTPS olmalıdır.

    Backend'i Aynı Sunucuda Çalıştırmak: Reverse Proxy#

    React uygulamanız bir API'ye konuşuyorsa ve o API'yi de aynı sunucuda çalıştırıyorsanız, ikisini tek alan adı altında birleştirmenin temiz yolu ters vekil (reverse proxy) kurmaktır. Böylece siteadi.com statik React dosyalarını, siteadi.com/api ise arka plandaki Node.js sürecini gösterir; tarayıcı tarafında CORS ayarıyla uğraşmazsınız çünkü her şey aynı kaynaktan gelir.

    server {
        listen 80;
        server_name siteadi.com;
        root /var/www/siteadi.com;
    
        location / {
            try_files $uri $uri/ /index.html;
        }
    
        location /api/ {
            proxy_pass http://127.0.0.1:3001/;
            proxy_http_version 1.1;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
    

    Arka plandaki Node.js sürecinin siz SSH oturumunu kapattığınızda ölmemesi ve sunucu yeniden başladığında kendi kendine kalkması için bir süreç yöneticisi kullanmanız gerekir; bu konunun tamamını pm2 ile Node.js süreç yönetimi yazısında ele aldım. Paylaşımlı hostingte reverse proxy kuramazsınız; orada Node.js uygulamasını cPanel'in kendi Node.js uygulama yöneticisiyle çalıştırırsınız.

    Next.js Farkı: Her React Projesi Statik Değildir#

    Buraya kadar anlatılan her şey tarayıcıda çalışan bir React uygulaması içindir. Next.js kullanıyorsanız tablo tamamen değişir çünkü Next.js varsayılan olarak sunucu tarafında çalışan bir uygulamadır: her istekte Node.js süreci HTML üretir.

    Üç senaryo var:

    Statik dışa aktarım. Projeniz sunucu tarafı özellik kullanmıyorsa (API rotaları, sunucu bileşenlerinde veritabanı sorgusu, getServerSideProps gibi) yapılandırmaya output: 'export' ekleyip statik HTML üretebilirsiniz. Çıkan out klasörünü tıpkı yukarıdaki gibi public_html içine atarsınız ve paylaşımlı hosting yeterlidir.

    Node.js olarak çalıştırma. Sunucu tarafı özellik kullanıyorsanız uygulama gerçekten çalışmak zorundadır: npm run build sonrası npm start ile sürekli açık bir Node.js süreci gerekir, önüne de reverse proxy koyarsınız. Bu senaryo paylaşımlı hostingte kural olarak mümkün değildir; kendi sunucunuza ihtiyacınız olur.

    cPanel'in Node.js uygulama yöneticisi. Bazı paylaşımlı paketlerde Passenger tabanlı bir Node.js çalıştırma arayüzü bulunur; küçük uygulamalar için iş görür ama bellek limitleri ve sürüm kısıtları nedeniyle ciddi bir Next.js projesinde dar gelir. Bu ortamın kurulumunu Node.js uygulaması cPanel Passenger yazısında bulabilirsiniz.

    Kısaca karar kuralı şudur: uygulamanız derlendikten sonra çalışmak için Node.js'e ihtiyaç duyuyorsa paylaşımlı hosting yetmez, duymuyorsa fazlasıyla yeter.

    Yükleme Sonrası Kontrol Listesi ve Sık Hatalar#

    Yükleme bittikten sonra sırayla şunlara bakın:

    1. Ana sayfa açılıyor mu, adres çubuğunda fazladan bir klasör adı var mı?
    2. Bir iç sayfaya gidip F5 yapın — 404 geliyorsa .htaccess yok ya da okunmuyordur.
    3. Tarayıcıda F12 → Console sekmesi tamamen temiz mi? Kırmızı satır varsa mesajı okuyun, tahmin etmeyin.
    4. Network sekmesinde main.*.js dosyasının durumu 200 ve tipi script mi? Tip document görünüyorsa HTML dönmüştür.
    5. API istekleri doğru adrese mi gidiyor, localhost kalmış mı?
    6. Site HTTPS ile açılıyor mu, kilit simgesi kırık mı?
    7. Yeni sürüm yüklediğinizde eski ekranı görüyorsanız Ctrl+F5 yapın; sorun sürüyorsa eski static klasörünü silmemişsinizdir.

    En sık karşılaştığım üç hata ve tek satırlık nedenleri: beyaz ekran ve konsolda varlık 404'leri (homepage/base ayarı eksik), Unexpected token '<' (rewrite kuralları varlık dosyalarını da yakalıyor), yenilemede 404 (.htaccess yok veya AllowOverride kapalı olduğu için okunmuyor). Üçüncü durumda dosyanız yerinde olsa bile işe yaramaz; paylaşımlı hostingte .htaccess genelde etkindir ama kendi sunucunuzda Apache yapılandırmasında AllowOverride All satırının bulunması gerekir.

    PHP tabanlı bir projeyi aynı sunucuda yayınlıyorsanız oradaki kurulum mantığı farklıdır; Laravel projesi hostinge yükleme yazısı o tarafı ayrıca anlatıyor.

    Sıkça Sorulan Sorular#

    React projesi için Node.js kurulu bir sunucu şart mı#

    Hayır, tarayıcıda çalışan klasik bir React uygulaması için şart değildir. npm run build komutunu kendi bilgisayarınızda çalıştırırsınız ve sunucuya yalnızca derlenmiş HTML, CSS ve JS dosyalarını yüklersiniz; bunları servis etmek için herhangi bir statik hosting yeterlidir. Node.js ancak uygulamanız sunucu tarafında çalışıyorsa, örneğin Next.js'in standart modunu veya kendi API'nizi çalıştıracaksanız gerekir. Bu ayrımı bilmek, paylaşımlı hostingin size yetip yetmeyeceğini belirleyen tek sorudur.

    node_modules klasörünü de yüklemem gerekiyor mu#

    Hayır, kesinlikle gerekmez ve yüklememelisiniz. node_modules yalnızca derleme sırasında kullanılan geliştirme bağımlılıklarını içerir; ihtiyacınız olan kod zaten build çıktısının içine derlenmiştir. İçinde on binlerce küçük dosya bulunduğu için FTP ile aktarımı saatler sürer, disk kotanızı boş yere doldurur ve hiçbir işlevi olmaz. Sunucuya yükleyeceğiniz tek şey build veya dist klasörünün içeriğidir.

    Sayfayı yenileyince neden 404 alıyorum#

    Çünkü sunucu, adres çubuğundaki yolu gerçek bir dosya sanıp diskte arıyor ve bulamıyor. React Router adresleri tarayıcı tarafında yönetir; menüden geçişlerde sunucuya istek gitmediği için sorun görünmez, ama yenilediğinizde istek doğrudan sunucuya ulaşır. Çözüm, var olmayan tüm yolları index.html dosyasına yönlendirmektir: Apache'de .htaccess içine rewrite kuralı, Nginx'te try_files $uri $uri/ /index.html; satırı. Kuralı yazarken gerçek dosya ve klasörleri kural dışında bırakmayı unutmayın.

    Uncaught SyntaxError Unexpected token hatası ne anlama geliyor#

    Bu hata, tarayıcının JavaScript dosyası beklediği yerde HTML aldığı anlamına gelir. Neredeyse her zaman sebebi, yönlendirme kuralınızın varlık dosyalarını da yakalayıp onlara index.html göndermesidir. Rewrite kuralından önce "istenen yol gerçek bir dosya veya klasörse dokunma" koşullarını eklediğinizde hata kaybolur. Tarayıcıda ağ sekmesinden ilgili JS dosyasına tıklayıp yanıt içeriğine bakarsanız HTML döndüğünü doğrudan görebilirsiniz.

    React uygulamamı alt klasörde nasıl yayınlarım#

    Üç ayarı birlikte yapmanız gerekir. Create React App'te package.json içine "homepage": "/klasor" ekleyin, Vite'ta vite.config.js içinde base: "/klasor/" tanımlayın; bu, varlık yollarının doğru başlamasını sağlar. Ardından React Router'ı <BrowserRouter basename="/klasor"> şeklinde başlatın. Son olarak .htaccess dosyasını o alt klasörün içine koyup RewriteBase /klasor/ yazın. Üçünden biri eksikse ya beyaz ekran ya da yenilemede 404 alırsınız.

    API adresini sunucuda nasıl değiştiririm#

    Sunucudaki dosyaları düzenleyerek değil, yeniden derleyerek. Ortam değişkenleri derleme anında çıktının içine gömülür, bu yüzden .env.production dosyasındaki adresi güncelledikten sonra npm run build komutunu tekrar çalıştırıp yeni çıktıyı yüklemeniz gerekir. Ayrıca bu değerlerin tarayıcıya indiğini ve herkes tarafından görülebildiğini unutmayın; gizli anahtarları asla ön yüz ortam değişkenine koymayın, onların yeri arka uçtur.

    Next.js projesini paylaşımlı hostinge yükleyebilir miyim#

    Ancak projeyi statik olarak dışa aktarabiliyorsanız yükleyebilirsiniz. Yapılandırmaya output: 'export' ekleyip derlediğinizde ortaya çıkan out klasörü sıradan bir statik site gibi davranır ve paylaşımlı hostingte sorunsuz çalışır. Ancak projeniz sunucu tarafı veri çekme, API rotaları veya görsel optimizasyonu gibi çalışma anında sunucu gerektiren özellikler kullanıyorsa statik dışa aktarım mümkün olmaz; bu durumda sürekli çalışan bir Node.js süreci, dolayısıyla kendi sunucunuz gerekir.

    Yeni sürümü yükledim ama eski site görünüyor#

    Önce tarayıcı önbelleğini şüpheli görün ve Ctrl+F5 ile sert yenileme yapın, ardından gizli sekmede kontrol edin. React derlemeleri dosya adlarına içerik damgası eklediği için normalde bu sorun yaşanmaz; yaşanıyorsa büyük ihtimalle index.html dosyası güncellenmemiştir ya da eski static klasörü silinmeden yeni dosyalar üstüne kopyalanmıştır. Önünde bir CDN veya sunucu önbelleği varsa oradan da temizlemeniz gerekir.

    Kapanış#

    React projesini kendi sunucunuzda yayınlamak, bulut platformlarının otomatik akışına alışmış birine ilk bakışta karmaşık görünse de aslında üç karardan ibarettir: neyi yükleyeceksiniz (derleme çıktısının içeriği), nereye yükleyeceksiniz (public_html ya da sunucu kökü) ve sunucuya bilinmeyen yolları nasıl anlatacaksınız (.htaccess rewrite ya da try_files). Bu üçünü doğru kurduğunuzda "yenileyince 404" şikâyeti dahil sorunların büyük bölümü ortadan kalkar. Alt dizin kurulumu yapıyorsanız homepage/base ve basename ayarlarını birlikte düşünmeyi, API adresini de ortam değişkeninden okumayı alışkanlık hâline getirin.

    Uygulamanız tamamen tarayıcıda çalışıyorsa giriş seviyesi bir web hosting paketi fazlasıyla yeterlidir; derlenmiş dosyaları servis etmek sunucuya neredeyse hiç yük bindirmez. Next.js'in sunucu tarafı modunu, kendi Node.js API'nizi ya da bir ters vekil kurulumunu çalıştıracaksanız kök erişimi olan bir sanal sunucu tarafına geçmeniz gerekir; sunucu yönetimiyle uğraşmak istemiyorsanız sunucu yönetimi hizmeti kurulum ve bakım tarafını üstlenir. Uygulamanız API'ye konuşuyorsa yayına almadan önce SSL sertifikanızı kurup her iki tarafı da HTTPS'e taşımayı ilk işiniz yapın; aksi hâlde tarayıcı isteklerinizi sessizce engeller.

    reactdeployyayına alma

    Uygulamaya geçmeye hazır mısınız?

    NVMe SSD, ücretsiz SSL ve %99.9 uptime garantisiyle Clou.TR hosting ve sunucu çözümleriyle projenizi hayata geçirin.