Apache Virtual Host Definition File (VHDF)

Uit De Vliegende Brigade
(Doorverwezen vanaf Apache virtuele host-definitie)
Naar navigatie springen Naar zoeken springen
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

When you use the Apache webserver to host more than one domain or website on the same computer, you have to work with Virtual Hosts and their associate files.

The name of the game

Let's use VHDF as abbreviation for the unwieldly Apache Virtual Host Definition File.

ChatGPT (2023.09):

While there isn't a widely recognized standard abbreviation for "Apache Virtual Host Definition File," you can use a shortened form like "VHDF" or "VHost File" to refer to it informally. However, it's essential to ensure that the abbreviation is clear and understandable within the context of your documentation or discussions. You can also use "Apache VHost Config" or "Apache Virtual Host Config" to be more explicit about what the file contains.
Ultimately, clarity is more important than a specific abbreviation.

I think the abbreviation VHDL doesn't win a beauty prize either, let's check what others use:

  • Apache2 Virtual Host [1]
  • Apache2 Virtual Host Configuration [2]

Location

The usual location for VHDFs: /etc/apache2/sites-available. Bv.: /etc/apache2/sites-available/flip.thomas

Default file from 2015

Een aantal veelvoorkomende instellingen. Let op: Dit is een combinatie van Drupal- & MediaWiki-bestanden.

<VirtualHost *:80>

ServerName example.com
ServerAlias www.example.com
DirectoryIndex index.php index.html index.htm
DocumentRoot /var/www/example.com   # Gebruik altijd /var/www/domeinnaam

<Directory /var/www/example.com>

	AllowOverride All     # .htaccess mag alle directives overriden
	Require all granted   # Alle IP-adressen ter wereld kunnen example.com bezoeken

        # Enable Drupal CleanURLs
	##########################
        #
	RewriteEngine on
	RewriteBase /
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

</Directory>

# Upload-directory beveiligen
#############################
# Voorbeeld afkomstig van https://www.mediawiki.org/wiki/Manual:Security#Upload_security
# maar waarschijnlijk universeel toepasbaar

<Directory /var/www/example.com/public>   # Dit is de MediaWiki upload-map

   # Ignore .htaccess files
   AllowOverride None
   
   # Serve HTML as plaintext, don't execute SHTML
   AddType text/plain .html .htm .shtml .php .phtml .php5
   
   # Don't run arbitrary PHP code.
   php_admin_flag engine off
   
   # If you've other scripting languages, disable them too.

</Directory>

LogLevel warn
ErrorLog /var/log/apache2/error.log                    # Eén error-log-bestand voor alle domeinen
CustomLog /var/log/apache2/access.log vhost_combined   # Eén access-log-bestand voor alle domeinen, type 'vhost_combined'

</VirtualHost>

Evaluation (2023.09)

What I think of this file, 8 years and a bunch of knowledge later:

  • I wouldn't combine setting for various CMSs in one file - Have different files for different situaitons
  • The statement about universally applicable upload directory security is nonsense
  • You need to know what the file says before deploying it!

Geen aparte log-files

Tot voort kort gebruikte ik dit soort virtuele host-definities:

<VirtualHost *:80>

	ServerName example.com
	ServerAlias www.example.com
	DirectoryIndex index.php index.html index.htm
	DocumentRoot /var/www/example.com/public

	<Directory /var/www/example.com/public>
		AllowOverride All
		Require all granted
		RewriteEngine on
		RewriteBase /
		RewriteCond %{REQUEST_FILENAME} !-f
		RewriteCond %{REQUEST_FILENAME} !-d
		RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
	</Directory>

	LogLevel warn
	ErrorLog /var/www/example.com/log/error.log
	CustomLog /var/www/example.com/log/access.log combines

</VirtualHost>

Hier kleven een paar nadelen aan:

  • Voor elk domein worden twee aparte logfiles bijgehouden. Daar ga ik nooit iets mee doen, want veel te veel werk. Daarnaast hoeven log files niet gescheiden te zijn, want ik ben de enige met toegang tot deze server
  • Elk domein heeft een structuur met drie mappen (public, log, backup) en ook dat is onnodig.

Merk verder op dat combines refereert naar het combines log format dat gedefineerd is in apache2.conf. Dit zijn de definities van logformaten (apache2.conf):

LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent

Als je de logbestanden van meerdere virtuele hosts combineerd, is het handig om het vhost_combined-formaat te gebruiken, want de parameter %v geeft de virtuele host aan, en da's handig met filteren. Locatie van gecombineerde virtuele hostbestanden: /var/log/apache2/access.log en /var/log/apache2/error.log.

Bovenstaand virtueel hostbestand wordt daardoor onherstelbaar verbeterd tot:

<VirtualHost *:80>

	ServerName example.com
	ServerAlias www.example.com
	DirectoryIndex index.php index.html index.htm
	DocumentRoot /var/www/example.com

	<Directory /var/www/example.com>
		AllowOverride All
		Require all granted
		RewriteEngine on
		RewriteBase /
		RewriteCond %{REQUEST_FILENAME} !-f
		RewriteCond %{REQUEST_FILENAME} !-d
		RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
	</Directory>

	LogLevel warn
	ErrorLog /var/log/apache2/error.log
	CustomLog /var/log/apache2/access.log vhost_combined

</VirtualHost>

Inventory: Common settings

I wanted to get an overview of common VHDFs and/or settings for WordPress/WooCommerce. Suprisingly, I can't find much online, and ChatGPT, unreliable as it is, really helps!

Example Nicolas Ramy

[3]: Contains two syntax errors, but has an interesting RewriteRule section nevertheless:

RewriteEngine On
RewriteRule ^index\.php$ - [L]
RewriteCond $1 ^(index\.php)?$ [OR]
RewriteCond $1 \.(gif|jpg|png|ico|css|js)$ [NC,OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.*)$ - [S=1]
RewriteRule . /index.php [L]

A suggestion from ChatGPT (2023.09)

A suggested VHDF for WordPress. Probably not accurate nor reliable, but probably worth examining. With inline comments from me:

#
# This VHDF is for traffic on port 80, which is http and not https. That's
# wrong. I would only put a Redirect in this file, and have everything else in
# the file for https. Actually, you can combine those two VirtualHost
# definitions in one file, but due to the way tha Let's Encrypt works, I've
# done it always in two files
#
<VirtualHost *:80>
   #
   # ServerAdmin
   ########################################
   #
   # This would be redundant, as usually there is one server admin for the
   # whole server → Move this to a general Apache configuration file
   #
   ServerAdmin webmaster@example.com

   ServerName yourdomain.com
   ServerAlias www.yourdomain.com
   DocumentRoot /var/www/html/yourdomain.com

   <Directory /var/www/html/yourdomain.com>

      # Options directive
      ########################################
      #
      # Two options are included:
      #
      # * "Indexes": Enable listing directories when there is no default
      #   index file. I think this is quite wrong
      # * "FollowSymlinks": Enable Apache to follow symbolic links.
      #   This can have quite some security implications, and I am not aware
      #   that this is desired
      #
      Options Indexes FollowSymLinks


      # AllowOverride directive
      ########################################
      #
      # "AllowOverride" specifies to what degree global settings can be
      # overriden through .htaccess. E.g., for an upload folder, you might
      # want to impose restrictions here (in the VHDL file) and deny any
      # possibilities to override
      #
      AllowOverride All


      # Require directive
      ########################################
      #
      # Related to .htaccess control stuff. In this case, everybody is
      # welcome
      #
      Require all granted

   </Directory>

   # Logging
   ########################################
   #
   # Here, separate log files are maintained for each domain - A matter of
   # personal preference, I think
   #
   ErrorLog ${APACHE_LOG_DIR}/yourdomain.com_error.log
   CustomLog ${APACHE_LOG_DIR}/yourdomain.com_access.log combined


   # Compression???
   ########################################
   #
   # * ChatGPT: "Enable compression for better performance"
   # * Interesting: This is new to me
   #
   AddOutputFilterByType DEFLATE text/plain text/html text/xml text/css text/javascript application/javascript


   # ChatGPT: "WordPress specific rewrites"
   ########################################
   #
   # The remaining directives are under this header
   #
   RewriteEngine On


   # RewriteBase
   ########################################
   #
   # Why is this needed? It isn't applied anywhere, is it?
   #
   RewriteBase /


   # RewriteRule ^index\.php$ - [L]
   ########################################
   #
   # What it does:
   #
   # * Look for URL "index.php"
   # * "-": No substitution; keep it as it is
   # * [L]: Stop applying more rewrite rules after this one
   #
   # The reason for this RewriteRule is probably in the [L] part: When coming
   # across this URL, don't do any rewriting. Why have such a rule? Maybe for
   # performance issues: Once this rule has been processed, Apache stops
   # looking for more rules? - I'm unconvinced.
   #
   RewriteRule ^index\.php$ - [L]


   # RewriteRule . /index.php [L]
   ########################################
   #
   # Rewrite any URL into /index.php. I don't understand
   #
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteCond %{REQUEST_FILENAME} !-d
   RewriteRule . /index.php [L]

</VirtualHost>

Securing the uploads directory

Require all denied is the current formulation of what used to be Deny from all. It means that Apache blocks access to all files to which this command applies. E.g.:

<FilesMatch "\.php$">
   Deny from all
</FilesMatch>

Here, it blocks access to all files with the extention php. This could be extended to include all files with extention .sh, but that wouldn't make much sense, as shell scripts don't need an extension.

A more complete example of securing the uploads directory:

<Directory /var/www/html/wordpress/wp-content/uploads>
    Options -Indexes
    AllowOverride None
    Require all granted
    <FilesMatch "\.(php|php\.)$">
        Deny from all
    </FilesMatch>
</Directory>

Lastly: It isn't possible in Apache, to block access to executable files (like chmod +x). No worries: For this I have shell scripts that reset all relevant settings.

Zie ook

Bronnen

Require all granted