kyoukhana
By:
kyoukhana

enable hotlinking to images css not working

March 10, 2017 492 views
Nginx Ubuntu 16.04

I am trying to figure out how to enable hotlinking on my site in nginx but it doesn't seem to be working. Here is the code for my configuration. I don't want people direct access to .mp3 .jpg

Here is the code below for the configuration

include forge-conf/mydomain.com/before/*;

server {
    listen 80;
    listen [::]:80;
    server_name mydomain.com;
    root /home/forge/mydomain.com/public;

    # FORGE SSL (DO NOT REMOVE!)
    # ssl_certificate;
    # ssl_certificate_key;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
       ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/nginx/dhparams.pem;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm index.php;

    charset utf-8;

    # FORGE CONFIG (DOT NOT REMOVE!)
    include forge-conf/mydomain.com/server/*;

   location / {
       try_files $uri $uri/ /index.php?$query_string;
}




    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/mydomain.com-error.log error;

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
    }

    #Prevent hotlinking
location ~* (\.jpg|\.png|\.css|\.mp3)$ {
    valid_referers blocked mydomain.com www.mydomain.com;
    if ($invalid_referer) {
        return 444;
    }
}


    location ~ /\.ht {
        deny all;
    }
}

# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/mydomain.com/after/*;
12 Answers

@kyoukhana

Instead of this line:

location ~* (\.jpg|\.png|\.css|\.mp3)$ {

Try using:

location ~ .(jpe?g|png|css|mp3)$ {

The above will cover jpeg, jpg, png, css, and mp3. You can extend that list by simply adding a new |ext where ext is the extension of the file without the . or \ used in your current.

I tried that. Didn't work. Here is the configuration.

location ~ .(jpe?g|png|css|mp3)$ {
    valid_referers none blocked mydomain.com www.mydomain.com;
    if ($invalid_referer) {
        return 444; # or 403 Forbidden
    }
}
  • Try this, when you only replace mydomain.com with your real domain:

    location ~ \.(jpe?g|png|gif|css|mp3)$ {
        valid_referers none blocked server_names mydomain.com www.mydomain.com;
        if ($invalid_referer) {
            return 444; # or 403 Forbidden
        }
    }
    
    • Actually try this instead:

      location ~ \.(jpe?g|png|gif|css|mp3)$ {
          valid_referers server_names mydomain.com www.mydomain.com;
          if ($invalid_referer) {
              return 444; # or 403 Forbidden
          }
      }
      
      • I tried that and restarted but nginx didn't like that configuration for some reason

        • If you run the following, it should point in a direction

          tail -20 /var/log/nginx/error.log
          

i got the following error

2017/03/10 20:40:14 [emerg] 1742#1742: conflicting parameter "mydomain.com" in /etc/nginx/sites-enabled/mydomain.com:77

@hansen Here is what is on line 77

location ~ /\.ht {
    deny all;
}
  • I think your configuration has changed since (and you pasted 3 lines), so run the following to test the configuration again and it should tell you about problems.
    nginx -t

Here is the full configuration when i run nginx -t i get the following error

[emerg] conflicting parameter "mydomain.com" in /etc/nginx/nginx.conf:64

Line 64 is this

fastcgireadtimeout 300;

# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/mydomain.com/before/*;

server {
    listen 80;
    listen [::]:80;
    server_name mydomain.com;
    root /home/forge/mydomain.com/public;

    # FORGE SSL (DO NOT REMOVE!)
    # ssl_certificate;
    # ssl_certificate_key;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/nginx/dhparams.pem;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm index.php;

    charset utf-8;

    # FORGE CONFIG (DOT NOT REMOVE!)
    include forge-conf/mydomain.com/server/*;

   location / {
       try_files $uri $uri/ /index.php?$query_string;
}




    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/mydomain.com-error.log error;

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
    }





## Deny certain Referers (case insensitive)
    ## The ~* makes it case insensitive as opposed to just a ~
 if ($http_referer ~* (babes|click|diamond|forsale|girl|jewelry|love|nudit|organic|poker|porn|poweroversoftware|sex|teen|video|webcam|zippo))
    {  return 403;   }




location ~ /\.ht {
    deny all;
}

location ~ \.(jpe?g|png|gif|css|mp3)$ {
    valid_referers server_names mydomain.com www.mydomain.com;
    if ($invalid_referer) {
        return 444; # or 403 Forbidden
    }
}


}

# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/mydomain.com/after/*;

  • Sorry @kyoukhana I didn't see your post. Just add a @hansen and it'll notify me.

    Unless something has changed, then run this command to list all configurations of Nginx, but only show specifically line 64.

    nginx -T | awk 'FNR>=64 && FNR<=64'
    

Thanks for the help so i got the following after running the command

nginx -T | awk 'FNR>=64 && FNR<=64'
nginx: [emerg] conflicting parameter "mydomain.com" in /etc/nginx/nginx.conf:64
nginx: configuration file /etc/nginx/nginx.conf test failed
  • @kyoukhana You forgot the @hansen so I don't get notified.

    You probably need to all your entire Nginx configuration, cause I simply don't know where it fails.
    Just run nginx -T or at least the entire nginx.conf and copy+paste everything into a code block here.

Hi @hansen here is my entire configuration file. When I ran nginx -T i get the following error

[emerg] conflicting parameter "restorechi.com" in /etc/nginx/nginx.conf:64
nginx: configuration file /etc/nginx/nginx.conf test failed
Here is the entire configuration file
# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/mydomain.com/before/*;

server {
    listen 80;
    listen [::]:80;
    server_name mydomain.com;
    root /home/forge/mydomain.com/public;

    # FORGE SSL (DO NOT REMOVE!)
    # ssl_certificate;
    # ssl_certificate_key;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers '';
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/nginx/dhparams.pem;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm index.php;

    charset utf-8;

    # FORGE CONFIG (DOT NOT REMOVE!)
    include forge-conf/mydomain.com/server/*;

   location / {
       try_files $uri $uri/ /index.php?$query_string;
}




    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/mydomain.com-error.log error;

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
    }





## Deny certain Referers (case insensitive)
    ## The ~* makes it case insensitive as opposed to just a ~
 if ($http_referer ~* (babes|click|diamond|forsale|girl|jewelry|love|nudit|organic|poker|porn|poweroversoftware|sex|teen|video|webcam|zippo))
    {  return 403;   }

###
location ~ \.(jpe?g|png|gif|css|mp3)$ {
    valid_referers server_names mydomain.com www.mydomain.com;
    if ($invalid_referer) {
        return 444; # or 403 Forbidden
    }
}
###


location ~ /\.ht {
    deny all;
}



}

# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/mydomain.com/after/*;

@kyoukhana

I'm not 100% familiar with how Forge sets up configuration, though normally, anything included before or after a server block is included in the global http block, so the include blocks before and after:

include forge-conf/mydomain.com/before/*;
include forge-conf/mydomain.com/after/*;

... may be redundant or may need to be included within the server block. That said, since this block is listening on port 80, there's no need for the SSL directives to exist unless this is just a portion of the configuration. SSL doesn't work on port 80, thus that configuration should be removed. You need to be listening on port 443 if you're going to set SSL directives.

So to start, we should remove:

    # FORGE SSL (DO NOT REMOVE!)
    # ssl_certificate;
    # ssl_certificate_key;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers '';
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/nginx/dhparams.pem;

I would also recommend stripping down your server block to the basics and then adding each block back until we see where the error is coming from since it's not 100% clear right now.

One thing to keep in mind is that NGINX reports the error on the line after all include have been processed. So when you run nginx -t and it says there's an issue on line 64, line 64 doesn't mean line 64 of your configuration as you see it, it means line 64 of the complete configuration, after all include have been processed.

So to truly find line 64, you'd need to paste all of the configuration together as a single block.

Don't get me wrong, I too break down my configuration files, sometimes it's the only way to keep the files clean, so what they and you are doing isn't wrong at all, but it does make troubleshooting a bit harder since the line being referenced most likely resides inside one of the included files.

That said, I'd backup your server block, and the replace it with the following, which is a very stripped down version of your current.

server {
    listen 80;
    listen [::]:80;
    server_name mydomain.com;
    root /home/forge/mydomain.com/public;

    access_log off;
    error_log  /var/log/nginx/mydomain.com-error.log error;

    error_page 404 /index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
    }
}

.. then service nginx reload or:

nginx -t \
&& nginx -s reload

Let's see if that works. If it does, we can piece the server block back together little by little.

@jtittle @hansen So I changed the configuration like this. I got a error

Command
nginx -t
Error
nginx: [emerg] conflicting parameter "restorechi.com" in /etc/nginx/nginx.conf:64
nginx: configuration file /etc/nginx/nginx.conf test failed
Nginx Configuration
server {
    listen 80;
    listen [::]:80;
    server_name mydomain.com;
    root /home/forge/mydomain.com/public;

    access_log off;
    error_log  /var/log/nginx/mydomain.com-error.log error;

     index index.html index.htm index.php;

    charset utf-8;





    error_page 404 /index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
    }



    ###
location ~ \.(jpe?g|png|gif|css|mp3)$ {
    valid_referers server_names mydomain.com www.mydomain.com;
    if ($invalid_referer) {
        return 444; # or 403 Forbidden
    }
}
###


}

@kyoukhana

If the error is pointing to another domain, then we'd need to look at the other domains' server blocks too and potentially set them up in the same minimalistic format -- then add blocks one by one as it's hard to tell without seeing 100% of your configuration, as in all server blocks, all included files, etc.

@jtittle @hansen Ok so here is something interesting this didn't give me any errors. But I can still grab my images from another domain.

# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/mydomain.com/before/*;

server {
    listen 80;
    listen [::]:80;
    server_name mydomain.com;
    root /home/forge/mydomain.com/public;

    # FORGE SSL (DO NOT REMOVE!)
    # ssl_certificate;
    # ssl_certificate_key;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers '';
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/nginx/dhparams.pem;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm index.php;

    charset utf-8;

    # FORGE CONFIG (DOT NOT REMOVE!)
    include forge-conf/mydomain.com/server/*;

   location / {
       try_files $uri $uri/ /index.php?$query_string;
}




    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/mydomain.com-error.log error;

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
    }



location ~ .(gif|png|jpe?g)$ {
    valid_referers blocked mydomain.com www.mydomain.com;
    if ($invalid_referer) {
        return 403;
    }
}




## Deny certain Referers (case insensitive)
    ## The ~* makes it case insensitive as opposed to just a ~
 if ($http_referer ~* (babes|click|diamond|forsale|girl|jewelry|love|nudit|organic|poker|porn|poweroversoftware|sex|teen|video|webcam|zippo))
    {  return 403;   }




location ~ /\.ht {
    deny all;
}



}

# FORGE CONFIG (DOT NOT REMOVE!)
include forge-conf/mydomain.com/after/*;
  • @kyoukhana
    Okay, so what did you change, since it now works?
    And what is Forge? Is that some configuration tool? If yes, then you need to use that tool, since that might be replacing changes done directly in the configuration files.

    You still have two location ~ \.php$ sections. You should only have one.

    And the referral blocking section should still look like this, where you of course replace mydomain.com with whatever is your actual domain:

    location ~ \.(jpe?g|png|gif|css|mp3)$ {
        valid_referers server_names mydomain.com www.mydomain.com;
        if ($invalid_referer) {
            return 444; # or 403 Forbidden
        }
    }
    
  • @kyoukhana And it seems like you have both php7.0 and php7.1 installed. You only want one of those, probably php7.1

Just php 7.1 want installed. I am using Laravel Forge. But I solved the issue. The code was working just takes time for it to initialize. I just got back to it the other day. Thanks for all the help

Have another answer? Share your knowledge.