Mục tiêu: Xây dựng trang web xem camera IP nội bộ từ xa qua mạng 4G với độ trễ cực thấp (WebRTC), giao diện đáp ứng mọi thiết bị (đặc biệt là tự động xoay ngang trên iPhone), và hạ tầng bảo mật an toàn sau tường lửa FortiGate.

Bước 1: Tối ưu Camera Hikvision và tạo Link RTSP.

Trước khi đụng đến phần mềm hay code, camera của bạn phải phát ra luồng dữ liệu chuẩn để trình duyệt web có thể đọc được.

  1. Dùng trình duyệt đăng nhập vào địa chỉ IP nội bộ của Camera Hikvision (Ví dụ: 172.16.40.10).
  2. Vào Configuration (Cấu hình) -> Video/Audio.
  3. Chỉnh thông số:
    • Video Encoding: Chọn H.264 (Bắt buộc).
    • H.264+ (Smart Codec): Chọn OFF.
    • Lưu lại cài đặt.
  4. Ghi ra giấy đường link RTSP của camera này theo công thức: rtsp://[tên_đăng_nhập]:[mật_khẩu]@[IP_Camera]:554/Streaming/Channels/102 (Ví dụ: rtsp://admin:matkhau123@172.16.40.10:554/Streaming/Channels/102).

Bước 2: Tải phần mềm MediaMTX.

MediaMTX là lõi máy chủ giúp chuyển đổi luồng RTSP (ở Bước 1) sang chuẩn WebRTC siêu tốc.

  1. Lên máy chủ Windows Server của bạn, mở trình duyệt vào trang Github của MediaMTX: https://github.com/bluenviron/mediamtx/releases
  2. Tải bản dành cho Windows (file có đuôi …windows_amd64.zip).
  3. Tạo một thư mục ổ C (Ví dụ: C:\MediaMTX) và giải nén toàn bộ file vừa tải vào đó. Bạn sẽ thấy 2 file quan trọng nhất là mediamtx.exe và mediamtx.yml.

Bước 3: Cấu hình MediaMTX

Bây giờ chúng ta sẽ nạp link camera ở Bước 1 vào MediaMTX.

  1. Mở file mediamtx.yml bằng Notepad.
  2. Tìm dòng webrtcICEHostNAT1To1IPs (nằm ở khoảng giữa file). Xóa dấu # ở đầu dòng và điền địa chỉ IP WAN (IP mặt tiền Internet của nhà bạn, hoặc có thể là domain) vào.
    • Ví dụ: webrtcICEHostNAT1To1IPs: [“sangngnuyen.drayddns.com”]
  3. Cuộn xuống dưới cùng file, tìm mục paths:. Khai báo link camera của bạn vào đây:

YAML

paths:
  cam_noi_bo:
    source: rtsp://admin:matkhau123@192.168.1.10:554/Streaming/Channels/102

    source: rtsp://admin:matkhau123@192.168.1.10:554/Streaming/Channels/102

  1. Lưu file mediamtx.yml lại.
  2. Click đúp chuột chạy file mediamtx.exe. Một cửa sổ màu đen (CMD) hiện lên báo chữ “đang chạy” là thành công. Cứ để cửa sổ đó chạy ngầm.

Bước 4: NAT Port (Modem Draytek và Mở cửa tường lửa).

MediaMTX đã chạy, nhưng nó đang bị nhốt trong mạng nội bộ. Bạn phải đục tường lửa để hình ảnh đi ra ngoài 4G. (Do mình đang sử dụng tường lữa fortinet và Modem draytek nên cần phải Nat port 2 lần).

  1. Truy cập Modem nhà mạng (Viettel/VNPT/FPT):
    1. Mở (NAT/Port Forwarding) cổng 443 (giao thức TCP). Trỏ về IP của FortiGate.
    1. Mở cổng 8189 (giao thức UDP). Trỏ về IP của FortiGate.
  2. Truy cập tường lửa FortiGate:
    1. Tạo Virtual IP (VIP) mở cổng 443 (TCP) trỏ về máy chủ IIS/MediaMTX (Ví dụ: 172.16.10.16).

Tạo Virtual IP mở cổng 8189 (UDP) trỏ về máy chủ IIS/MediaMTX

Bước 5: Cấu hình máy chủ IIS Reverse Proxy.

Đến bước này, bên ngoài đã có thể đâm xuyên tường lửa vào máy chủ qua cổng 443. Giờ ta phải nhờ IIS dẫn đường tiếp.

  1. Mở IIS Manager trên máy chủ. Đảm bảo bạn đã cài chứng chỉ SSL cho tên miền sangnguyen.drayddns.com để chạy HTTPS (Port 443).
  2. Tải và cài đặt 2 module cho IIS: ARR (Application Request Routing) và URL Rewrite.

– Để cài đặt Application Request Routing (ARR) và URL Rewrite trên IIS, bạn phải cài đặt URL Rewrite trước, sau đó mới cài ARR vì ARR yêu cầu các thư viện của module Rewrite để có thể hoạt động.

Do Microsoft hiện đã ngừng hỗ trợ công cụ Web Platform Installer (WebPI), bạn sẽ cần tải và cài đặt trực tiếp qua các file .msi từ trang chủ.

Tải và cài đặt URL Rewrite Module 2.1:Bắt buộc cài đặt trước.

  • Truy cập trang tải xuống chính thức của Microsoft: URL Rewrite Module 2.1.
  • Cuộn trang xuống phần Download URL Rewrite Module 2.1, chọn tải phiên bản x64 (dành cho Windows Server bản 64-bit).
  • Chạy file cài đặt .msi vừa tải về và chọn Next liên tục để hoàn tất.

Tải và cài đặt Application Request Routing (ARR) 3.0:Cài đặt sau URL Rewrite.

  • Truy cập trang Microsoft Download Center: ARR 3.0 (x64).
  • Nhấn nút Download để tải file requestRouter_amd64.msi.
  • Chạy file cài đặt và làm theo trình hướng dẫn trên màn hình.

Mở Command Prompt hoặc PowerShell bằng quyền Quản trị (Run as Administrator) và chạy lệnh sau để buộc IIS nhận diện module vừa cài:

DOS

Iisreset

  • Kích hoạt tính năng Reverse Proxy trên ARR:Cấu hình hệ thống điều hướng.
  • Mở Internet Information Services (IIS) Manager.
  • Ở cột Connections bên trái, nhấp chọn trực tiếp vào tên máy chủ (Server Name) của bạn.
  • Ở khung giữa, tìm và nhấp đúp vào biểu tượng Application Request Routing Cache.
  • Nhìn sang cột Actions bên phải, nhấp vào Server Proxy Settings…
  • Đánh dấu tick vào ô Enable proxy.
  • Nhấn Apply ở cột Actions bên phải để lưu cấu hình.
  1. Cấu hình quy tắc URL Rewrite:
    • Name: Tự đặt tên
    • Pattern: ^(cam_noi_bo|cua_sau|cua_truoc|truoc_cua_kg)(.*) (phần này liên quan chổ file mediamtx.yml của Mediamxt)
    • Rewrite URL: http://172.16.10.16:8889/{R:1}{R:2} (IP máy chủ web)
    • Sau đó bấm Apply.

Bước 6: Đưa code PHP lên Website hiển thị.

Hạ tầng mạng và máy chủ đã xong hoàn toàn. Bước cuối cùng là tạo mặt tiền trang web cho người dùng bấm xem.

  1. Vào thư mục chứa mã nguồn website trên máy chủ IIS (Thường là C:\inetpub\wwwroot hoặc thư mục web bạn tự tạo).
  2. Tạo một file mới tên là xemcamerahik.php.
  3. Copy toàn bộ đoạn code PHP, HTML, CSS (Code bên dưới, Code này gồm có 4 khung camera + bảo mật khi xem ) dán vào file này và lưu lại.
<?php
// ==============================================================================
// PHẦN 1: BẢO MẬT GIAO DIỆN (CHỐNG XEM TRỘM)
// ==============================================================================

// ĐẶT MẬT KHẨU QUẢN TRỊ CỦA BẠN Ở ĐÂY
$password = 'Nhập mk ở đây'; 
$da_dang_nhap = false;

// Kiểm tra xem người dùng đã nhập đúng mật khẩu chưa
if (isset($_POST['mat_khau']) && $_POST['mat_khau'] === $password) {
    $da_dang_nhap = true; // Cho phép đi tiếp nếu đúng
}

// Nếu chưa nhập hoặc nhập sai mật khẩu -> Hiển thị form và khóa các dòng code phía dưới
if (!$da_dang_nhap) {
    echo '
    <!DOCTYPE html>
    <html lang="vi">
    <head>
        <meta charset="UTF-8">
        <title>Hệ Thống An Ninh</title>
        <style>
            /* CSS trang trí cho khung đăng nhập */
            body { font-family: Arial, sans-serif; background: #111; color: #fff; text-align: center; padding-top: 150px; }
            .login-box { background: #222; padding: 30px; border-radius: 8px; border: 2px solid #444; display: inline-block; box-shadow: 0 4px 15px rgba(0,0,0,0.5); }
            input { padding: 10px; width: 200px; border-radius: 4px; border: 1px solid #555; background: #333; color: #fff; outline: none; margin-bottom: 15px; }
            button { padding: 10px 20px; background: #00bcd4; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; }
            button:hover { background: #0097a7; }
        </style>
    </head>
    <body>
        <div class="login-box">
            <h3 style="margin-top:0; color:#00bcd4;">NHẬP MẬT KHẨU QUẢN TRỊ</h3>
            <form method="POST">
                <input type="password" name="mat_khau" placeholder="Mật khẩu..." required autofocus><br>
                <button type="submit">Truy cập Camera</button>
            </form>
        </div>
    </body>
    </html>
    ';
    exit; // Lệnh exit chặn không cho chạy phần load Camera API ở dưới khi chưa có mật khẩu
}
?>

<!-- ĐOẠN SCRIPT XÓA DẤU VẾT: Ép trình duyệt quên mật khẩu ngay sau khi load xong. Nếu ấn F5 là khóa lại ngay -->
<script>
    if (window.history.replaceState) {
        window.history.replaceState(null, null, window.location.href);
    }
</script>
<?php
// ==============================================================================
// PHẦN 2: CẤU HÌNH DATA 4 CAMERA (Chạy bằng MediaMTX)
// ==============================================================================
$camData = [
    [
        'index' => 0, 
        'name' => 'CAMERA HIK NỘI BỘ', 
        'url' => 'https://sangnguyen.drayddns.com/cam_noi_bo/', // Chạy WebRTC
        'error' => ''
    ],
    [
        'index' => 1, 
        'name' => 'CỬA SAU NHÀ HG', 
        'url' => '', // Để trống link tạm thời
        'error' => 'Chờ cấu hình mạng (NAT)'
    ],
    [
        'index' => 2, 
        'name' => 'CỬA TRƯƠC NHÀ HG', 
        'url' => '',
        'error' => 'Chờ cấu hình mạng (NAT)'
    ],
    [
        'index' => 3, 
        'name' => 'TRƯỚC CỬA NHÀ KG', 
        'url' => '',
        'error' => 'Chờ cấu hình mạng (NAT)'
    ]
];
?>

<!DOCTYPE html>
<html lang="vi">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hệ thống Giám sát Đa màn hình</title>
    <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
    <style>
        body { font-family: Arial, sans-serif; background: #111; color: #fff; margin: 0; padding: 10px; text-align: center; }
        h2 { margin-top: 10px; margin-bottom: 15px; color: #00bcd4; text-transform: uppercase; letter-spacing: 1px; }
        .grid-container { display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; max-width: 80%; margin: 0 auto; }
        .cam-box { background: #222; border: 2px solid #444; border-radius: 8px; position: relative; aspect-ratio: 16/9; overflow: hidden; box-shadow: 0 4px 10px rgba(0,0,0,0.5); }
        .cam-name { position: absolute; top: 25px; left: 10px; background: rgba(0,0,0,0.7); color: #fff; padding: 5px 10px; font-size: 14px; font-weight: bold; border-radius: 4px; z-index: 10; }
        video { width: 100%; height: 100%; object-fit: cover; background: #000; }
        .error-msg { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #ff4444; font-size: 14px; width: 80%; }
        @media (max-width: 768px) { .grid-container { grid-template-columns: 1fr; max-width: 95%; } }
        
       /* CSS cho nút bấm phóng to */
        .rotate-btn {
            position: absolute;
            top: 25px; /* Đổi bottom thành top và để 25px cho ngang hàng với tên cam */
            right: 10px; /* Giữ nguyên right để nằm bên phải */
            background: rgba(0, 0, 0, 0.7);
            color: #fff;
            border: 1px solid #444;
            padding: 6px 12px;
            font-size: 14px;
            border-radius: 4px;
            cursor: pointer;
            z-index: 999; 
        }
        .rotate-btn:hover { background: #00bcd4; color: #000; }

        /* CSS đặc trị Fullscreen ngang cho iPhone (dùng dự phòng) */
        .ios-fullscreen {
            position: fixed !important;
            top: 50% !important;
            left: 50% !important;
            width: 100vh !important; 
            height: 100vw !important; 
            transform: translate(-50%, -50%) rotate(90deg) !important;
            z-index: 9999 !important;
            background: #000 !important;
            border: none !important;
            border-radius: 0 !important;
            max-width: none !important;
        }
    </style>
</head>
<body>
    <h2>XEM CAMERA NHÀ ÔNG 6 DŨNG HIHI</h2>
    <div class="grid-container">
        <?php foreach ($camData as $c): ?>
            <div class="cam-box">
                <!-- Chữ tên Cam đã được hạ xuống 25px trong CSS -->
                <div class="cam-name"><?php echo htmlspecialchars($c['name']); ?></div>
                
                <?php if ($c['url']): ?>
                    <!-- Iframe WebRTC (đã bật quyền allowfullscreen) -->
                    <iframe src="<?php echo $c['url']; ?>" width="100%" height="100%" style="border:none; position:absolute; top:0; left:0; z-index: 1;" scrolling="no" allow="fullscreen" allowfullscreen></iframe>
                    
                    <!-- NÚT BẤM PHÓNG TO -->
                    <button class="rotate-btn" onclick="fullScreenLandscape(this)">🔲 Xoay Hình </button>
                    
                <?php else: ?>
                    <div class="error-msg"><?php echo $c['error']; ?></div>
                <?php endif; ?>
            </div>
        <?php endforeach; ?>
    </div>

  <script>
function fullScreenLandscape(btn) {
    let camBox = btn.closest('.cam-box');
    if (!camBox) return;

    // Nhận diện iPhone / iPad
    let isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);

    if (isIOS) {
        // ĐẶC TRỊ IPHONE: Dùng CSS ép khung hình quay ngang 90 độ, phủ kín màn hình
        // Bất chấp điện thoại đang cầm dọc hay bật khóa xoay
        if (camBox.classList.contains('ios-fullscreen')) {
            camBox.classList.remove('ios-fullscreen');
            btn.innerHTML = "🔲 Xoay hình";
        } else {
            camBox.classList.add('ios-fullscreen');
            btn.innerHTML = "❌ Thu nhỏ";
        }
        return; 
    }

    // ==========================================
    // DÀNH CHO ANDROID VÀ MÁY TÍNH (Vẫn chạy Fullscreen chuẩn)
    // ==========================================
    function lockLandscape() {
        if (screen.orientation && screen.orientation.lock) {
            screen.orientation.lock('landscape').catch(e => {});
        }
    }
    
    if (!document.fullscreenElement && !document.webkitFullscreenElement) {
        if (camBox.requestFullscreen) {
            camBox.requestFullscreen().then(lockLandscape).catch(e => {});
        } else if (camBox.webkitRequestFullscreen) {
            camBox.webkitRequestFullscreen();
            lockLandscape();
        }
    } else {
        if (document.exitFullscreen) document.exitFullscreen();
        else if (document.webkitExitFullscreen) document.webkitExitFullscreen();
    }
}
</script>
</body>
</html>

4. Cầm điện thoại, tắt Wifi bật 4G, vào link https://sangnguyen.drayddns.com, nhập mật khẩu đã cấu hình và tận hưởng thành quả!

Leave a Reply

Your email address will not be published. Required fields are marked *

Xin thông báo hiện tại thì chưa có gì để thông báo khi nào có thông báo admin sẽ thông báo sau.