6

I was using this block for redirecting the website's IP to the actual URL:

# IP to domain redirect
server {
        # tell on which port this server listens
        listen [::]:80;
        listen 80;

        # listen on the IP
        server_name xx.xx.xx.xxx;

        # and redirect to the domain
        return 301 $scheme://example.com$request_uri;
}

However I decided to remove it but the redirection doesn't go away. I'm aware that my browser had already hard-cached that redirection and I won't see the change so I used curl -I xx.xx.xx.xxx via SSH to see the response, where xx.xx.xx.xxx is the server's Public IP:

HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Tue, 10 Jan 2017 14:06:01 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: http://example.com/
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-UA-Compatible: IE=Edge

As you can see the redirection is still there. In addition I pinged the IP from third party sources and they confirm that the 301 redirect is there. So I'm really confused how is this possible when there's no redirection rule at all.

Other things I've done:

  • I've checked my iptables and there are no PREROUTING chains of any kind.
  • I didn't forget to restart Nginx and I even rebooted the server.
  • Since I'm using FastCGI Caching I've purged the whole FastCGI Nginx cache.
  • Since the server is behind CloudFlare I've purged the whole cache on their end too. But it is obvious that the above 301 response is not coming from CloudFlare because they set easily recognizable headers and those are not theirs.

Here's the Nginx conf. Obviously in production this block is segmented in several files but for the purpose of this question I paste it in one block.

user www-data;
worker_processes 4;
pid /run/nginx.pid;

events {
        worker_connections 1024;
        multi_accept on;
}

worker_rlimit_nofile 10000;

http {
        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;

        client_body_timeout 12;
        client_header_timeout 12;
        keepalive_timeout 15;
        send_timeout 10;

        open_file_cache          max=10000 inactive=5m;
        open_file_cache_valid    2m;
        open_file_cache_min_uses 1;
        open_file_cache_errors   on;

        types_hash_max_size 2048;
        server_tokens off;

        server_names_hash_bucket_size 64;
        server_name_in_redirect off;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # Logging Settings
        ##

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        ##
        # Gzip Settings
        ##

        gzip on;
        gzip_disable "msie6";

        gzip_vary on;
        gzip_proxied any;
        gzip_comp_level 6;
        gzip_min_length 256;
        gzip_buffers 16 8k;
        gzip_http_version 1.1;
        gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

        ##
        # Virtual Host Configs
        ##

        fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:800m inactive=4h;
        fastcgi_cache_key "$scheme$request_method$host$request_uri";
        fastcgi_cache_use_stale error timeout invalid_header http_500;
        fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
        add_header X-Cache $upstream_cache_status;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        add_header "X-UA-Compatible" "IE=Edge";

        # www to non-www redirect
        server {
                # don't forget to tell on which port this server listens
                listen [::]:80;
                listen 80;

                # listen on the 'www' host
                server_name www.example.com;

                # and redirect to the non-www host (declared below)
                return 301 $scheme://example.com$request_uri;
        }

        # Begin the server config
        server {
                listen [::]:80;
                listen 80;

                # The host name to respond to
                server_name example.com;

                # The location of access and error logs (symlinked to /var/www/example.com/logs/)
                access_log /var/log/nginx/example.com.access.log;
                error_log /var/log/nginx/example.com.error.log;

                # Root for static files
                root /var/www/example.com/htdocs;
                index index.php index.html index.htm;

                # Find and replace CDN urls
                subs_filter example.com/wp-content/uploads/         cdn.example.com/wp-content/uploads/;
                subs_filter example.com/wp-content/themes/          cdn.example.com/wp-content/themes/;
                subs_filter example.com/wp-content/plugins/         cdn.example.com/wp-content/plugins/;
                subs_filter example.com/apple-touch-icon.png        cdn.example.com/apple-touch-icon.png;

                # Cache every page
                set $skip_cache 0;

                # POST requests and urls with a query string should always go to PHP
                if ($request_method = POST) {
                        set $skip_cache 1;
                }

                # Don't cache queries
                if ($query_string) {
                        set $skip_cache 1;
                }

                # Cache only these queries
                if ($query_string ~* "orderby|r_sortby|results") {
                        set $skip_cache 0;
                }

                # Don't cache uris containing the following segments
                if ($request_uri ~* "/wp-admin/|/xmlrpc.php|/opcache.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
                        set $skip_cache 1;
                }

                # Don't use the cache for logged in users or recent commenters
                if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
                        set $skip_cache 1;
                }

                # Don't log robots.txt and favicon.ico
                location ~ /(robots.txt|favicon.ico) { 
                        access_log off; 
                        log_not_found off; 
                }

                # Prevent clients from accessing hidden files (starting with a dot) - .htaccess or .htpasswd
                location ~ /\. { 
                        deny all; 
                        access_log off; 
                        log_not_found off; 
                }

                # Prevent clients from accessing backup/config/source files
                location ~* (?:\.(?:bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)|~)$ { 
                        deny all; 
                        access_log off;
                        log_not_found off;
                }

                # Don't allow access to files in /wp-admin/includes folder
                location ~* /wp-admin/includes { 
                        deny all;
                        access_log off;
                        log_not_found off;
                }

                # Don't allow php execution in wp-includes folder
                location ~* /wp-includes/.*.php$ {
                        deny all;
                        access_log off;
                        log_not_found off;
                }

                # Don't allow php execution in wp-content folder
                location ~* /wp-content/.*.php$ {
                        deny all;
                        access_log off;
                        log_not_found off;
                }

                # Don't allow php execution in uploads and files folders
                location ~* /(?:uploads|files)/.*\.php$ { 
                        deny all; 
                        access_log off;
                        log_not_found off;
                }

                # Deny access to XML-RPC requests
                # location = /xmlrpc.php {
                #       deny all;
                #       access_log off;
                #       log_not_found off;
                # }

                # Deny access to sensitive files
                location ~ /(wp-config.php|install.php|readme.html|licence.txt) { 
                        deny all;
                        access_log off;
                        log_not_found off;
                }

                # Redirect feed to FeedBurner
                if ($http_user_agent !~ "FeedBurner|FeedValidator") {
                        rewrite ^/feed/?.*$ http://feeds.example.com/example redirect;
                }

                # Strip/Redirect these queries
                if ($query_string ~* "fb_xd_fragment|fb_action_ids|iframe") {
                        rewrite ^(.*)$ $1? redirect;
                }

                rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.xml$ "/index.php?xml_sitemap=params=$2" last;
                rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.xml\.gz$ "/index.php?xml_sitemap=params=$2;zip=true" last;
                rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.html$ "/index.php?xml_sitemap=params=$2;html=true" last;
                rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.html.gz$ "/index.php?xml_sitemap=params=$2;html=true;zip=true" last;

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

                location ~ \.php$ {
                        # try_files $uri =404;
                        # try_files $uri =404 /index.php?$args;
                        try_files $uri /index.php?$args;
                        fastcgi_split_path_info ^(.+\.php)(/.+)$;

                        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
                        include fastcgi_params;

                        # Combat (110: Connection timed out) while reading response header from upstream
                        fastcgi_read_timeout 120;

                        fastcgi_cache_bypass $skip_cache;
                        fastcgi_no_cache $skip_cache;

                        fastcgi_cache WORDPRESS;
                        fastcgi_cache_valid 4h;

                        # combat error 'upstream sent too big header...' 
                        fastcgi_buffers 32 64k;
                        fastcgi_buffer_size 64k;
                }

                # Purge ULR only within localhost
                location ~ /purge(/.*) {
                        allow 127.0.0.1;
                        deny all;
                        fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1";
                }       

                # cache.appcache, your document html and data
                location ~* \.(?:manifest|appcache|html?|xml|json)$ {
                        expires -1;
                }

                # Feed
                location ~* \.(?:rss|atom)$ {
                        add_header Pragma public;
                        add_header Cache-Control "public";
                        expires 4h;
                }

                # Media: images, icons, video, audio, HTC, CSS, Javascript, and WebFonts
                location ~ \.(css|js|htc|ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
                        access_log off;
                        log_not_found off;
                        add_header Pragma public;
                        add_header Cache-Control "public";
                        expires max;
                }
        }

        server {
                listen 127.0.0.1:80;
                server_name 127.0.0.1;
                location /nginx_status {
                        stub_status on;
                        access_log off;
                        allow 127.0.0.1;
                        deny all;
                }
        }
}

I've also done curl -I 127.1and the response is the following:

HTTP/1.1 200 OK
Server: nginx
Date: Wed, 11 Jan 2017 14:09:08 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 Apr 2016 13:31:19 GMT
Connection: keep-alive
Vary: Accept-Encoding
ETag: "571f6da7-264"
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-UA-Compatible: IE=Edge
Accept-Ranges: bytes

# Test 1: See what happens when you delete 301 directive for other URLs

  1. I've redirected one non-existent test URL to a real URL via Nginx conf. I reloaded Nginx. I visited the test URL and by doing that I cached the redirection into the browser and thus probably at CloudFlare and FastCGI Cache (that is if FastCGI even caches redirection). After that I curl-ed that test URL from SSH and got 301 response. Now I got one example of a solid redirection.

  2. Then I removed the redirection from Nginx conf, reloaded Nginx and visited the test URL via browser. Redirection is still there. However when I curl-ed the test URL via SSH I got no redirection but proper 404 Not Found status. Redirection at Nginx server level was gone after removing the redirection code from the nginx conf.

# Test 2: Change public IP redirection to 302

I moved back the IP-to-domain redirection directive to Nginx conf but this time with return 302.

# IP to domain redirect
server {
        # tell on which port this server listens
        listen [::]:80;
        listen 80;

        # listen on the IP
        server_name xx.xx.xx.xxx;

        # and redirect to the domain
        return 302 $scheme://example.com$request_uri;
}

I've reloaded Nginx and curl-ed the IP. I was surprised to see 302 Moved Temporarily response:

HTTP/1.1 302 Moved Temporarily
Server: nginx
Date: Thu, 12 Jan 2017 14:46:49 GMT
Content-Type: text/html
Content-Length: 154
Connection: keep-alive
Location: http://example.com/
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-UA-Compatible: IE=Edge

After removing this very same directive altogether and reloading Nginx the response via CURL is back to 301 Moved Permanently.

This test tells me that the problem is probably not a caching issue. It MUST be some other rule somewhere in the conf files or the server's architecture in general that makes the public IP to 301 redirect to the domain.

# Test 3: Put site into development mode at CloudFlare and purge all the cache.

I've put the site into development mode at CF and I've purged everything. I've done curl from both the local machine on the same network and from my PC at home. The response in both cases was 301.

# Test 4: Check if ipv6 redirects too.

I've done curl to the server's public ipv6.

curl -I -g "http://[server:public:ipv6:here]/"

The response is 301 Moved Permanently pointing to the website's domain which is even more puzzling and almost unbelievable. This ipv6 redirection was never ever set on my part to begin with, unless the redirection server block posted at the beginning of this question encompasses ipv6 redirection too.

Any thoughts?

Vila
  • 169
  • 1
  • 1
  • 4
  • Have you successfully restarted `nginx`? Test the configuration using `nginx -t` – Richard Smith Jan 10 '17 at 14:36
  • 1
    I forgot to add that in the question. I've reloaded Nginx with `sudo nginx -t && sudo service nginx reload`. I've also restarted it `service nginx restart` as if the first command was not enough. I even rebooted the server. Still, the redirect is there. – Vila Jan 10 '17 at 15:17
  • 1
    If it's not your config, I reckon it's some proxy (like CloudFlare) still having that cached. Did you try 'curl' from localhost? – Nikolay Dimitrov Jan 11 '17 at 03:42
  • Read my question. It clearly states what I've tried and that includes curl. – Vila Jan 11 '17 at 08:33
  • Nobody said it didn't include `curl`, we noticed. @gubble asked if you've used it from localhost or not. You may have used it locally but not via 127.1 (?). To clarify what Gubble asked, did you use `curl yourPublicIPaddress` or `curl yourPrivateIPaddress` ? –  Jan 11 '17 at 09:05
  • Please update your question with more precise details. For instance, why are you using two server block for same example.com???? Did you mean that one is example1.com and the other example2.com??? OR if it was only to redirect www to non-www, why didn't you use your redirection out of server block via a conditional statement? –  Jan 11 '17 at 09:13
  • @FarazX, First, that has nothing to do with my question, second recommended and correct www to non-www and vice versa nginx redirection is the exact way I'm using. With separate server block as per the [nginx official documentation](http://nginx.org/en/docs/http/converting_rewrite_rules.html). – Vila Jan 11 '17 at 10:51
  • @FarazX, I'm not sure what you mean when you say "curl yourPublicIPaddress or curl yourPrivateIPaddress?" I'm hitting the website's PUBLIC IP from SSH. The same IP that was in the now deleted redirect block. And the output clearly states that the redirect happens at my server. Regardless, in the question I'm also mentioning that I've hit that IP from third parties that couldn't have cached the redirect, but the redirect is still there. – Vila Jan 11 '17 at 11:07
  • First of all, it has MANY things to do with your question, and I will clarify if you let. Secondly, NGINX official doc is not wrong, yes you can use seperate server blocks, but not the best choice! Thirdly, OK, do you know what Private ranges are? 10.0.0.0-10.255.255.255, 192.168.0.0-192.168.255.255, 172.16.0.0-172.31.255.255 OK? Curl your website with localhost, it means that use: `curl 127.1` Alright? 127.1 is equal to 127.0.0.1. In this case, IF you are using cloud, OR if your VPS provider is using cloud to manage VPSs, you won't see 301 redirection status code. –  Jan 11 '17 at 11:16
  • In other words, you will find out that you are not doing things wrong and the cloud or the VPS provider is caching, and you can easily contact them. If you are using multiple VPSs or multiple dedicated servers, you can ssh to your webserver, or one of you servers in the same VLAN, and then use `curl andYourWebServerPRIVATEadd`, for instance, `curl 172.16.55.43`. Please check all things mentioned, and let us know what is going on. BTW, join the chat room I'm gonna open to avoid extended discussions in comments. Cheers. –  Jan 11 '17 at 11:19
  • Let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/51584/discussion-between-farazx-and-vila). –  Jan 11 '17 at 11:19
  • Although I replied in chat I think short version of my comment needs to be here: nginx doc: > "The right way is to define a separate server for example.org" so I'm 100% positive that I'm using the right method for www to non-www redirection. I've done curl -I 127.1 and the response is 200 OK so there's no redirection but still what's the point of that? – Vila Jan 11 '17 at 14:03
  • @Vila OK I'm not saying it is not, I agree that it is the rightest way, but not the best way. You can always use tricky methods depending on your project. Anyway, that was just an advice to search more and never rely on one doc even if it's official. –  Jan 11 '17 at 16:23
  • Is the request direct to the VPS or is it via a load balancer? – hookenz Jan 11 '17 at 21:40
  • So as I thought, it returns 200 when querying the server directly. That's the end of discussion then.. – Nikolay Dimitrov Jan 12 '17 at 04:39
  • @Matt the call is direct to the VPS. – Vila Jan 12 '17 at 07:05
  • @gubble I don't understand how's the end of discussion? Hit to 127.1 and return 200 means absolutely nothing. Read about the little test I made at the end of my question. – Vila Jan 12 '17 at 07:07
  • Humor me with this one, even though it probably won't solve it. Go to CloudFlare, put the site into development mode, then manually clear the cache. Do a curl both from a local machine on the same network as the server and from a PC on the internet. Edit the question with the results then reply tagging my name. – Tim Jan 12 '17 at 17:32
  • Another thing to try is adding "default_server" as follows to your main server block "listen 80 default_server". I believe this is a better way to achieve what you were trying to do than and IP based server block. – Tim Jan 12 '17 at 17:34
  • @Tim I've done CF test. Included in the question. Where do you want me to put the default_server? IP-to-domain redirect server block is removed and should be removed for the purpose of testing. You want it in the main server block? – Vila Jan 12 '17 at 18:33
  • default_server is how it should've been done, if you don't understand where default_server goes you should read documentation. Probably won't help with this problem. Something somewhere is caching, you need to find it. I'm thinking at this point you need to give a third party access to your server to do systematic problem solving. – Tim Jan 12 '17 at 18:39

2 Answers2

2

Due to the result of curl 127.1 that you tested and mentioned in your question, you are getting 200 HTTP Status Code - whilst using curl locally, and by using 127.1 instead of your Public IP Address.

The reason you are getting 200 Status Code locally, is that you could've successfully removed the 301 redirection line and your NGINX is working fine after restarting the daemon. So don't you worry about NGINX, the problem is something else caching the redirection.

How to find out what is causing the issue, and where it is from ?

There might be two things causing problem - depending on if you are using your own servers or you are using VPSs provided by somewhere like GoDaddy, OVH, or etc. :

  1. Some thing in your own architecture is caching odds and sods
  2. Something in your VPS Provider is caching odds and sods

If you have multiple servers, you can use the steps below to find out which one of the told possibilities is the reason, and if you do not, I recommend you contact with the provider or if you are not using VPS at all and you're using your own servers, check if you are using something like Proxy, Cloud services, Caching Server, or whatsoever that might cache stuff - (Consider that the reason might be caused by both of the told possibilities) ↴

  1. Login via SSH to one of the other servers in the same VLAN that you own, for instance your Storage server.

  2. Guess that your Storage is using 192.168.1.122 and your WebServer is using 192.168.1.125 as their Private IP Address.

  3. From Storage Server, use curl 192.168.1.125 to see if you are still getting 200 or you are getting 301.

  4. If 301, this is something in your architecture that is caching stuff, it might be some service or some other servers you may own like a LoadBalancer.

  5. And if you are getting 200, this is not your architecture, so contact your provider.

What is the Reason 301 Status Code is causing problem ?

301 Redirection is called PERMANENT Redirection! So everything receiving it - including most of the browsers available today - will consider it PERMANENT until it gets expired! This is an expected thing and nothing is acting weird, this is PERMANENT THING's nature!

301 is a one-way street.

CONCLUSION :

NEVER, NEVER EVER use permanent stuff IF you are not 100% - personally would say 500% - sure! Somewhere like Google, like Apple, like RedHat, and other big big companies and manufacturers can use 301 since they know what they are doing, and they own most of the technologies everyone would use, and ALSO, they know how their plan will be going to be in the next 5 years ahead. You can use 301 for simple redirecting that you may use every day like what you have used it for (www to non-www). But never use it permanently until you get sure about the next five years of your project - or at least 2 years.

I hope you can fix your problem soon, and I hope I could help you with the answer.

Cheers mate.

  • I don't use my own servers. I use only one single VPS. Also as basic DDoS protection in front of the server I use CloudFlare. I've updated the question with little test I made. I'm not sure your answer helps. Anyhow, thank you very much. – Vila Jan 11 '17 at 20:14
  • I purged CloudFlare cache and FastCGI cache. Doesn't help. As I've said I made a little test with other URLs. The result suggests that IP redirection happens somewhere at server architecture but not in nginx conf. – Vila Jan 11 '17 at 20:28
  • 2
    I would suggest using 302 in future – Nikolay Dimitrov Jan 12 '17 at 04:40
  • @gubble indeed, highly recommended. –  Jan 12 '17 at 04:41
  • @gubble still you don't provide help for the current problem. We all know what to do in the future, especially after realizing a mistake. – Vila Jan 12 '17 at 07:08
-1

you can use permanently redirect every time. for un permanenly or remove redirect, just remove the line of redirect statement.

if you have domain like this ci.com and will redirect to laravel.com

and you remove redirect statement, u open the browser you still open redirect page. that because browser cached.

try using curl and it will show default domain because curl not cached.

Conclusion remove cache on browser