Skip to content

Instantly share code, notes, and snippets.

@goregrish
Last active June 15, 2025 12:58
Show Gist options
  • Select an option

  • Save goregrish/a169b0a72fcc7c30d374d1a2f8a772d2 to your computer and use it in GitHub Desktop.

Select an option

Save goregrish/a169b0a72fcc7c30d374d1a2f8a772d2 to your computer and use it in GitHub Desktop.

Revisions

  1. goregrish revised this gist Jun 15, 2025. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion secure_link.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    ## Nginx ngx_http_secure_link_module and PHP
    ## How to use Nginx ngx_http_secure_link_module and PHP

    Three example nginx locations and the PHP required for mp4 secure_links.
    ```
  2. goregrish revised this gist Jun 15, 2025. No changes.
  3. goregrish revised this gist Apr 5, 2021. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions secure_link.md
    Original file line number Diff line number Diff line change
    @@ -22,7 +22,7 @@ secure_link_md5 "$secure_link_expires$uri$remote_addr secretword";
    if ($secure_link = "0") { return 410; } # deny expired links
    }
    ```
    #### or use
    #### or use option (2)

    ```
    # works
    @@ -35,7 +35,7 @@ location ~ \.(mp3|mp4) {
    }
    ```

    #### or use
    #### or use option (3)

    ```
    # works
    @@ -48,7 +48,7 @@ location ^~ /data/videos {
    }
    ```

    #### optional way of handling status errors, 404 it all
    #### another optional way of handling status errors, 404 it all

    ```
    location ~ \.mp4$ {
  4. goregrish revised this gist Apr 5, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions secure_link.md
    Original file line number Diff line number Diff line change
    @@ -99,7 +99,7 @@ server {
    listen 443 ssl;
    server_name www.mydomain.com;
    # managed by Certbot SSL certs
    include snippets/orgssl.conf;
    include snippets/ssl.conf;
    return 301 https://mydomain.com$request_uri;
    }
    @@ -113,7 +113,7 @@ server {
    access_log off;
    # managed by Certbot SSL certs
    include snippets/orgssl.conf;
    include snippets/ssl.conf;
    root /srv/www/webroot;
    index index.php index.html;
  5. goregrish revised this gist Apr 5, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion secure_link.md
    Original file line number Diff line number Diff line change
    @@ -81,7 +81,7 @@ $path = '/data/videos/file.mp4'; // path to your mp4 file
    $ttl = 15; // IMPORTANT: ttl 15 seconds for testing the expires!!!
    // 3600 seconds equals 1 hour, change as you require it
    $userIp = $_SERVER["HTTP_CF_CONNECTING_IP"]; // if behind cloudflare nginx & CF https://tinyurl.com/58h3s3et
    // normally you would read this from something like $_SERVER['REMOTE_ADDR'];
    // normally from something like $_SERVER['REMOTE_ADDR'];
    echo $vidurl = buildSecureLink($baseUrl, $path, $secret, $ttl, $userIp); // link built
    ```
  6. goregrish revised this gist Apr 5, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion secure_link.md
    Original file line number Diff line number Diff line change
    @@ -80,7 +80,7 @@ $baseUrl = 'https://mydomain.com'; // no trailing slash
    $path = '/data/videos/file.mp4'; // path to your mp4 file
    $ttl = 15; // IMPORTANT: ttl 15 seconds for testing the expires!!!
    // 3600 seconds equals 1 hour, change as you require it
    $userIp = $_SERVER["HTTP_CF_CONNECTING_IP"]; // if behind cloudflare
    $userIp = $_SERVER["HTTP_CF_CONNECTING_IP"]; // if behind cloudflare nginx & CF https://tinyurl.com/58h3s3et
    // normally you would read this from something like $_SERVER['REMOTE_ADDR'];
    echo $vidurl = buildSecureLink($baseUrl, $path, $secret, $ttl, $userIp); // link built
  7. goregrish revised this gist Apr 5, 2021. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions secure_link.md
    Original file line number Diff line number Diff line change
    @@ -81,6 +81,7 @@ $path = '/data/videos/file.mp4'; // path to your mp4 file
    $ttl = 15; // IMPORTANT: ttl 15 seconds for testing the expires!!!
    // 3600 seconds equals 1 hour, change as you require it
    $userIp = $_SERVER["HTTP_CF_CONNECTING_IP"]; // if behind cloudflare
    // normally you would read this from something like $_SERVER['REMOTE_ADDR'];
    echo $vidurl = buildSecureLink($baseUrl, $path, $secret, $ttl, $userIp); // link built
    ```
  8. goregrish revised this gist Apr 5, 2021. No changes.
  9. goregrish revised this gist Apr 5, 2021. 1 changed file with 156 additions and 1 deletion.
    157 changes: 156 additions & 1 deletion secure_link.md
    Original file line number Diff line number Diff line change
    @@ -1 +1,156 @@
    --tba--
    ## Nginx ngx_http_secure_link_module and PHP

    Three example nginx locations and the PHP required for mp4 secure_links.
    ```
    before: https://https://mydomain.com/data/videos/file.mp4
    after : https://mydomain.com/data/videos/file.mp4?md5=Vtzs2WCnCqRsE47EH6U6pQ&expires=1617601227
    ```
    make sure the secret password you use match in both lines below
    ```
    $remote_addr secretword << in nginx config section
    $secret = 'secretword'; << in PHP file
    ```

    #### nginx location

    ```
    # works
    location ~ \.mp4$ {
    secure_link $arg_md5,$arg_expires;
    secure_link_md5 "$secure_link_expires$uri$remote_addr secretword";
    if ($secure_link = "") { return 403; } # deny direct links
    if ($secure_link = "0") { return 410; } # deny expired links
    }
    ```
    #### or use

    ```
    # works
    location ~ \.(mp3|mp4) {
    root /srv/www/webroot;
    secure_link $arg_md5,$arg_expires;
    secure_link_md5 "$secure_link_expires$uri$remote_addr secretword";
    if ($secure_link = "") { return 403; }
    if ($secure_link = "0") { return 410; }
    }
    ```

    #### or use

    ```
    # works
    location ^~ /data/videos {
    alias /srv/www/webroot/data/videos;
    secure_link $arg_md5,$arg_expires;
    secure_link_md5 "$secure_link_expires$uri$remote_addr secretword";
    if ($secure_link = "") { return 403; }
    if ($secure_link = "0") { return 410; }
    }
    ```

    #### optional way of handling status errors, 404 it all

    ```
    location ~ \.mp4$ {
    secure_link $arg_md5,$arg_expires;
    secure_link_md5 "$secure_link_expires$uri$remote_addr secretword";
    # In production environment, we should not reveal to potential attacker
    # why authentication has failed
    if ($secure_link != "1") {
    return 404;
    }
    }
    ```
    #### secure_links.php will build and echo the expires URL

    ```
    <?php
    function buildSecureLink($baseUrl, $path, $secret, $ttl, $userIp)
    {
    $expires = time() + $ttl;
    $md5 = md5("$expires$path$userIp $secret", true);
    $md5 = base64_encode($md5);
    $md5 = strtr($md5, '+/', '-_');
    $md5 = str_replace('=', '', $md5);
    return $baseUrl . $path . '?md5=' . $md5 . '&expires=' . $expires;
    }
    $secret = 'secretword'; // matches with nginx config
    $baseUrl = 'https://mydomain.com'; // no trailing slash
    $path = '/data/videos/file.mp4'; // path to your mp4 file
    $ttl = 15; // IMPORTANT: ttl 15 seconds for testing the expires!!!
    // 3600 seconds equals 1 hour, change as you require it
    $userIp = $_SERVER["HTTP_CF_CONNECTING_IP"]; // if behind cloudflare
    echo $vidurl = buildSecureLink($baseUrl, $path, $secret, $ttl, $userIp); // link built
    ```

    #### full domain.conf example

    ```
    server {
    listen 80;
    server_name www.mydomain.com mydomain.com;
    return 301 https://mydomain.com$request_uri;
    }
    server {
    listen 443 ssl;
    server_name www.mydomain.com;
    # managed by Certbot SSL certs
    include snippets/orgssl.conf;
    return 301 https://mydomain.com$request_uri;
    }
    # above redirects unsecure and www. to https://mydomain.com
    server {
    listen [::]:443 ssl; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    server_name mydomain.com;
    error_log /var/log/nginx/mydomain.log warn;
    access_log off;
    # managed by Certbot SSL certs
    include snippets/orgssl.conf;
    root /srv/www/webroot;
    index index.php index.html;
    location / {
    try_files $uri $uri/ /index.php?$args;
    }
    # secure_links for videos
    location ^~ /data/videos {
    alias /srv/www/webroot/data/videos;
    secure_link $arg_md5,$arg_expires;
    secure_link_md5 "$secure_link_expires$uri$remote_addr secretword";
    if ($secure_link = "") { return 403; }
    if ($secure_link = "0") { return 410; }
    }
    # handling of the request
    location ~ [^/]\.php(/|$) {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    if (!-f $document_root$fastcgi_script_name) {
    return 404;
    }
    # Mitigate https://httpoxy.org/ vulnerabilities
    fastcgi_param HTTP_PROXY "";
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    # include the fastcgi_param setting
    include fastcgi_params;
    # SCRIPT_FILENAME parameter is used for PHP FPM determining
    # the script name. If it is not set in fastcgi_params file,
    # i.e. /etc/nginx/fastcgi_params or in the parent contexts,
    # please comment off following line:
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    }
    ```
  10. goregrish renamed this gist Apr 5, 2021. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  11. goregrish created this gist Apr 5, 2021.
    1 change: 1 addition & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    --tba--