Laravel na sdíleném hostingu Wedos i OneBit

11.9.2018 (aktualizováno 8.10.2018) Pavel Tipy & triky, PHP

Zprovoznění velkých frameworků jako je Laravel může být na obyčejném sdíleném hostingu trochu složitější úkol, pro začátečníky možná i úkol nemožný. V případě kombinace Laravel a Wedos to ale není tak náročné i bez zásahů do vendor složky.

Laravel na sdíleném hostingu Wedos i OneBit

1. Laravel na sdíleném hostingu Wedos i OneBit
2. Jak na Laravel frontu na sdíleném hostingu


Wedos patří mezi nejznámější hostingy na české scéně. Je relativně levný a pro běžné uživatelé dostačuje. Laravel je také nejznámější framework, ale ve světě. A zatímco zahraniční hostiny nabízí přístup k příkazové řádce, Composeru atd. u Wedosu se toho jeho zákazníci nedočkají. Jedině si pořídit VPSku, ale to chce ještě lepší znalosti.

Testováno s Laravelem 5.4, 5.6 a 5.7 a na Wedosu a OneBitu. Všechny níže popsané úpravy fungují pro všechny verze a očekávám stejné řešení také pro Laravel 5.5 a pro jiné hostingy.
Rovněž na Wedosu projekty dávám vždy do složky domains/domena.cz případně subdomény do domains/subdomena.domena.cz

Přesměrování do složky public

Hlavní soubor index.php pro spouštění aplikace je ve složce public a zde by také měl směřovat DocumentRoot virtual hostu. To ale na běžném hostingu nemustí jít změnit, proto je potřeba do rootu projektu vložit další .htaccess, který toto přesměrování provede. 

<IfModule mod_rewrite.c>
    RewriteEngine on

    RewriteCond %{REQUEST_URI} !^public
    RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

Jiným řešením by bylo vložit nový index.php a provést include indexu z publicu. Tím je ale možné přistupovat také k dalším souborům mimo složku public, což je potencionálně nebezpečné. Řešení se souborem .htaccess je proto rozhodně lepší a doporučené.

Běžné použití a problém s .htaccess a .env

Prvním problémem bude Error 500 se zprávou, že se jedná pravděpodobně o chybu v souboru .htaccess. A chyba je opravdu v souboru public/.htaccess, protože Wedos nedovoluje měnit MultiViews. Stačí tedy tyto řádky ze souboru odebrat.

<IfModule mod_negotiation.c>
    Options -MultiViews -Indexes
</IfModule>

Druhý problém je funkce getenv, která vrací vždy false/null. Podle dokumentace při použití FastCGI zde může být problém. Naštěstí Laravel dovoluje přepsat své základní funkce, která getenv používá. Chyba se projevu jednou z těchto hlášek:

  • No application encryption key has been specified
  • The only supported ciphers are AES-128-CBC and AES-256-CBC ...

Na hostingu OneBit není potřeba přetížit funkci env - funguje bez problému i bez

Pro přepsání stačí do souboru public/index.php vložit funkci níže, případně vložit pomocí require. Na Wedosu se totiž soubor .env přečte a jeho hodnoty se uloží do superglobální proměnné $_ENV

/**
 * Gets the value of an environment variable.
 *
 * @param  string  $key
 * @param  mixed   $default
 * @return mixed
 */
function env($key, $default = null)
{
    $value = isset($_ENV[$key]) ? $_ENV[$key] : false;
    // Pro použití v PHP7 lze použít i text níže
    // $value = $_ENV[$key] ?? false;

    if ($value === false) {
        return value($default);
    }

    switch (strtolower($value)) {
        case 'true':
        case '(true)':
            return true;
        case 'false':
        case '(false)':
            return false;
        case 'empty':
        case '(empty)':
            return '';
        case 'null':
        case '(null)':
            return;
    }

    if (($valueLength = strlen($value)) > 1 && $value[0] === '"' && $value[$valueLength - 1] === '"') {
        return substr($value, 1, -1);
    }

    return $value;
}

Chyby se zobrazují stále

Výše zmíněné opravy dostačují k tomu, aby běžný web na Laravelu fungoval. Pokud je stále zobrazena chyba ohledně klíče, je potřeba vymazat soubory ve složce bootstrap/cache.

Laravel 5.5+ a problém s emaily

Laravel 5.4 a níž podporoval pro odesílání emailů driver mail, který využíval základní PHP funkci mail(). Od verze Laravelu 5.5 tato možnost ale odpadá. Důvodem je, že na pozadí se využívá knihovna SwiftMailer, která tuto možnost úplně odstranila. Pokud tedy je v konfigu driver mail, ve skutečnosti se využije sendmail, který skončí chybou proc_open() has been disabled for security reasons.

Nejlepší možnost je použití služby jako je Mailgun a další. Pokud se emaily odesílají jednou za čas, lze použít i základní SMTP od Wedosu, stejně jako v případě emailové schránky. Je ale nutné SMTP použít na portu 587.

Zprovoznění Artisan::call

Přístup k příkazové řádce na Wedosu není. Příkazy Artisanu ale jdou naštěstí spouštět přímo z PHP skriptů. Při pokusu zavolání Artisan::call ale vyskočí chyba: Funkce putenv je z bezpečnostních důvodů zakázaná. První možnost je volání odebrat všude v kódu, což je ale ve složce vendor. To se mi osobně příčí, proto je zde možnost, jak chybu ignorovat.

POZOR: Controller je doporučené nasměrovat pomocí rout, které jsou pouze pro přihlášené uživatele, nebo jinak ošetřené! 

Ideální je napsat si ArtisanController, případně servisu, podobnou tomu níže. Před spuštěním funkce Artisan::call se nastaví vlastní error handler, který bude chyby odchytávat. V případě chyby ohledně putenv ji bude ignorovat a skript poběží dál.

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Symfony\Component\Console\Output\BufferedOutput;

class ArtisanController extends Controller
{
    private $output;
    private $previousErrorHandler = false;

    public function __construct()
    {
        $this->output = new BufferedOutput;
    }

    public function errorHandler($errno, $errstr, $errfile, $errline)
    {
        if ($errno == 2 && preg_match('/putenv\(\)/i', $errstr)) {
            return true;
        }
        if ($this->previousErrorHandler != null) {
            return call_user_func($this->previousErrorHandler, $errno, $errstr, $errfile, $errline);
        }
        return false;
    }

    protected function callArtisan($command, $parameters = [])
    {
        if ($this->previousErrorHandler === false) {
            $this->previousErrorHandler = set_error_handler( [$this, 'errorHandler']);
        }

        $exit = Artisan::call($command, $parameters, $this->output);
        $outputText = "Command: $command\n---------\n";
        $outputText .= $this->output->fetch();
        $outputText .= "Exit code: ".intval($exit);

        return response($outputText, 200)
                  ->header('Content-Type', 'text/plain');
    }
    
    // Routy jsou nasměrovány na tuto funkci a podobné
    public function down()
    {
        $this->callArtisan("down");
    }
}

Na OneBit není nutné odchytávání chyb, protože funkce putenv není zakázána

Chyba is_executable()

Svého času byla chyba v Symfony balíčku Process, který neměl ošetřené spouštění binárky PHP a vykonávaní skritpu skončilo chybou File(...) is not within the allowed path(s). To je ale již opraveno, viz commit, stačí tedy spustit composer update

Deploy Laravel webu na Wedos

Deploy na Wedos mám vytvořen pomocí FTP Deployment a vždy spustím 3 příkazy:

php composer.phar install --no-dev
php deployment.phar deploy-config.php
php composer.phar install

První odstraní všechny závislosti pro vývoj, následně dojde k nahrání na FTP a poté se závislosti doinstalují zpět. Konfigurační soubor deploy-config.php obsahuje následující.

return [
    'live_deploy' => [
        'remote'        => "ftp://...",
        'user'          => "",
        'password'      => "",

        'ignore'        => '.git*
            /bootstrap/compiled.php
            /bootstrap/cache/*
            /deployment.*
            /config_live
            /resources/assets/*
            /storage/*.key
            /storage/app/public/*
            /storage/app/*
            /storage/framework/cache/*
            /storage/framework/sessions/*
            /storage/framework/testing/*
            /storage/framework/views/*
            /storage/framework/config.php
            /storage/framework/routes.php
            /storage/framework/schedule-*
            /storage/framework/compiled.php
            /storage/framework/services.json
            /storage/framework/events.scanned.php
            /storage/framework/routes.scanned.php
            /storage/framework/down
            /storage/logs/*
            .env
            *.log
            /.htaccess
        ',

        'afterUpload' => [
            "https://url.to.live/artisan/down",
        ],

        'purge' => [
            'bootstrap/cache'
        ],

        'after' => [
            "upload: config_live/live_deploy.env .env",
            "upload: config_live/live_deploy.htaccess .htaccess",
            // artisan/deploy spustí:
            // view:clear, view:cache, config:cache, route:cache, migrate
            "https://url.to.live/artisan/deploy",
        ],
    ]
];

Máte další problémy se spuštěním Laravelu na sdíleném hostingu, nebo informace o jiném webhostingu než je Wedos? Podělte se v komentářích

Přidat komentář

Právě odpovídáte na existující komentář. Zrušit

Komentáře

Vigosh

17.9.2018 17:24

Dobrý den, děkuji za článek. Po nastavení vše funguje, kromě jedné věci - DELETE http requesty definované v api.php. Při volání jakékoliv DELETE funkce se vrátí 403 Access Denied (Description: You are not allowed to access the document you requested). Netušíte, kde by mohla být chyba?

Odpovědět

Pavel

http://www.kutac.cz/blog/ 17.9.2018 17:55

Jsem rád, že návod pomohl.
Důvodem 403 je ale chyba jinde. Nyní jsem si DELETE request vytvořil přes aplikaci Postman a vše normálně funguje.

Vigosh

19.9.2018 21:25

FYI: Tak problém měl samotný Wedos. Na zákaznickém chatu jsem byl prvně lehce odpalkován, že problém není na jejich straně. Podruhé jsem se ale tak rychle nevzdal a problém byl předán výše - odborníkovi. Po jednom dni jsem dostal tuto odpověď:

Dobrý den,

na nových webových serverech byly nedopatřením HTTP metody DELETE, PURGE atd. zakázány. Jednalo se tedy o problém na naší straně a není třeba se obávat, že se z ničeho nic znovu objeví.

Omlouváme se za komplikace.

Novinky z blogu

Zachycení událostí CSS animací v Javascriptu

CSS animace dokázaly na mnoha místech nahradit Javascript, který byl dříve jedinou schůdnou možností. Nejen pro svou jednoduchost jsou stále populárnější. Jenže co, když chci...

Další články