Do site da Apache :
The Listen directive does not implement Virtual Hosts - it only tells
the main server what addresses and ports to listen on. If no
directives are used, the server will behave in the same
way for all accepted requests. However, can be used to
specify a different behavior for one or more of the addresses or
ports. To implement a VirtualHost, the server must first be told to
listen to the address and port to be used. Then a
section should be created for the specified address and port to set
the behavior of this virtual host. Note that if the is
set for an address and port that the server is not listening to, it
cannot be accessed.
O Apache é muito flexível. A maneira mais básica de usá-lo é sem hosts virtuais. Se você não estiver usando hosts virtuais, poderá usar a diretiva Listen
para especificar quais interfaces de rede e portas serão usadas. Você pode especificar basicamente todas as opções que podem ser especificadas em um host virtual diretamente no seu arquivo http.conf (que é como o Apache.org o empacota na última vez que verifiquei o BTW).
As diretivas
VirtualHost
são substituições para esse comportamento padrão. Eles dizem ao Apache para tratar certas combinações de IP e porta de maneira diferente. Se o Apache não tivesse os dois, você precisaria usar hosts virtuais. Isso costumava ser um problema maior quando os hosts virtuais foram inventados pela primeira vez. Na época, os navegadores não sabiam como lidar com eles e, embora o suporte tenha sido adicionado a todos os navegadores populares logo depois, muitas pessoas continuaram a usar navegadores desatualizados no momento. Como isso foi há muito tempo, a maioria das distribuições do Apache agora usam hosts virtuais por padrão porque são mais flexíveis e possibilitam uma resposta diferente dependendo do IP, porta ou nome.
Mesmo agora que temos hosts virtuais, o fato de podermos especificar uma configuração padrão para nosso domínio é útil. Considere o caso em que alguém insere um nome de subdomínio inválido. Como temos um site padrão, podemos usá-lo para mostrar uma página personalizada \ site quando alguém tentar acessá-lo.
O tipo reverso de situação também pode ser verdadeiro. Se você quiser, poderá tornar sites-enabled
uma pasta compartilhada e ajustar o conteúdo dos arquivos de configuração de portas por servidor para balancear a carga de muitos servidores.
Dito isso, acho estranho que o Apache não tenha uma maneira de defini-los automaticamente com base na configuração do host virtual.
Apenas por diversão, eu escrevi um script que poderia fazer isso funcionar automaticamente. Você pode tentar se quiser, mas eu avisá-lo que você deve ser cauteloso sobre o uso, porque é quase completamente não testado. Significado ISTO NÃO É CÓDIGO DE PRODUÇÃO:
<?php
$path=dirname(__FILE__); // The current file path. It is used so all other paths can reliably be set relatively.
$cfg=array(
'output_file'=>"$path/var/ports.conf.out", // This is the file to be generated.
'template_file'=>"$path/tpl_default.php",
'glob_patterns'=>array( // This array contains a list of directories to search for virtual hosts in.
"$path/test-enabled/*", // For now I'd just test some copies which you can play with. Once everything is
), // good then you can change this to /etc/apache/sites-enabled
);
##############
define('IS_CLI', PHP_SAPI==='cli');
echo "Auto Vhost Script\n------------------\n\n";
//echo "Arguments: \n"; print_r(arguments($argv));
echo "Output File:\n\t{$cfg['output_file']}\n";
if(!isset($cfg['output_file'])||!is_writable(dirname($cfg['output_file'])))
die("ERROR: Cannot write to output file.\n");
echo "Template File:\n\t{$cfg['template_file']}\n";
if(!isset($cfg['template_file'])||!is_readable(dirname($cfg['template_file'])))
die("ERROR: Cannot read to template file.\n");
echo "Search Paths:\n";
foreach($cfg['glob_patterns'] as $pattern) {
echo "\t$pattern\n";
}
echo "\nReading configuration files...\n";
$vhosts=array();
foreach($cfg['glob_patterns'] as $pattern) {
echo ">> $pattern\n";
$files=glob($pattern);
foreach($files as $file) {
echo "\t>> ". basename($file) ."\n";
$handle=@fopen($file, "r");
if($handle) {
while(($buffer=fgets($handle, 4096))!==false) {
$status=procLine($buffer);
if(!$status) die("ERROR: Failed reading input line.\n");
if($status===TRUE) continue;
$vhosts[]=$status;
}
if(!feof($handle)) die("ERROR: Unexpected fgets() fail.\n");
fclose($handle);
}
}
}
echo "\n\nGenerating template data...\n";
$nvhost=array();
$listen=array();
foreach($vhosts as $vhost) {
// We're just going to assume that if you have multiple VirtualHost for the same port that means you want to use
// *:port . You could improve this by actually checking to see if multiple hosts have been assigned to this port
// but you'd need to rearrange the data a little.
if($vhost['is_name']||isset($nvhost[$vhost['port']])) {
$nvhost[$vhost['port']]='NameVirtualHost *:'.$vhost['port'];
$listen[$vhost['port']]='Listen '.$vhost['port'];
} else {
$nvhost[$vhost['port']]='NameVirtualHost '.$vhost['host'].':'.$vhost['port'];
if($vhost['host']=='*')
$listen[$vhost['port']]='Listen '.$vhost['port'];
else $listen[$vhost['port']]='Listen '.$vhost['host'].':'.$vhost['port'];
}
}
echo "\n\nWriting output file...\n";
$tpl=file_get_contents($cfg['template_file']);
if($tpl) {
$tpl=str_replace('{NAME_VHOST}', implode("\n", $nvhost), $tpl);
$tpl=str_replace('{LISTEN}', implode("\n", $listen), $tpl);
file_put_contents($cfg['output_file'], $tpl);
}
echo "\n\nDone.\n";
function procLine($line) {
if(!preg_match("/^(\w)*<VirtualHost(.)*>(\w)*/", $line)) return true;
$host=substr($line, strpos($line, 'VirtualHost')+12, strlen($line)-strrpos($line, '>')+2);
$last_square=strrpos($host, ']'); // This is in case the host is specified in IPv6 format
$cln=strrpos($host, ':');
if($cln!==FALSE && $cln+1<strlen($host) && $cln>$last_square) {
$port=substr($host, $cln+1);
$host=substr($host, 0, $cln);
} else $port='80';
$is_range=strpos($host, '*')!==FALSE;
$is_ip=$is_range||filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)!==FALSE;
$is_name=!$is_ip;
return array('host'=>$host, 'port'=>$port, 'is_name'=>$is_name, 'is_ip'=>$is_ip, 'is_range'=>$is_range);
}
Tudo o que precisa ser configurado é a variável $cfg
na parte superior do script e um modelo de arquivo de configuração de portas. Para usá-lo, execute-o com PHP: php path/to/auto_vhost.php
. Uma vez que você consiga esse trabalho, você pode adicionar a chamada php a /etc/init.d/apache2
perto do topo (ou se você olhar, existe um lugar um pouco melhor, mas só porque isso realmente não é necessário nos comandos service apache2 stop
). Isso fará com que esse script seja executado logo antes do Apache ser iniciado ou reiniciado, de modo que ele seja carregado.
Aqui está um exemplo de arquivo de modelo para isso:
# This file was generated from a template by auto_vhost.php
{NAME_VHOST}
{LISTEN}
<IfModule mod_ssl.c>
# If you add NameVirtualHost *:443 here, you will also have to change
# the VirtualHost statement in /etc/apache2/sites-available/default-ssl
# to <VirtualHost *:443>
# Server Name Indication for SSL named virtual hosts is currently not
# supported by MSIE on Windows XP.
Listen 443
</IfModule>
<IfModule mod_gnutls.c>
Listen 443
</IfModule>