Laravel registro diario creado con permisos incorrectos


Tengo un script que corro usando php artisan (con usuario root), y a veces causa que el archivo de registro diario se cree antes que el usuario apache www-data lo que significa que cuando un usuario real usa mi aplicación web, obtengo el error de permiso de carpeta:

No se pudo abrir la secuencia: Permiso denegado

Cambio los permisos de nuevo a www-data cada vez, pero quiero resolver esto teniendo el archivo de registro siempre creado con el permisos correctos.

He considerado crear un trabajo cron que cree el archivo o lo toque para asegurarme de que tenga el permiso correcto todos los días, pero estoy buscando una solución mejor que no dependa de otro script.

También hemos considerado envolver php artisan en otro script para asegurarnos de que siempre se ejecuta con las credenciales www-data, pero algunas cosas que queremos hacer son en realidad procedimientos root que apache no debería permitir hacer.

¿Alguna sugerencia más?

Author: Moshe Katz, 2014-12-28

13 answers

Comencemos con lo que es constante.

Tienes un comando php artisan, ejecutado por root.

Es seguro asumir que este comando se ejecuta diariamente.

Solución No 1:

, ya que el usuario que crea los archivos es el que tiene el permiso para escribir en él por defecto, podemos separar los registros de usuario:

App/start/global.php

/*
|--------------------------------------------------------------------------
| Application Error Logger
|--------------------------------------------------------------------------
|
| Here we will configure the error logger setup for the application which
| is built on top of the wonderful Monolog library. By default we will
| build a basic log file setup which creates a single file for logs.
|
*/

Log::useDailyFiles(storage_path().'/logs/laravel-'.get_current_user().'.log');

Si su usuario www-data creara un registro de errores, resultaría en: storage/logs/laravel-www-data-2015-4-27.log.

Si su usuario root creara un registro de errores, resultaría en: storage/logs/laravel-root-2015-4-27.log.

Solución No 2:

Cambie el registro utilizado por su comando artisan, en su script php.

En su función run(), agregue esta línea al comienzo:

Log::useFiles(storage_path().'/logs/laravel-'.__CLASS__.'-'.Carbon::now()->format('Y-m-d').'.log');

Si el nombre de su clase es ArtisanRunner, entonces su archivo de registro será:

storage/logs/laravel-ArtisanRunner-2015-4-27.log.

Conclusión: La solución número 1 es mejor, dado que delinea sus registros por usuario, y por lo tanto no se producirán errores.

EDITAR: Como señaló jason, get_current_user() devuelve el nombre del propietario del script. Por lo tanto, para que la solución no.1 se aplique, chown sus archivos de clase artisan al nombre de usuario requerido.

 50
Author: Mysteryos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-07 16:34:35

Para Laravel 5.1 uso lo siguiente hacia la parte inferior de bootstrap/app.php (como se menciona en los documentos):

/**
 * Configure Monolog.
 */
$app->configureMonologUsing(function(Monolog\Logger $monolog) {
    $filename = storage_path('logs/laravel-'.php_sapi_name().'.log');
    $handler = new Monolog\Handler\RotatingFileHandler($filename);
    $monolog->pushHandler($handler);
});

Hay muchos otros Controladores que puedes usar en su lugar, por supuesto.

 57
Author: Sam Wilson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-22 04:39:33

Para tales propósitos, debe usar ACL avanzado en sus archivos y directorios. setfacl sería su respuesta aquí. Si desea dar a www-data permisos de usuario para escribir en los archivos de root en un directorio específico, puede hacerlo de la siguiente manera:

setfacl -d -m default:www-data:you-chosen-group:rwx /my/folder

Después de emitir esto, está configurando permisos para rwx para www-data usuario en todos los archivos en /my/folder/ sin importar quién los creó. Por favor, vea este y esta pregunta para referencia. Además, puedes compruebe documentos para setfacl.

Hazme saber si esto ayuda.

 19
Author: Paul Tomkiel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-13 12:36:31

Para mí este problema era mucho más que permisos de registro...Tuve problemas con cualquier cosa relacionada con las carpetas bootstrap/cache y storage donde un usuario crearía un archivo/carpeta y el otro no podría editar/eliminar debido a los permisos estándar 644 y 755.

Los escenarios típicos son:

  • El bootstrap / cache / compiled.archivo php creado por el usuario apache pero no editable por el usuario composer al ejecutar el comando composer install

  • El usuario apache creando caché que no se puede borrar usando el usuario composer

  • Las temidas condiciones de carrera de troncos descritas anteriormente.

El sueño es que no importa qué usuario cree el archivo/carpeta, los otros usuarios que necesitan acceder tienen exactamente los mismos permisos que el autor original.

TL; DR?

Así es como se hace.

Necesitamos crear un grupo de usuarios compartidos llamado laravel, el grupo consta de todos los usuarios que necesitan acceso a los directorios storage y bootstrap/cache. A continuación, debemos asegurarnos de que los archivos y carpetas recién creados tengan los permisos laravel group y 664 y 775 respectivamente.

Es fácil hacer esto para los archivos/directorios existentes, pero se necesita un poco de magia para modificar las reglas de creación de archivos/carpetas predeterminadas...

## create user group
sudo groupadd laravel

## add composer user to group
sudo gpasswd -a composer-user laravel

## add web server to group
sudo gpasswd -a apache laravel

## jump to laravel path
sudo cd /path/to/your/beautiful/laravel-application

## optional: if you've been playing around with permissions
## consider resetting all files and directories to the default
sudo find ./ -type d -exec chmod 755 {} \;
sudo find ./ -type f -exec chmod 644 {} \;

## give users part of the laravel group the standard RW and RWX
## permissions for the existing files and folders respectively
sudo chown -R :laravel ./storage
sudo chown -R :laravel ./bootstrap/cache
sudo find ./storage -type d -exec chmod 775 {} \;
sudo find ./bootstrap/cache -type d -exec chmod 775 {} \;
sudo find ./storage -type f -exec chmod 664 {} \;
sudo find ./bootstrap/cache -type f -exec chmod 664 {} \;


## give the newly created files/directories the group of the parent directory 
## e.g. the laravel group
sudo find ./bootstrap/cache -type d -exec chmod g+s {} \;
sudo find ./storage -type d -exec chmod g+s {} \;

## let newly created files/directories inherit the default owner 
## permissions up to maximum permission of rwx e.g. new files get 664, 
## folders get 775
sudo setfacl -R -d -m g::rwx ./storage
sudo setfacl -R -d -m g::rwx ./bootstrap/cache

## Reboot so group file permissions refresh (required on Debian and Centos)
sudo shutdown now -r

Puramente para fines de depuración, descubrí que dividir los registros en ambos usuarios de cli / web + era beneficioso, así que modificé la respuesta de Sam Wilson ligeramente. Mi caso de uso fue que la cola se ejecutó bajo su propio usuario, por lo que ayudó a distinguir entre el usuario de composer usando la cli (por ejemplo, pruebas unitarias) y el demonio de cola.

$app->configureMonologUsing(function(MonologLogger $monolog) {
     $processUser = posix_getpwuid(posix_geteuid());
     $processName= $processUser['name'];

     $filename = storage_path('logs/laravel-'.php_sapi_name().'-'.$processName.'.log');
     $handler = new MonologHandlerRotatingFileHandler($filename);
     $monolog->pushHandler($handler);
}); 
 7
Author: Andrew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-30 12:27:17

Laravel 5.1

En nuestro caso, queríamos crear archivos de registro para que todos los procesos y usuarios del grupo deploy tuvieran permisos de lectura/escritura, por lo que necesitábamos nuevos archivos creados con el permiso 0664. El valor predeterminado para los archivos de registro nuevos es 0644. Así que esta fue nuestra solución.

También agregamos un formateador para agregar nuevas líneas y un registro más legible

$app->configureMonologUsing(function(Monolog\Logger $monolog) {
    $filename = storage_path('/logs/laravel.log');
    $handler = new Monolog\Handler\RotatingFileHandler($filename, 0, \Monolog\Logger::DEBUG, true, 0664);
    $handler->setFormatter(new \Monolog\Formatter\LineFormatter(null, null, true, true));
    $monolog->pushHandler($handler);
});

También es posible combinar esto con la respuesta aceptada

$app->configureMonologUsing(function(Monolog\Logger $monolog) {
    $filename = storage_path('/logs/laravel-' . php_sapi_name() . '.log');
    $handler = new Monolog\Handler\RotatingFileHandler($filename, 0, \Monolog\Logger::DEBUG, true, 0664);
    $handler->setFormatter(new \Monolog\Formatter\LineFormatter(null, null, true, true));
    $monolog->pushHandler($handler);
});
 6
Author: Artur Käpp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-04 09:00:44

Laravel versión 5.6.10 y posterior tiene soporte para un elemento permission en la configuración para el controlador single y el controlador daily:

    'daily' => [
        'driver' => 'daily',
        'path' => storage_path('logs/laravel.log'),
        'level' => 'debug',
        'days' => 7,
        'permission' => 0664,
    ],

No hay necesidad de hacer malabares con Monolog en el script de bootstrap.

Específicamente, se agregó soporte en https://github.com/laravel/framework/commit/4d31633dca9594c9121afbbaa0190210de28fed8 .

 6
Author: crishoj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-22 17:44:37

Me encontré con el mismo problema en Laravel 5.6

En config/logging.php acabo de actualizar el valor de ruta del canal diario con php_sapi_name() en él.

Esto crea un directorio separado para diferentes php_sapi_name y coloca el archivo de registro con la marca de tiempo en su directorio perticular.

'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/' . php_sapi_name() . '/laravel.log'),
            'level' => 'debug',
            'days' => 7,
        ]

Así que para mí,

  • Los archivos de registro se crean en fpm-fcgi directorio: Registros de sitio web, owner: www-data
  • Los archivos de registro se crean bajo el directorio cli: desde el artisan comando(cronjob). owner: root

Más información sobre Laravel 5.6 logging: https://laravel.com/docs/5.6/logging

Aquí está mi config/logging.php archivo:

<?php

return [
    /*
    |--------------------------------------------------------------------------
    | Default Log Channel
    |--------------------------------------------------------------------------
    |
    | This option defines the default log channel that gets used when writing
    | messages to the logs. The name specified in this option should match
    | one of the channels defined in the "channels" configuration array.
    |
    */
    'default' => env('LOG_CHANNEL', 'stack'),
    /*
    |--------------------------------------------------------------------------
    | Log Channels
    |--------------------------------------------------------------------------
    |
    | Here you may configure the log channels for your application. Out of
    | the box, Laravel uses the Monolog PHP logging library. This gives
    | you a variety of powerful log handlers / formatters to utilize.
    |
    | Available Drivers: "single", "daily", "slack", "syslog",
    |                    "errorlog", "custom", "stack"
    |
    */
    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['daily'],
        ],
        'single' => [
            'driver' => 'single',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
        ],
        'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/' . php_sapi_name() . '/laravel.log'),
            'level' => 'debug',
            'days' => 7,
        ],
        'slack' => [
            'driver' => 'slack',
            'url' => env('LOG_SLACK_WEBHOOK_URL'),
            'username' => 'Laravel Log',
            'level' => 'critical',
        ],
        'syslog' => [
            'driver' => 'syslog',
            'level' => 'debug',
        ],
        'errorlog' => [
            'driver' => 'errorlog',
            'level' => 'debug',
        ],
    ],
];
 5
Author: Lahar Shah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-19 17:47:51

Agregue algo como lo siguiente al inicio de su archivo app/start/artisan.php (esto es con Laravel 4):

// If effectively root, touch the log file and make sure it belongs to www-data
if (posix_geteuid() === 0) {
    $file = storage_path() . '/logs/laravel.log';
    touch($file);
    chown($file, 'www-data');
    chgrp($file, 'www-data');
    chmod($file, 0664);
}

Ajuste la ruta si el archivo de registro diario que menciona no es el archivo de registro estándar de Laravel. También es posible que no desee cambiar el grupo o establecer los permisos como lo estoy haciendo aquí. Lo anterior establece el grupo en www-data y establece los permisos de escritura del grupo. Luego he agregado mi usuario regular al grupo www-data para que ejecutar comandos artisan como mi usuario regular aún pueda escribir en el registro.

Un ajuste relacionado es poner lo siguiente al comienzo de su archivo app/start/global.php:

umask(0002);

Si haces esto, la línea chmod anterior se vuelve discutible. Con el umask establecido en esto, cualquier archivo nuevo que PHP (y por lo tanto Laravel) haga tendrá sus permisos enmascarados solo para que "otros" usuarios no tengan permisos de escritura. Esto significa que los directorios comenzarán como rwxrwxr-x y los archivos como rw-rw-r--. Así que si www-data está ejecutando PHP, cualquier caché y archivos de registro que haga será escribible por defecto por cualquiera en el grupo principal de ese usuario, que es www-data.

 3
Author: tremby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-25 01:48:07

Laravel 5.5

Añadir este código a bootstrap/app.php:

$app->configureMonologUsing(function (Monolog\Logger $monolog) {
    $filename = storage_path('logs/' . php_sapi_name() . '-' . posix_getpwuid(posix_geteuid())['name'] . '.log');
    $monolog->pushHandler($handler = new Monolog\Handler\RotatingFileHandler($filename, 30));
    $handler->setFilenameFormat('laravel-{date}-{filename}', 'Y-m-d');
    $formatter = new \Monolog\Formatter\LineFormatter(null, null, true, true);
    $formatter->includeStacktraces();
    $handler->setFormatter($formatter);
});
  • Almacenará archivos como este: laravel-2018-01-27-cli-raph.log y laravel-2018-01-27-fpm-cgi-raph.log que es más legible.
  • Se conservan nuevas líneas (como el comportamiento predeterminado de Laravel)
  • Funciona con Laravel Log Viewer

Laravel 5.6

Usted tiene que crear una clase para su registrador:

<?php

namespace App;

use Monolog\Logger as MonologLogger;

class Logger {
    public function __invoke(array $config)
    {
        $monolog = new MonologLogger('my-logger');
        $filename = storage_path('logs/' . php_sapi_name() . '-' . posix_getpwuid(posix_geteuid())['name'] . '.log');
        $monolog->pushHandler($handler = new \Monolog\Handler\RotatingFileHandler($filename, 30));
        $handler->setFilenameFormat('laravel-{date}-{filename}', 'Y-m-d');
        $formatter = new \Monolog\Formatter\LineFormatter(null, null, true, true);
        $formatter->includeStacktraces();
        $handler->setFormatter($formatter);
        return $monolog;
    }
}

Entonces, tienes que registrarlo en config/logging.php:

'channels' => [
    'custom' => [
        'driver' => 'custom',
        'via' => App\Logging\CreateCustomLogger::class,
    ],
],

El mismo comportamiento que para 5.5:

  • Almacenará archivos como este: laravel-2018-01-27-cli-raph.log y laravel-2018-01-27-fpm-cgi-raph.log que es más legible.
  • Se conservan nuevas líneas (como el comportamiento predeterminado de Laravel)
  • Funciona con Laravel Log Viewer
 3
Author: rap-2-h,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-20 11:14:25

Laravel 5.4

\Log::getMonolog()->popHandler(); \Log::useDailyFiles(storage_path('/logs/laravel-').get_current_user().'.log');

Añadir a boot función en AppServiceProvider

 2
Author: StupidDev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-01 03:43:25

Una forma no Laravel de hacer que esto funcione es simplemente ejecutar su cronjob como www-data.

Eg https://askubuntu.com/questions/189189/how-to-run-crontab-as-userwww-data

/etc/crontab

*/5 * * * * www-data php /var/www/public/voto_m/artisan top >/dev/null 2>&1
 1
Author: user2662680,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-14 15:45:31

(Laravel 5.6) Recientemente me encontré con el mismo problema y simplemente configuré un comando programado para que se ejecute en /app/Console/Kernel.php.

$schedule->exec('chown -R www-data:www-data /var/www/**********/storage/logs')->everyMinute();

Sé que es un poco exagerado, pero funciona como un encanto y no he tenido ningún problema desde entonces.

 1
Author: Ague Mort,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-26 01:59:03

La mejor manera que encontré es que fideloper sugiera, http://fideloper.com/laravel-log-file-name , puede establecer la configuración de registro de laravel sin la clase touch Log. Tener diferentes nombres para programas de consola y programas Http, creo, es la mejor solución.

 -1
Author: Giacomo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-04 09:46:54