Utilizzo di VirtualDocumentRoot * solo * se esiste una radice del documento adatta


8

Vorrei impostare un ambiente in cui gli host virtuali di Apache possano essere creati dinamicamente senza ricaricare la configurazione.

Posso farlo con mod_vhost_alias , ho impostato il mio host virtuale predefinito in questo modo

<VirtualHost *>
  UseCanonicalName Off
  VirtualDocumentRoot /var/www/sandboxes/domains/%0
  ServerName catchall.host
</VirtualHost>

Funziona bene, ma se viene fatta una richiesta per un nome host che non è attualmente impostato, viene visualizzato l'errore 404 Not Found.

Quello che mi piacerebbe davvero fare è solo avviare questo VirtualHost solo se esiste la radice del documento, altrimenti provare a far corrispondere un altro vhost (in altre parole, far funzionare la presenza di VirtualDocumentRoot nello stesso modo in cui si usa un ServerAlias)

Ho provato a renderlo il secondo vhost, con il primo vhost che gestiva solo tutte le richieste, ma questo non ha funzionato - le richieste per i domini in cui è stato configurato un VirtualDocumentRoot stavano passando al vhost predefinito.

Quindi, come posso avere configurato vhosts dinamicamente, ma con un fallback a un altro vhost per quelli che non sono ancora configurati?

Risposte:


7

Ho trovato una soluzione alternativa che funziona per me.

Posso usare un ErrorDocument per raccogliere l'errore 404 in uno script PHP. All'inizio sembrava problematico. Se non c'è DocumentRoot, dove vivrà lo script?

Potrei usare un URL per il messaggio di errore, pubblicato da un dominio diverso. Tuttavia, nei test non ho trovato alcun modo di sapere quale fosse il dominio inizialmente richiesto.

La risposta è stata Alias una directory e servire gli errori da quello, quindi il mio vhost assomiglia a questo

<VirtualHost *>
  UseCanonicalName Off
  VirtualDocumentRoot /var/www/sandboxes/domains/%0
  ServerName catchall.host
  Alias /errors /var/www/default/errors/
  ErrorDocument 404 /errors/notfound.php
</VirtualHost>

Ora, quando viene richiesto un dominio non configurato, viene invece invocato lo script in /var/www/default/errors/notfound.php. Questo script può controllare $ _SERVER ['HTTP_HOST'] per vedere quale dominio è stato richiesto. Se è effettivamente configurato, allora abbiamo un normale 404. Se non è configurato, possiamo visualizzare un messaggio di errore alternativo. Nel mio caso, è dove mostro un'interfaccia utente per aiutare a configurare il vhost.


Non lancerebbe un 404 come stato per ogni richiesta al valore predefinito?
Kyle

1
Il gestore degli errori viene invocato solo se VirtualDocumentRoot non esiste (o in realtà era un 404, ma notfound.php può facilmente dire la differenza).
Paul Dixon,

3

Ho trovato la tua domanda su Google. Ho avuto esattamente lo stesso problema e ho applicato la correzione come descritto nella risposta di Paul . Tuttavia, per la mia complessa app Web, non ero contento di instradare tutte le richieste attraverso un singolo notfound.php.

Alla fine, sono riuscito a risolvere il problema senza script esterni, solo modificando la mia configurazione di VirtualHost.

Inizialmente, il mio VirtualHost era configurato in questo modo:

<VirtualHost *:80>
    Usecanonicalname Off
    Virtualdocumentroot /mnt/ramdisk/www/cms-%-3.0-development/
</VirtualHost>

Avevo URL simili a client1.domainname.com, client2.domainname.comewhatever.domainname.com

che si è risolto in /mnt/ramdisk/www/cms-client1-development/, /mnt/ramdisk/www/cms-client2-development/e/mnt/ramdisk/www/cms-whatever-development/

Tuttavia, un URL come nonexistent.domainname.commi darebbe un 404 perché la directory /mnt/ramdisk/www/cms-nonexistent-development/non esisteva. Volevo che questi sottodomini usassero la directory/mnt/ramdisk/www/cms-default-development/

Ho risolto questo problema usando ModRewritee ModProxy:

<VirtualHost *:80>
    Usecanonicalname Off
    Virtualdocumentroot /mnt/ramdisk/www/cms-%-3.0-development/
    RewriteEngine on
    RewriteCond %{HTTP_HOST} ^(.*)\.domainname\.com$ [NC]
    RewriteCond /mnt/ramdisk/www/cms-%1-development/ !-d
    RewriteRule (.*) http://default.domainname.com/$1 [P,L]
</VirtualHost>

Quello che fa è: prendi il sottodominio (la parte prima .domainname.com), inseriscilo nel percorso (% 1) e le richieste proxy all'URL predefinito solo se la directory non esiste.

Utilizzando un proxy, il processo è trasparente e l'utente pensa di visitare http://nonexistent.domainname.com , mentre in realtà visualizza il contenuto da http://default.domainname.com/ .


3

Mi sono anche imbattuto in questa domanda su Google per il fallback del vhost dinamico di apache2 e la risposta di Luc mi ha aiutato molto a risolvere il mio problema, ma voglio ancora mostrare cosa ho fatto per raggiungere i miei obiettivi, principalmente perché comportava alcuni lavori extra e perché penso potrebbe essere utile per eventuali googler futuri ...

I miei obiettivi

  • vhosting dinamico per tutti i domini e sottodomini che puntano al mio VPS
  • foo.com dovrebbe servire lo stesso contenuto di www.foo.com
  • fallback per domini sconosciuti a una sorta di impostazione predefinita
  • fallback per sottodomini sconosciuti di foo.coma www.foo.commeno che wwwnon sia disponibile, fallback invece al valore predefinito

DNS

Ho un paio di domini (e tutti i loro sottodomini) che puntano al mio VPS, ad esempio:

  • foo.com
  • bar.com
  • foobar.com

filesystem

Ho le seguenti directory, i domini contengono directory con i nomi dei sottodomini disponibili, è richiesta la directory www, ma la configurazione dovrebbe essere in grado di gestire la situazione in cui non è presente. Localhost viene utilizzato come fallback predefinito:

/var
  /www
    /localhost
    /foo.com
       /www
       /bar
    /bar.com
       /foo

test

Traducendo i miei obiettivi in ​​casi verificabili:

  • foo.com dovrebbe essere servito da foo.com/www
  • www.foo.com dovrebbe essere servito da foo.com/www
  • bar.foo.com dovrebbe essere servito da foo.com/bar
  • foo.foo.com dovrebbe essere servito da foo.com/www (foo.com/foo non esiste)
  • bar.com dovrebbe essere servito da localhost (bar.com/www non esiste)
  • www.bar.com dovrebbe essere servito da localhost (bar.com/www non esiste)
  • foo.bar.com dovrebbe essere servito da bar.com/foo
  • bar.bar.com dovrebbe essere servito da localhost (bar.com/bar non esiste)
  • foobar.com dovrebbe essere servito da localhost (foobar.com non esiste)
  • www.foobar.com dovrebbe essere servito da localhost (foobar.com non esiste)
  • foo.foobar.com dovrebbe essere servito da localhost (foobar.com non esiste)

La soluzione

Questo utilizza: mod_rewrite, mod_proxy_httpe naturalmente mod_vhost_alias.

ServerName my.domain
ServerAdmin admin@my.domain

<VirtualHost *:80>
    ServerName localhost
    VirtualDocumentRoot /var/www/localhost
</VirtualHost>

<VirtualHost *:80>
    ServerName sub.domain
    ServerAlias *.*.*
    VirtualDocumentRoot /var/www/%-2.0.%-1.0/%-3

    RewriteEngine on

    RewriteCond %{HTTP_HOST} ^(.*)\.(.*)\.(.*)$ [NC]
    RewriteCond /var/www/%2.%3 !-d
    RewriteRule (.*) http://localhost/$1 [P]

    RewriteCond %{HTTP_HOST} ^(.*)\.(.*)\.(.*)$ [NC]
    RewriteCond /var/www/%2.%3/%1 !-d
    RewriteCond /var/www/%2.%3/www !-d
    RewriteRule (.*) http://localhost/$1 [P]

    RewriteCond %{HTTP_HOST} ^(.*)\.(.*)\.(.*)$ [NC]
    RewriteCond /var/www/%2.%3/%1 !-d
    RewriteRule (.*) http://%2.%3/$1 [P]
</VirtualHost>

<VirtualHost *:80>
    ServerName bare.domain
    ServerAlias *.*
    VirtualDocumentRoot /var/www/%-2.0.%-1.0/www

    RewriteEngine on

    RewriteCond %{HTTP_HOST} ^(.*)\.(.*)$ [NC]
    RewriteCond /var/www/%1.%2 !-d [OR]
    RewriteCond /var/www/%1.%2/www !-d
    RewriteRule (.*) http://localhost/$1 [P]
</VirtualHost>

Come funziona? Sono definiti tre host virtuali:

localhost

Localhost funge da predefinito. Tutte le richieste non risolvibili sono servite da localhost. Configurare un collegamento simbolico da localhost a uno dei tuoi domini è come impostare quel sito come predefinito.

sub.domain

Il vhost del sottodominio accetta tutte le richieste sotto forma di *.*.*. Per impostazione predefinita, tutte le richieste vengono soddisfatte /domain.com/subcome definito da VirtualDocumentRoot /var/www/%-2.0.%-1.0/%-3.

ricaderci:

Il primo RewriteRulesi occupa di domini sconosciuti, ad es. domain.comla directory non esiste, eseguendo il proxy del sito Web localhost.

Il secondo RewriteRuleinoltre esegue il proxy a localhost quando non sono presenti sia domain.com/subla domain.com/wwwdirectory che la directory.

Il terzo RewriteRuleproxy a domain.comquando domain.com/subnon esiste. Sappiamo domain.com/wwwche esiste a causa del secondo blocco di riscrittura.

bare.domain

Il vhost bare.domain accetta le *.*richieste e le serve/domain.com/www

Qui il RewriteRuleproxy sarà localhost quando domain.como domain.com/wwwnon esistono.

^ $%. * !!!

Ho avuto qualche problema confezionamento mia testa intorno a tutti coloro $e %segni nella RewriteConde RewriteRulecosì spiegherò su di loro qui:

    ServerAlias *.*.*
    VirtualDocumentRoot /var/www/%-2.0.%-1.0/%-3
    RewriteCond %{HTTP_HOST} ^(.*)\.(.*)\.(.*)$ [NC]
    RewriteCond /var/www/%2.%3/%1 !-d
    RewriteRule (.*) http://%2.%3/$1 [P]
  • I *nel ServerAliassono solo caratteri jolly.
  • Gli %nin VirtualDocumentRootsono dal nome del documento interpolazione .
  • I %nnel secondo si RewriteCondriferiscono alle selezioni (.*)dal primo RewriteCond, ad es. le parti del dominio richiesto.
  • Anche %nnel RewriteRulefare.
  • Il $1in si RewriteRuleriferisce alla selezione (.*)all'inizio del RewriteRule. Che cattura tutto dal dominio fino all'URL ?della richiesta. Qualsiasi querystring viene automaticamente aggiunta all'URL da mod_proxy.

1

Basta lanciarlo là fuori, ottengo lo stesso risultato (meno il reindirizzamento localhost) di RemyNL, ma includendo anche l'indirizzo IP quando mi connetto direttamente:

<VirtualHost _default_:80>
    RewriteEngine On
    RewriteCond %{HTTPS} Off [OR] 
    RewriteCond %{HTTP:X-Forwarded-Proto} !https
    RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]
</VirtualHost>

<VirtualHost _default_:443>
    ServerName a.b.c.d
    ServerAlias *.*.*.*
    VirtualDocumentRoot /var/www/%0
</VirtualHost>

<VirtualHost _default_:443>
    ServerName a.b.c
    ServerAlias *.*.*
    VirtualDocumentRoot /var/www/%-2.0.%-1.0/%-3
</VirtualHost>

<VirtualHost _default_:443>
    ServerName a.b
    ServerAlias *.*
    VirtualDocumentRoot /var/www/%-2.0.%-1.0/www
</VirtualHost>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.