vhost apache unter osx
Joachim
- webserver
Hi,
ich bin Server-Dau, es ist grade Weihnachten vorbei und ich bastle nur an einer lokalen Testumgebung, also bitte nicht hauen.
Ich möchte mir also zum Testen vHosts einrichten (OS X 10.4, "eingebauter" Apache):
Listen 9100
<VirtualHost 0.0.0.0:9100>
DocumentRoot ".../9100"
ServerName 127.0.0.1
ErrorLog ".../9100_error_log"
TransferLog ".../9100_access_log"
</VirtualHost>
localhost:9100 wird anschliessend gefunden (auch weitere vHosts, die ich so anlege) Bei Aufruf lediglich von "localhost" wird der Server jedoch nicht mehr gefunden. Lösche ich alle "Listen", findet Apache unter "localhost" wieder sein DocumentRoot.
Einen Tipp woran das liegt? In der httpd.conf steht jetzt also:
Port 80
Listen 9100
Listen 9200
...
und natürlich die vHosts wie oben.
Gruesse, Joachim
hallo,
Listen 9100
Das ist ungewöhnlich, aber nicht falsch.
<VirtualHost 0.0.0.0:9100>
Das ergibt eine Fehlermeldung. Es gibt keinen namensbasierten VirtHost, der auf der IP 0.0.0.0 liegen darf. Verwende eine IP, die zulässig ist.
ServerName 127.0.0.1
Ich halte es für günstiger, hier einen "Namen" einzusetzen (etwa "www.myhome.test"), und keine IP.
localhost:9100 wird anschliessend gefunden
Weil "localhost" in deiner lokalen hosts-Datei nach 127.0.0.1 aufgelöst wird.
Bei Aufruf lediglich von "localhost" wird der Server jedoch nicht mehr gefunden.
Das liegt, wie du bereits herausgefunden hast, an deinem "Listen"-Eintrag. Dein Server "hört" ausschließlich auf port 9100, und wenn du den nicht explizit in der Adreßzeile angibst, sucht dein Browser auf port 80 herum, wo er natürlich keinen "localhost" finden kann.
Grüße aus Berlin
Christoph S.
Hi Christoph,
Listen 9100
Das ist ungewöhnlich, aber nicht falsch.
ich hab das von einer PC-Konfiguration übernommen, das wurde gemacht um keine Einträge in die host-Datei machen zu müssen
<VirtualHost 0.0.0.0:9100>
Verwende eine IP, die zulässig ist.
Welche IP's sind denn zulässig?
Das liegt, wie du bereits herausgefunden hast, an deinem "Listen"-Eintrag. Dein Server "hört" ausschließlich auf port 9100, und wenn du den nicht explizit in der Adreßzeile angibst, sucht dein Browser auf port 80 herum, wo er natürlich keinen "localhost" finden kann.
hm, es stehen ja nun mehrere Listen-Einträge in der httpd.conf, die auch bei entsprechender Url-Angabe gefunden werden. Sollte Apache also nicht auf mehreren Ports hören?
Danke & Gruesse, Joachim
hallo,
Listen 9100
Das ist ungewöhnlich, aber nicht falsch.
ich hab das von einer PC-Konfiguration übernommen, das wurde gemacht um keine Einträge in die host-Datei machen zu müssen
Das ist eine unsinnige Begründung. Die lokale hosts-Datei hat mit den ports des Apache (bzw. des TCP/IP-Protokolls) nichts zu tun.
hm, es stehen ja nun mehrere Listen-Einträge in der httpd.conf, die auch bei entsprechender Url-Angabe gefunden werden. Sollte Apache also nicht auf mehreren Ports hören?
Doch das kann er durchaus.
Grüße aus Berlin
Christoph S.
Hi,
Doch das kann er durchaus.
ha!
Listen *:80
Listen *:9100
...
das klappt
Danke und Gruesse, Joachim
Hallo,
Listen 9100
<VirtualHost 0.0.0.0:9100>
Wenn Du willst, dass der virtuelle Host für ALLE IPs und Port 9100 gilt, dann musst Du sowas machen wie:
<VirtualHost *:9100>
0.0.0.0 kannst Du nur bei Listen als Platzhalter für "alles" verwenden - und das strenggenommen auch nur auf Grund der Tatsache, dass in der C-Sockets-API INADDR_ANY aus praktischen Gründen für "0.0.0.0" steht, was aber im ENDEFFEKT relativ willkürlich gewählt ist.
Achja, beachte, dass Du Dir damit nur einen IP+Port-basierten VHost anlegst, keinen namensbasierten (was Du aber vmtl. willst).
Viele Grüße,
Christian
Hi,
<VirtualHost *:9100>
vor allem auch beim Listen ;-)
Danke auch Dir, Gruesse, Joachim
Hi,
<VirtualHost *:9100>
vor allem auch beim Listen ;-)
Das ist egal, Listen 80, Listen *:80 und Listen 0.0.0.0:80 sind äquivalent (auf den SELFHTML-Servern verwenden wir zum Beispiel Listen 80, NameVirtualHost *:80 und <VirtualHost *:80>). Nur bei <VirtualHost> ist das eben nicht mehr so egal.
Hintergrund: Bei der Listen-Direktive gibt man nur an, wo das Betriebssystem lauschen soll. Die folgende Tabelle soll verdeutlichen, warum die drei beschriebenen Varianten im Endeffekt identisch sind:
Konfigurationsdatei | Apache intern | Betriebssystem
-----------------------+-------------------------+-------------------------
keine Angabe | alle Interfaces | alle Interfaces
* | alle Interfaces | alle Interfaces
0.0.0.0 | 0.0.0.0 | alle Interfaces
"keine Angabe" und "*" sind bereits auf Apache-Ebene identisch (d.h. der Apache interpretiert sie genauso). Aus 0.0.0.0 macht erst das Betriebssystem "alle Interfaces".
Was ist nun mit dem <VirtualHost>? Bei <VirtualHost> spielt es keine _direkte_ Rolle, WO der Apache nun genau lauscht, sondern wohin die konkrete Verbindung aufgebaut wurde.
Beispiel: Der Apache lauscht auf allen Interfaces, dies sei zum einen eine normale Netzwerkkarte (oder WLAN) mit 10.0.0.1 (als Beispiel jetzt mal), zum anderen natürlich localhost mit 127.0.0.1. Wenn nun eine Verbindung hereinkommt, dann fragt der Apache das Betriebssystem "Woher kommt die Verbindung?" (daher bekommt er dann die Client-IP für REMOTE_ADDR etc.) und "Wohin geht die Verbindung?" Die Antwort auf die zweite Frage scheint auf den ersten Blick trivial: "Na du selbst" - aber es ist eben ein Unterschied, ob ich http://10.0.0.1/ oder http://127.0.0.1/ in die Adresszeile eingebe. Sprich: Die konkrete (!) Verbindung spielt bei <VirtualHost> eine Rolle - soll sie ja auch, das ist ja der Witz daran. ;-)
Nun, das Betriebssystem gibt in unserem Beispiel entweder 10.0.0.1 oder 127.0.0.1 zurück, andere Möglichkeiten gibt es nicht[1]. Der Apache vergleicht dies nun mit seiner Regel für <VirtualHost>. Probieren wir aus, was passiert, wenn die drei Listen-Angabemöglichkeiten für "alles" in <VirtualHost> stehen:
- keine Angabe
-> geht schonmal gar nicht, weil <VirtualHost> primär eine IP
erwartet und keinen Port (der optional ist), während es bei Listen
genau umgekehrt ist: Ein Port wird erwartet, die IP ist optional
- *
-> funktioniert, Apache interpretiert * als "alle IPs" und dann ist
ihm egal, ob die IP nun 127.0.0.1 oder 10.0.0.1 oder sonstwas ist
- 0.0.0.0
-> funktioniert nicht, Apache interpretiert an dieser IP NICHTS mehr
herum (das hat bei Listen ja auch das Betriebssystem gemacht! Das
ist hier aber nicht mehr involviert, weil es hier ja nur die IP
der Verbindung ZURÜCKGEGEBEN hat und das war's) und deswegen schlägt
der IP-Vergleich fehl. Was passiert also? Der Default-Host wird
genommen. Und das ist genau das von Dir im Ausgangsposting
beschriebene verhalten.
Viele Grüße,
Christian
[1] Jaja, 127.0.0.1 ist eigentlich ein /8er-Netz, das unterschlage ich jetzt einmal, weil's das Verständnis nicht weiterbringt.
hallo Christian,
gut geschrieben und vermutlich überzeugend - aber obwohl ich dir ein "hilfreich" draufgeklebt habe, gibt es Anmerkungen dazu.
Listen 80, Listen *:80 und Listen 0.0.0.0:80 sind äquivalent
Im strengen Sinn nicht. Die ersten beiden ("Listen 80" und "Listen *:80") sind es. 0.0.0.0 ist es nur in der Art, in der der Apache diese "IP" behandelt.
Es könnte sich lohnen, hier bei künftigen SELFHTML-Ausgaben auf diese "IP" einzugehen, beispielsweise dann, wenn über die Rolle von "privaten" IP-Adressen und Netzwerkmasken wenigstens andeutungsweise im Webserver-Kapitel - oder an anderer geeigneter Stelle - eingegangen werden sollte.
(auf den SELFHTML-Servern verwenden wir zum Beispiel Listen 80, NameVirtualHost *:80 und <VirtualHost *:80>)
Nett, das zu erfahren, aber eigentlich keine Überraschung.
Nur bei <VirtualHost> ist das eben nicht mehr so egal.
Full ACK.
Hintergrund: Bei der Listen-Direktive gibt man nur an, wo das Betriebssystem lauschen soll.
Das halte ich für eine fragwürdige und deshalb auch zu diskutierende Aussage. In der Apache-Dokumentation steht: "Die Direktive Listen weist den Apache an, nur an den angegebenen IP-Adressen oder Ports zu lauschen". Da ist also nichts von "Betriebssystem" formuliert.
Die folgende Tabelle [...]
...transportiert diesen Irrtum, was den Terminus "Betriebssystem" angeht. Die Aussage, die aus ihr herausgelesen werden kann, ist allerdings wiederum wahr und richtig.
Was ist nun mit dem <VirtualHost>? Bei <VirtualHost> spielt es keine _direkte_ Rolle, WO der Apache nun genau lauscht, sondern wohin die konkrete Verbindung aufgebaut wurde.
Auch das ist vollkommen richtig.
Beispiel: Der Apache lauscht auf allen Interfaces, dies sei zum einen eine normale Netzwerkkarte (oder WLAN) mit 10.0.0.1 (als Beispiel jetzt mal), zum anderen natürlich localhost mit 127.0.0.1.
Und das ist es erneut nicht ganz. Dem Apache sind "Interfaces" ziemlich egal - hier könnte es allerdings sein, daß du unter "Interface" etwas anderes verstehst als ich. Den Apache interessiert als HTTP-Server nun einmal nur eines: das Protokoll, über das er erreichbar ist. Wer ihm dieses Protokoll (bzw. Anfragen, die über dieses Protokoll hereinkommen) zuleitet, ist ihm völlig egal.
Netzwerkkarten sind natürlicherweise dazu da, die über das OSI-Modell verfügbaren Protokolle zu vermitteln, darunter auch HTTP. Im Betriebssystem gibt es weitere Bestandteile (in der Regel Bibliotheken), die HTTP können - und nach meinem Verständnis sind das eben nicht "Interfaces". "localhost" ist an solche Bestandteile des Betriebssystems gebunden, da er nicht nur von einem eventuell vorhandenen Apache, sondern auch von mancher anderen Software in Anspruch genommen werden kann (sowohl unter Windows wie unter Linux). "Interfaces" wie die Netzwerkkarte sind das nicht. Und den Apache interessiert nun überhaupt nicht, ob eine Anfrage über die Netzwerkkarte eintrifft oder über eine zum Betriebssystem gehörende Bibliothek. Ihn interessiert, ob seine Konfiguration mit der IP etwas anfangen kann.
Wenn nun eine Verbindung hereinkommt, dann fragt der Apache das Betriebssystem "Woher kommt die Verbindung?"
Nein, das tut er meines Wissens nicht. Er fragt allerdings das Protokoll, ob er denn mit den hereinkommenden Paketen etwas anfangen soll, und
(daher bekommt er dann die Client-IP für REMOTE_ADDR etc.)
glaubt diese Informationen nach Bestätigung.
es ist eben ein Unterschied, ob ich http://10.0.0.1/ oder http://127.0.0.1/ in die Adresszeile eingebe.
Ja, das ist es, sogar _sehr_.
Die konkrete (!) Verbindung spielt bei <VirtualHost> eine Rolle
ACK.
Ich hatte in meiner Antwort stillschweigend vorausgesetzt, daß es um einen namensbasierten VirtHost geht, obwohl die Angaben im OP für diese Einschätzung nicht ausreichen. Wenn ich deine Ausführungen richtig lese, gehst du ebenfalls davon aus, daß der OP einen namensbasierten VirtHost haben möchte - wenn nicht, müßten wir gegebenenfalls weiterdiskutieren.
Grüße aus Berlin
Christoph S.
Hallo Christoph,
Listen 80, Listen *:80 und Listen 0.0.0.0:80 sind äquivalent
Im strengen Sinn nicht.
Das schrieb ich ja selbst. ;-)
Aber wenn man nur IPv4 einsetzt, dann haben sie die gleiche Wirkung, das meinte ich mit äquivalent - nicht mehr, nicht weniger.
Hintergrund: Bei der Listen-Direktive gibt man nur an, wo das Betriebssystem lauschen soll.
Das halte ich für eine fragwürdige und deshalb auch zu diskutierende Aussage. In der Apache-Dokumentation steht: "Die Direktive Listen weist den Apache an, nur an den angegebenen IP-Adressen oder Ports zu lauschen". Da ist also nichts von "Betriebssystem" formuliert.
Ähm, ich wollte das ganze jetzt nicht mit technischem Slang überladen, aber da Du das jetzt anzweifelst:
Der Apache ruft im Endeffekt nur die Systemaufrufe bind() und listen() auf. Wenn ich mal aus dem Apache-Code zitieren darf. Aus server/listen.c:
// Zeile 132 (Apache 2.2 SVN)
if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS)
[...]
// Zeile 140 (Apache 2.2 SVN)
if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS)
Hier werden die Funktionen apr_socket_bind() und apr_socket_listen() aufgerufen. Diese sind im Endeffekt NICHTS ANDERES als Wrapper um die Systemaufrufe bind() und listen().
bind() sagt dem Betriebssystem: "Dieses Socket ist an diese Adresse gebunden" während listen() sagt "Lausche auf eingehende Verbindungen".
Schauen wir uns nun Zeile 603 von server/listen.c an, die die "Listen"-Einträge verarbeitet:
rv = apr_parse_addr_port(&host, &scope_id, &port, argv[0], cmd->pool);
Dort wird die Funktion apr_parse_addr_port() aufgerufen, die im Endeffekt nichts anderes tut, als die Variablen host, scope_id und port zu befüllen auf Grund der Daten, die als Angabe für Listen angegeben wurden.
Beispiel: Listen 10.0.0.1:1234
Nach Aufruf der Funktion:
host == "10.0.0.1"
scope_id == NULL
port == "1234"
Beispiel: Listen 1234
host == NULL
scope_id == NULL
port == "1234"
Beispiel: Listen *:1234
host == "*"
scope_id == NULL
port == "1234"
[scope_id ist eh nur für IPv6 und kann hier ignoriert werden]
Weiter unten ist dann noch folgende Abfrage drin:
if (host && !strcmp(host, "*")) {
host = NULL;
}
Sprich: Wenn host angegeben wurde und das gleiche ist wie "*", dann wird host auf NULL gesetzt. Hier haben wir die Äquivalenz von "*" und keiner Angabe (ok, soweit waren wir uns ja eh einig).
Dann wird weiter unten die Funktion alloc_listener() mit host und port aufgerufen, schauen wir uns die an:
In Zeile 244 der gleichen Datei sehen wir, dass die Variable host als Parameter addr übergeben wird, während der Parameter für den Port gleich heißt: port.
In Zeile 283 steht:
if ((status = apr_sockaddr_info_get(&sa, addr, APR_UNSPEC, port, 0,
process->pool))
Dort wird also eine Struktur des Types apr_sockaddr_t (so wird sa deklariert) gefüllt mit den Daten aus addr und port. Im Endeffekt füllt diese Funktion aus der Apache Portable Runtime die sockaddr_t-Struktur so, dass das Betriebssystem beim bind()-Aufruf etwas damit anfangen kann. Wenn addr "0.0.0.0" ist, dann ändert die Funktion an der IP gar nichts, lässt sie vom Betriebssystem einfach umrechnen in die maschinenlesbare Form. Wenn addr dagegen NULL ist (d.h. wenn "alle Adressen" gefordert werden), dann füllt die Funktion die Struktur mit der Adresse, die für "alle Interfaces" steht - und die ist eben "0.0.0.0" auf allen Betriebssystemen.
Das Betriebssystem bekommt also in jedem Fall eine struct sockaddr_in zu sehen, bei der der Eintrag sin_addr auf INADDR_ANY (= 0) gesetzt ist - was dann das Betriebssystem anweist "dieser Socket ist an alle IP-Adressen gebunden".
Die folgende Tabelle [...]
...transportiert diesen Irrtum, was den Terminus "Betriebssystem" angeht.
Nein, siehe oben.
Beispiel: Der Apache lauscht auf allen Interfaces, dies sei zum einen eine normale Netzwerkkarte (oder WLAN) mit 10.0.0.1 (als Beispiel jetzt mal), zum anderen natürlich localhost mit 127.0.0.1.
Und das ist es erneut nicht ganz. Dem Apache sind "Interfaces" ziemlich egal - hier könnte es allerdings sein, daß du unter "Interface" etwas anderes verstehst als ich.
Unter Interface verstehe ich alles, was unter ifconfig (UNIX) bzw. ipconfig (Windows) zu sehen ist - und da gehört localhost auch dazu!
Natürlich ist 'lo' (für Localhost) nur ein internes Interface, aber es ist ein Interface.
Wie das Interface physikalisch realisiert ist, interessiert den Apache natürlich wirklich nicht, das ist klar. Aber unterschiedliche physikalische Interfaces führen eben auch zu unterschiedlichen "logischen" Interfaces, die zwar alle, was IP angeht, gleich ansteuerbar sind, aber dennoch unterscheidbar sind!
Wenn ein Programm sich ber bind() an eine Adresse binden will, dann MUSS ein Interface diese Adresse als eingestellte IP-Adresse besitzen, sonst gibt's einen Fehler. Sprich: Wenn ich zwei Interfaces 'lo' (mit 127.0.0.1 als IP) und 'eth0' (mit 10.0.0.1 als IP) habe, dann kann ich NICHT sagen "nimm 10.0.0.2 als IP, an die Du den Socket binden sollst" - dann schlägt der Aufruf von bind() nämlich fehl! Warum? Weil's kein Interface mit dieser IP gibt!
Natürlich übergibt man an bind() immer Adressen, an die ein Dienst gebunden werden soll, weil das viel universeller (aus Programmsicht) ist, als sich um Interfaces im Programm direkt kümmern zu müssen - aber der Systemkern setzt sowas immer so um, dass das passende Interface für diese IP herausgesucht wird.
Wenn nun eine Verbindung hereinkommt, dann fragt der Apache das Betriebssystem "Woher kommt die Verbindung?"
Nein, das tut er meines Wissens nicht.
Doch. Zum Beispiel (andere MPMs machen's natürlich genauso) ruft server/mpm/prefork/prefork.c die Funktion ap_run_create_connection() auf. Das führt dann dazu, dass im Endeffekt core_create_conn() in server/core.c, Zeile 3873 aufgerufen wird. In Zeile 3890 steht nun:
if ((rv = apr_socket_addr_get(&c->local_addr, APR_LOCAL, csd))
Sprich: Dort wird in das Feld local_addr der Struktur c die lokale (!) Adresse der bestehenden Verbindung eingetragen!
Und an Hand derer kann der Server dann auch für IP-basierte virtuelle Hosts unterscheiden.
Und etwas weiter unten macht er das gleiche für die Remote-Adresse, um so die Client-IP zu kennen.
Er fragt allerdings das Protokoll, ob er denn mit den hereinkommenden Paketen etwas anfangen soll,
Was genau meinst Du damit? "Fragt das Protokoll?" Und wie kommst Du auf Pakete? Wenn man TCP macht, können einem die Pakete egal sein.
Ich hatte in meiner Antwort stillschweigend vorausgesetzt, daß es um einen namensbasierten VirtHost geht, obwohl die Angaben im OP für diese Einschätzung nicht ausreichen. Wenn ich deine Ausführungen richtig lese, gehst du ebenfalls davon aus, daß der OP einen namensbasierten VirtHost haben möchte
Nein, ich setzte das eben nicht vorraus, sondern IP-basierte virtuelle Hosts. Was ja hier auch sinnvoll ist, denn der OP will ja nur, dass auf einem anderen Port ein anderer Host erscheint, jedoch nicht, dass unter dem anderen Port verschiedene Hosts erreichbar sind.
Viele Grüße,
Christian