I'm installing an application on Laravel 5.4 in a Linux Ubuntu 16.04 environment with NGINX. I have seen that a lot of people (just like me) always come across a 500 error in the browser, right after the installation is completed. The official Laravel website in its documentation reminds the user to pay attention to this possibility:
Directory Permissions
After installing Laravel, you may need to configure some permissions. Directories within the storage and the bootstrap/cache directories should be writable by your web server or Laravel will not run. If you are using the Homestead virtual machine, these permissions should already be set.
======================================================= ====
Browser Error
The test.app page is not working
test.app is currently unable to handle this request.
HTTP ERROR 500
======================================================= ====
Checking the error in the test.app-error.log file
ila@ig:/var/log/nginx$ gedit test.app-error.log
And this is what I find:
2017/03/11 15:10:08 [error] 9306#9306: *1 FastCGI sent in stderr:
"PHP message: PHP Fatal error:
Uncaught UnexpectedValueException: The stream or file "/home/ila/vhosts/test.app/storage/logs/laravel.log"
could not be opened: failed to open stream: Permission denied in "/home/ila/vhosts/test.app/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php:107"
Stack trace:
#0 /home/ila/vhosts/test.app/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php(37): Monolog\Handler\StreamHandler->write(Array)
#1 /home/ila/vhosts/test.app/vendor/monolog/monolog/src/Monolog/Logger.php(337): Monolog\Handler\AbstractProcessingHandler->handle(Array)
#2 /home/ila/vhosts/test.app/vendor/monolog/monolog/src/Monolog/Logger.php(616): Monolog\Logger->addRecord(400, Object(UnexpectedValueException), Array)
#3 /home/ila/vhosts/test.app/vendor/laravel/framework/src/Illuminate/Log/Writer.php(203): Monolog\Logger->error(Object(UnexpectedValueException), Array)
#4 /home/ila/vhosts/test.app/vendor/laravel/framework/src/Illuminate/Log/Writer.php(114): Illuminate\Log\Writer->write...
PHP message: PHP Fatal error:
Uncaught UnexpectedValueException: The stream or file "/home/ila/vhosts/test.app/storage/logs/laravel.log"
could not be opened: failed to open stream: Permission denied in
/home/ila/vhosts/test.app/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php:107
Stack trace:
#0 /home/ila/vhosts/test.app/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php(37): Monolog\Handler\StreamHandler->write(Array)
#1 /home/ila/vhosts/test.app/vendor/monolog/monolog/src/Monolog/Logger.php(337): Monolog\Handler\AbstractProcessingHandler->handle(Array)
#2 /home/ila/vhosts/test.app/vendor/monolog/monolog/src/Monolog/Logger.php(616): Monolog\Logger->addRecord(400, Object(Symfony\Component\Debug\Exception\FatalErrorException), Array)
#3 /home/ila/vhosts/test.app/vendor/laravel/framework/src/Illuminate/Log/Writer.php(203): Monolog\Logger->error(Object(Symfony\Component\Debug\Exception\FatalErrorException), Arr
======================================================= ====
In my view this error is not very clear ...
It says that the "/home/ila/vhosts/test.app/storage/logs/*laravel.log*"
file can not be opened ( could not be ) and Permission denied for "/home/ila/vhosts/test.app/vendor/monolog/monolog/src/Monolog/Handler/*StreamHandler.php:107*"
We have 2 errors here.
Checking out what this function is on line 107 is this method:
protected function write(array $record)
{
if (!is_resource($this->stream)) {
if (null === $this->url || '' === $this->url) {
throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().');
}
$this->createDir();
$this->errorMessage = null;
set_error_handler(array($this, 'customErrorHandler'));
$this->stream = fopen($this->url, 'a');
if ($this->filePermission !== null) {
@chmod($this->url, $this->filePermission);
}
restore_error_handler();
if (!is_resource($this->stream)) {
$this->stream = null;
throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$this->errorMessage, $this->url));
}
}
if ($this->useLocking) {
// ignoring errors here, there's not much we can do about them
flock($this->stream, LOCK_EX);
}
$this->streamWrite($this->stream, $record);
if ($this->useLocking) {
flock($this->stream, LOCK_UN);
}
}
This method is creating and writing something to the system.
The fact is that shortly after installing laravel the laravel.log file does not exist inside "/ home / ila / vhosts / test.app / storage / logs /" . Then it needs to be created to later write an error log.
So, in my opinion, it would be clearer if the message was file laravel.log not found, and no guarantee guaranteed to be created . Of course if it was not created you can not record anything in it. This is unnecessary.
The message says it can not be read ! This made me a bit confused because users u (User), groups g (Group) and others o (others) can all read r (Read) == > d rwx rwx r-x .
See here at the terminal:
ila@ig:~/vhosts/test.app/storage(master)$ ll
total 20
drwxrwxrwx 5 ila www-data 4096 Mar 11 13:43 ./
drwxr-xr-x 15 ila www-data 4096 Mar 11 14:48 ../
drwxrwxr-x 3 ila www-data 4096 Mar 11 13:43 app/
drwxrwxr-x 5 ila www-data 4096 Mar 11 13:43 framework/
drwxrwxr-x 2 ila www-data 4096 Mar 11 13:43 logs/
The way to solve this problem, in my opinion, seems stranger still. Note that ila and www-data (NGINX) both have rwx permission in / home / ila / vhosts / test. app / storage /... ".
Then the conclusion is that it is neither ila or www-data that is trying to create the laravel.log others), other users.
An immediate non-LOGICAL approach would be to assign rwx permission to the (Others). And that's what I've seen the staff do.
So: we will write () permission to the (other) to the storage directory / recursively -R
ila @ ig: ~ / vhosts / test.app (master) $ sudo chmod guo + w -R storage / turns the folder " ... / storage /..." in rwx rwx rwx = > 777 , which seems to compromise the security of the Laravel application .
======================================================= ====
Checking
ila@ig:~/vhosts/test.app/storage(master)$ ll
total 20
drwxrwxrwx 5 ila www-data 4096 Mar 11 13:43 ./
drwxr-xr-x 15 ila www-data 4096 Mar 11 14:48 ../
drwxrwxrwx 3 ila www-data 4096 Mar 11 13:43 app/
drwxrwxrwx 5 ila www-data 4096 Mar 11 13:43 framework/
drwxrwxrwx 2 ila www-data 4096 Mar 11 13:43 logs/
And the file was created and the owner is www-data:
ila@ig:~/vhosts/test.app/storage/logs(master)$ ll
total 20
drwxrwxrwx 2 ila www-data 4096 Mar 11 15:26 ./
drwxrwxrwx 5 ila www-data 4096 Mar 11 13:43 ../
-rw-rw-rw- 1 ila www-data 14 Mar 11 13:43 .gitignore
-rw-r--r-- 1 www-data www-data 4626 Mar 11 23:22 laravel.log
Here at this point there is no longer the error 500 because the file "laravel.log" has already been created by someone o (Others) .
NOTE that there will be other similar errors (Permission denied) if at some point some user can not read, create or execute files inside folders or files.
Thinking about the right solution and what I find online we have 3 options:
$ sudo chmod guo+w -R test.app/
folders? The fact is that granting 777 permission to storage / and any other file in the application solves the problem, but what would be the best approach to not compromise security?
Update
The user running the NGINX server.
It is usually set to www-data by default.
We can check in the NGINX configuration file in /etc/nginx/nginx.conf
or by running ps to be sure.
ila@ig:~$ grep user /etc/nginx/nginx.conf
user www-data;
ila@ig:~$ ps aux|grep nginx|grep -v grep
root 29809 0.0 0.0 123888 1864 ? Ss Mar12 0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
www-data 29810 0.0 0.0 124500 5656 ? S Mar12 0:11 nginx: worker process
www-data 29811 0.0 0.0 124500 5652 ? S Mar12 0:07 nginx: worker process
www-data 29812 0.0 0.0 124336 4860 ? S Mar12 0:12 nginx: worker process
www-data 29813 0.0 0.0 124348 5104 ? S Mar12 0:15 nginx: worker process
www-data 29814 0.0 0.0 124336 4796 ? S Mar12 0:12 nginx: worker process