(An addendum to the previous mod_acceptfilter proposal.)
From my experience on #apache, it appears that Mere Mortals have a great deal of difficulty successfully configuring virtual hosts. I think this is understandable; the algorithm used to allocate requests to virtual host sections is complicated, and it conflates two radically different concepts: the assignment of a listener to a particular ip:port (or a particular ip), and the assignment of named virtual hosts within an ip[:port] listener.
Successfully configuring a name virtual host, in the current configuration system, requires co-ordinating three directives which often appear in different parts of the configuration: Listen, NameVirtualHost, and <VirtualHost>
Minor discrepancies in the ip:port specifications in these directives can cause named virtual hosts to fail to work without providing any useful error messages.
In addition, not all protocols support the concept of named virtual hosts.
I'm interested in peoples' reactions to the following proposal:
Directive: <Listen ([<transport> "/"](ip | "*" | "_default_")[":" <port>])+> Context: main configuration
This is the combination of an existing Listen directive with an existing (non-named) Virtual Host directive; that is, you could replace
Listen 1.2.3.4:80 <VirtualHost 1.2.3.4:80> #... </VirtualHost>
with
<Listen 1.2.3.4:80> # ... </Listen>
Directive: <NameVirtualHost (<name> | "_default_")+> Context: <Listen> section
This provides the definition of a single named virtual host within a single Listener; it replaces the existing NameVirtualHost and <VirtualHost> directives. Exactly one <NameVirtualHost> must be tagged with the _default_ name; if there is one it will be used if no <name> matches or no virtual host name is provided by the client.
It is an error to provide a <NameVirtualHost> in a <Listen> section for a protocol which does not support named virtual hosts.
It is an error to provide more than one <NameVirtualHost _default_> section in the same <Listen> section.
If no <NameVirtualHost _default_> is provided, the first <NameVirtualHost>
section will be used as a default, for backwards pseudo-compatibility,
but a warning will be generated.
-------------------
Example configurations:
1) Simple configuration, a number of virtual hosts with different document roots:
Current: --------
Listen *:80 #... #... NameVirtualHost *:80 #... #... <VirtualHost *:80> ServerName this.does.not.match.any.name.com DocumentRoot /var/www/noname DirectoryIndex stopUsingNetscape2.html </VirtualHost>
<VirtualHost *:80> ServerName www.example.com ServerAlias example.com DocumentRoot /var/www/example </VirtualHost>
<VirtualHost *:80> ServerName www.example2.com ServerAlias example2.com DocumentRoot /var/www/example2 </VirtualHost>
Proposed: ---------
<Listen *:http> <NameVirtualHost _default_> DocumentRoot /var/www/noname DirectoryIndex stopUsingNetscape2.html </NameVirtualHost>
<NameVirtualHost www.example.com example.com> DocumentRoot /var/www/example </NameVirtualHost>
<NameVirtualHost www.example2.com example2.com> DocumentRoot /var/www/example2 </NameVirtualHost> </Listen>
----------------------------------------------------
2) A configuration with named virtual hosts on one ip and non named virtual hosts on another one
Current: --------
Listen *:80 #... #... NameVirtualHost 1.2.3.4:80 #... #... <VirtualHost 1.2.3.4:80> ServerName this.does.not.match.any.name.com DocumentRoot /var/www/noname DirectoryIndex stopUsingNetscape2.html </VirtualHost>
<VirtualHost 1.2.3.4:80> ServerName www.example.com ServerAlias example.com DocumentRoot /var/www/example </VirtualHost>
<VirtualHost 1.2.3.4:80> ServerName www.example2.com ServerAlias example2.com DocumentRoot /var/www/example2 </VirtualHost>
<VirtualHost 1.2.3.5:80> # This is not a named virtual host, but it is # not locally obvious ServerName www.example3.com DocumentRoot /var/www/example3 </VirtualHost>
Proposed: ---------
<Listen 1.2.3.4:http> <NameVirtualHost _default_> DocumentRoot /var/www/noname DirectoryIndex stopUsingNetscape2.html </NameVirtualHost>
<NameVirtualHost www.example.com example.com> DocumentRoot /var/www/example </NameVirtualHost>
<NameVirtualHost www.example2.com example2.com> DocumentRoot /var/www/example2 </NameVirtualHost> </Listen>
<Listen 1.2.3.5:http> ServerName www.example3.com DocumentRoot /var/www/example3 </Listen>
------------------------------------------------------
3) I am aware that this proposal does not provide for the current possibility of doing something like:
Listen 1.2.3.4:80 Listen 192.168.1.1:80
NameVirtualHost *:80 <VirtualHost 1.2.3.4:80> # Only available on the external interface ServerName www.example.com </VirtualHost>
<VirtualHost *:80> # Available on both interfaces ServerName www.example2.com </VirtualHost>
<VirtualHost 192.168.1.1:80> # Only available on the internal interface ServerName www.example3.com </VirtualHost>
I don't believe this is a common configuration case, although it certainly exists. Such configurations could continue to use the current mechanism, or they could use something like:
<Listen 1.2.3.4:80> Include conf/example.conf Include conf/example2.conf </Listen>
<Listen 192.168.1.1:80> Include conf/example3.conf Include conf/example2.conf </Listen>
This is, of course, subtly different: the default named virtual host assignment is example.com on the external port and example3.com (instead of example2.com) on the internal port.
Also, there are various alternatives to include files, such as mod_macro.