Denne posten tar for seg oppsett av det som kalles "mass virtual hosting" på Apache.
Det finnes forskjellige måter å gjøre dette på også, og måten jeg gjør det på er sikkert ikke den beste, men det funker for meg og har gjort det lenge.
Min config, som ikke er min i det hele tatt, men tilpasset mine behov basert på en config for et webcluster i en tidligere jobb, benytter seg av Apaches mod_rewrite. Configen ble brukt på Apache 2.0 på webclusteret, og tilpasset Apache 1.3 for min egen server. Etterhvert ble Apache oppgradert til 2.0, 2.2 og sist til 2.4, og configen har blitt tilpasset i takt med oppgraderingene.
Apache har også en egen modul for nettopp dette, mod_vhost_alias, som i følge dokumentasjonen skal gjøre akkurat det samme denne configen gjør, men jeg har ikke blitt helt venner med mod_vhost_alias siden den legger føringer for mappestruktur og ikke fungerer med subdomener. Configen under gir meg helt frie tøyler til å lage akkurat den mappestrukturen jeg vil, og den fungerer med subdomener helt automagisk.
Dette er altså min auto-vhost-config for Apache, som jeg har brukt i 12 år. Den er noe dyr i drift siden den er basert på et lass rewrite-statements, men den funker bra og har blitt oppdatert fra Apache 1.3 til 2.0 til 2.2 til 2.4 gjennom årenes løp.
Siste versjon for Apache 2.4 ser slik ut:
# # Use name-based virtual hosting. # #NameVirtualHost *:80 # Deprecated in Apache 2.4 <Virtualhost *:80> <Directory /www/> # AllowOverride FileInfo AuthConfig Limit Indexes Options AllowOverride All Options MultiViews Includes FollowSymlinks ExecCGI Indexes <Limit GET POST OPTIONS> Require all granted </Limit> <LimitExcept GET POST OPTIONS> Require all granted </LimitExcept> </Directory> Alias /error/ "/usr/local/www/apache24/error/" <Directory "/usr/local/www/apache24/error/"> AllowOverride None Options IncludesNoExec AddOutputFilter Includes html AddHandler type-map var Require all granted LanguagePriority en cs de es fr it ja ko nl pl pt-br ro sv tr ForceLanguagePriority Prefer Fallback </Directory> ErrorDocument 400 /error/HTTP_BAD_REQUEST.html.var ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var ErrorDocument 403 /error/HTTP_FORBIDDEN.html.var ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var ErrorDocument 405 /error/HTTP_METHOD_NOT_ALLOWED.html.var ErrorDocument 408 /error/HTTP_REQUEST_TIME_OUT.html.var ErrorDocument 410 /error/HTTP_GONE.html.var ErrorDocument 411 /error/HTTP_LENGTH_REQUIRED.html.var ErrorDocument 412 /error/HTTP_PRECONDITION_FAILED.html.var ErrorDocument 413 /error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var ErrorDocument 414 /error/HTTP_REQUEST_URI_TOO_LARGE.html.var ErrorDocument 415 /error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var ErrorDocument 500 /error/HTTP_INTERNAL_SERVER_ERROR.html.var ErrorDocument 501 /error/HTTP_NOT_IMPLEMENTED.html.var ErrorDocument 502 /error/HTTP_BAD_GATEWAY.html.var ErrorDocument 503 /error/HTTP_SERVICE_UNAVAILABLE.html.var ErrorDocument 506 /error/HTTP_VARIANT_ALSO_VARIES.html.var # Activate the magic RewriteEngine On # Remove the Vary header for MSIE, since it doesn't support pipelining. Not sure about recent versions, and old versions shouldn't be used. We don't want to support old versions anyway. Header unset Vary RewriteCond %{REQUEST_METHOD} !^(GET|POST|HEAD)$ RewriteRule .* - [F] # We need to force mime types for cgi scripts and php scripts. # We create our own function variable called "lowercase" RewriteMap lowercase int:tolower ### CGI # Deal with CGIs -- force a MIME type RewriteCond %{REQUEST_URI} ^/cgi-bin/ # Remove www. from request RewriteCond %{HTTP_HOST} ^(www\.)?(.+)$ [NC] # Check if there is a symlink for domain in /www RewriteCond /www/${lowercase:%2} -l # Do the redirect RewriteRule ^/cgi-bin/(.*)$ /www/${lowercase:%2}/htdocs/cgi-bin/$1 [E=DOCUMENT_ROOT:/www/${lowercase:%2}/htdocs,T=application/x-httpd-cgi,L] # Deal with errors if something isn't found RewriteCond %{REQUEST_URI} ^/error/ # Serve regular files # Remove www from request RewriteCond %{HTTP_HOST} ^(www\.)?(.+)$ [NC] # Check if there is a symlink for domain RewriteCond /www/${lowercase:%2} -l # Redirect and get files RewriteRule ^/error/(.*)$ /www/error/$1 [E=DOCUMENT_ROOT:/www/${lowercase:%2}htdocs,L] ### PHP handling # Check if the requested file is a PHP file RewriteCond %{REQUEST_URI} \.(php|php3|php4|php5|phtml) # Remove www. from request RewriteCond %{HTTP_HOST} ^(www\.)?(.+)$ [NC] # Check if there is a symlink for domain RewriteCond /www/${lowercase:%2} -l # Do the redirect RewriteRule ^/(.*)$ /www/${lowercase:%2}/htdocs/$1 [E=DOCUMENT_ROOT:/www/${lowercase:%2}/htdocs,T=application/x-httpd-php,L] # otherwise # Remove www. from request RewriteCond %{HTTP_HOST} ^(www\.)?(.+)$ [NC] # Check if there is a symlink for domain in /www RewriteCond /www/${lowercase:%2} -l # Do the redirect RewriteRule ^/(.*)$ /www/${lowercase:%2}/htdocs/$1 [E=DOCUMENT_ROOT:/www/${lowercase:%2}/htdocs,L] ####### SUBDOMAINS ######## # Deal with CGIs -- force a MIME type RewriteCond %{REQUEST_URI} ^/cgi-bin/ # Remove www. from request RewriteCond %{HTTP_HOST} ^(www\.)?(.+?)\.(.+)$ [NC] # Check if subdomain folder exists RewriteCond /www/${lowercase:%3}/subdomener/${lowercase:%2} -d # Do the redirect RewriteRule ^/(.*)$ /www/${lowercase:%3}/subdomener/${lowercase:%2}/$1 [E=DOCUMENT_ROOT:/www/${lowercase:%3}/subdomener/${lowercase:%2},T=application/x-httpd-cgi,L] # Handle errors RewriteCond %{REQUEST_URI} ^/error/ RewriteCond %{HTTP_HOST} ^(www\.)?(.+?)\.(.+)$ [NC] RewriteCond /www/${lowercase:%3}/subdomener/${lowercase:%2} -d RewriteRule ^/error/(.*)$ /www/error/$1 [E=DOCUMENT_ROOT:/www/${lowercase:%3}/subdomener/${lowercase:%2},L] ### PHP, again # Check if the requested file is a PHP file (note the .pthml missing - gotta love consistency. Should be cleaned up further.) RewriteCond %{REQUEST_URI} \.(php|php3|php4|php5) # Remove www. from request RewriteCond %{HTTP_HOST} ^(www\.)?(.+?)\.(.+)$ [NC] # Check if subdomain folder exists RewriteCond /www/${lowercase:%3}/subdomener/${lowercase:%2} -d # Do the redirect RewriteRule ^/(.*)$ /www/${lowercase:%3}/subdomener/${lowercase:%2}/$1 [E=DOCUMENT_ROOT:/www/${lowercase:%3}/subdomener/${lowercase:%2},T=application/x-httpd-php,L] # Remove www. from request RewriteCond %{HTTP_HOST} ^(www\.)?(.+?)\.(.+)$ [NC] # Check if subdomain folder exists under the main domain name - note: we do NOT # make symlinks for subdomains, they just work automagically! RewriteCond /www/${lowercase:%3}/subdomener/${lowercase:%2} -d # Do the redirect RewriteRule ^/(.*)$ /www/${lowercase:%3}/subdomener/${lowercase:%2}/$1 [E=DOCUMENT_ROOT:/www/${lowercase:%3}/subdomener/${lowercase:%2},L] # If nothing else matches, redirect to a default page that has an explanation. Use with care. #RewriteRule ^.*$ https://example.net/error/feil.html [R,L] </Virtualhost>
Under /www må du opprette symbolske lenker til der webfilene faktisk ligger. Hvor de ligger er uvesentlig så lenge katalogstrukturen under domenenavnet er som følger:
/home/user/www/example.com/htdocs /home/user/www/example.com/subdomener
For å opprette subdomener, bruk følgende struktur:
/home/user/www/example.com/subdomener/ting /home/user/www/example.com/subdomener/jubel Disse vil da nås i en nettleser som følger:
http(s)://example.com http(s)://ting.example.com http(s)://jubel.example.com
Merk at du linker til domene-mappen, ikke htdocs-mappen. Eksempel:
# cd /www # ln -s /home/user/www/example.com example.com
Om du ønsker å bruke andre mappenavn enn htdocs og subdomener kan du endre dem til hva du vil så lenge det oppdateres i configen.