Apache 在“NameVirtualHost”和“Listen”中设置端口

Apache 在“NameVirtualHost”和“Listen”中设置端口

在阿帕奇ports.conf我有

NameVirtualHost *:80
Listen 80

我不明白既然端口NameVirtualHost *:80已经设置了,为什么还有一个单独的Listen 80.

这是什么意思?如果它们不同的话会怎样?

答案1

来自阿帕奇网站:

Listen 指令不实现虚拟主机 - 它只告诉主服务器要侦听哪些地址和端口。如果不使用指令,服务器将以相同的方式处理所有接受的请求。但是,可用于为一个或多个地址或端口指定不同的行为。要实现 VirtualHost,必须首先告诉服务器侦听要使用的地址和端口。然后应该为指定的地址和端口创建一个部分来设置该虚拟主机的行为。注意,如果设置了服务器没有监听的地址和端口,则无法访问。

阿帕奇非常灵活。最基本的使用方法是不使用虚拟主机。如果您不使用虚拟主机,则可以使用该Listen指令指定要使用的网络接口和端口。您基本上可以在 http.conf 文件中指定可以在虚拟主机中指定的每个选项(这就是我上次检查的 Apache.org 打包它的方式)。

VirtualHost指令会覆盖此默认行为。它们告诉 Apache 以不同的方式对待某些 IP 和端口组合。如果 Apache 两者都没有,那么您将需要使用虚拟主机。当虚拟主机首次发明时,这曾经是一个更大的问题。当时的浏览器不知道如何处理它们,尽管不久之后所有流行的浏览器都添加了支持,但当时许多人仍然继续使用过时的浏览器。因为那是很久以前的事了,大多数 Apache 发行版现在默认使用虚拟主机,因为它们更灵活,并且可以根据 IP、端口或名称做出不同的响应。

即使现在我们有了虚拟主机,我们可以为域指定默认配置这一事实也是有用的。考虑有人输入无效子域名的情况。由于我们有一个默认网站,因此当有人尝试访问它时,我们可以使用它来显示自定义页面\站点。

相反的情况也可能成立。如果您愿意,您可以创建sites-enabled一个共享文件夹并在每个服务器的基础上调整端口配置文件的内容,以便平衡许多服务器的负载。

话虽如此,我确实认为 Apache 似乎没有办法根据虚拟主机配置自动设置它们,这很奇怪。

只是为了好玩,我编写了一个可以自动完成这项工作的脚本。如果您愿意,可以尝试一下,但我警告您在使用它时应该谨慎,因为它几乎完全未经测试。意思是这不是生产代码:

<?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);
}

需要设置的只是$cfg脚本顶部的变量和端口配置文件模板。要使用它,请使用 PHP 运行它:php path/to/auto_vhost.php.一旦你开始工作,你可以将 php 调用添加到顶部附近(或者如果你看看实际上有一个稍微好一点的地方,但只是因为这在命令/etc/init.d/apache2中确实不需要)。service apache2 stop这样做将导致该脚本在 Apache 启动或重新启动之前运行,以便加载该脚本。

这是一个示例模板文件:

# 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>

答案2

Listen 80告诉 Apache 实际上在端口 80 上设置套接字,与命名无关。

NameVirtualHost *:80告诉 Apache 引用此特定地址/端口套接字的指定虚拟主机配置,与设置套接字无关。

如果它们不同的话会怎样?

不同之处在于您的配置将被破坏并且您的服务器将无法工作。

答案3

默认情况下,每个程序都需要一个端口,并通过以下Kernel方式将数据包分派给程序:port numbers

Listen 80

你告诉内核我的apache想要使用端口80,当你使用des-port 80时给我......,如果你尝试:

root@debian:/home/mohsen# netstat -anp |egrep apache
tcp6       0      0 :::80                   :::*                    LISTEN      25791/apache2   

当你改变Listen 线路时,netstat 的输出将会改变。

但,Virtualhosts

它不冲突端口,有关更多详细信息,请阅读VirtualHost by nameVirtualHost by IP

相关内容