# ============================================================================= # 3E Eğitim — lokal geliştirme nginx yapılandırması (HTTPS) # ============================================================================= # Kurulum: # ln -sf /Users/sets/Projects/3e-egitim/deployment/nginx/egitim.dev.sets.fyi.conf \ # /opt/homebrew/etc/nginx/servers/3eegitim.conf # nginx -t && nginx -s reload # # DNS: Cloudflare, sets.fyi zone'unda BEŞ A kaydı → 10.31.1.25 (bu makine). # # ⚠ `panel.` 03.08.2026'da eklendi (müşteri paneli kendi host'una taşındı). # Wildcard sertifika (`*.egitim.dev.sets.fyi`) onu zaten kapsıyor; eksik olan # yalnız A kaydıdır. # # egitim.dev.sets.fyi landing (yalnız landing + posta webhook'ları) # panel.egitim.dev.sets.fyi müşteri paneli — KENDİ KÖKÜNDE + katılımcı # ofis.egitim.dev.sets.fyi planlamacı, satışçı, eğitmen, yönetici # backoffice.egitim.dev.sets.fyi Filament # ws.infra.egitim.dev.sets.fyi Reverb # # ⚠ Cloudflare proxy'si (turuncu bulut) KAPALI olmak zorunda. 10.31.1.25 bir # RFC1918 adresi; Cloudflare oraya proxy edemez. Aynı desen puanbenim'de de # kullanılıyor (`puanbenim.dev.sets.fyi` → gri bulut → makinede nginx + LE). # # ⚠ Adresler yalnız BU AĞDAN açılır. Public DNS'te duruyor olması dışarıdan # erişilebilir oldukları anlamına gelmez: 10.31.1.25 internetten routable # değildir. Telefondan denemek için aynı wifi'ye bağlanmak gerekir. # # TLS: Let's Encrypt, DNS-01 (Cloudflare API). # # acme.sh --issue --dns dns_cf --server letsencrypt \ # -d egitim.dev.sets.fyi -d '*.egitim.dev.sets.fyi' \ # -d '*.infra.egitim.dev.sets.fyi' --keylength ec-256 # # ⚠ DNS-01 tercih değil ZORUNLULUK: Let's Encrypt HTTP-01 için 10.31.1.25'e # ulaşamaz. Yenileme acme.sh'in kendi cron'u ile yapılır ve reloadcmd nginx'i # yeniden yükler. # # ⚠ TLS'in kendisi de zorunluluk, konfor değil: tarayıcılar WebAuthn'u yalnız # güvenli bağlamda açar, düz http'de `PublicKeyCredential` tanımlı bile # değildir. Passkey bu kurulum olmadan lokalde denenemez (spec §5.2). # # PHP-FPM: PHP 8.5 → 127.0.0.1:9000 (php@8.3 9001'de, dokunulmuyor) # # Production karşılığı: # egitim.3egrp.com (landing) # panel.egitim.3egrp.com (müşteri paneli + katılımcı) # ofis.egitim.3egrp.com (planlamacı, satışçı, eğitmen, yönetici) # backoffice.egitim.3egrp.com (Filament) # ws.infra.egitim.3egrp.com (Reverb) — infra.* core servis çatı subdomaini # ============================================================================= # --- 80 → 443 ---------------------------------------------------------------- # Tek istisna ACME'nin HTTP-01 yolu değil (DNS-01 kullanıyoruz); burada # yönlendirmeden başka bir şey yok. http üzerinden gelen istek uygulamaya hiç # ulaşmaz — yarısı güvenli bir oturum, güvenli olmayan bir oturumdur. server { listen 80; server_name egitim.dev.sets.fyi panel.egitim.dev.sets.fyi ofis.egitim.dev.sets.fyi backoffice.egitim.dev.sets.fyi ws.infra.egitim.dev.sets.fyi; return 301 https://$host$request_uri; } # --- Ortak TLS ayarları ------------------------------------------------------ # Sertifika üç adı da kapsıyor: apex + `*.egitim` + `*.infra.egitim`. Wildcard # TEK etiket eşler, bu yüzden `ws.infra.…` için ikinci wildcard gerekti. # # Aşağıdaki iki server bloğu aynı sertifikayı kullanır; ayrı durmalarının sebebi # WebSocket bloğunun buffering/timeout ayarlarının HTTP tarafını etkilememesi. # --- Uygulama hostları ------------------------------------------------------- server { listen 443 ssl; http2 on; server_name egitim.dev.sets.fyi panel.egitim.dev.sets.fyi ofis.egitim.dev.sets.fyi backoffice.egitim.dev.sets.fyi; ssl_certificate /opt/homebrew/etc/nginx/ssl/egitim.dev.sets.fyi/fullchain.pem; ssl_certificate_key /opt/homebrew/etc/nginx/ssl/egitim.dev.sets.fyi/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_session_cache shared:egitim_tls:10m; ssl_session_timeout 1d; root /Users/sets/Projects/3e-egitim/public; index index.php; charset utf-8; client_max_body_size 64M; # evrak/fis fotografi yuklemeleri (AD-24) access_log /opt/homebrew/var/log/nginx/3eegitim-access.log; error_log /opt/homebrew/var/log/nginx/3eegitim-error.log; location / { try_files $uri $uri/ /index.php?$query_string; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } # Vite dev server (npm run dev) hot dosyasi location /build/ { try_files $uri =404; expires 1y; add_header Cache-Control "public, immutable"; } error_page 404 /index.php; # ⛔ A content package's recordings (EGT-257). INTERNAL: no visitor can ask # for this address. The application checks the licence and the person, # then answers with `X-Accel-Redirect` and nginx serves the file — ranges, # seeking and all — without holding a PHP worker for the length of a film. # The pool is shared with every other site on the machine. location ^~ /_recordings/ { internal; alias /Users/sets/Projects/3e-egitim/storage/app/recordings/; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; fastcgi_param DOCUMENT_ROOT $realpath_root; include fastcgi_params; # ⚠ Bu ikisi olmadan Laravel istegi http sanir: `url()` ve `route()` # http:// uretir, https sayfada mixed content olarak bloklanir ve panel # varlik yukleyemez. TLS burada sonlandigi icin FPM'e ayrica soylenmesi # gerekir. fastcgi_param HTTPS on; fastcgi_param REQUEST_SCHEME https; fastcgi_read_timeout 300; fastcgi_buffer_size 32k; fastcgi_buffers 16 32k; } location ~ /\.(?!well-known).* { deny all; } } # --- Reverb WebSocket (AD-22) ------------------------------------------------- # # ⛔ http2 KAPALI, ve bu bilinçli (05.08.2026). WebSocket el sıkışması klasik # `Upgrade` başlığıyla yapılır ve HTTP/2 üzerinde bu başlık yoktur; nginx # RFC 8441 genişletilmiş CONNECT'i desteklemediği için h2 ile gelen bir # istemci 500 alır. Tarayıcılar WS için kendiliğinden 1.1'e düşer — yani # açık bırakmak "çalışıyor ama bazı istemcilerde patlıyor" demek olurdu. # Ölçüldü: h2 → 500, http1.1 → 101 Switching Protocols. # # ⚠ Bu blok yalnız soket taşır; h2'nin buraya kazandıracağı bir şey de yok. # # ⛔ REVERB PORTU 20230 (port kayit defteri blok 2, +30 — 11.08.2026 tasima). # Burasi o tasimada ATLANDI: prod ve local prod yapilandirmalari 20230'a # alindi, dev 8080'de kaldi ve `.env` 20230'u soyluyordu. Sonuc, hicbir yerde # hata vermeyen bir kopukluk — sayfa aciliyor, yalnizca canli guncelleme # calismiyor ve konsola 502 dusuyordu (12.08.2026'da tarayici turunda goruldu). # `.env`'deki `REVERB_SERVER_PORT` ile birebir ayni olmak zorunda. server { listen 443 ssl; server_name ws.infra.egitim.dev.sets.fyi; ssl_certificate /opt/homebrew/etc/nginx/ssl/egitim.dev.sets.fyi/fullchain.pem; ssl_certificate_key /opt/homebrew/etc/nginx/ssl/egitim.dev.sets.fyi/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; access_log /opt/homebrew/var/log/nginx/3eegitim-ws-access.log; error_log /opt/homebrew/var/log/nginx/3eegitim-ws-error.log; location / { proxy_pass http://127.0.0.1:20230; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # WebSocket upgrade proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; # Uzun omurlu baglantilar — WS icin buffering kapali, timeout uzun. # Ayri subdomain olmasinin sebebi: bu ayarlar HTTP tarafini etkilemesin. proxy_buffering off; proxy_read_timeout 3600s; proxy_send_timeout 3600s; } }