# HSOSKY PlayWeb — VirtualHost cho Apache trên Windows (Laragon)
# Dùng sau Cloudflare: Cloudflare lo HTTPS ở biên, origin chỉ cần cổng 80.
#
# Chép vào: C:\laragon\etc\apache2\sites-enabled\play.hsosky.com.conf
# rồi Laragon -> Reload.
#
# ROOT trỏ vào thư mục public, KHÔNG phải thư mục cha. Trỏ nhầm vào cha thì
# bridge.mjs, start-bridge.bat, README.html và chính file .conf này đều tải
# về được từ ngoài Internet.
#
# Cần bật trong httpd.conf:
# mod_proxy, mod_proxy_http, mod_proxy_wstunnel, mod_rewrite,
# mod_headers, mod_deflate, mod_filter
define ROOT "C:/laragon/www/playweb/public"
define SITE "play.hsosky.com"
DocumentRoot "${ROOT}"
ServerName ${SITE}
# None vì thư mục này không có .htaccess — khỏi tốn một lượt
# tìm file mỗi request
AllowOverride None
Require all granted
Options -Indexes +FollowSymLinks
DirectoryIndex index.html
# --- CẦU NỐI WEBSOCKET — BẮT BUỘC ------------------------------------
# Thiếu phần này game vẫn tải và vẽ bình thường nhưng KHÔNG kết nối
# được máy chủ, kẹt ở màn đăng nhập mà không báo lỗi rõ ràng.
#
# Qua Cloudflare: trang chạy https nên game tự dùng wss://. Cloudflare
# nhận wss ở biên rồi chuyển về origin thành ws:// cổng 80 — đúng cái
# khối này nhận.
ProxyPreserveHost On
ProxyRequests Off
ProxyPass /socket-bridge ws://127.0.0.1:8081/socket-bridge connectiontimeout=15 timeout=3600
ProxyPassReverse /socket-bridge ws://127.0.0.1:8081/socket-bridge
# --- Gửi bản .gz nén sẵn (classes.js: 10.4MB -> 765KB) ---------------
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/socket-bridge
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.gz -f
RewriteRule ^(.*)$ $1.gz [QSA,L]
# Trả file .gz nhưng phải khai đúng loại nội dung gốc
Header set Content-Encoding gzip
Header append Vary Accept-Encoding
ForceType application/javascript
Header set Content-Encoding gzip
Header append Vary Accept-Encoding
ForceType text/html
# JS luôn được gọi kèm ?v=N, số đó đổi mỗi khi nội dung đổi
Header set Cache-Control "public, max-age=31536000, immutable"
# JAR không đánh phiên bản — dựa vào ETag để nhận 304 rỗng
Header set Cache-Control "public, max-age=3600, must-revalidate"
# HTML là nơi chứa số ?v mới — cache nó là người chơi mắc kẹt bản cũ
Header set Cache-Control "no-cache"
# Nén động cho file chưa có sẵn .gz.
# AddOutputFilterByType do mod_filter cung cấp (không phải mod_deflate),
# nên phải guard bằng mod_filter — guard nhầm là Apache không khởi động.
AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json image/svg+xml
ErrorLog "logs/playweb-error.log"
CustomLog "logs/playweb-access.log" common
# Không cần vì Cloudflare đã kết thúc TLS ở biên.
# Nếu sau này bỏ Cloudflare thì mới cần thêm khối 443 kèm chứng chỉ thật.