Решил я тут своё портфолио сделать на Laravel 7. Чтобы главная страница была лендингом, а всю информацию на ней можно было менять с помощью админки. Не суть. Дело дошло до деплоя. Нашел пару хороших туториалов, как это сделать на полноценном сервере со всеми заморочками. В деплое я не очень силен, я вообще больше фронт, чем фулстек. И, если писать и тестить на PHP я еще могу, то до управления сервером и т.п. я еще не дорос. Но пришлось разбираться.
Сейчас пройдемся по всем шагам, начиная с запуска через SSH и заканчивая рабочим сайтом. Постараемся обойти все подводные камни.
Возможно, вы сможете найти аналогичные инструкции в интернете. Ведь я же в конце концов нашел. Правда не в одном месте, не без помощи StackOverflow и вряд ли на русском. Я помучился. Поэтому решил вам жизнь упростить.
Делать мы всё будем с дроплетом на DigitalOcean. Это, конечно, необязательно, выбирайте любой хостинг. Дойдете до рабочего сервера на Ubuntu, возвращайтесь. Для тех, кто все же решил делать на DigitalOcean, будут еще советы по настройке домена. А также реферальная ссылка на 100$.
Все специфические для DigitalOcean шаги будут даны в подобных сносках.
Начнем.
Создаем пользователя
ssh root@[IP-адрес вашего дроплета]
adduser laravel
usermod -aG sudo laravel
su laravel
Добавляем ему SSH
mkdir ~/.ssh
chmod 700 ~/.ssh
vim ~/.ssh/authorized_keys
- Вставляем публичный ключ
chmod 600 ~/.ssh/authorized_keys
Фаервол
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status
Nginx
sudo apt update
sudo apt install -y nginx
sudo ufw allow 'Nginx HTTP'
sudo ufw status
MySQL
sudo apt install -y mysql-server
sudo mysql_secure_installation
,NYNNY
sudo mysql
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '<Ваш пароль для MySQL>';
SELECT user,authentication_string,plugin,host FROM mysql.user;
FLUSH PRIVILEGES;
exit
PHP
sudo apt update
sudo apt install -y curl wget gnupg2 ca-certificates lsb-release apt-transport-https
sudo apt-add-repository ppa:ondrej/php
sudo apt update
7.3:
sudo apt install -y php7.3-fpm php7.3-mysql
7.4:
sudo apt install -y php7.4-fpm php7.4-mysql
sudo vim /etc/nginx/sites-available/<Ваш домен>
Базовая настройка:
server {
listen 80;
root /var/www/html;
index index.php index.html index.htm index.nginx-debian.html;
server_name <Ваш домен или IP>;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
Только HTTP настройка под Laravel:
server {
listen 80;
listen [::]:80;
root /var/www/html/<Имя проекта>/public;
index index.php index.html index.htm index.nginx-debian.html;
server_name <Ваш домен или IP>;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
HTTPS настройка под Laravel:
server {
listen 80;
listen [::]:80;
server_name <Ваш домен> www.<Ваш домен>;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name <Ваш домен> www.<Ваш домен>;
root /var/www/html/<Имя проекта>/public;
ssl_certificate /etc/letsencrypt/live/<Ваш домен>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<Ваш домен>/privkey.pem;
ssl_protocols TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_prefer_server_ciphers on;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.php index.html index.htm index.nginx-debian.html;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
location ~ /\.ht {
deny all;
}
location ~ /.well-known {
allow all;
}
}
sudo ln -s /etc/nginx/sites-available/<Ваш домен> /etc/nginx/sites-enabled/
sudo unlink /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
Laravel
7.3:
sudo apt install -y php7.3-mbstring php7.3-xml composer unzip
7.4:
sudo apt install -y php7.4-mbstring php7.4-xml composer unzip
mysql -u root -p
CREATE DATABASE laravel DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
GRANT ALL ON laravel.* TO 'root'@'localhost' IDENTIFIED BY '<Ваш пароль от MySQL>';
FLUSH PRIVILEGES;
exit
cd /var/www/html
sudo mkdir -p <Имя проекта>
sudo chown laravel:laravel <Имя проекта>
cd ./<Имя проекта>
git clone <ссылка на проект> .
/git clone -b <имя ветки> --single-branch <ссылка на проект> .
composer install
vim .env
APP_NAME=Laravel
APP_ENV=production
APP_KEY=
APP_DEBUG=false
APP_URL=http://<Ваш домен>
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=<Ваш пароль от MySQL>
php artisan migrate
php artisan key:generate
sudo chown -R $USER:www-data storage
sudo chown -R $USER:www-data bootstrap/cache
chmod -R 775 storage
chmod -R 775 bootstrap/cache
HTTPS
sudo add-apt-repository ppa:certbot/certbot
sudo apt install -y python-certbot-nginx
sudo certbot certonly --webroot --webroot-path=/var/www/html/<Имя проекта>/public -d <Ваш домен> -d www.<Ваш домен>
sudo nginx -t
sudo ufw allow 'Nginx HTTPS'
sudo ufw status
sudo systemctl reload nginx
Создаем дроплет на DigitalOcean и регистрируем новый SSH-ключ
Я искренне верю, что вы сами разберетесь с регистрацией на DigitalOcean. Она непростая, с кучей верификаций и прочей байды. Если у вас при верификации с помощью документов постоянно возникает ошибка сети, попробуйте всё сделать через VPN, должно помочь.
В меню сверху нажимаем Create->Droplets. Выбираем Ubuntu.
Как только зарегистировались, вы получите 100$ на счет. Но не обольщайтесь. У вас есть всего 60 дней, чтобы их потратить. А это очень мало. Вы можете, как и я, захотеть использовать план подороже, чтобы потом, когда уже пойдут реальные деньги, пересесть на подешевле. Сразу говорю, не получится. Увеличивать можно, уменьшать нельзя. Такие дела. Я выбираю Standard->$5.
Регион я выбираю ближайший к нам Frankfurt. VPC Network->default-fra1
Аутентификацию сразу сделаем через SSH. Нажимаем New SSH Key. Если у вас нет SSH, справа есть очень простая инструкция. Открываем bash-терминал, вставляемssh-keygen
. Потом заходим в файл с публичным ключом/Users/<Ваше имя пользователя>/.ssh/id_rsa.pub
(или простоcat ~/.ssh/id_rsa.pub
), копируем содержимое и вставляем в окно слева. Имя любое.
Придумываем для дроплета хостнейм.
Нажимаем Create Droplet
Создаем нового пользователя
ssh root@[IP-адрес вашего дроплета]
- Are you sure you want to continue connecting (yes/no/[fingerprint])?
yes
- Введите ваш пароль от SSH
- Создаем пользователя laravel:
adduser laravel
- Введите пароль и другую информацию (я ввожу только Full Name)
- Добавляем пользователя в группу sudo:
usermod -aG sudo laravel
SSH для нового пользователя
- Переключаемся на нового пользователя:
su laravel
Все действия далее, до конца статьи, мы проводим от имени пользователя laravel. Поэтому, если вы вдруг прервались, перезайдите и введите su laravel
mkdir ~/.ssh
chmod 700 ~/.ssh
vim ~/.ssh/authorized_keys
Мы открыли файл в Vim. Если вы с ним не знакомы вообще, можете работать в Nano, ваше право.
Для того, чтобы по ходу статьи пользоваться редактором Vim, вам достаточно знать следующее.
- В Vim есть разные режимы: обычный (Normal mode), в котором вы вводите команды и выбираете режимы и остальные.
- Чтобы выйти из любого режима и попасть в обычный режим достаточно нажать
Esc
- Передвигаться: можно просто стрелками
- Выйти без сохранения
<Normal mode>
::q!
- Выйти и сохранить
<Normal mode>
::wq
- Перейти в режим ввода текста
<Normal mode>
:i
(от англ. insert)
- Вставляем наш публичный ключ (который мы делали выше)
- Защищаем от изменений:
chmod 600 ~/.ssh/authorized_keys
Устанавливаем фаервол
- Смотрим все доступные настройки:
sudo ufw app list
- Разрешаем OpenSSH (иначе нас залочит):
sudo ufw allow OpenSSH
- Запускаем фаервол:
sudo ufw enable
,y
- Проверяем:
sudo ufw status
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
Все в порядке.
Устанавливаем Nginx
При установке вас иногда будет спрашивать "Вы уверены?". Отвечайте y
(ну только, если уверены).
sudo apt update
sudo apt install nginx
Добавляем Nginx в настройки фаервола
sudo ufw app list
sudo ufw allow 'Nginx HTTP'
sudo ufw status
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
Nginx HTTP ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
Nginx HTTP (v6) ALLOW Anywhere (v6)
Перейдите по вашему IP. Если все идет хорошо, вы должны увидеть следующее.
Устанавливаем MySQL
sudo apt install mysql-server
- Запускаем автоматический скрипт по защите
sudo mysql_secure_installation
Ответьте на поставленные вопросы. Если вы не знаете, что отвечать, вот рекомендуемые варианты:
Validate password plugin —
N
Remove anonymous users? —
Y
Disallow root login remotely? —
N
Remove test database and access to it? —
N
Reload privilege tables now? —
Y
Заходим в MySQL:
sudo mysql
Смотрим методы доступа:
SELECT user,authentication_string,plugin,host FROM mysql.user;
Устанавливаем пароль для root:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '<Ваш пароль для MySQL>';
Смотрим методы доступа снова:
SELECT user,authentication_string,plugin,host FROM mysql.user;
Применяем изменения и выходим из MySQL:
FLUSH PRIVILEGES;
иexit
Теперь, чтобы войти в MySQL нужно использовать
mysql -u root -p
и вводить пароль
Устанавливаем PHP
Воспользуемся сторонним репозиторием от Ondrej Sury
sudo apt update
sudo apt install -y curl wget gnupg2 ca-certificates lsb-release apt-transport-https
sudo apt-add-repository ppa:ondrej/php
sudo apt update
Теперь выбираем. Для Laravel 7 можно выбрать PHP 7.3 или 7.4. Отличие будет лишь в цифрах 3 и 4.
- 7.3:
sudo apt install -y php7.3-fpm php7.3-mysql
- 7.4:
sudo apt install -y php7.4-fpm php7.4-mysql
PHP FastCGI Process Manager (fpm) работает с PHP запросами. mysql, естественно, для работы с MySQL.
Дальше я все буду делать на 7.4.
Настраиваем Nginx
sudo vim /etc/nginx/sites-available/<Ваш домен>
Вместо "<Ваш домен>" впишите домен (например, mysite.ru
), который хотите использовать в будущем. Если у вас такого пока нет, пишите любой, потом просто повторите действия в этой главе для своего домена, когда выберите его.
Вписываем следующее:
server {
listen 80;
root /var/www/html;
index index.php index.html index.htm index.nginx-debian.html;
server_name <Ваш домен или IP>;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
Если Вы выбрали версию 7.3 вместо php7.4-fpm.sock
впишите php7.4-fpm.sock
.
Слушаем 80 порт на server_name
, когда приходим запрос в корне /var/www/html
берем index-файл. Если после server_name
что-то есть, ищем такой файл. Не находим, выбрасываем 404. Если заканчивается на .php
, прогоняем через fpm
. Если есть .ht
, запрещаем (403).
- Делаем ссылку из
sites-available
вsites-enabled
:sudo ln -s /etc/nginx/sites-available/<Ваш домен> /etc/nginx/sites-enabled/
- Удаляем ссылку на
default
:sudo unlink /etc/nginx/sites-enabled/default
- Проверяем на ошибки:
sudo nginx -t
- Перезагружаем:
sudo systemctl reload nginx
Проверяем работу:
sudo vim /var/www/html/info.php
- Пишем:
<?php phpinfo();
- Переходим на
<Ваш IP>/info.php
Вы должны увидеть что-то подобное:
Теперь этот файл можно удалить: sudo rm /var/www/html/info.php
Ставим Laravel
7.3:
sudo apt install php7.3-mbstring php7.3-xml composer unzip
7.4:
sudo apt install php7.4-mbstring php7.4-xml composer unzip
Заходим в MySQL:
mysql -u root -p
Создаем БД с именем laravel:
CREATE DATABASE laravel DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
Предоставляем root доступ к laravel:
GRANT ALL ON laravel.* TO 'root'@'localhost' IDENTIFIED BY '<Ваш пароль от MySQL>';
FLUSH PRIVILEGES;
exit
cd /var/www/html
Создаем папку для проекта:
sudo mkdir -p <Имя проекта>
Предоставляем пользователю laravel права на проект:
sudo chown laravel:laravel <Имя проекта>
Далее нужно перенести проект. Например, клонированием с Github.
cd ./<Имя проекта>
git clone <ссылка на проект> .
Стоит учитывать, что, если вы не сохраняли статические файлы (например, из /public
) на Github, то их у вас, естественно, не будет. Я, например, для решения этого создал отдельную ветку deploy
, из которой уже и клонировал: git clone -b <имя ветки> --single-branch <ссылка на проект> .
.
- Устанавливаем зависимости:
composer install
- Создаем .env:
vim .env
Базовая версию его выглядит так:
APP_NAME=Laravel
APP_ENV=production
APP_KEY=
APP_DEBUG=false
APP_URL=http://<Ваш домен>
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=<Ваш пароль от MySQL>
Если вы копируете свой .env, замените APP_ENV на production, APP_DEBUG на false и впишите правильные настройки для MySQL.
- Мигрируем БД:
php artisan migrate
- Генерируем код:
php artisan key:generate
Меняем разрешения:
sudo chown -R $USER:www-data storage
sudo chown -R $USER:www-data bootstrap/cache
chmod -R 775 storage
chmod -R 775 bootstrap/cache
Последнее, что осталось, – перенастроить Nginx под Laravel:
sudo vim /etc/nginx/sites-available/<Ваш домен>
server {
listen 80;
listen [::]:80;
root /var/www/html/<Имя проекта>/public;
index index.php index.html index.htm index.nginx-debian.html;
server_name <Ваш домен или IP>;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}
Как и в прошлый раз, если Вы выбрали версию 7.3 вместо php7.4-fpm.sock
впишите php7.4-fpm.sock
.
Настройка домена на DigitalOcean
Всё, на самом деле, очень просто. Вы покупаете домен (где угодно), переходите на DigitalOcean в Create->Domains/DNS. В поле Add a domain вы вписываете этот домен, нажимаете добавить. Затем переходите в настройки домена и в поле HOSTNAME вписываете @. Выбираете проект и нажимаете Create record.
Теперь переходите на сайт, где покупали домен, находите там "DNS Серверы" (или что-то подобное) и вписываете серверы DigitalOcean (а именноns1.digitalocean.com
,ns2.digitalocean.com
,ns3.digitalocean.com
). Теперь надо немного (или много) подождать, пока эти настройки будут приняты. Готово!
Единственная проблема – у вас сайт будет открываться только как HTTP. Чтобы был HTTPS, переходим к следующей части.
Настроиваем HTTPS
Устанавливаем certbot и передаем ему имя домена (формата mysite.ru
) и имя домена с www (www.mysite.ru
).
sudo add-apt-repository ppa:certbot/certbot
sudo apt install python-certbot-nginx
sudo certbot certonly --webroot --webroot-path=/var/www/html/<Имя проекта>/public -d <Ваш домен> -d www.<Ваш домен>
Теперь надо перенастроить Nginx (не забудьте подставить свои значения):
server {
listen 80;
listen [::]:80;
server_name <Ваш домен> www.<Ваш домен>;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name <Ваш домен> www.<Ваш домен>;
root /var/www/html/<Имя проекта>/public;
ssl_certificate /etc/letsencrypt/live/<Ваш домен>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<Ваш домен>/privkey.pem;
ssl_protocols TLSv1.2;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_prefer_server_ciphers on;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.php index.html index.htm index.nginx-debian.html;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
location ~ /\.ht {
deny all;
}
location ~ /.well-known {
allow all;
}
}
Думаю, вы уже поняли, что нужно поменять для PHP 7.3.
Тут, на самом деле, все просто. Мы просто перенаправляем все запросы с HTTP (порт 80) на HTTPS (порт 443). А там делаем все тоже самое, что и раньше, но уже с шифрованием.
Осталось поставить разрешения в фаерволе:
sudo nginx -t
sudo ufw app list
sudo ufw allow 'Nginx HTTPS'
sudo ufw status
sudo systemctl reload nginx
Теперь все должно работать, как надо.
[Дополнительно] Установка Node.js
Если вдруг вам понадобилось запускать npm-команды прямо на сервере, вам нужно установить Node.js.
sudo apt update
sudo apt install -y nodejs npm
nodejs -v
Всё, я остановился на этом этапе. В принципе, результат меня устраивает. Возможно, я перейду с DigitalOcean куда-нибудь поближе к России и подешевле. Но так как я уже прошел все круги верификации на сайте и всё делал там, я показывал на их примере. К тому же их стартовые 100 долларов – отличный плацдарм для тренировок.
P.S. Отдельная благодарность автору вот этого гиста, который послужил основой всех вышеперечисленных действий. Он в некоторых моментах не работает для Laravel 7, я это поправил.
P.P.S. Если вы вдруг топовый инженер, который думает командами из bash, пожалуйста, не судите строго. Возможно, вам уровень этой статьи покажется низковатым, но я был бы рад найти такую, когда она мне была нужна. Если есть предложения по улучшению, я обеими руками "за".
teamfighter
Один вопрос. Как масштабироваться будете?
Вот у вас взлетел ваш проект и завтра к вам пришли 100000 уников. И ваш сайт приказал долго жить.
Я не работал с DO, поэтому предложил бы использовать AWS ECS. ECS (Elastic container service) это некий аналог кубернетеса от AWS. Запаковываете ваш ларавел в докер контейнер, создаете ECS кластер, таск дефинишн для сервиса, сервис с лоад балансером, пихаете всё это хозяйство туда. Тип раннеров fargate.
Монтируете AWS EFS (Elastic file storage) в места контейнера где нужен persistent storage (типа /var/www/data — но лучше бы все хранить в базах. Например в аналоге монги — Dynamodb).
Создаете RDS под базу данных, добавляете в переменные окружения креды для подключения.
Закрываете все снаружи AWS Cloudfront.
Все, вы восхитительны. По деньгам с учетом AWS Free tier будет стоить также, но ВСЮ инфру можно описать через тот же terraform или CloudFormation, а также например настроить пайплайны для автоматизации деплоя изменений laravel. Я уж не говорю о том что если проект выстрелит, то масштабировать его сможете за 15 минут с перекурами под любую нагрузку.
А если уж говорить про ваш метод — то и тут лучше бы воспользоваться terraform+ansible например.
Ручные изменения на любом сервере — зло.
Все вышесказанное является моим личным мнением и никоим образом не принижает нужности вашей статьи. К сожалению, многие все еще делают так)
anonymous
Автор все-таки решал конкретную задачу — хостинг своего портфолио. А не хостинг проекта, который может выстрелить и потребовать масштабирования.
evgeniyPP Автор
Тоже верно. Для портфолио даже то, что я сделал — оверкилл. Моё старое было на Gatsby и хостилось на бесплатных мощностях Zeit Now/Vercel.
evgeniyPP Автор
Я не говорю, что мой подход, — production-ready best practice. Я сам новичок во всем этом. Спасибо за предложение, я обязательно разберусь. Вполне возможно, ваш вариант лучше.