Нужна была нормальная система заявок: клиент пишет, видит статус, история не теряется в мессенджерах. Развернул TicketGo Support Ticket System (Laravel) на поддомене support.krivoshein.site за Nginx + PHP-FPM + MariaDB. Ниже – шаги, конфиг и грабли, на которые реально напоролся.
1. Зачем тикет-система
- Прозрачность – клиент видит статус обращения, не нужно писать «ну как там?» каждые два часа.
- История – переписка и вложения в одном месте, контекст не размазан по чатам.
- Фиксация – заявка не «теряется», пока кто-то был в отпуске.
- Лояльность – предсказуемая поддержка обычно ценится выше, чем «ответьте в мессенджере когда получится».
TicketGo на CodeCanyon – готовое Laravel-приложение с интерфейсом под заявки, роли, вложения. Свой велосипед писать не хотелось.
2. Поддомен и SSL
- Поддомен:
support.krivoshein.site. - Сертификат Let’s Encrypt через Certbot, редирект HTTP → HTTPS.
- Проверка: заход на
http://...сразу уводит наhttps://....
Выпуск сертификата:
certbot --nginx -d support.krivoshein.site
Certbot сам дописывает HTTPS-редирект в конфиг Nginx. После правок:
nginx -t systemctl reload nginx
3. Laravel-проект и Nginx
- Код лежит в
/var/www/support.krivoshein.site. rootвеб-сервера смотрит вpublic– стандарт Laravel:app,config,vendorне торчат наружу.- PHP-FPM обрабатывает
.php, статику Nginx отдаёт сам.
Рабочий vhost (схематично, пути под ваш сервер):
server {
if ($host = support.krivoshein.site) {
return 301 https://$host$request_uri;
}
listen 80;
listen [::]:80;
server_name support.krivoshein.site;
return 301 https://support.krivoshein.site$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name support.krivoshein.site;
root /var/www/support.krivoshein.site/public;
ssl_certificate /etc/letsencrypt/live/support.krivoshein.site/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/support.krivoshein.site/privkey.pem;
ssl_trusted_certificate /etc/ssl/krivoshein.site/ca-bundle.crt;
index index.php index.html index.htm;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
location ~* \.(css|js|png|jpg|jpeg|gif|ico|woff|woff2|ttf|svg)$ {
expires max;
log_not_found off;
access_log off;
}
location ~* ^/public/(css|assets|market_assets|images|landing|uploads|storage|installer|js|vendor)/(.*)$ {
rewrite ^/public/(.*)$ /public/$1 break;
}
location ~ /\.(?!well-known).* {
deny all;
}
error_log /var/log/nginx/support.krivoshein.site-error.log;
access_log /var/log/nginx/support.krivoshein.site-access.log;
}
Зависимости и ключ приложения:
cd /var/www/support.krivoshein.site composer install cp .env.example .env php artisan key:generate
4. База данных
- БД и пользователь в MariaDB; креды только в
.env, не в репозитории. - Миграции:
php artisan migrate– таблицы тикетов должны появиться без ошибок.
Фрагмент .env (пароль сюда не кладём):
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel_db DB_USERNAME=laravel_user DB_PASSWORD=
Создание БД:
CREATE DATABASE laravel_db; CREATE USER 'laravel_user'@'localhost' IDENTIFIED BY 'your_secure_password'; GRANT ALL PRIVILEGES ON laravel_db.* TO 'laravel_user'@'localhost'; FLUSH PRIVILEGES;
php artisan migrate
5. Проблемы и решения
SSL и поддомен
Нужно было аккуратно сцепить сертификаты Let’s Encrypt и редирект. После nginx -t и reload HTTPS стабильно открывался:
nginx -t systemctl reload nginx
Access denied к БД
Laravel ругался на доступ: в пароле был символ #, в .env такие значения лучше брать в кавычки. Плюс DB_HOST=localhost иногда уезжает в unix-socket с неожиданным путём – для предсказуемости поставил 127.0.0.1:
DB_HOST=127.0.0.1
502 Bad Gateway
На сервере несколько пулов PHP-FPM. Nginx смотрел не на тот сокет. Указал явный путь /run/php/php8.2-fpm.sock и проверил, что сервис жив:
systemctl status php8.2-fpm
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
Папка uploads
К заявкам крепятся файлы. Сначала uploads лежала вне public – понадобился alias:
location /uploads/ {
alias /var/www/support.krivoshein.site/uploads/;
expires max;
log_not_found off;
access_log off;
}
Параллельно ловились 404: в URL одно имя файла, на диске другое. Для быстрого фикса скопировал каталог в public:
cp -r /var/www/support.krivoshein.site/uploads /var/www/support.krivoshein.site/public/
Аккуратнее по-laravel’овски – storage + symlink (когда будет время довести):
mv /var/www/support.krivoshein.site/public/uploads /var/www/support.krivoshein.site/storage/app/public/ php artisan storage:link
Несовпадение имён логотипов
Часть 404 была из-за путей в настройках: админка ждала одно имя, на диске лежало другое. Сверка директории:
ls -l /var/www/support.krivoshein.site/uploads/logo
И правка значений в БД:
UPDATE settings SET value = 'uploads/logo/logo-dark.png' WHERE name = 'dark_logo'; UPDATE settings SET value = 'uploads/logo/logo-light.png' WHERE name = 'light_logo'; UPDATE settings SET value = 'uploads/logo/favicon.png' WHERE name = 'favicon';
6. Финальная проверка
Сброс кэшей Laravel и reload Nginx:
php artisan config:clear php artisan cache:clear php artisan route:clear php artisan view:clear systemctl reload nginx
Логи на старте полезно подержать открытыми:
tail -f /var/log/nginx/support.krivoshein.site-error.log tail -f /var/www/support.krivoshein.site/storage/logs/laravel.log
Критерий «готово»: клиент создаёт заявку, вешает файл, стили и скрипты грузятся, админка видит тикеты.
7. Итог
Сейчас тикет-система живёт на support.krivoshein.site:
- клиенты ведут обращения в одном интерфейсе и видят прогресс;
- все заявки собраны в админке, проще расставлять приоритеты.
В планах: довести storage для вложений «по учебнику Laravel», автодеплой и более гибкие уведомления. На текущем уровне задача закрыта – быстрая и прозрачная поддержка без хаоса в мессенджерах.
