使用.htaccess(PHP)快速创建子域


122

我希望创建一个系统,该系统在注册时将在我的网站上为用户帐户区域创建一个子域。

例如johndoe.website.com

我认为这与.htaccess文件有关,并且可能重定向到网站上的其他位置吗?我真的不知道 但是,任何让我起步的信息将不胜感激。

创建注册区域不是问题-我已经做了很多次了。我只是不确定从子域开始。

Answers:


125

快速淘汰

  1. 您需要在DNS服务器* .website.com上创建通配符域
  2. 然后,在您的vhost容器中,您还需要指定通配符* .website.com-这是在DOC中完成的ServerAlias
  3. 然后提取并验证PHP中的子域并显示适当的数据

长版

1.创建一个通配符DNS条目

在DNS设置中,您需要创建一个通配符域条目,例如*.example.org。通配符条目如下所示:

*.example.org.   3600  A  127.0.0.1

2.在vhost中包含通配符

接下来,在Apache配置中,您需要设置一个虚拟主机容器,该容器在ServerAlias DOCs指令中指定通配符。虚拟主机容器示例:

<VirtualHost *:80>
  ServerName server.example.org
  ServerAlias *.example.org
  UseCanonicalName Off
</VirtualHost>

3.确定您在PHP中使用的是哪个子域

然后,在您的PHP脚本中,您可以通过查看$_SERVER超级全局变量来查找域。这是在PHP中获取子域的示例:

preg_match('/([^.]+)\.example\.org/', $_SERVER['SERVER_NAME'], $matches);
if(isset($matches[1])) {
    $subdomain = $matches[1];
}

我在这里使用了正则表达式,以允许人们通过www.subdomain.example.org或subdomain.example.org访问您的网站。

如果您从未想到过要与www打交道。(或其他子域),则可以像下面这样简单地使用子字符串:

$subdomain = substr(
                 $_SERVER['SERVER_NAME'], 0,
                 strpos($_SERVER['SERVER_NAME'], '.')
             );

大规模虚拟主机

大规模虚拟主机与上述方案略有不同,因为您通常会使用它来托管许多不同的网站,而不是像问题所建议的那样尝试使用它为应用程序提供动力。

之前,我已经在博客上发布了一篇基于mod_rewrite的大规模虚拟主机环境的文档,您可以看看这是否是您希望采用的方法。当然,也有相应的Apache手册页

Apache还具有处理海量虚拟主机的内部方式,该方式比我使用的mod_rewrite方法的灵活性稍差。所有这些都在Apache 动态配置的批量虚拟主机手册页面上进行了描述。


如果您可以使用wildcard subdomains,请参阅我的解决方案以在Windows中执行此操作.htaccess
丹·布雷

我不相信可以从.htaccess中添加虚拟主机,这也使我对安全性感到厌烦。从2.4开始,应该可以根据主机名选择基本目录(但是Dan的方法也有一些问题)考虑:RewriteRule "^/?(.*)" "http://%{HTTP_HOST}/%{HTTP_HOST}/$1" [L,R,NE]
symcbean

请注意,实现此功能的PHP代码一定不能作为Web服务器uid(应通过sudo作为专用用户)运行
symcbean

12

您可以首先允许每个子域,然后检查该子域是否有效。例如:

RewriteEngine on
RewriteCond %{HTTP_HOST} ^[^.]+\.example\.com$
RewriteRule !^index\.php$ index.php [L]

在内部,index.php您可以使用以下方法提取子域:

if (preg_match('/^([^.]+)\.example\.com$/', $_SERVER['HTTP_HOST'], $match)) {
    var_dump($match[1]);
}

但这一切都要求您的Web服务器接受每个子域名。


3
此外,它要求您的DNS服务器解析每个子域名。
混乱

1
我已经在其他网站上看到了这一点,当然他们不必每次都解析每个子域吗?
Ben McRae

1
好吧,这取决于您的意思。如果您的意思是,每当互联网上的某个人查找foo.somedomain.com并没有对其进行缓存时,他们的DNS服务器都必须对其进行解析,然后是。
混乱

如果您要说的话,他们是否必须专门为每个域设置DNS记录,请参阅Treffynnon的答案。
混乱

好的,谢谢你。我不太了解Treffynnon通过在vhost中指定通配符是什么意思?
Ben McRae


6

我发现使用PHP更容易。实际上是在cPanel中创建一个子域,并在所需域名下创建文件夹。正如您将在cPanel中手动进行的操作一样,但是所有这些操作都是通过简单的PHP函数在几毫秒内完成的。无需点击:)

function create_subdomain($subDomain,$cPanelUser,$cPanelPass,$rootDomain) {

    //  $buildRequest = "/frontend/x3/subdomain/doadddomain.html?rootdomain=" . $rootDomain . "&domain=" . $subDomain;

    $buildRequest = "/frontend/x3/subdomain/doadddomain.html?rootdomain=" . $rootDomain . "&domain=" . $subDomain . "&dir=public_html/subdomains/" . $subDomain;

    $openSocket = fsockopen('localhost',2082);
    if(!$openSocket) {
        return "Socket error";
        exit();
    }

    $authString = $cPanelUser . ":" . $cPanelPass;
    $authPass = base64_encode($authString);
    $buildHeaders  = "GET " . $buildRequest ."\r\n";
    $buildHeaders .= "HTTP/1.0\r\n";
    $buildHeaders .= "Host:localhost\r\n";
    $buildHeaders .= "Authorization: Basic " . $authPass . "\r\n";
    $buildHeaders .= "\r\n";

    fputs($openSocket, $buildHeaders);
        while(!feof($openSocket)) {
           fgets($openSocket,128);
        }
    fclose($openSocket);

    $newDomain = "http://" . $subDomain . "." . $rootDomain . "/";

   //  return "Created subdomain $newDomain";

}

检查它是否在cPanel上成功创建,并通过FTP(或文件管理器)检查public_html / subdomain文件夹中的内容。如果您在创建子域时使用cPanel设置添加内容,则与动态创建子域无关。
Adrian P.

没有没有在cPanel的创建
鲁奇

然后,您在cPanel上没有足够的权限。这是共享主机VPS还是专用服务器?
Adrian P.

不创建子域可能有多种原因。与上面的脚本无关,但与您的DNS配置有关。阅读并在cPanel论坛上寻求帮助。forums.cpanel.net/threads/subdomains-not-working.228132
Adrian P.

5

最简单的方法是重定向所有子域(使用通配符*)以指向您的/ wwwroot。然后使用以下代码将.htaccess放入此文件夹:

RewriteCond %{ENV:REDIRECT_SUBDOMAIN} ="" 
RewriteCond %{HTTP_HOST} ^([a-z0-9][-a-z0-9]+)\.domain\.com\.?(:80)?$ [NC] 
RewriteCond %{DOCUMENT_ROOT}/%1 -d 
RewriteRule ^(.*) %1/$1 [E=SUBDOMAIN:%1,L] 
RewriteRule ^ - [E=SUBDOMAIN:%{ENV:REDIRECT_SUBDOMAIN},L]

这样就可以实现/ wwwroot文件夹的每个子文件夹都可以通过子域(foldername.domain.com)接受。

在几年前的http://www.webmasterworld.com/apache/3163397.htm找到


4

与.htaccess无关。您需要为子域设置DNS记录和虚拟主机。


4

Mod_vhost_alias是执行此操作的正确模块。

用一行可以告诉Apache查看正确的位置,使用目录哈希等等。例如,该行:

VirtualDocumentRoot /http/users/%3.1/%3.2/%3

会在请求subdomain.yourdomain.com时告诉Apache将文档根目录设置为/ http / users / s / u / subdomain


0

我认为带有Apache动态批量虚拟主机的通配DNS也是一种合理的解决方案。虽然,我从未尝试过。

如果您需要扩展到多个服务器,或者其他解决方案对您不起作用,建议您使用数据库驱动的DNS服务器。我过去已成功使用MyDNS。由于它使用MySQL(或PostgreSQL),因此您可以使用PHP或几乎其他任何方式即时更新DNS。该代码看起来好像并没有在一段时间内进行更新,但是它是DNS,因此并不是最先进的代码。


0

通配符子域创建方法

首先,您必须使用服务器DNS编辑器创建DNS设置。

  1. A使用*服务器IP地址中的主机通配符在DNS设置中创建记录。

    * 1400 IN A ip_address

  2. 再次A在DNS设置中使用主机@domain_name.tld服务器IP地址创建一条记录。tld表示顶级域名或域名的扩展名,例如.com,.org等。

    @ 1400 IN A ip_address 要么 domain_name.tld 1400 IN A ip_address

  3. 创建如下CNAME记录:

    www 1400 IN A domainname.tld

  4. 使用*通配符创建子域,例如*.domain.tld
  5. 在您的的子域目录中创建htaccess,*.domain.tld并将以下代码放入:

    Options +FollowSymLinks 
    RewriteEngine On 
    RewriteBase /
    RewriteRule ^([aA-zZ0-9]+)$ index.php?data=$1
    RewriteCond %{HTTP_HOST} ^([aA-zZ0-9]+)\.([aA-zZ0-9-]+)\.([aA-zZ]+)
    RewriteRule ([aA-zZ0-9]+) index.php?data=%1

    测试您的第一个通配符子域,例如 example.domainname.tld

如果您不希望使用htaccess将数据作为参数传递,则还可以使用以下编码来获取数据:

define("SUBDOMAIN_PARENT","domainname.tld");   
class getData
    {
         function __construct()
        {
            $this->data="";
            $http_host=$_SERVER['HTTP_HOST'];
         $subdom_data= str_replace(SUBDOMAIN_PARENT,"",$http_host);
         $expl_subdom_data=explode(".",$subdom_data);
      $expl_subdom_data=array_filter($expl_subdom_data);

            if($expl_subdom_data!=NULL)
            {
           $this->data=end($expl_subdom_data);
            }
       }
    }
$GLOBALS['get_data']=new getData();

并在任何位置使用您的全局变量global $get_data

echo $get_data->data; //example

(注意:此类主要用于从中获取确切的子域名,http_host因为在您的子域之前合并的一些额外名称也适用,例如www.example.domainname.tld。此返回值,$_GET['data']='wwww'所以我的建议是使用$_SERVER['http_host']for获取确切的值,而不是在中使用$_SERVER['query_string']或传递的htaccess参数您的索引页)

6.加快此通配符子域的执行速度,在TTL-DNS设置中使用N秒。

7.在给定的ttl时间(600-10分钟)后检查子域,例如=> http://abc.domain.tld

(请注意:通配符子域不会覆盖现有子域。因为“优先级”始终是您现有子域的优先级)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.