When starting new applications, a developer often needs to set up a new virtual host. This includes setting up new configuration files for Apache or new Nginx site entries. Sometimes you need to do this manually. Other times, it’s handled automatically if you just define a site-to-folder mapping. But wouldn’t it be practical if we could skip that step, too, and just have any URL ending in, for example, .local.com
look for its files automatically, so all we need to do is change our etc/hosts
file only once ever? Whoa!
In this tutorial, we’ll set up Nginx and Apache to automatically look inside certain folders when it detects a given URL format. For example, the URL mynewsite.local.com
will automatically look inside the DOC_ROOT/nynewsite/public
folder for the index.php
file. You will then be able to define other patterns suitable for generic scripts, standard MVC apps (public/index.php
) and Symfony/Silex based apps (web/app.php
) – all depending on the URL format (e.g. mynewsite.sf2local.com
could look inside web/
for app.php
, as is typical of those frameworks).
This tutorial will be Unix-centric, but is Windows-friendly if you use our Homestead Improved box.
Before we begin, make sure you have something.local.com
in your /etc/hosts
file, so that we can test this URL as we go along. If desired, modify it to your liking. I’ll be focusing on the local.com
suffix for triggering Vhost lookups inside the something
folder in our document root, but this can be literally anything that’s valid in a URL charset.
Setting up for Nginx
Assuming you have an Nginx setup running, either via Homestead Improved or any other means, let’s create a new entry in the folder Nginx typically uses to read site configurations from: sites-available
. In a standard installation, Nginx will include everything from the folder sites-enabled
in its configuration. Putting the file we’re about to write into sites-available
will require us to activate it later.
vim /etc/nginx/sites-available/wildcard.conf
We first define a server
block and tell it to listen on port 80:
server {
listen 80;
}
Everything else we write will be put inside the server block, below the listen
statement.
server_name ~^(www\.)?(?<sname>.+?).local.com$;
This right here is the most important part. It tells Nginx “The server name will come in the form of this regular expression. Pull out the sname
bit, save it for later”.
root /home/vagrant/Code/$sname;
This tells Nginx “The root folder of this web application is in this location”. Since it appends sname
from the above regex, the path becomes dynamic, corresponding to the URL. If you’re not running a virtual machine, or have a differently set up root folder in general, feel free to change this – just make sure it ends in $sname;
. If your apps typically have their front controller in the public
folder, feel free to append public
so the root
statement looks like this:
root /home/vagrant/Code/$sname/public;
This approach is what I’ll be using in the final version of the file.
The rest of the configuration can stay the same as usual. That’s more or less it, unless you would also like to have dynamic error logs, in which case the error log entries in the file should look like this:
access_log /var/log/nginx/$sname-access.log;
error_log /var/log/nginx/wildcard-error.log debug;
Note that we cannot have a variable in the error log, only the access log. Not sure why this was implemented like this. This does mean, unfortunately, that your wildcard error logs will be merged.
What follows is the full code of the configuration file we wrote. Depending on your installation, some other things may vary (like php-fpm lines etc.) but that’s outside the scope of this tutorial.
```
server {
listen 80;
server_name ~^(www\.)?(?<sname>.+?).local.com$;
root /home/vagrant/Code/$sname/public;
index index.html index.htm index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log /var/log/nginx/$sname-access.log;
error_log /var/log/nginx/wildcard-error.log debug;
error_page 404 /index.php;
sendfile off;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
It’s possible that your Nginx installation is set up differently, so you might need to look around for site configuration files. It’s also possible that all your Nginx configuration is in a single file, in which case just add the above configuration to it – that might also be a file called default
in your sites-available
folder. Doesn’t matter where this configuration is, as long as it’s loaded – see configuration auto-include locations by peeking inside etc/nginx/nginx.conf
.
Finally, we need to enable the new configuration by creating a symlink in the sites-enabled
folder:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/myapp
sudo service nginx restart
If you now visit something.local.com
in your browser, the files from (in my case) vagrant/Code/something/public
will be loaded.
Setting up for Apache
In this section, I’ll assume you have a running Apache instance that serves your PHP sites as usual. This could be via PuPHPet or with your friendly neighborhood *AMP stack, irrelevant – as long as it works.
First, we need to make sure mod_vhost_alias
is enabled. This is the Apache mod used to give us the functionality we need. There are two ways to do this. In more streamlined installations, the command a2enmod
will be available in the terminal, and all it takes is sudo a2enmod vhost_alias
. In others, again due to the curse of Linux, you’ll need to look inside the main configuration file, either /etc/apache2/apache2.conf
or /etc/apache2/httpd.conf
or the like. If this is your case, try and find a line containing mod_vhost_alias
. If it’s not there, add the following line:
LoadModule vhost_alias_module modules/mod_vhost_alias.so
Note that the path at the end needs to match the location of Apache modules on your system. This also varies due to the curse of Linux, but is often in /etc/apache2/mods-available
.
Just like Nginx, Apache usually loads its Vhost configurations from /etc/apache2/sites-available
and by extension /etc/apache2/sites-enabled
. It usually also comes with a module for easy enabling and disabling of sites, like so: sudo a2ensite mysite.conf
. This is, for all intents and purposes, identical to the Nginx section above on creating a symlink to enable a new configuration. It loads these alphabetically, so we’ll make a new configuration file in sites-enabled
(or do it in sites-available
and enable the site subsequently) called 000-default.conf
.
The first statement we put in there will be:
UseCanonicalName Off
This is required so that we can dynamically assign aliases to the URLs Apache receives. Then, we define the VirtualHost block:
<VirtualHost *:80>
ServerName vhosts.fqdn
ServerAlias *.local.com
VirtualDocumentRoot /var/www/%1+
</VirtualHost>
The %1
means “Take the first part of the dot-separated domain name”. For other options, and if you wish to configure it differently, see the docs.
If we now put the folder something
into /var/www
and inside it index.php
with some Hello World content, it should all work. But in this case, it’ll output the contents of the PHP file as text. We need to configure the rest of the VirtualHost’s parameters as usual. I’ll paste my PuPHPet version below – your configuration may vary.
UseCanonicalName Off
<VirtualHost *:80>
ServerName vhosts.fqdn
ServerAlias *.local.com
VirtualDocumentRoot /var/www/%1
<Directory ~ "/var/www/.*">
Options Indexes FollowSymlinks MultiViews
AllowOverride All
Require all granted
<FilesMatch "\.php$">
Require all granted
SetHandler proxy:fcgi://127.0.0.1:9000
</FilesMatch>
</Directory>
</VirtualHost>
Now, if you reload Apache configuration with sudo service apache2 restart
or whichever command works on your distribution, you should be able to access something.local.com
in your browser and once again see it working if you put some PHP files into var/www/something/public
.
Optional: dnsmasq
Optionally, if you’re on Linux or OS X, you can install dnsmasq.
Dnsmasq is a tool which, among other things, forwards a range of URLs to a given IP. It’s like regex support for /etc/hosts
. With this tool, you can set all URLs ending in .local.com
or whatever else you choose to redirect to your virtual machine’s IP or to your localhost. This means you never have to edit your hosts
file again – whenever you start a new project, your URLs and Vhosts can be assumed ready and you can start working right away, minimizing devops dramatically.
On OS X with the Homebrew package manager:
brew install dnsmasq
On your Linux distributions, download the tarball.
If you want to further automate this, you can add dnsmasq as a Vagrant plugin.
To set up dnsmasq to forward a URL pattern to your IP, and to set up your OS to forward all URL calls to dnsmasq so it can actually do this, see this excellent guide.
Conclusion
In this tutorial, we’ve learned how to automate that part of devops we all regularly deal with – setting up new Vhosts and their domains. It’s only a couple of minutes on every project, especially with packages like Homestead Improved, but it’s still a couple of minutes – and being able to quickly switch into another mock project for testing that one script you just thought of or need to try out is priceless for one’s workflow.
Did this tutorial help you? Would you have liked to get more information on certain topics? Let us know!
Frequently Asked Questions on Setting Automatic Virtual Hosts in Nginx and Apache
What is the difference between Nginx and Apache?
Nginx and Apache are both powerful web servers, but they have some key differences. Apache, an open-source HTTP server, is known for its power and flexibility. It supports a variety of features including load balancing, CGI, SSL, and virtual domains. On the other hand, Nginx is renowned for its speed and efficiency. It’s designed to use fewer resources and handle more simultaneous connections, making it ideal for high-traffic websites. However, it doesn’t support some of the advanced features that Apache does.
How do I set up a virtual host in Nginx?
Setting up a virtual host in Nginx involves creating a server block. First, you’ll need to open the Nginx configuration file in a text editor. Then, you can add a new server block for your virtual host. This block should include the server name (your domain name) and the root directory for your website files. Once you’ve added the server block, you can save and close the configuration file. Finally, you’ll need to test the configuration and restart Nginx to apply the changes.
How do I set up a virtual host in Apache?
In Apache, you can set up a virtual host by adding a new VirtualHost block to the Apache configuration file. This block should include the ServerName (your domain name), the DocumentRoot (the directory where your website files are located), and any other necessary directives. After adding the VirtualHost block, you’ll need to save and close the configuration file. Then, you can test the configuration and restart Apache to apply the changes.
Can I use both Nginx and Apache on the same server?
Yes, it’s possible to use both Nginx and Apache on the same server. This is often done to take advantage of the strengths of both web servers. For example, you might use Nginx as a reverse proxy to handle static content and pass dynamic requests to Apache. However, this setup can be more complex and requires careful configuration to ensure that both servers work together correctly.
How do I troubleshoot issues with my virtual hosts?
If you’re having trouble with your virtual hosts, there are several steps you can take to troubleshoot the issue. First, check the configuration files for any errors or typos. You can also use the configuration test commands for Nginx and Apache to check for any syntax errors. If the configuration files are correct, you might need to check the error logs for your web server. These logs can provide valuable information about what’s causing the issue.
How do I secure my virtual hosts?
Securing your virtual hosts involves several steps. First, you should ensure that your web server is up to date and configured correctly. You should also use SSL/TLS to encrypt the connection between your server and your visitors. Additionally, you should limit access to sensitive areas of your website and use strong passwords for any administrative accounts. Finally, you should regularly monitor your server for any signs of suspicious activity.
How do I optimize my virtual hosts for performance?
Optimizing your virtual hosts for performance can involve several strategies. These might include enabling caching, compressing your website files, optimizing your database queries, and using a content delivery network (CDN). You should also monitor your server’s resource usage and adjust your configuration as needed to ensure that your server can handle the traffic to your website.
How do I migrate my virtual hosts to a new server?
Migrating your virtual hosts to a new server involves copying your website files and configuration files to the new server. You’ll also need to update your DNS records to point to the new server’s IP address. It’s important to test your website on the new server before updating the DNS records to ensure that everything is working correctly.
Can I use virtual hosts with a dynamic IP address?
Yes, you can use virtual hosts with a dynamic IP address. However, this can be more complex because the IP address can change. You’ll need to use a dynamic DNS service to update your DNS records whenever your IP address changes.
How do I manage multiple virtual hosts?
Managing multiple virtual hosts involves keeping track of each virtual host’s configuration and website files. You might find it helpful to use a naming convention for your configuration files to make them easier to identify. You should also regularly check each virtual host for any issues or updates. If you’re managing a large number of virtual hosts, you might find it helpful to use a web hosting control panel or a configuration management tool.
Bruno is a blockchain developer and technical educator at the Web3 Foundation, the foundation that's building the next generation of the free people's internet. He runs two newsletters you should subscribe to if you're interested in Web3.0: Dot Leap covers ecosystem and tech development of Web3, and NFT Review covers the evolution of the non-fungible token (digital collectibles) ecosystem inside this emerging new web. His current passion project is RMRK.app, the most advanced NFT system in the world, which allows NFTs to own other NFTs, NFTs to react to emotion, NFTs to be governed democratically, and NFTs to be multiple things at once.