Make your own mp4 Pull CDN with VPS

      No Comments on Make your own mp4 Pull CDN with VPS

Before post we test and working good for me.

A Pull CDN (Content Delivery Network) is a type of CDN configuration where content is fetched (“pulled”) from the origin server only when a request is made for that content. Here’s how it works:

1. **Initial Request**: When a user makes a request for content, the CDN checks if it has the requested content in its cache.
2. **Cache Miss**: If the content is not in the CDN’s cache (a “cache miss”), the CDN retrieves the content from the origin server.
3. **Cache Storage**: The CDN then caches this content in its local servers (or edge servers) distributed across various geographical locations.
4. **Subsequent Requests**: For subsequent requests for the same content, the CDN serves the content directly from its cache, reducing the load on the origin server and improving the content delivery speed to the end-user.

 Key Benefits of a Pull CDN:
– **Reduced Load on Origin Server**: Since the CDN caches and serves content, it reduces the number of requests hitting the origin server.
– **Improved Load Times**: By serving content from geographically closer edge servers, the CDN can significantly reduce the latency and improve load times for users.
– **Scalability**: A pull CDN can easily handle spikes in traffic by distributing the load across multiple edge servers.
– **Ease of Use**: Content is automatically cached without needing to manually push updates to the CDN.

How to Implement a Pull CDN:
1. **Set Up CDN Edge Servers**: Deploy CDN servers in various geographical locations.
2. **Configure Origin Server**: Ensure your origin server is set up to handle initial requests and has the necessary bandwidth.
3. **CDN Configuration**: Configure the CDN to pull content from the origin server upon request. This typically involves setting up the correct DNS settings and defining caching rules.
4. **Define Cache Expiry Rules**: Set rules for how long content should be cached before it is considered stale and needs to be re-fetched from the origin server.
5. **Monitor and Optimize**: Continuously monitor the performance and adjust caching rules and server configurations to optimize delivery.

Would you like more details on setting up your own pull CDN or specific examples of configurations?

 

We need:

First we need 5X vps

3x for vps for mp4 file delivery

1x for managed database

1x for storage mp4 file

Geo dns like cloudns  or cloudflare round-robin load balancing

Setup:

Make a database like that


CREATE TABLE file_cache (
    id INT AUTO_INCREMENT PRIMARY KEY,
    file_name VARCHAR(255) NOT NULL,
    last_access_time DATETIME NOT NULL
);

 

Here is nginx config


location / {
        try_files $uri /handler.php?file=$uri;
    }

location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/tmp/php-cgi-7.4.sock; # Update to match your PHP version and socket
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

 

here is handler.php


php
$storageServer = 'origin url here';
$cacheDir = 'path';
$expiryHours = 24;

function getDatabaseConnection() {
    $dsn = 'mysql:host=localhost;dbname=;charset=utf8';
    $username = '';
    $password = '';

    try {
        $pdo = new PDO($dsn, $username, $password);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $pdo;
    } catch (PDOException $e) {
        die("Database connection failed: " . $e->getMessage());
    }
}

function updateLastAccessTime($fileName) {
    $pdo = getDatabaseConnection();
    $stmt = $pdo->prepare("INSERT INTO file_cache (file_name, last_access_time) VALUES (:file_name, NOW()) ON DUPLICATE KEY UPDATE last_access_time = NOW()");
    $stmt->execute(['file_name' => $fileName]);
}

function logDebug($message) {
    error_log($message . PHP_EOL, 3, '/root/files/debug.log');
}

function serveFile($filePath) {
    if (!file_exists($filePath)) {
        http_response_code(404);
        echo "File not found.";
        logDebug("File not found: $filePath");
        exit;
    }

    $size = filesize($filePath);
    $length = $size;
    $start = 0;
    $end = $size - 1;

    header('Content-Type: video/mp4');
    header('Content-Disposition: inline; filename="' . basename($filePath) . '"');
    header('Accept-Ranges: bytes');

    if (isset($_SERVER['HTTP_RANGE'])) {
        $range = $_SERVER['HTTP_RANGE'];
        list(, $range) = explode('=', $range, 2);
        if (strpos($range, ',') !== false) {
            header('HTTP/1.1 416 Requested Range Not Satisfiable');
            header("Content-Range: bytes */$size");
            logDebug("Invalid range: $range");
            exit;
        }

        $range = explode('-', $range);
        $start = intval($range[0]);
        $end = ($range[1] && is_numeric($range[1])) ? intval($range[1]) : $size - 1;

        if ($start > $end || $start > $size - 1 || $end >= $size) {
            header('HTTP/1.1 416 Requested Range Not Satisfiable');
            header("Content-Range: bytes */$size");
            logDebug("Invalid range start-end: $start-$end");
            exit;
        }

        $length = $end - $start + 1;
        header('HTTP/1.1 206 Partial Content');
        header("Content-Range: bytes $start-$end/$size");
        header("Content-Length: $length");
        logDebug("Serving range: $start-$end of $filePath");
        $fp = fopen($filePath, 'rb');
        fseek($fp, $start);
        $bufferSize = 8192;
        while (!feof($fp) && ($p = ftell($fp)) <= $end) { if ($p + $bufferSize > $end) {
                $bufferSize = $end - $p + 1;
            }
            echo fread($fp, $bufferSize);
            flush();
        }
        fclose($fp);
    } else {
        header("Content-Length: $size");
        logDebug("Serving full file: $filePath");
        readfile($filePath);
    }
    updateLastAccessTime(basename($filePath));
    exit;
}

function downloadFile($remoteFile, $localFile) {
    logDebug("Downloading file: $remoteFile to $localFile");
    file_put_contents($localFile, fopen($remoteFile, 'r'));
    return file_exists($localFile);
}

$fileName = basename($_GET['file']);
$cachedFile = $cacheDir . $fileName;

if (file_exists($cachedFile)) {
    serveFile($cachedFile);
} else {
    $remoteFile = $storageServer . $fileName;
    if (downloadFile($remoteFile, $cachedFile)) {
        serveFile($cachedFile);
    } else {
        http_response_code(500);
        echo "Error downloading file.";
        logDebug("Error downloading file: $remoteFile");
    }
}
delete_old_files.php

$cacheDir = 'path';
$expiryHours = 24;

function getDatabaseConnection() {
    $dsn = 'mysql:host=localhost;dbname=your_db;charset=utf8';
    $username = 'your_username';
    $password = 'your_password';

    try {
        $pdo = new PDO($dsn, $username, $password);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $pdo;
    } catch (PDOException $e) {
        die("Database connection failed: " . $e->getMessage());
    }
}

function deleteExpiredFiles() {
    global $cacheDir, $expiryHours;
    $pdo = getDatabaseConnection();
    $expiryTime = date('Y-m-d H:i:s', strtotime("-$expiryHours hours"));
    $stmt = $pdo->prepare("SELECT file_name FROM file_cache WHERE last_access_time < :expiry_time"); $stmt->execute(['expiry_time' => $expiryTime]);
    $files = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($files as $file) {
        $filePath = $cacheDir . $file['file_name'];
        if (file_exists($filePath)) {
            unlink($filePath);
        }
    }

    $stmt = $pdo->prepare("DELETE FROM file_cache WHERE last_access_time < :expiry_time"); $stmt->execute(['expiry_time' => $expiryTime]);
}

// Run the deletion process
deleteExpiredFiles();

How it work:.

When call a file the handler check the file in Cdn and if not exists it download from your origin and serve it .From next file serve if from cdn .By delete_old_files.php file will be removed after x time last usage.

Leave a Reply

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