Where does PHP get $_SERVER[‘SERVER_NAME’] – Apache versus NGINX

Have you ever wondered where PHP gets the domain name of its server?  I know, the answer is $_SERVER['SERVER_NAME'] – but where does that value actually come from?
Obviously, it comes from the server (the clue is in the name of the superglobal!), but where does the server get it from?  Let’s look at the two most common web servers, apache and nginx.  We’ll use a simple test script;

# index.php
<?= $_SERVER['SERVER_NAME'] . PHP_EOL ?>

We’ll add a couple of aliases to our server

# /etc/hosts
127.0.0.1 foo bar

OK, apache first.

$ telnet foo 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
GET / HTTP/1.1
host: foo

HTTP/1.1 200 OK
Content-Type: text/html
(a few other headers, not relevant here)

foo
Connection closed by foreign host.
$ telnet bar 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
GET / HTTP/1.1
host: bar

HTTP/1.1 200 OK
Content-Type: text/html
(a few other headers, not relevant here)

bar
Connection closed by foreign host.

Now, what happens if you pass an unexpected value in the host field?

$ telnet foo 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
GET / HTTP/1.1
host: Fish Are Best!

HTTP/1.1 200 OK
Content-Type: text/html
(a few other headers, not relevant here)

fish are best!
Connection closed by foreign host.

Apache just converts the host field to lower case and passes it back to you. If you are using $_SERVER['SERVER_NAME'] in your PHP code, I hope you’re treating it a user-supplied, and hence unclean!

Next nginx. We’ll use the following line in our configuration:

server_name foo bar;

When we specify host: foo, we get back foo, and when we specify host: bar we also get foo! If we specify a bogus host host: Fish Are Best! we reassuringly also get foo.

Now, let us change the order of domains in the configuration block.

server_name bar foo;

Now, we get back bar for all requests. nginx always uses the first domain listed in the server_name directive.

This could be a gotcha if you have

server_name example.com www.example.com;

and you use the server_name to set a cookie path.

So, to summarise,

apache$_SERVER['SERVER_NAME'] is a lower-cased version of whatever you pass in the host field.

nginx$_SERVER['SERVER_NAME'] is the first entry in the server_name directive.

This entry was posted in Uncategorized and tagged , , . Bookmark the permalink.