16A. Serving multiple domains using Virtual Hosts (Apache)
"The term Virtual Host refers to the practice of running more than one web site (such as company1.example.com and company2.example.com) on a single machine."
"Virtual hosts can be "IP-based", meaning that we have a different IP address for every web site, or "name-based", meaning that we have multiple names running on each IP address." - Apache Virtual Host documentationIt is important to recognize that the first step in name-based virtual host resolution is IP-based resolution. Name-based virtual host resolution only chooses the most appropriate name-based virtual host after narrowing down the candidates to the best IP-based match.
In this article, we'll run several name-based web sites on a single IP address (name-based). In other words, our server has a single IP address, and multiple aliases (CNAMES) point to this machine in DNS.
The basic unit that describes an individual site or domain is called a virtual host.
Each domain that is configured will direct the visitor to a specific directory holding that site's information.
We will walk through how to set up Apache virtual hosts on an Ubuntu 14.04 VPS. During this process, we'll learn how to serve different content to different visitors depending on which domains they are requesting.
Let's install Apache:
$ sudo apt-get update $ sudo apt-get install apache2
We'll use two domains:
- example.com
- example.org
Temporarily, we'll access the site from our local machine after setting up /etc/hosts. In production, we may want to set CNAMES for those sites.
As a first step, we'll make a directory public_html that will hold the data for visitors.
Our document root will be under the /var/www directory. We will create a directory here for both of our virtual hosts:
$ sudo mkdir -p /var/www/example.com/public_html $ sudo mkdir -p /var/www/example.org/public_html
We may also need to modify our permissions so that read access is permitted to the general web directory and all of the files and folders it contains so that pages can be served correctly:
$ sudo chmod -R 755 /var/www $ sudo chown -R www-data:www-data /var/www/example.com $ sudo chown -R www-data:www-data /var/www/example.org drwxr-xr-x 3 www-data www-data 4096 Dec 2 17:22 example.com drwxr-xr-x 3 www-data www-data 4096 Dec 2 17:22 example.org
Create /var/www/example.org/public_html/index.html:
<html> <body> <title>Example.org</title> </head> <body> <h1>Success - example.org virtual host is working!</h1> </body> </html>
Same to example.org.
Virtual host files are the files that specify the actual configuration of our virtual hosts and dictate how the Apache web server will respond to various domain requests.
Apache provides a default virtual host file (000-default.conf):
$ ls /etc/apache2/sites-available 000-default.conf default-ssl.conf
We are going to copy it over to create a virtual host file for each of our domains.
$ sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/example.com.conf
Here is the copied default Virtual host configuration file (/etc/apache2/sites-available/example.com.conf):
<VirtualHost *:80> # The ServerName directive sets the request scheme, hostname and port that # the server uses to identify itself. This is used when creating # redirection URLs. In the context of virtual hosts, the ServerName # specifies what hostname must appear in the request's Host: header to # match this virtual host. For the default virtual host (this file) this # value is not decisive as it is used as a last resort host regardless. # However, you must set it for any further virtual host explicitly. #ServerName www.example.com ServerAdmin webmaster@localhost DocumentRoot /var/www/html # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, # error, crit, alert, emerg. # It is also possible to configure the loglevel for particular # modules, e.g. #LogLevel info ssl:warn ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined # For most configuration files from conf-available/, which are # enabled or disabled at a global level, it is possible to # include a line for only one particular virtual host. For example the # following line enables the CGI configuration for this host only # after it has been globally disabled with "a2disconf". #Include conf-available/serve-cgi-bin.conf </VirtualHost>
We will modify the items here for our first domain and add some additional directives. This virtual host section matches any requests that are made on port 80, the default HTTP port.
First, we need to change the ServerAdmin directive to an email that the site administrator can receive emails through.
ServerAdmin admin@example.com
Then, we need to add two more directives:
- ServerName : It establishes the base domain that should match for this virtual host definition. This will most likely be our domain.
- ServerAlias : It defines further names that should match as if they were the base name. This is useful for matching hosts we defined, like www
So, the two lines should look like this:
ServerName example.com ServerAlias www.example.com
Lastly, we need to change for a basic virtual host file is the location of the document root for this domain. We already created the directory we need, so we just need to alter the DocumentRoot directive to reflect the directory we created:
DocumentRoot /var/www/example.com/public_html
Here is our final configuration file (/etc/apache2/sites-available/example.com.conf):
<VirtualHost *:80> ServerAdmin admin@example.com ServerName example.com ServerAlias www.example.com DocumentRoot /var/www/example.com/public_html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
Now, let's work on the other one:
$ sudo cp /etc/apache2/sites-available/example.com.conf /etc/apache2/sites-available/example.org.conf
After modifying the file, we should have the following:
<VirtualHost *:80> ServerAdmin admin@example.org ServerName example.org ServerAlias www.example.org DocumentRoot /var/www/example.org/public_html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
Now that we have created our virtual host files, we must enable them using a2ensite:
$ sudo a2ensite example.com.conf $ sudo a2ensite example.org.conf
We need to restart Apache to make these changes take effect:
$ sudo service apache2 restart
Centos does not have a2ensite, and we need to do exactly what it does in Debian.
Basically, it sets a soft link for sites-available/example.com.conf to sites-enabled/example.com.conf:
Now that we have created our virtual host files, we must enable them using a2ensite:$ sudo ln -s /etc/apache2/sites-available/example.com.conf /etc/apache2/sites-enabled/example.com.conf $ sudo ln -s /etc/apache2/sites-available/example.org.conf /etc/apache2/sites-enabled/example.org.conf
Depending on the system, httpd can be used instead of the apache2.
Also, note that we should let Apache know where it supposed to look for any conf file. We set it in /etc/apache2/conf/apache2.conf, and added the last line:
... # Supplemental configuration # # Load config files in the "/etc/apache2/conf.d" directory, if any. IncludeOptional conf.d/*.conf IncludeOptional sites-enabled/*.conf
Now, we should restart Apache to make these changes take effect:
$ sudo apachectl restart
Instead of using two configuration files for the two domains, we can simply use one default configuration file 000-default.conf by combining the two configure statements like this:
<VirtualHost *:80> ServerAdmin admin@example.com ServerName example.com ServerAlias www.example.com DocumentRoot /var/www/example.com/public_html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> <VirtualHost *:80> ServerAdmin admin@example.org ServerName example.org ServerAlias www.example.org DocumentRoot /var/www/example.org/public_html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
Because we're not using actual domain names, we need to setup our local host file (/etc/hosts):
127.0.0.1 localhost 54.153.24.251 example.com 54.153.24.251 example.org
Type http://example.com on our local browser:
For http://example.org:
"You should avoid using .htaccess files completely if you have access to httpd main server config file. Using .htaccess files slows down your Apache http server. Any directive that you can include in a .htaccess file is better set in a Directory block, as it will have the same effect with better performance." - Apache HTTP Server Tutorial: .htaccess files
The .htaccess page may slow down our server somewhat. This is because of the location of the page: the .htaccess file affects the pages in its directory and all of the directories under it. Each time a page loads, the server scans its directory, and any above it until it reaches the highest directory or an .htaccess file. This process will occur as long as the AllowOverride allows the use of .htaccess files, whether or not the file the .htaccess files actually exists.
How to Activate an .htaccess file
If we have access to the server settings, we can edit the configuration to allow the .htaccess file to override standard website configs. Open the apache2 default host configuration file.
$ sudo nano /etc/apache2/sites-available/default
Once inside that file, change the line that says AllowOverride from None to All. The section should now look like this:
<Directory /var/www/> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory>
After we save and exit that file, restart apache.
$ sudo service apache2 restart
In the configuration, FollowSymLinks means if a dir is a symbol link, follow the link, and Indexes means a dir can be show as list if no index page.
Access control - Upgrading to 2.4 from 2.2
Here are some examples of old and new ways to do the same access control.
In this example, all requests are denied:
2.2 configuration:Order deny,allow Deny from all2.4 configuration:
Require all denied
In this example, all requests are allowed:
2.2 configuration:Order allow,deny Allow from all2.4 configuration:
Require all granted
In the following example, all hosts in the example.org domain are allowed access; all other hosts are denied access:
2.2 configuration:Order Deny,Allow Deny from all Allow from example.org2.4 configuration:
Require host example.org
In this sample, we have two domains sfvue.com and einsteinish.com which are using Django framework.
References are:
- 1. Setup CentOS 7 hosted on VPS
- 1B. Setup CentOS 7 hosted on VPS (multi-domain hosting setup) - Name server and Zone File settings (from GoDaddy to Linode)
- A sample production app (sfvue.com) with virtualenv and Apache
In this section, we'll only deal with Apache configuration for name-based multiple domain server.
The configurations are available in /etc/httpd/sites-available folder:
$ ls /etc/httpd/sites-available einsteinish.com.conf sfvue.com.conf
Also, we have aliases for the two domain in /etc/httpd/sites-enabled folder:
$ ls -la /etc/httpd/sites-enabled total 8 drwxr-xr-x 2 root root 4096 Jan 4 13:34 . drwxr-xr-x 8 root root 4096 Dec 17 20:31 .. lrwxrwxrwx 1 root root 47 Jan 4 13:34 einsteinish.com.conf -> /etc/httpd/sites-available/einsteinish.com.conf lrwxrwxrwx 1 root root 41 Jan 3 17:59 sfvue.com.conf -> /etc/httpd/sites-available/sfvue.com.conf
Note that in /etc/httpd/conf/httpd.conf file, we need to add the following line to tell Apache where it can find configuration:
IncludeOptional sites-enabled/*.conf
The configurations files look like this.
/etc/httpd/sites-available/sfvue.com.conf:
<VirtualHost *:80> ServerAdmin webmaster@sfvue.com ServerName sfvue.com ErrorLog /var/www/sfvue.com/logs/error.log CustomLog /var/www/sfvue.com/logs/access.log combined WSGIDaemonProcess sfvue3 python-path=/var/www/django/sfvue3:/var/www/django/sfvue3/venv/lib/python2.7/site-packages WSGIProcessGroup sfvue3 WSGIScriptAlias / /var/www/django/sfvue3/sfvue/wsgi.py Alias /static/ /var/www/django/sfvue3/static/ </VirtualHost> <Directory /> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> WSGIPythonPath /var/www/django/sfvue3/ <Directory "/var/www/django/sfvue3/sfvue"> <Files wsgi.py> Require all granted </Files> </Directory>
/etc/httpd/sites-available/einsteinish.com.conf:
<VirtualHost *:80> ServerAdmin webmaster@einsteinish.com ServerName einsteinish.com ErrorLog /var/www/einsteinish.com/logs/error.log CustomLog /var/www/einsteinish.com/logs/access.log combined WSGIDaemonProcess einsteinish3 python-path=/var/www/django/einsteinish3:/var/www/django/einsteinish3/venv/lib/python2.7/site-packages WSGIProcessGroup einsteinish3 WSGIScriptAlias / /var/www/django/einsteinish3/einsteinish/wsgi.py Alias /static/ /var/www/django/einsteinish3/static/ </VirtualHost> <Directory /> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> WSGIPythonPath /var/www/django/einsteinish3/ <Directory "/var/www/django/einsteinish3/einsteinish"> <Files wsgi.py> Require all granted </Files> </Directory>
The two sites have similar file structure. Here is one of them:
DevOps
DevOps / Sys Admin Q & A
Linux - system, cmds & shell
- Linux Tips - links, vmstats, rsync
- Linux Tips 2 - ctrl a, curl r, tail -f, umask
- Linux - bash I
- Linux - bash II
- Linux - Uncompressing 7z file
- Linux - sed I (substitution: sed 's///', sed -i)
- Linux - sed II (file spacing, numbering, text conversion and substitution)
- Linux - sed III (selective printing of certain lines, selective definition of certain lines)
- Linux - 7 File types : Regular, Directory, Block file, Character device file, Pipe file, Symbolic link file, and Socket file
- Linux shell programming - introduction
- Linux shell programming - variables and functions (readonly, unset, and functions)
- Linux shell programming - special shell variables
- Linux shell programming : arrays - three different ways of declaring arrays & looping with $*/$@
- Linux shell programming : operations on array
- Linux shell programming : variables & commands substitution
- Linux shell programming : metacharacters & quotes
- Linux shell programming : input/output redirection & here document
- Linux shell programming : loop control - for, while, break, and break n
- Linux shell programming : string
- Linux shell programming : for-loop
- Linux shell programming : if/elif/else/fi
- Linux shell programming : Test
- Managing User Account - useradd, usermod, and userdel
- Linux Secure Shell (SSH) I : key generation, private key and public key
- Linux Secure Shell (SSH) II : ssh-agent & scp
- Linux Secure Shell (SSH) III : SSH Tunnel as Proxy - Dynamic Port Forwarding (SOCKS Proxy)
- Linux Secure Shell (SSH) IV : Local port forwarding (outgoing ssh tunnel)
- Linux Secure Shell (SSH) V : Reverse SSH Tunnel (remote port forwarding / incoming ssh tunnel) /)
- Linux Processes and Signals
- Linux Drivers 1
- tcpdump
- Linux Debugging using gdb
- Embedded Systems Programming I - Introduction
- Embedded Systems Programming II - gcc ARM Toolchain and Simple Code on Ubuntu/Fedora
- LXC (Linux Container) Install and Run
- Linux IPTables
- Hadoop - 1. Setting up on Ubuntu for Single-Node Cluster
- Hadoop - 2. Runing on Ubuntu for Single-Node Cluster
- ownCloud 7 install
- Ubuntu 14.04 guest on Mac OSX host using VirtualBox I
- Ubuntu 14.04 guest on Mac OSX host using VirtualBox II
- Windows 8 guest on Mac OSX host using VirtualBox I
- Ubuntu Package Management System (apt-get vs dpkg)
- RPM Packaging
- How to Make a Self-Signed SSL Certificate
- Linux Q & A
- DevOps / Sys Admin questions
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization