16

How can I configure apache so that it refuses connections coming directly to the IP address (http://xxx.xxx.xxx.xxx) instead of the vhost name http://example.com?

My VirtualHost configuration:

ServerName example.com

<VirtualHost *:80>

        ServerName example.com

        DocumentRoot /var/www/           
        <Directory /var/www/>                    
                AllowOverride All
                Order allow,deny
                allow from all
        </Directory>

</VirtualHost>
Alex
  • 322
  • 1
  • 4
  • 12

6 Answers6

31

You cannot have it refuse connections, since the hostname (or IP) that the user is trying to use as their HTTP host is not known to the server until the client actually sends an HTTP request. The TCP listener is always bound to the IP address.

Would an HTTP error response be acceptable instead?

<VirtualHost *:80>
    ServerName catchall
    <Location />
        Order allow,deny
        Deny from all
    </Location>
</VirtualHost>

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/
    <Directory /var/www/>
        AllowOverride All
        Order allow,deny
        allow from all
    </Directory>
</VirtualHost>
Shane Madden
  • 114,520
  • 13
  • 181
  • 251
  • Well, thin brings up a 403 Forbidden for requests not coming from the domain, which is not bad in my situation. However, I want the server to be "non existent" for those requests. I'm sure this can be done somehow, maybe not with apache but on system level? – Alex Mar 22 '14 at 19:10
  • 3
    @Alex No, it's completely impossible. The TCP connection must be established and the client must send their HTTP request (or their SNI header, I suppose) before there's any way for the server to determine whether they're trying to hit the domain name or the IP address in their HTTP request. – Shane Madden Mar 22 '14 at 19:24
  • @ShaneMadden Completely impossible? I understand that the server needs to know the IP of the user before it can choose what to do with it, but it's completely impossible to not respond to this hit once it knows its identity? Can't the server just hang the connection until timeout? – HelpingHand Oct 03 '14 at 13:19
  • 3
    @HelpingHand Not the IP of the user. The server needs to know the host header the user will send in the HTTP request, which it doesn't have until after the TCP connection is fully established. – Shane Madden Oct 03 '14 at 15:13
  • @ShaneMadden Oh, okay... Thanks for clearing that up for me. It's always been a question of mine and I wanted to be entirely sure that its impossible. Right now I just return a 403 Forbidden on my server. Seems like the only solution... – HelpingHand Oct 08 '14 at 14:36
  • @ShaneMadden Can you do this using iptables? – HelpingHand Oct 24 '14 at 14:43
  • 1
    @HelpingHand No, it doesn't have visibility into the HTTP communication happening in the connections. – Shane Madden Oct 24 '14 at 17:33
  • @ShaneMadden Your answer works great with port 80 but I wonder why it does not work when I just change the port to 443 to do the same for https connections?? I get error from browser: "This site can’t provide a secure connection" – Tarik Jul 31 '17 at 12:48
  • @Tarik you'll need to add your certificate configurations otherwise it will just respond to an HTTPS request with HTTP. – MikeSchem Mar 18 '21 at 22:10
3

A clean way to handle this is with a RewriteRule as follows

<If "%{HTTP_HOST} == 'x.x.x.x'">
  RewriteRule ^.*$ http://www.example.com/$1 [L]
</If>

Though this does expose the site associated with the ip versus denying access to a server called by ip. But simple and clean if this is acceptable.

1
<VirtualHost *:80>

ServerName xxx.xxx.xxx.xxx  #your server web server IP
        <Location />
                Order deny,allow
                Deny from all
        </Location>

</VirtualHost>

This is will Forbidden access for accessing by IP

BongSey
  • 11
  • 2
0

Since Apache 2.5.1 there's a parameter called StrictHostCheck. Simply open your /etc/apache2.conf file and add the following line:

StrictHostCheck ON

Then restart your apache2 service:

service apache2 restart

Since now, your website will be only accessible if the host matches the one set in ServerName (example.com, as in your example). All other requests will be denied with code 400 Bad Request.

Here you can find more documention on StrictHostCheck.

0

The order of VirtualHost is important to limit access by hostname. If you want to call only www.example.com and deny the rest, just use the VirtualHost tag with www.example.com on the bottom and use the rest on the top like this.

<VirtualHost *>
    ServerName null
</VirtualHost>

<VirtualHost *>
    ServerName www.example.com
</VirtualHost>
Ray Chakrit
  • 101
  • 1
0

You Have to go to lower layer it only comes to my mind in the firewall chain having a validation check for the REQUEST HOST & what you have with Apache this will allow the package to be ignored or dropped

Chaddy
  • 1
  • It's perfectly possible to do this at the apache level though, so this would be overkill. A simple method would be to ensure the first vhost was a catchall which denied access in an HTTP friendly way. – Paul Dixon Jun 21 '15 at 07:27