Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mstnorris's avatar

Allow certain IP addresses and redirect the rest in Nginx and Forge

I would like to only allow certain IP addresses to my site while it is still in development and redirect the rest to a different URL or route.

Is this possible using Laravel alone?

If so I would prefer that solution, if not, is there an elegant and easy way to do this with Nginx? I have looked up how to allow / block IP addresses and that works but I am unsure how to redirect the others.

0 likes
20 replies
mstnorris's avatar

As I said I know how to block / allow IP addresses but I don't know how to redirect the others to a different page. I have got it at the moment so that my IP address is allowed and others are not, yet the redirect doesn't work. It only works on my IP address which is the opposite to what I want.

This is my Nginx sites-available/mydomain.co.uk file

server {
    listen 80;
    server_name mydomain.co.uk;
    root /home/forge/mydomain.co.uk/public;

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

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    index index.html index.htm index.php;

    charset utf-8;

    location / {
    allow 111.222.333.444;
    deny all;
    error_page 403 comingsoon;
        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.co.uk-error.log error;

    error_page 404 /index.php;

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

    location ~ /\.ht {
        deny all;
    }
}
2 likes
mstnorris's avatar

@bashy, I tried this a couple of ways. Using your code above, I hardcoded http://mydomain.com/comingsoon and I set up a route for this. It didn't work.

I also dropped everything apart from the comingsoon and that too didn't work.

mstnorris's avatar

Thank you. This is what my /etc/nginx/sites-available/mydomain.com file looks like

server {
    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;

    index index.html index.htm index.php;

    charset utf-8;

    location / {
    error_page 403 = @deny;
    allow 111.222.333.444;
    deny all;
    try_files $uri $uri/ /index.php?$query_string;
    }

    location @deny {
    return 301 http://mydomain.com/comingsoon;
    }

    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/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }
}
bashy's avatar

Okay after an hour or so I've got it worked out.

This is 101% tested :)

# Set the 403 (forbidden page)
error_page 403 = @denied;

# Allow certain IP and deny all others (can use subnets, see Nginx docs).
# This block goes down the list until it finds a match, then executes the try_files part.
location / {
    allow 192.168.22.10;
    allow 192.168.22.1;
    deny all;

    # You can change this to use index.php?$query_string like normal.
    try_files $uri $uri/ @allowed;
}

# This is the handler for the try_files above.
# Just showing you can return anything.
location @allowed {
    default_type text/html;
    return 200 'Allowed via $REMOTE_ADDR';
}

# This is the handler for 403 error_page, set above.
location @denied {
    default_type text/html;
    return 403 'Denied via $REMOTE_ADDR';

    # Can enable a redirect elsewhere
    #return 301 http://example.com/soon
}

Also posted it on my blog: https://bashy.im/blog/nginx-security-allow-certain-ips-and-deny-everything-else

mstnorris's avatar

@bashy, thank you for spending the time going through that. I have added your suggestion to my file and I still see the site as normal. I assume that I shouldn't be replacing the whole file with your code above. I'm not getting any errors but basing it on the fact that you have tested it I guess I mist be going wrong somewhere. This is what I have now

server {
    listen 80;
    server_name mydomain.co.uk;
    root /home/forge/mydomain.co.uk/public;

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

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    index index.html index.htm index.php;

    charset utf-8;

    error_page 403 = @denied;

    location / {
        allow 111.222.333.444;
        allow 555.666.777.888;
        deny all;
        try_files $uri $uri/ @allowed;
    }

    location @allowed {
       default_type text/html;
       echo 'Allowed via $REMOTE_ADDR';
    }

    location @denied {
       default_type text/html;
       echo 'Denied via $REMOTE_ADDR';
    }

    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.co.uk-error.log error;

    error_page 404 /index.php;

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

    location ~ /\.ht {
        deny all;
    }
}
1 like
bashy's avatar

So your IP isn't in the allowed but you see "Allowed via x.x.x.x"?

mstnorris's avatar

@bashy My IP is allowed and I do see "Allowed via x.x.x.x" but I want that to show the actual page they are trying to see.

Everyone else should be redirected to http://mydomain.com/comingsoon which at the moment throws the error "Too many redirects..."

bashy's avatar

Yeah it's in the comments in my reply

# You can change this to use index.php?$query_string like normal.
try_files $uri $uri/ @allowed;

So

try_files $uri $uri/ /index.php?$query_string;
mstnorris's avatar

Can the try_files go in the @allowed function?

Like so...

location / {
      allow 111.222.333.444;
      allow 555.666.777.888;
      deny all;
      try_files $uri $uri/ @allowed;
  }

  location @allowed {
     default_type text/html;
     try_files $uri $uri/ /index.php?$query_string;
  }

  location @denied {
     default_type text/html;
     echo 'Denied via $REMOTE_ADDR';
  }
bashy's avatar

No need to use the @allowed location part

location / {
    allow 111.222.333.444;
    allow 555.666.777.888;
    deny all;

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

location @denied {
    default_type text/html;
    return 403 'Denied via $REMOTE_ADDR';
}
mstnorris's avatar

@bashy, I still get the error in Safari that there are too many redirects. Did you say that you got it working?

bashy's avatar

Works for me using both methods.

Make sure to clear any browser redirect caches. Use cURL to check it live

curl -I http://example.com
FutureWeb's avatar

Hi @bashy

I too am trying to restrict access but to a certain dir and to allow a number of ips I have created an include "admin-ips" which is simply a list of ips like so: allow 123.123.123.123; this works if I restrict at root level location / { but not if I just try to restrict access to the admin folder i.e everyone gets redirected to site.com even if they are in the admin-ips include

 location ~ /admin {
         error_page 403 = @deny; // or just return a file
        include includes/admin-ips
        deny all;
        try_files $uri $uri/ /index.php?$query_string;
  }

 location @deny {
          return 301 http://site.com;
  }
bashy's avatar

@futureweb Just tested what I've put above and it's still working fine on nginx/1.15.8

Have you tried without the include?

Please or to participate in this conversation.