How to hide /frontend/web in url addresses on apache

There is an issue on Yii2 to redirecting / urls to /frontend/web.
In other words we need a way to hidden /frontend/web from addresses.
We will do this without changing Apache configuration and creating virtual host or setting document root (It's good for share hostings that we have not access to apache.conf)

Let's do it:

1- Create .htaccess file on the root directory with this content

Options -Indexes

<IfModule mod_rewrite.c> 
  RewriteEngine on
  
  RewriteCond %{REQUEST_URI} !^public
  RewriteRule ^(.*)$ frontend/web/$1 [L] 
</IfModule>

# Deny accessing below extensions
<Files ~ "(.json|.lock|.git)">
Order allow,deny
Deny from all
</Files>

# Deny accessing dot files
RewriteRule (^\.|/\.) - [F]

2- Create .htaccess file in frontend/web with the below contents

RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d 

RewriteRule . index.php

3- Now, we should play a little with frontend config of framework
You must open the frontend/config/main.php file and set $baseUrl for \yii\web\Request and \yii\web\urlManager.
$baseUrl is the url your application point to. if you host your application in the root directory of www you may set the $baseUrl to '/'

For another example if you are developing a blog system and your application hosted in www/blog you must set the baseUrl to '/blog'

<?php
$params = array_merge(
    require(__DIR__ . '/../../common/config/params.php'),
    require(__DIR__ . '/../../common/config/params-local.php'),
    require(__DIR__ . '/params.php'),
    require(__DIR__ . '/params-local.php')
);


return [
    'id' => 'app-frontend',
    'basePath' => dirname(__DIR__),
    'bootstrap' => ['log'],
    'controllerNamespace' => 'frontend\controllers',
	
    'components' => [
		
		'request' => [
			'baseUrl' => '/',
		],
		
        'user' => [
            'identityClass' => 'common\models\User',
            'enableAutoLogin' => true,
        ],
		
        'log' => [
            'traceLevel' => YII_DEBUG ? 3 : 0,
            'targets' => [
                [
                    'class' => 'yii\log\FileTarget',
                    'levels' => ['error', 'warning'],
                ],
            ],
        ],
		
        'errorHandler' => [
            'errorAction' => 'site/error',
        ],
		
		'urlManager' => [
			'baseUrl' => '/',
			'enablePrettyUrl' => true,
			'showScriptName' => false,
			'rules' => []
		]
    ],
    'params' => $params,
];

Soft Way

If you not sure where your application will host, you must do it in pragmatically way. for this purpose we change the config file as below

<?php
$params = array_merge(
    require(__DIR__ . '/../../common/config/params.php'),
    require(__DIR__ . '/../../common/config/params-local.php'),
    require(__DIR__ . '/params.php'),
    require(__DIR__ . '/params-local.php')
);

use \yii\web\Request;
$baseUrl = str_replace('/frontend/web', '', (new Request)->getBaseUrl());

return [
    'id' => 'app-frontend',
    'basePath' => dirname(__DIR__),
    'bootstrap' => ['log'],
    'controllerNamespace' => 'frontend\controllers',
	
    'components' => [
		
		'request' => [
			'baseUrl' => $baseUrl,
		],
		
        'user' => [
            'identityClass' => 'common\models\User',
            'enableAutoLogin' => true,
        ],
		
        'log' => [
            'traceLevel' => YII_DEBUG ? 3 : 0,
            'targets' => [
                [
                    'class' => 'yii\log\FileTarget',
                    'levels' => ['error', 'warning'],
                ],
            ],
        ],
		
        'errorHandler' => [
            'errorAction' => 'site/error',
        ],
		
		'urlManager' => [
			'baseUrl' => $baseUrl,
			'enablePrettyUrl' => true,
			'showScriptName' => false,
			'rules' => []
		]
    ],
    'params' => $params,
];

As you see above we use \yii\web\Request to find $baseUrl of application. but because the returned $baseUrl contains /frontend/web we remove it

use \yii\web\Request;
$baseUrl = str_replace('/frontend/web', '', (new Request)->getBaseUrl());

enjoy !