diff --git a/README.md b/README.md
index 78ce750..e0e5970 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,30 @@ Website tĩnh (Ladipage). Cần chạy qua **web server cục bộ** — không
2. Trình duyệt sẽ mở: `http://localhost:8080/www.mewedding.vn/index.html`
3. Dừng server: nhấn `Ctrl+C` trong cửa sổ đen (hoặc đóng cửa sổ).
+## Mở qua WiFi (điện thoại / máy khác cùng mạng)
+
+1. Máy tính và điện thoại **cùng WiFi** (không dùng guest network chặn LAN).
+2. Chạy **`start.bat`** — cửa sổ PowerShell in thêm dòng dạng:
+ `http://192.168.x.x:8080/www.mewedding.vn/index.html`
+3. Trên điện thoại, mở đúng URL đó (thay `192.168.x.x` bằng IP hiện in ra).
+4. **Điện thoại không vào được** (hay gặp nhất):
+ - Chạy lại **`setup-wifi.ps1`** (Admin) — script mở **firewall cổng 8080** và đặt Wi-Fi sang **Private**.
+ - Trên điện thoại dùng đúng URL dòng **`>>> DIEN THOAI`** (thường `http://192.168.1.x:8080/...`), không dùng `localhost`.
+ - Điện thoại **tắt 4G/5G**, chỉ dùng WiFi cùng nhà; tắt VPN trên PC/điện thoại.
+ - Router: tắt **AP isolation / client isolation** nếu bật.
+ - Cửa sổ `start.bat` có dòng `192.168.x.x -> ...` khi điện thoại truy cập → server nhận được; không có dòng → firewall/router chặn.
+6. **Ảnh không hiện trên điện thoại:** trang cần **internet** cho font/icon LadiPage (`https://w.ladicdn.com`). Ảnh trong thư mục `w.ladicdn.com` tải từ máy tính — nếu vẫn trống, xem cửa sổ server có dòng `[404]` (sai đường dẫn). Tải lại trang sau khi chạy lại `start.bat`.
+5. Lần đầu bind cổng lỗi: chạy **một lần** (PowerShell **Admin**), trong thư mục dự án:
+ ```powershell
+ cd "E:\WD\WD-HN"
+ powershell -ExecutionPolicy Bypass -File .\setup-wifi.ps1
+ ```
+ Hoặc lệnh tay (**không** dùng `%USERNAME%` trong PowerShell — sẽ lỗi 1332):
+ ```powershell
+ netsh http add urlacl url=http://+:8080/ user="$env:USERDOMAIN\$env:USERNAME"
+ ```
+ Trong **CMD (Admin)** thì dùng được: `netsh http add urlacl url=http://+:8080/ user=%USERNAME%`
+
## Chạy bằng PowerShell
```powershell
diff --git a/kill-server.ps1 b/kill-server.ps1
new file mode 100644
index 0000000..d630bc2
--- /dev/null
+++ b/kill-server.ps1
@@ -0,0 +1,7 @@
+Get-CimInstance Win32_Process |
+ Where-Object { $_.CommandLine -like '*serve.ps1*' } |
+ ForEach-Object {
+ Write-Host "Dung PID $($_.ProcessId)"
+ Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
+ }
+Start-Sleep -Seconds 2
diff --git a/mo-firewall.bat b/mo-firewall.bat
new file mode 100644
index 0000000..00bd489
--- /dev/null
+++ b/mo-firewall.bat
@@ -0,0 +1,8 @@
+@echo off
+chcp 65001 >nul
+cd /d "%~dp0"
+echo.
+echo Dang mo firewall cong 8080 (can cua so Admin)...
+echo.
+powershell -NoProfile -Command "Start-Process powershell -Verb RunAs -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File \"\"%~dp0setup-wifi.ps1\"\"'"
+timeout /t 3 >nul
diff --git a/restart.bat b/restart.bat
new file mode 100644
index 0000000..0053650
--- /dev/null
+++ b/restart.bat
@@ -0,0 +1,9 @@
+@echo off
+chcp 65001 >nul
+cd /d "%~dp0"
+echo.
+echo Dang dung server cu (neu co)...
+powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0kill-server.ps1"
+echo.
+echo Dang khoi dong lai...
+start "Thiep cuoi" powershell -NoProfile -ExecutionPolicy Bypass -NoExit -File "%~dp0serve.ps1"
diff --git a/serve.ps1 b/serve.ps1
index 21da04a..e6660d5 100644
--- a/serve.ps1
+++ b/serve.ps1
@@ -1,7 +1,9 @@
# Simple static file server for the wedding site (Windows, no Node/Python required)
+# Listens on localhost + LAN IPs so phones on the same WiFi can open the site.
$ErrorActionPreference = "Stop"
$root = $PSScriptRoot
$port = 8080
+$sitePath = "/www.mewedding.vn/index.html"
$mime = @{
".html" = "text/html; charset=utf-8"
@@ -30,71 +32,208 @@ function Get-ContentType([string]$path) {
return "application/octet-stream"
}
-function Send-File([System.Net.HttpListenerContext]$ctx, [string]$filePath) {
- $bytes = [System.IO.File]::ReadAllBytes($filePath)
- $ctx.Response.ContentType = Get-ContentType $filePath
+function Send-File([System.Net.HttpListenerContext]$ctx, [string]$filePath, [string]$extraContentType = $null) {
+ $bytes = if ($extraContentType -eq 'text/html') {
+ $text = [System.IO.File]::ReadAllText($filePath, [Text.UTF8Encoding]::new($false))
+ if ($text -notmatch '
Xác nhận tham dự