Configure virtual hosts for separated apps in Advanced Project Template

When developing web applications in PHP based on Yii 2’s Advanced Project Template you have a clear separation between two applications:

  • Backend — for service’s admins
  • Frontend — for regular users

There’s also a separate console application but it isn’t important from web applications perspective as it is not accessed remotely via URL, but rather locally in console.

In local development environment you can separate access to these two applications using various methods:

  • Two separate domains — i.e. frontend.localhost and backend.localhost
  • Two subdomains — i.e. app.localhost and admin.app.localhost
  • Separate port — i.e. app.localhost and app.localhost:8080

This article deals with all three scenarios, but using XAMPP/Apache for Windows only. You must adjust provided examples, if you’re running Apache on different operating system.

General information

You need to keep these points in mind in order to go easily through rest of this post:

  1. Always change Apache’s configuration file not .htaccess file in your webroot folder
  2. When you play with virtual hosts don’t forget about adding special entry for localhost itself
  3. Always restart Apache after even tiniest configuration change

When setting a new virtual host in Apache the configuration is as simple as two lines:

<VirtualHost *:80>
    ServerName domain
    DocumentRoot "/path/"
</VirtualHost>

All other additions that you’ll see in the below examples (i.e. the whole <Directory></Directory> block) is for assuring correct name resolution for Yii 2 framework itself, but has noting to do with virtual hosts or setting separate domains for backend and frontend applications in Yii 2’s Advanced Project Template.

Three scenarios

Two separate domains

This scenario is very similar to the one given in Yii 2 guide. Open C:\XAMPP\apache\conf\extra\httpd-vhosts.conf file (adjust path to your local XAMPP installation) and put these three blocks at the end of it:

<VirtualHost *:80>
    ServerName fontend.localhost
    DocumentRoot "/XAMPP/htdocs/yii-application/frontend/web/"
    <Directory "/XAMPP/htdocs/yii-application/frontend/web/">
        RewriteEngine on
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . index.php
        DirectoryIndex index.php
        Require all granted
    </Directory>
</VirtualHost>
<VirtualHost *:80>
    ServerName backend.localhost
    DocumentRoot "/XAMPP/htdocs/yii-application/backend/web/"
    <Directory "/XAMPP/htdocs/yii-application/backend/web/">
        RewriteEngine on
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . index.php
        DirectoryIndex index.php
        Require all granted
    </Directory>
</VirtualHost>
<VirtualHost *:80>
    ServerName localhost
    DocumentRoot "/XAMPP/htdocs/"
</VirtualHost>

Adjust elements given in bold to match your system configuration.

Open c:\Windows\System32\Drivers\etc\hosts file and put these two entries at the end of it:

	127.0.0.1       fontend.localhost
	127.0.0.1       backend.localhost

Restart Apache and check in your browser, if http://fontend.localhost/ and http://backend.localhost/ works.

Main domain + subdomain

This scenario is so similar to the one given above that you could even call it an alternative version of the previous one. Again open httpd-vhosts.conf file and put three similar blocks at the end of it:

<VirtualHost *:80>
    ServerName app.test
    DocumentRoot "/XAMPP/htdocs/yii-application/frontend/web/"
    <Directory "/XAMPP/htdocs/yii-application/frontend/web/">
        RewriteEngine on
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . index.php
        DirectoryIndex index.php
        Require all granted
    </Directory>
</VirtualHost>
<VirtualHost *:80>
    ServerName admin.app.test
    DocumentRoot "/XAMPP/htdocs/yii-application/backend/web/"
    <Directory "/XAMPP/htdocs/yii-application/backend/web/">
        RewriteEngine on
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . index.php
        DirectoryIndex index.php
        Require all granted
    </Directory>
</VirtualHost>
<VirtualHost *:80>
    ServerName localhost
    DocumentRoot "/XAMPP/htdocs/"
</VirtualHost>

Again, open c:\Windows\System32\Drivers\etc\hosts file and put these two entries at the end of it:

	127.0.0.1       app.test
	127.0.0.1       admin.app.test

Restart Apache and check in your browser, if the defined virtual hosts are accessible.

Separate port

This is the trickiest scenario of all three but also the safest one, because you can designate a separate port for your admin panel (backend application) and then block that port on your router, so it will be accessible from your local network or even local computer only.

We start with the same part of adding three blocks to httpd-vhosts.conf file:

<VirtualHost *:80>
    ServerName app.test
    DocumentRoot "/XAMPP/htdocs/yii-application/frontend/web/"
    <Directory "/XAMPP/htdocs/yii-application/frontend/web/">
        RewriteEngine on
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . index.php
        DirectoryIndex index.php
        Require all granted
    </Directory>
</VirtualHost>
<VirtualHost *:8080>
    ServerName app.test
    DocumentRoot "/XAMPP/htdocs/yii-application/backend/web/"
    <Directory "/XAMPP/htdocs/yii-application/backend/web/">
        RewriteEngine on
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . index.php
        DirectoryIndex index.php
        Require all granted
    </Directory>
</VirtualHost>
<VirtualHost *:80>
    ServerName localhost
    DocumentRoot "/XAMPP/htdocs/"
</VirtualHost>

We put only one entry this time to the end of c:\Windows\System32\Drivers\etc\hosts file:

	127.0.0.1       app.test

Now, we need to modify the main Apache configuration file. Hit Config button in the Apache line in XAMPP Control Panel and select Apache (httpd.conf) item from the dropdown menu:

Or directly edit C:\XAMPP\apache\conf\httpd.conf file.

Locate Listen 80 line within it and add Listen 8080 below.

#
# Listen: Allows you to bind Apache to specific IP addresses and/or
# ports, instead of the default. See also the <VirtualHost>
# directive.
#
# Change this to Listen on specific IP addresses as shown below to 
# prevent Apache from glomming onto all bound IP addresses.
#
#Listen 12.34.56.78:80
Listen 80
Listen 8080

Save file and restart Apache. You should see the difference immediately in XAMPP Control Panel:

If everything goes well, you should be able to access both frontend and backend under the same domain and under different ports (80 or none for frontend and 8080 for backend):

Which domain or port to use?

You can use nearly every domain and subdomain combination, you figure out. Only keep in mind that if you use an existing top-level domain (i.e. dev or .local) you will have to prefix it with slash (/) when pasting URL to your browser, to not confuse it.

If you for example type just app.dev into browser, it will try to open such URL (as such top-level domain exists) instead of calling your local Apache server.

Similarly, if you use (and type in your browser’s address bar) just app.local it will most likely perform a web search for such term, again instead of running your local website, because .local is a special domain, not registered as top-level domain, but still valid in the wild Internet.

You can use any port you wish, as long as it is in range (1-65365) and as long as it is not being used by some other service or device in your local network.

My app… everywhere

You may be surprised to see your app up and running even for some local address that you’ve never defined as a virtual host. This is normal.

Rule of the thumb says: Apache executes the first VirtualHost in case of unknown server name.

You have two options to work this problem around.

You may move the third block (that we defined for localhost) as first one in your to httpd-vhosts.conf file:

<VirtualHost *:80>
    ServerName localhost
    DocumentRoot "/XAMPP/htdocs/"
</VirtualHost>
<VirtualHost *:80>
    ServerName fontend.localhost
    DocumentRoot "/XAMPP/htdocs/yii-application/frontend/web/"
    <Directory "/XAMPP/htdocs/yii-application/frontend/web/">
        RewriteEngine on
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . index.php
        DirectoryIndex index.php
        Require all granted
    </Directory>
</VirtualHost>
<VirtualHost *:80>
    ServerName backend.localhost
    DocumentRoot "/XAMPP/htdocs/yii-application/backend/web/"
    <Directory "/XAMPP/htdocs/yii-application/backend/web/">
        RewriteEngine on
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . index.php
        DirectoryIndex index.php
        Require all granted
    </Directory>
</VirtualHost>

This way, if you (or anyone else) types a local URL that cannot be resolved into any existing virtual server, it will be treated as directory listing of your root (htdocs) folder.

The other option is to use first virtual server (first block) to route any not-matching requests into some nice looking error address. Simply address it to some DocumentRoot with a certain index.html or index.php files that contains some error message.

That would be all, yiiolks! :)

Leave a Reply