Laravel и shared-hosting

Июль, 2024

# Проблема

Популярнейшая ошибка начинающих разработчиков - размещение проекта на виртуальном хостинге и как следствие загрузка всего исходного кода в общедоступный каталог public_html или иной, как в случае с простыми CMS, например, WordPress. С Laravel такой подход не работает и вместо сайта отображается, или каталог с файлами, или 403 Forbidden, или сообщение о циклической переадресации, или не работают ссылки на стили, скрипты и обычные файлы.

В попытках запустить проект, разработчик совершает серьёзную ошибку и пытается перенаправить запросы в public/index.php из корня проекта.

Во-первых, это нарушение безопасности, файл .env доступен в web, как и всё остальное (composer.json, любые приватные файлы на диске, например, дамп базы данных).
Во-вторых, переадресация запросов через .htaccess это дополнительная нагрузка и увеличение TTFB.
В-третьих, это приводит к другим разнообразным проблемам связанных с некорректной "переадресацией" запроса.

Ни в коем случае не проксируй запросы через htaccess, только содержимое public должно быть доступно в web.

# Проблема хостингов

Шаред-хостинги не подходят под фреймворки, которые более требовательны к окружению, чем CMS. Даже с наличием ssh-доступа и более-менее функционального cli, проблемы не ограничиваются корневой директорией:

  • Ограниченные ресурсы железа.
  • Могут быть недоступны какие-либо расширения php.
  • Может не быть требуемой версии php для web или для cli.
  • Ограниченные возможности настройки php.ini или баз данных.
  • Сложности с запуском демона для очередей.
  • Отсутствует node или установлена устаревшая версия.
  • Нет возможности использовать Websockets, Supervisor, Octane, Docker, Redis, Varnish, Meilisearch...

Данный список можно продолжать очень долго, всё зависит от технологий использующихся в проекте. Если ко всему этому и нет нормальной консоли с php cli и git, то это вообще безумие...

В примерах ниже будет использоваться public_html как директория web-сервера. Имя директории варьируется от провайдера и в твоём случае может быть иной, например, www, docs, html, htdocs, domains и т.д.

# Решение 1: Взять VPS

Отказаться от шаред-хостинга и взять по той же цене обычный VPS, в котором можно свободно настроить среду. Это самый адекватный и правильный вариант. Для настройки сервера тебе понадобятся базовые знания в linux, которые должны быть у каждого backend разработчика. Если у тебя VPS или решил на него перейти, то смотри второй пункт «Как настроить DocumentRoot».

# Решение 2: Настроить DocumentRoot

Настроить web-сервер и изменить document_root так, чтобы он смотрел в public

1# Nginx
2server {
3 root /srv/example.com/public;
4}
1# Apache
2<VirtualHost>
3 DocumentRoot /srv/example.com/public
4</VirtualHost>
highlight by torchlight.dev

Некоторые современные хостинги позволяют настраивать корневую директорию, уточни у тех. поддержки и если такой возможности нет, то читай дальше...

# Решение 3: Сделать SymLink

Создать символическую ссылку на public
Сделать это можно через консоль или в файловом менеджере (зависит от провайдера)

  1. Приложение загружается в любую доступную директорию кроме public_html или на один уровень выше, так чтобы public_html хостинга и public фреймворка были в одной директории. Расположение проекта может быть любым, главное указать правильный путь к директории public в символической ссылке.
  2. Удаляется директория хостинга public_html
  3. Создаётся симлинк public_html на public любым доступным способом:
    1ln -s /path_to_project/public /path_to_old/public_html
    highlight by torchlight.dev

    Обрати внимание, что пути указаны абсолютно.

В результате мы "восстанавливаем" public_html, но это уже не директория, а ссылка на public
Поэтому настройки web-сервера остаются прежними, а запросы приходят в public/index.php

Это простой вариант, но не все хостеры дают возможность создавать символические ссылки.

Также данный вариант не рекомендуется при использовании OPCache, чтобы обезопасить развертывание приложений из-за realpath-кэша, подробнее читай в статье "Обзор расширения OPCache" .

# Решение 4: Переименовать public

Переименовать public в public_html
Для этого переименовываем саму директорию и переопределяем путь в App\Providers\AppServiceProvider

1public function register()
2{
3 $this->app->bind('path.public', function() {
4 return base_path().'/public_html';
5 });
6}
highlight by torchlight.dev

Обрати внимание, что для локальной разработки директорию придётся переименовать всем кто работает с проектом.

Если используется Laravel 8.x или более старая версия, то для работы php artisan serve необходимо изменить путь в server.php .

Если используется Mix, то потребуется использовать mix.setPublicPath()
Если используется Vite, то необходимо изменить build_path

Также не забудь внести изменения в .gitignore